目录
Sass基础
Sass整体介绍
Sass是一种CSS扩展语言,同时Sass也是一种CSS预处理工具
Sass官网:http://www.sass-lang.com/
Sass中文网:https://www.sass.hk/
CSS预处理工具
我们需要一些类似CSS的前置文件,通过对这些前置文件的编译与解析,最终生成浏览器可识别的CSS文件
常见的CSS预处理工具有:Sass、less、stylus,三者在语法、编译环境、工具库上都有异同和各自优劣之处
Sass工作流程
.sass文件与.scss文件的区别
<!-- .sass -->
#sidebar
width:30%;
background-color:#faa
<!-- .scss -->
#sidebar {
width:30%;
background-color:#faa
}
Sass能帮助我们解决什么问题
嵌套规则
通过花括号的方式解决复杂的css父子样式嵌套问题
变量规则
通过变量将公共样式抽离,减少冗余css代码
条件逻辑
像高级语言一样编写逻辑性的css代码
Sass环境安装
- 安装Sass之前要先安装Ruby,因为Sass是基于Ruby这个语言开发的,首先打开Ruby官网:http://www.ruby-lang.org/zh_cn/
- 首先检查电脑上是否有自带的Ruby,在命令行工具中键入:ruby -v,如果显示版本号,说明电脑中已安装有ruby,否则到官网上下载ruby安装包(需要用梯子,否则很慢)
- 安装时记得勾选Add Ruby executable to your PATH,会自动添加ruby路径到环境变量。
- 安装完成后,打开cmd,键入:ruby -v,显示版本号,安装成功。
- 下面来安装sass,在cmd中键入:gem install sass,再键入:sass -v,若出现版本号说明安装成功。
- 安装完sass,要对sass进行编译,编译sass有很多种方式:
命令行方式
略
使用sublime SassBuild插件
- 新建一个文件夹,在cmd中键入:cd,并把新建文件夹拖拽到cmd窗口中,自动生成绝对路径
- 进入新建文件夹后,在cmd中键入:mkdir test,新建一个名为test的文件夹
- 在cmd中键入:cd.>dome.scss,新建一个与test文件夹同级的dome.scss文件,把dome.css放进test文件夹中
- 在dome.css文件中写入一些样式,比如:
$abc:#ff0;
.div{
color:$abc;
}
- 接下来安装sass插件,由于我们没有package control,所以要下载一个,点击View→Show Console,在控制台输入:
import urllib.request,os; pf = 'Package Control.sublime-package';
ipp =sublime.installed_packages_path();
urllib.request.install_opener( urllib.request.build_opener( urllib.request.ProxyHandler()) );
open(os.path.join(ipp, pf), 'wb').write(urllib.request.urlopen('http://sublime.wbond.net/' + pf.replace(' ','%20')).read())
- 这时候package control就出现了,打开并键入:install package,然后在弹出的窗口中输入sass build,点击安装
- 安装成功后,点击Tools→Build System→SASS(如果选择SASS-Compressed,会将css文件编译成压缩风格)
- 这时候对dome.css中的样式进行修改,然后ctrl+B(Build)进行编译,会发现同一目录下生成了一个dome.css文件,自动将scss文件编译成css文件
- 为了更方便地进行sass样式的修改和编译,将ctrl+B集成到ctrl+S中,还是打开package control,键入:install package,再键入:sublimeOnSaveBuild,这样再去改动sass文件,然后ctrl+S保存,就会自动编译了。
使用koala软件
koala官网:http://koala-app.com/
- 在koala中打开test文件夹,删除原来的dome.css用作测试
- 在右侧options中勾选编译文件的要求以及格式,点击compile,右键dome.scss文件,点击set Output Path,弹出文件所在目录,可以看到dome.css文件也被成功编译了。
Sass核心基础知识
Sass变量和引用
变量格式
在sass中,同样是后定义的覆盖先定义的,但在变量后加上!default声明之后,它就可以被在它之前定义的同一属性的属性值覆盖
sass中也可以定义字符串变量,插值变量可以把字符串转换成非字符串
$width: 300px;
$height: 300px;
$color: #e03434;
$baseWidth:200px;
$baseWidth:300px; //变量baseWidth的值被覆盖为300px
$baseWidth:100px !default; //默认属性,虽然定义在最后,但同一变量名下它的优先级最低,会被300覆盖
$str: 'hello.jpeg';
$class:'div';
.div1 {
width: $width;
height: $width;
border: 1px solid $color;
background-image: url('./img/'+$str);
background-size: contain;
}
.div2 {
width: $baseWidth; <!-- 取300px -->
height: $width;
border: 1px solid $color;
background-image: url('./img/'+$str);
//sass中提供插值变量语法
//background-image: url('./img/#{$str}');
background-size: contain;
}
#{$class}{ <!-- #{'div'}→div -->
width:$width;
height:$height;
}
变量类型
变量作用域
Sass的变量的作用域是基于{}的,{}内可以正常使用,{}外是无法找到的
$width:300px;
$color:#ffee932;
.div1{
width:$width;
height:$width;
$widthInner:100px;
}
.div2{
width:$widthInner; //编译出错,div1外部不能引用内部定义的变量
}
=========================================================
.div1{
height:$width;
$widthInner:100px;
width:$widthInner; //编译成功,div1内部定义的变量可以在内部使用
}
.div2{
width:$width; //只能引用最外层定义的变量
}
import规则
当满足以下四种条件中的任何一个时,不会转换成Sass中的特有语法,而是保留css的import语法:
- 引入的是css文件
- 引入以http://为开头的文件
- 引入文件名是一个url()的文件
- 引入任何有media queries
Sass中import能将不同的文件集中import,可以将不同类别的文件定义在不同的Sass中,从而合成一个完整的css文件进行编译
@import 'org.css'; //第一种情况,仍是css中的import,不会进行集中编译
$width:300px;
$color:#ffe932;
用Partials方法解决:将要引入的css文件命名为以_开头,然后在引入过程中去掉_和扩展名
//新建一个_base.scss文件,写入一些样式
//在另一个css文件中引入
@import 'base'; //不加_也不加扩展名
说明:在什么位置import,被引入的样式表就会出现在什么地方,但这样会导致一些我们不想看到的覆盖问题,为了解决这个问题,需要用到!default定义方式给被引入的css文件中的属性设置默认值,这样属性值的覆盖与否就不会依赖于引入css样式表的位置
Sass数据类型
number类型
如$width:300px、$zoomValue:2
/*number*/
$width:300px;
$zoomValue:2;
.div{
widht:$width;
height:$width;
zoom:$zoomValue;
}
color类型
如$color:red、$:colorHex:#ffe932
/*color*/
$color:red;
$colorHex:#ffe932;
.div{
color:$color;
background-color:$colorHex;
}
string类型
如$str:'hello.jpeg'; url('images/'+$str);
/*string*/
$str:'hello.jpeg';
.div{
background-image:url('images/'+$str);
}
数组类型
如$list:(100px,200px,'string',2);数组中的元素可以是任意类型,也可以是不同类型
/*list*/
$list:(100px,200px,'string',2);
.div{
width:nth($list,1); //Sass数组下标从1开始,这里width为100px
height:nth($list,2);
zoom:index($list,'string'); //zoom:3
}
map类型
如$map:(top:1px,left:2px,bottom:3px,left:4px);
/*map*/
$map:(top:1px,left:2px,bottom:3px,right:4px);
.div{
top:map-get($map,top);
left:map-get($map,left);
}
/*循环遍历map,左边key是样式名,右边value是样式值*/
.div{
@each $key,$value in $map{
#{$key}:$value;
}
}
//渲染结果如下
.div{
top:1px;
left:2px;
bottom:3px;
right:4px;
}
Sass变量运算
Sass在进行乘除运算时,一般只需要其中一个具体操作数带单位,并且要用()括起来。如果用变量的方式进行乘除运算,则不需要带()。
/*加减乘除*/
$num1:100px;
$num2:200px;
$width:$num1+$num2;
.div{
width:$width;
}
.div{
font:10px/8px; //这种写法是错误的
font:(10px/8); //1.25px
font:(10px*8); //80px
width:$width/2; //150px
margin-left:(5px+8px/2); //9px,遵循混合运算的规则
}
/*颜色运算*/
$color1:#010203;
$color2:#040506;
$color3:#a69e61;
.div{
color:$color1+$color2; //#050709,直接对颜色进行数值相加,但不推荐使用这种方法
color:mix($color1,$color2); //#030405,,取两个颜色的混合色,具有现实意义,推荐使用mix()方法
color:red($color1); //1,获得该颜色对应的rgb值中red的数值
color:red($color3); //166
color:green($color3); //158,获得该颜色对应的rgb值中green的数值
color:rgb(red($color3),green($color3),blue($color3)); //#a69e61
}
/*字符串*/
$str:'hello.jpeg';
.div{
background-image:url('images/'+$str);
}
Sass mixin(混合宏)
定义方法:@mixin mixin名称 {样式名:样式值 ……};
引用方法:@include mixin名称;
/*一般mixin*/
@mixin helloMixin{
display:inline-block;
font:{
size:20px;
weight:500;
};
color:red;
}
.div{
@include helloMixin;
}
//编译结果如下
.div{
display:inline-block;
font-size:20px;
font-weight:500;
color:red;
}
/*嵌套mixin*/
@mixin helloMixin2{
padding:10px;
@include helloMixin;
background-color:red;
}
.div{
width:100px;
@include helloMixin2;
}
//编译结果
.div{
width:100px;
padding:10px;
display:inline-block;
font-size:20px;
font-weight:500;
color:red;
background-color:red;
}
/*参数mixin*/
@mixin sexy-border($color,$width){
border:{
color:$color;
width:$width;
style:dashed;
};
}
.div{
width:100px;
@include helloMixin2;
}
.div{
@include sexy-border(blue,2px);
}
Sass继承和嵌套
简单继承
/*简单继承*/
.div{
border:1px;
background-color:red;
}
.divext{
@exttend .div
border-width:3px;
}
//编译结果
.div, .divext{
border:1px;
background-color:red;
}
.divext{
border-width:3px;
}
关联属性继承
/*关联属性继承*/
.div1{
border:1px;
background-color:red;
}
.div1.other{
background-image:url('hello.jpeg');
}
.divext{
@extend .div1;
}
//编译结果
.div1, .divext{
border:1px;
background-color:red;
}
.div1.other, .other.divext{
background-image:url('hello.jpeg');
}
链式继承
/*链式继承*/
.div1{
border:1px solid #000;
}
.div2{
@extend .div1;
color:red;
}
.div3{
@extend .div2;
color:#000;
}
//编译结果
.div1, .divext, .div2, .div3{
border:1px solid #000;
}
.div2, .div3{
color:red;
}
.div3{
color:#000;
}
伪类继承
/*伪类继承*/
a:hover{
text-decoration:underline;
}
.hoverlink{
color:red;
@extend :hover;
}
//编译结果
a:hover, a.hoverlink{
text-decoration:underline;
}
.hoverlink{
color:red;
}
选择器嵌套
$width:300px;
$color:#fff;
.div1{
width:$width;
height:$width;
background-color:$color;
.div-inner{
width:$width;
height:$width;
background-color:$color;
.div-inner-inner{
width:$width;
height:$width;
background-color:$color;
}
}
a{
color:red;
}
}
//编译结果
.div1{
width:$width;
height:$width;
background-color:$color;
}
.div1 .div-inner{
width:$width;
height:$width;
background-color:$color;
}
.div1 .div-inner .div-inner-inner{
width:300px;
height:300px;
background-color:#color;
}
.div1 a{
color:red;
}
属性嵌套
在css中以-分离的属性都可以使用嵌套
.div1{
width:$width;
height:$width;
background-color:#color;
.div-inner{
border:{
left:1px solid #000;
top:2px solid #000;
};
background:{
image:url('abc.png');
color:#000;
}
}
}
//编译结果
.div1{
width:$width;
height:$width;
background-color:#color;
}
.div1 .div-inner{
border-left:1px solid #000;
border-top:2px solid #000;
background-image:url('abc.png');
background-color:#000;
}
Sass条件控制
@if
$type:'tony';
p {
@if $type=='bufy'{
color:red;
}@else if $type=='tim'{
color:blue;
}@else if $type=='tony'{
color:green;
}@else{
color:black;
}
}
//编译结果
p{
color:green;
}
======================================================
@if还可以写在括号外面
@if $type=='bufy'{
.div{
color:red;
}
}@else{
.div{
color:blue;
}
}
//编辑结果
.div{
color:blue;
}
@for
@for $i from 1 through 3{ //i是自增量
.item#{$i} {
width:1px*$i;
}
}
//编译结果
.item1{
width:1px;
}
.item2{
width:2px;
}
.item3{
width:3px;
}
==========================================
这里through如果改为to则自增量i的值不会取到3
@for $i from 1 to 3{ //i是自增量
.item#{$i} {
width:1px*$i;
}
}
//编译结果
.item1{
width:1px;
}
.item2{
width:2px;
}
=========================================
/*forlist*/
$list:(1,2,3,4,5);
@for $i from 1 through length($list){ //length()是内置函数
.item#{$i} {
width:1px*$i;
}
}
//编译结果
.item1{
width:1px;
}
.item2{
width:2px;
}
.item3{
width:3px;
}
.item4{
width:4px;
}
.item5{
width:5px;
}
@while
$i:6;
@while $i>0 {
.item#{$i}{
width:1px*$i;
}
$i:$i-2; //设置自增量的步长
}
.item6{
width:6px;
}
.item4{
width:4px;
}
.item2{
width:2px;
}
@each
$map:(top:1px,left:2px,bottom:3px,right:4px);
.div{
@each $key,$value in $map{ //$key和$value是特殊变量,表示map中的键和值不能更改名称
#{$key}:$value;
}
}
//编译结果
.div{
top:1px;
left:2px;
bottom:3px;
right:4px;
}
Sass内置函数
Number函数
- percentage($number):转换成百分比
- round($number):执行标准舍入,即总是将数值四舍五入为最接近的整数
- ceil($number):执行向上舍入,即它总是将数值向上舍入为最接近的整数
- floor($number):执行向下舍入,即它总是将数值向下舍入为最接近的整数
- abs($number):获取绝对值
- min($number):获取最小值
- max($number):获取最大值
- random():获取随机数
$number:70;
$number2:71;
$numberPercent:7;
$numberRound:25.9;
$abs:-3;
.div{
zoom:percentage($numberPercent); //编译结果zoom:700%;
zoom:round($numberRound); //编译结果为zoom:26;
zoom:ceil($numberRound); //编译结果为zoom:26;
zoom:floor($numberRound); //编译结果为zoom:25;
zoom:abs($abs); //编译结果为zoom:3;
zoom:min($number,$number2); //编译结果为zoom:70;
zoom:max($number,$number2); //编译结果为zoom:71;
zoom:random(); //从0到1取一个随机数
zoom:random(10); //从0到10取一个整数随机数
zoom:random(100); //从0到100取一个整数随机数
}
数组内置函数
- length($list):获取数组长度
- nth($list,$n):获取指定下标的元素,下标从1开始
- set-nth($list,$n,$value):替换指定下标的元素
- join($list1,$list2):拼接数组
- append($list,$val,[$separator]):从数组尾部添加元素
- index($list,$value):返回指定元素在数组中的位置
/*list*/
$list:(1,'p',3,4,5);
.div{
zoom:length($list); //编译结果:zoom:5;
zoom:nth($list,2); //编译结果:zoom:"p";
zoom:length($list); //编译结果:zoom:5;
@debug set-nth($list,1,'x'); //控制台打印"x","p",3,4,5
@debug join($list,(6,7,8)); //控制台打印1,"p",3,4,5,6,7,8
@debug append($list,'999'); //控制台打印1,"p",3,4,5,"999"
@debug index($list,'p'); //控制台打印2
}
字符串内置函数
- unquote($string):去除引号
- quote($string):添加引号
- str-length($string):获取字符串长度
- str-insert($string,$insert,$index):在指定位置插入字符
- str-index($string,$substring):返回指定字符在字符串的位置
- to-upper-case($string):转换成大写
- to-lower-case($string):转换成小写
/*string*/
$string:'hello';
$stringNo:hello;
$stringUpper:'HELLO';
.div{
background-image:unquote($string); //编译结果为background-image:hello;
background-image:quote($stringNo); //编译结果为background-image:'hello';
background-image:str-length($string); //编译结果为background-image:5;
@debug str-insert($string,'p',2); //编译结果为background-image:'hpello';
@debug str-index($string,'l'); //编译结果为background-image:3;返回第一次出现的位置
@debug to-upper-case($string); //编译结果为background-image:'HELLO';
@debug to-lower-case($stringUpper); //编译结果为background-image:'hello';
}
map内置函数
- map-get($map,$key):根据给定的key值,返回map中相关的值
- map-merge($map1,$map2):将两个map合并成一个新的map
- map-remove($map,$key):从map中删除一个key,返回一个新map
- map-keys($map):返回map中所有的key
- map-values($map):返回map中所有的value
- map-has-key($map,$key):根据给定的key值判断map是否有对应的value值,如果有返回true,否则返回false
- keywords($args):返回一个函数的参数,这个参数可以动态的设置key和value
/*map*/
$map: (top: 1px, left: 2px, bottom: 3px, right: 4px);
.div {
width:map-get($map,left); //编译结果为:width:2px;
@debug map-remove($map,left); //编辑结果为(top: 1px, bottom: 3px, right: 4px)
@debug:map-keys($map); //top,left,bottom,right
@debug:map-values($map); //1px,2px,3px,4px
@debug:map-has-key($map,top); //true
@debug:map-has-key($map,abc); //false
}
@mixin foo($args...) {
@debug keywords($args); //(arg1:"abc",arg2:"def")
}
@include foo($arg1: 'abc', $arg2: 'def');
自定义函数使用方法
/*自定义函数*/
$rem1 : 100px;
@function px2rem($px) {
$rem : 37.5px;
@debug $px;
@return ($px / $rem) + rem;
}
.div {
width: px2rem($rem1);
}
Vue基础详解
Vue具有组件化的、快速开发的特点
Vue的生命周期
beforeCreate 组件刚刚被创建
在实例初始化之后,数据观测(data observer)和event/datcher事件配置之前被调用。这里不允许用箭头函数,因为箭头函数没有this。
created 组件创建完成
在实例创建完成后立即被调用,在这一步,实例已完成以下的配置:数据观测(data observer),书型盒额方法的运算,watch/event事件回调。然后挂载阶段还没开始,$el属性目前不可见。
beforeMount 挂载之前
在挂载开始之前被调用,相关的渲染函数首次被调用
mounted 挂载之后【重要】
ajax请求大部分在mounted中进行,真实的dom操作也在mounted中进行。el被新创建的vm.$el替换,挂载成功
beforeUpdate 数据更新时调用
Updated 组件DOM已经更新,组件更新完毕
beforeDestory 组件销毁前调用
实例销毁前调用,在这一步,实例仍然完全可用
destoryed 组件销毁后调用
Vue实例销毁后调用。调用后,Vue实例指示的所有东西都会解绑定,所有的事件监听器会被移除
安装Vue
全局安装vue-cli
先安装node.js,在git上查看node版本和npm版本,如果显示版本号说明安装成功
#git
$node -v
$npm -v
下面安装vue-cli
#git
$npm install --global vue-cli
由于安装npm要访问国外网站资源,速度很慢,我们可以使用淘宝npm镜像cnpm
$npm install -g cnpm --registry=http://registry.npm.taobao.org
$cnpm install --global vue-cli
创建一个基于webpack模板的新项目
$vue init webpack my-project
设置项目相关信息,记得Install vue-router?(Y/n)输入Y,后面的都可以输入n。创建成功,ctrl+c退出。打开my-project,最初的项目结构vue已搭建成功。
安装依赖包
#git
$cd my-project
$npm install
$npm run dev
这里我在运行npm run dev后,发现localhost:8080是无法打开的,试了网上很多种方法都没有解决, 把host改为ip地址也没用,最后在解决Edge不能打开任何网页的过程,控制面板→网络和Internet→Internet选项→高级→重置,就解决了。(歪打正着,不知道原因是什么)
新建页面
在my-project的src文件夹下新建一个pages目录,在pages目录中新建一个demo1目录,在demo1目录下新建一个index.vue
#index.vue
<template>
<div>
hiyoritsai
</div>
</template>
配置路由
- path是访问的路径
- name是页面名称
- component是显示的页面,页面上的LOGO可以到app.vue中删除
配置方法一(可能会报错)
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld' //@就是src的缩写
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
},
{
path:'/demo1',
name:'demo1',
component:require("@/pages/demo1/index.vue") //@就是src的缩写,component写出页面所在位置
}
]
})
配置方法二
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import Demo1 from '@/pages/demo1/index.vue' //用引入的方式
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
},
{
path:'/demo1',
name:'demo1',
component:Demo1 //使用引入的Demo1
}
]
})
生命周期函数
<template>
<div>
hiyoritsai
</div>
</template>
<script>
export default{
data(){
return{
}
},
beforeCreate(){ //组件生成时自动调用
console.log('beforeCreate');
},
created(){
console.log('created');
},
beforeMount(){
console.log('beforeMount');
},
mounted(){
console.log('mounted');
}
}
</script>
选项数据
data
新建一个demo2,用前面说到的配置路由方法将demo2添加进去
data函数中定义我们要使用的数据,定义的变量可以渲染到模板上,这就叫数据绑定
data是全局组件变量的定义,我们在template中用{{ }}输出data函数中定义的变量,就叫做变量绑定
<template>
<div>
<div>haha</div>
<div>{{msg}}</div>
</div>
</template>
<script type="text/javascript">
export default{
data(){
return{
msg:'hiyoritsai'
}
}
}
</script>
computed
一个函数,用来绑定函数
<template>
<div>
<div>haha</div>
<div>{{msg}}</div>
</div>
</template>
<script type="text/javascript">
export default{
data(){
return{
msg:'hiyoritsai'
}
},
computed:{
}
}
</script>
methods
methods也是一个函数,它是给事件用的,用来绑定事件
<template>
<div>
<div>haha</div>
<div>msg</div>
<div @click="say('hi')">点击我</div> //一个事件
</div>
</template>
<script type="text/javascript">
export default{
data(){
return{
msg:'hiyoritsai',
num:1
}
},
computed:{
aDouble(){
return this.num*2;
}
},
methods:{
say(h){
alert(h);
}
}
}
</script>
模板语法
data
data中有许多变量,这些变量是服务于整个组件的,包括模板和定义的js函数。数据绑定就是用{{ }}去绑定data中定义的变量,要实现响应式就必须把数据在data中进行注册,没有在data中注册的变量是不会随着变量的修改重新渲染的,但如果不想让变量的变化被追踪,可以用Object.freeze()
<template>
<div>
<div>模板语法</div>
<div>
data:{{msg}}
</div>
</div>
</template>
<script type="text/javascript">
export default{
data(){
return{
msg:'hiyoritsai'
}
}
}
</script>
模板中嵌入js代码
<template>
<div>
<div>模板语法</div>
<div>
number:{{number+1}} <!--这是一个js表达式,页面中显示3-->
</div>
</div>
</template>
<script type="text/javascript">
export default{
data(){
return{
number:2
}
}
}
</script>
指令v-html、v-bind、v-on
v-html:快速生成一个子标签插入到元素中
<template>
<div>
<div>模板语法</div>
<div v-html="rawHtml"></div> <!--<div><span>123</span></div>-->
</div>
</template>
<script type="text/javascript">
export default{
data(){
return{
rawHtml:'<span>123</span>'
}
}
}
</script>
v-bind:可以动态地与data进行绑定
<template>
<div>
<div>模板语法</div>
<div v-bind:class="red"></div>
<div @click="change">修改颜色</div> //触发事件
</div>
</template>
<script type="text/javascript">
export default{
data(){
return{
red:'red active' //class名变成了一个变量
}
},
methods:{
change(){ //事件写在methods中
this.red='blue'; //动态改变class名
}
}
}
</script>
v-on: 用来绑定事件
<template>
<div>
<div>模板语法</div>
<div v-on:click="say('hi')">点击我</div>
<!--上条语句的简写方式就是@click="say('hi')"-->
</div>
</template>
<script type="text/javascript">
export default{
data(){
return{
red:'red active'
}
},
methods:{
say(h){
alert(h);
}
}
}
</script>
过滤器
过滤后就变成capitalize()中返回的值
<template>
<div>
<div>模板语法</div>
<div>{{message | capitalize}}</div> <!--过滤函数的函数名,自己定义-->
</div>
</template>
<script type="text/javascript">
export default{
data(){
return{
message:'message'
}
},
filters:{ <!--过滤函数写这里-->
capitalize(){
return 'capitalize';
}
}
}
</script>
计算属性
在模板中放入太多的逻辑会让模板过重且难以维护
计算属性下所有函数可以放到computed中
<template>
<div>
<div>计算属性</div>
<div>{{reversedMessage}}</div> //这里直接写函数名即可
</div>
</template>
<script type="text/javascript">
export default{
data(){
return{
msg:'helloworld'
}
},
computed:{
reversedMessage(){
return this.msg.split('').reverse().join('');
}
}
}
</script>
class与style绑定
v-bind指令
动态地绑定一个或多个特性
缩写 :
原始写法 v-bind:class,缩写写法 :class
class绑定
绑定1:{active: isActive, 'text-danger': hasError}
<template>
<div>
<div>class和style绑定</div>
<div v-bind:class="{active:isActive,'text-danger':hasError}"> //动态绑定class
</div>
</div>
</template>
<script type="text/javascript">
export default{
data(){
return{
isActive:true, //为true就添加这个样式
hasError:false //为false就删除这个样式
}
}
}
</script>
绑定2: classObject
<template>
<div>
<div>class和style绑定</div>
<div v-bind:class="classObject">
</div>
</div>
</template>
<script type="text/javascript">
export default{
data(){
return{
classObject:{
'active':true;
'text-danger':true
}
}
}
}
</script>
绑定3: [activeClass, errorClass]
<template>
<div>
<div>class和style绑定</div>
<div v-bind:class="[activeClass,errorClass]">
</div>
</div>
</template>
<script type="text/javascript">
export default{
data(){
return{
activeClass:'active',
errorClass:'text-danger'
}
}
}
</script>
通过v-bind绑定的样式同样可以在methods中修改
<template>
<div>
<div>class和style绑定</div>
<div v-bind:class="[activeClass,errorClass]"> //变成active5
</div>
</div>
</template>
<script type="text/javascript">
export default{
data(){
return{
activeClass:'active', //变成active5
errorClass:'text-danger'
},
{
this.activeClass='active5'
}
}
}
</script>
style绑定
绑定1:{color: activeColor,fontSize:'16px'}
<template>
<div>
<div v-bind:style="{ 'color': activeColor, 'fontSize': fontSize + 'px' }">style1</div>
</div>
</template>
<script>
export default{
data(){
return{
activeColor: 'black',
fontSize: 30,
}
}
}
</script>
绑定2:styleObject
<template>
<div>
<div v-bind:style="styleObject">style2</div>
</div>
</template>
<script>
export default{
data(){
return{
styleObject:{
'color': 'red',
'fontSize': '43px'
}
}
}
}
</script>
绑定3:[baseStyles, overridingStyle]
<template>
<div>
<div v-bind:style="[baseStyles, overridingStyles]">style3</div>
</div>
</template>
<script>
export default{
data(){
return{
baseStyles:{
color: 'red'
},
overridingStyles:{
fontSize: '53px'
}
}
}
}
</script>
条件渲染
v-if指令
v-if的值为true时,对应元素就进行展示,为false时,对应元素不进行展示
<template>
<div>
<div>条件渲染</div>
<h1 v-if="ok">hiyoritsai</h1> //ok:true,进行展示
</div>
</div>
</template>
<script type="text/javascript">
export default{
data(){
return{
ok:true
}
}
}
</script>
v-if v-else-if v-else
<template>
<div>
<div>条件渲染</div>
<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else-if="type === 'C'">
C
</div>
<div v-else>
Not A/B/C
</div>
var type = 'A'
if( type === 'A' ){
A
}else if( type === 'B' ){
B
}else if( type === 'C' ){
C
}else{
Not A/B/C
}
</template>
<script>
export default{
data(){
return{
type: 'D'
}
}
}
</script>
v-show
v-show与v-if类似,如果v-show的值是true,就展示对应的元素
<template>
<div>
<div v-show="isShow">123</div>
</div>
</template>
<script>
export default{
data(){
return{
isShow: true
}
}
}
</script>
列表渲染
v-for指令
用法1:v-for="item in items" 数组
items表示数组,item表示当前遍历的数组项,通过item.xx去访问数组元素的值。每遍历一项就会生成一个html元素
<template>
<div>
<div>列表渲染</div>
<ul id="example-1">
<li v-for="item in items">
{{ item.message }}
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
}
}
</script>
用法2:v-for="(item,index) in items" 数组
items表示数组,item表示当前遍历的数组项,index表示当前遍历到的数组元素的下标,index从0开始
<template>
<div>
<div>列表渲染</div>
<ul id="example-2">
<li v-for="(item, index) in items">
{{ index }} - {{ item.message }}
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
}
}
}
</script>
用法3:v-for="(value,key) in object" 对象
object是对象,key是对象中的属性名,value是对象中的属性值
<template>
<div>
<div>列表渲染</div>
<ul id="example-3">
<li v-for="(value, key) in obj">
{{ key }} : {{ value }}
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
obj: {
firstName: 'John',
lastName: 'Doe',
age: 30
}
}
}
}
</script>
事件处理器
v-on指令
缩写@
原始写法 v-on:click 缩写 @click
方法一:直接写js表达式(不建议用,只限代码很少的时候用)
<template>
<div>
<div>事件处理器</div>
<div id="example-1">
<button v-on:click="counter = counter + 1">增加 1</button>
<p>这个按钮被点击了 {{ counter }} 次。</p>
</div>
</div>
</template>
<script>
export default{
data(){
return{
counter : 0
}
}
}
</script>
方法二:写函数名,并在methods中定义函数
<template>
<div>
<div>事件处理器</div>
<div id="example-2">
<!-- `greet` 是在下面定义的方法名 -->
<button @click="greet">Greet</button> //绑定事件时写事件名,可以写greet()
</div>
</div>
</template>
<script>
export default{
data(){
return{
}
},
methods:{
greet(){
this.counter = this.counter + 1;
this.counter = this.counter - 1;
this.counter = this.counter * 2;
this.counter = this.counter * 2;
this.counter = this.counter * 2;
this.counter = this.counter * 2;
this.counter = this.counter * 2;
this.counter = this.counter * 2;
}
}
}
</script>
方法三:调用含参函数,函数在methods中定义
<template>
<div>
<div>事件处理器</div>
<div id="example-3">
<!-- `say` 是在下面定义的方法名 -->
<button @click="say('hi')">say</button>
</div>
</div>
</template>
<script>
export default{
data(){
return{
counter : 0
}
},
methods:{
say(h){
alert(h)
}
}
}
</script>
事件修饰符
.stop 阻止事件冒泡
冒泡:当前元素在事件被触发的同时往上冒去触发祖先元素的事件
若不想让事件冒泡,就要给事件加上.stop
<template>
<div>
<div>事件处理器</div>
<div @click="dothis2">
<button @click.stop="doThis">
<!--点击doThis,触发事件,由于冒泡,父元素dothis2的事件也会被触发-->
dothis
</button>
</div>
</div>
</template>
<script>
export default{
data(){
return{
counter : 0
}
},
dothis2(){
alert('dothis2')
},
doThis(){
alert('dothis')
}
}
}
</script>
自定义组件
组件写到components文件夹下
把我们要使用的组件写在components文件夹下,如countdown.vue
通过import导入自定义组件
<template>
<div>
<div>自定义组件</div>
<countdown></countdown> <!-- 注册后,可以直接作为标签使用 -->
<!--如果重命名的话<count-down></count-down>-->
</div>
</template>
<script type="text/javascript">
import countdown from '@/components/countdown.vue' //通过import导入自定义组件
export default{
data(){
return{
}
},
components:{ //注册组件
countdown
//也可以自行重命名,引用时就用我们定义的名字
//'count-down':countdowm
}
}
</script>
自定义一个倒计时组件
自定义组件写法与页面非常相似
<template>
<p :style="{color: col}">{{time}}</p>
</template>
<script>
export default{
data(){
return{
time: 10
}
},
mounted(){
var vm = this;
var t = setInterval(function(){
vm.time--;
if(vm.time == 0){
vm.$emit("end");
clearInterval(t);
}
},1000)
}
}
</script>
组件基本要素:props、$emit
父组件可以使用 props 把数据传给子组件。
子组件可以使用 $emit 触发父组件的自定义事件。
<template>
<div>
<div>自定义组件</div>
<count-down col="blue" @end="ending"></count-down> <!--父组件给子组件传值-->
</div>
</template>
<script>
import countdown from '@/components/countdown.vue'
export default{
data(){
return{
}
},
methods:{
ending(){ //父组件定义子组件调用的方法
alert("已经结束了")
}
},
components:{
'count-down':countdown
}
}
</script>
组件中props的定义
<template>
<p :style="{color: col}">{{time}}</p> <!--通过style应用props中定义的属性-->
</template>
<script>
export default{
data(){
return{
time: 10
}
},
mounted(){
var vm = this;
var t = setInterval(function(){
vm.time--;
if(vm.time == 0){
vm.$emit("end"); //子组件调用父组件中定义的方法
clearInterval(t);
}
},1000)
},
props:{ //col放在props中,默认值为'#000',类型是字符串
col:{
type: String,
default: '#000'
}
}
}
</script>
Vue中的DOM操作
Vue主流中不建议使用DOM操作,但是开发中难免需要用到DOM操作,比如需要用到jQuery这个插件,Vue中的DOM操作都是虚拟操作,只有在mounted才能进行真实的DOM操作。mounted中的DOM操作是针对已经生成的DOM
原生js写法
<template>
<div>
<div>Vue中DOM操作</div>
<div ref="head" id="head"></div>
</div>
</template>
<script>
export default{
data(){
return{
}
},
mounted(){
// DOM已经生成
document.getElementById('.head').innerHTML='helloworld';
}
}
</script>
jQuery写法
<template>
<div>
<div>Vue中DOM操作</div>
<div ref="head" id="head"></div>
</div>
</template>
<script>
export default{
data(){
return{
}
},
mounted(){
// DOM已经生成
$('.head').html='helloworld'; //不过要先在script中把jQuery引用进来
}
}
</script>
this.$refs
<template>
<div>
<div>Vue中DOM操作</div>
<div ref="head" id="head"></div> <!--用ref来绑定-->
</div>
</template>
<script>
export default{
data(){
return{
}
},
mounted(){
// DOM已经生成
this.$refs.head.innerHTML = 'helloworld'; //用this.$refs来访问ref绑定的元素
}
}
</script>
过渡效果
Vue中用一个<transition>标签把要设置过渡效果的元素括起来 ,再通过样式方式写过渡
<template>
<div>
<div>过渡效果</div>
<div id="demo">
<button v-on:click="show = !show">
Toggle
</button>
<transition name="fades"> <!-- 这里的name是样式名的前缀,要保持一致 -->
<p v-if="show">hello</p>
</transition>
<!--1、显示状态 opcity: 1 变到 0
2、隐藏
leave(整个过程) 离开 leave --- leave-active ----- leave-to
1、隐藏 opcity: 0 变到 1
2、显示
enter(整个过程) 进入 enter 0 --- enter-active ------ enter-to 1 -->
</div>
</div>
</template>
<script>
export default{
data(){
return{
show: true
}
}
}
</script>
<style>
.fades-enter-active, .fades-leave-active {
transition: opacity .5s
}
.fades-enter, .fades-leave-to {
opacity: 0
}
.fades-enter-to{
opacity: 1
}
</style>
在进入/离开的过渡中,会有 6 个 class 切换。
v-enter
:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。
v-enter-active
:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。
v-enter-to
: 2.1.8版及以上 定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 v-enter
被移除),在过渡/动画完成之后移除。
v-leave
: 定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。
v-leave-active
:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。
v-leave-to
: 2.1.8版及以上 定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave
被删除),在过渡/动画完成之后移除。
对于这些在过渡中切换的类名来说,如果你使用一个没有名字的 <transition>
,则 v-
是这些类名的默认前缀。如果你使用了 <transition name="my-transition">
,那么 v-enter
会替换为 my-transition-enter
。
路由vue-router
npm install引入vue-router包
主要作用:页面跳转功能
用法1:<router-link to="/demo1">xxx</router-link>【标签中跳转】
<template>
<div>
<div>vue-router</div>
<router-link to="/demo7">demo7</router-link>
</div>
</template>
<script type="text/javascript">
export default{
data(){
return{
}
}
}
</script>
用法2:<router-link :to="{name:'demo9',params:{userId:123}}">xxx</router-link>【标签中跳转并传递数据】
<template>
<div>
<div>vue-router</div>
<router-link :to="{name:'demo7',params:{userId:123}}">params</router-link>
<!--这里的name就是router下的index.js中的name-->
</div>
</template>
<script type="text/javascript">
export default{
data(){
return{
}
}
}
</script>
router-link向页面传递参数时,router下的index.js中path也要加上对应的通配符
{
path:'/demo7/:userId', //:userId 就是一个通配符,接收路由传递过来的userId的值
name:'demo7',
component:Demo7
}
在页面中使用路由传递过来的参数:this.$route.params.参数名
<template>
<div>
<div>自定义组件</div>
<countdown></countdown> <!-- 注册后,可以直接作为标签使用 -->
<div>{{userid}}</div>
</div>
</template>
<script type="text/javascript">
import countdown from '@/components/countdown.vue'
export default{
data(){
return{
userid:''
}
},
components:{ //注册组件
countdown
},
mounted(){
this.userid=this.$route.params.userId
}
}
</script>
router-link中的query可以使路由带上?并以键值对的形式出现
<template>
<div>
<div>vue-router</div>
<router-link :to="{name:'demo7',params:{userId:456},query:{plan:'private'}}">demo7</router-link>
<!--跳转页面的url为:http://localhost:8080/#/demo7/456?plan=private-->
</div>
</template>
<script type="text/javascript">
export default{
data(){
return{
}
}
}
</script>
在跳转页面中使用url传来的键值对:this.$route.query.参数名
<template>
<div>
<div>自定义组件</div>
<countdown></countdown> <!-- 注册后,可以直接作为标签使用 -->
<div>{{userid}}</div>
<div>{{plan}}</div>
</div>
</template>
<script type="text/javascript">
import countdown from '@/components/countdown.vue'
export default{
data(){
return{
userid:'',
plan:''
}
},
components:{ //注册组件
countdown
},
mounted(){
this.userid=this.$route.params.userId,
this.plan=this.$route.query.plan
}
}
</script>
用法3:this.$router.push({path:'/demo1'})【js中跳转】
<template>
<div>
<div>vue-router</div>
<div @click="toURL">toURL</div>
</div>
</template>
<script type="text/javascript">
export default{
data(){
return{
}
},
methods:{
toURL(){
this.$router.push({path:'/demo7'});
}
}
}
</script>
用法4:this.$router.push({name:'demo1',params:{userId:123}})【js中跳转并传递数据】
<template>
<div>
<div>vue-router</div>
<div @click="toURL">toURL</div>
</div>
</template>
<script type="text/javascript">
export default{
data(){
return{
}
},
methods:{
toURL(){
this.$router.push({name:'demo7',params:{userId:456},query:{plan:'private'}});
}
}
}
</script>
在跳转页面中使用url传递过来的参数方法同上
状态管理vuex
npm install引入vuex包
全局状态管理,所有页面共享数据
设置数据:this.$store.dispatch('increment',100000);
获取数据:this.$store.state.num;
安装Vuex
https://vuex.vuejs.org/zh/installation.html
#git
npm install vuex --save
来到项目的src目录下的main.js,导入store
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store/' //新增
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store, //新增
components: { App },
template: '<App/>'
})
在src目录下新建一个store文件夹,在该文件夹下新建一个index.js文件,并在这个文件中写入
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0,
num: 1
},
mutations: {
increment (state, num) { //mutations中的函数对state中的数据作修改
state.count++
state.num = num;
}
},
actions: {
inc ({ commit }, obj) {
commit('increment', obj) //increment调用的是mutations中的函数
}
}
})
注意:actions中调用的是mutations中的方法
获取store中的变量count
<template>
<div>
<div>vuex</div>
<div>{{msg}}</div>
<button @click="change"></button>
</div>
</template>
<script type="text/javascript">
export default{
data(){
return{
msg:'123'
}
},
methods:{
change(){
//vuex取数据
this.msg=this.$store.state.count; //可取出index.js中的count
//修改公共数据
this.$store.dispatch('inc',100000); //inc就是index.js中actions的commit,100000就是obj
this.msg=this.$store.state.num; //可取出index.js中的count
}
}
}
</script>
slot插槽
常用于组件调用中
在components目录下新建一个文件,假设叫做slot.vue,输入
<template>
<div>
<h1>插槽测试</h1>
<slot>
</slot>
<p>我是最底部</p>
<slot name="bottom">
</slot>
</div>
</template>
在index.vue中引入组件,并注册、使用
<template>
<div>
<div>slot插槽</div>
<slots></slots>
</div>
</template>
<script type="text/javascript">
import slots from '@/components/slot.vue'
export default{
data(){
return{
msg:'123'
}
},
components:{
slots
}
}
</script>
slot的作用:
- 当子组件有一部分内容是根据父组件传递过来的dom进行显示时,可用slot。如果子组件没有slot,那么父组件的slot中的内容也不会展示出来。
- 当有多个插槽时,为了让组件找到它想要的插槽,可以给插槽命名。
//父组件
<template>
<div>
<div>slot</div>
<slots>
<div>我在顶部</div>
<div slot="bottom">我在底部</div>
</slots>
</div>
</template>
<script type="text/javascript">
import slots from '@/components/slot.vue'
export default{
data(){
return{
msg:'123'
}
},
components:{
slots
}
}
</script>
//子组件
<template>
<div>
<h1>插槽测试</h1>
<slot> <!--若不给slot指定name,则slots标签中的元素都会被放到这里来-->
</slot>
<p>我是最底部</p>
<slot name="bottom">
</slot>
</div>
</template>
vue-resource请求
类似于ajax请求,当我们与后台程序员对接数据时就要用到请求
npm install引入vue-resource包
#git
npm install vue-resource --save
打开src目录下的main.js,引入vue-resource
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store/'
import VueResource from 'vue-resource' //新增
Vue.use(VueResource); //新增
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>'
})
this.$http.get('/someUrl') / this.$http.post('/someUrl',{foo:'bar'})
<template>
<div>
<div>vue-resource</div>
</div>
</template>
<script type="text/javascript">
export default{
data(){
return{
}
},
mounted(){
/*get请求*/
this.$http.get('/someUrl').then(response => { /*get里面是一个后台接口,response是相应数据*/
console.log(response.body);
}, response => {
// error callback
});
/*post请求*/
this.$http.post('/someUrl', {foo: 'bar'}).then(response => { /*往后台接口传键值对foo:bar*/
console.log(response.body);
}, response => {
// error callback
});
/*又一种get请求,可以传参数,可以根据后台需要设置header*/
// GET /someUrl?foo=bar
this.$http.get('/someUrl', {params: {foo: 'bar'}, headers: {'X-Custom': '...'}}).then(response => {
// success callback
}, response => {
// error callback
});
}
}
</script>
移动组件库Mint UI
安装Mint-UI
#git
npm install mint-ui -S
在src目录下的mian.js中引入全部组件
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store/'
import VueResource from 'vue-resource'
import MintUI from 'mint-ui'; //新增,把组件库导入
import 'mint-ui/lib/style.css'; //新增,把样式也导入
Vue.use(VueResource);
Vue.use(MintUI); //新增,使用组件
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>'
})
导入一个Tabbar组件
<template>
<div>
<div>Mint-UI</div>
<mt-tabbar v-model="selected"> <!--官网复制来的,可以根据我们需要来修改-->
<mt-tab-item id="tab1">
<img slot="icon" src="../../assets/logo.png">
tab1
</mt-tab-item>
<mt-tab-item id="tab2">
<img slot="icon" src="../../assets/logo.png">
tab2
</mt-tab-item>
<mt-tab-item id="tab3">
<img slot="icon" src="../../assets/logo.png">
tab3
</mt-tab-item>
<mt-tab-item id="tab4">
<img slot="icon" src="../../assets/logo.png">
tab4
</mt-tab-item>
</mt-tabbar>
</div>
</template>
<script type="text/javascript">
import Vue from 'vue'; //需要导入vue
import {Tabbar,TabItem} from 'mint-ui'; //需要导入Tabbar
Vue.component(Tabbar.name,Tabbar); //进行组件的注册
Vue.component(TabItem.name,TabItem);
export default{
data(){
return{
}
},
mounted(){
Tabbar();
}
}
</script>