摘要
简单学习一下Vue
正文
文档
介绍 — Vue.js 风格指南 — Vue.js hexo中对占位符的解析 | TonyStudio Vue是一套用于构建用户界面的渐进式JavaScript框架。
何为渐进式?
Vue可以创建自底向上逐层的应用,从简单应用到复杂应用。
如果是简单应用,只需要一个轻量的核心库。
如果是复杂应用,可以引入各式各样的vue插件。
Vue特点
采用组件化模式,可复用、好维护。一个.vue就可以作为一个组件,其中包含html、css、js 声明式编码,无需直接操作dom。像直接操作dom的就叫做命令式编码,有点像面向对象与面向过程的区别,具体区别可以看图。 使用虚拟dom和diff算法 ,尽量复用dom。也就是数据发生变化,只进行增量更新。
展开
一、上手 像vue下面这样的语法,就叫做模板语法 ,模板语法又分很多类。
1
2
3
< div id = "test" >
Hello {{message}}
</ div >
1.1 占位语法 遇到了点hexo的冲突问题,hexo中的占位符敲好也是{% raw %}{{}}{% endraw %}或者{% raw %}{%%}{% endraw %}
所以如果想要展示原内容的话,语法需要像下面这样使用
{% raw %}{% raw %}文章内容{% endraw %}{% endraw %}
{% raw %}{{content}}{% endraw %}表示占位符,content内容支持js表达式。
占位语法一般用于标签体内容
一般真实开发也只会有一个Vue示例,并且是配合组件一起用的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<!doctype html>
< html lang = "zh-CN" >
< head >
< meta charset = "UTF-8" >
< meta name = "viewport"
content = "width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" >
< meta http-equiv = "X-UA-Compatible" content = "ie=edge" >
< title > Document</ title >
</ head >
< body >
< div id = "root" >
Hello {{message.toUpperCase()}},My name is {{name}},now timestamp is {{Date.now()}}, I will calculate 1+1 for you, the result is
{{1+1}},
</ div >
< div id = "test" >
Hello {{message}}
</ div >
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
< script src = "https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js" ></ script >
< script >
Vue . config . productionTip = false ;
const app = new Vue ({
el : '#root' ,
data : {
message : 'Vue' ,
name : "ccc"
}
});
</ script >
</ body >
</ html >
1.2 指令语法 vue有很多指令,格式都是v-xxx。
像v-bind这种就是指令语法,v-bind可以简写为:。
指令语法用于标签,作用范围包含并大于占位语法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!doctype html>
< html lang = "zh" >
< head >
< meta charset = "UTF-8" >
< meta name = "viewport"
content = "width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" >
< meta http-equiv = "X-UA-Compatible" content = "ie=edge" >
< title > Document</ title >
</ head >
< body >
< div id = "app" >
< a v-bind:href = "link" > {{blogName}}</ a >
< a :href = "link" > {{blogName}}</ a >
</ div >
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
< script src = "https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js" ></ script >
< script >
Vue . config . productionTip = false ;
const app = new Vue ({
el : '#app' ,
data : {
blogName : '博客' ,
link : "https://meethigher.top"
}
});
</ script >
</ body >
</ html >
1.3 数据绑定 v-bind是单向数据绑定,也就是绑定的值,如果通过页面进行了修改,原本的值不会变化。
v-model支持双向数据绑定,如果页面的值发生变化,绑定的值也会变化。
v-model只能用在输入类元素,也就是内容可编辑的元素。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!doctype html>
< html lang = "zh" >
< head >
< meta charset = "UTF-8" >
< meta name = "viewport"
content = "width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" >
< meta http-equiv = "X-UA-Compatible" content = "ie=edge" >
< title > Document</ title >
</ head >
< body >
< div id = "root" >
单向数据绑定:< input type = "text" v-bind:value = "name" >
双向数据绑定:< input type = "text" v-model:value = "name" >
</ div >
< script src = "js/vue.js" ></ script >
< script >
new Vue ({
el : '#root' ,
data : {
name : 'test'
}
})
</ script >
</ body >
</ html >
1.4 el与data的两种写法 el两种写法
new对象时配置el属性 通过创建的对象使用$mount指定el的值 data两种写法
对象式 函数式 使用组件时,data必须使用函数式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
< script >
/*第一种写法*/
// new Vue({
// el:'#root',
// data: {
// name:'test'
// }
// });
/*第二种写法,el使用mount,data使用函数*/
const app = new Vue ({
//data: function ()可以简写为data()
data : function () {
//this是vue对象
console . log ( this );
return {
name : "test"
}
}
});
app . $mount ( "#root" );
</ script >
1.5 vue中的mvvm模型 M:model模型,对应data中数据
V:view视图,对应vue模板
VM:viewModel视图模板,对应vue对象
对使用者,跟后端的MVC没啥区别,只不过控制器换成了视图模板罢了。
视图模板本身和控制器作用也是一样的,调用数据model,将数据model返回给view视图使用。
1.6 数据代理 通过Object.defineProperty添加属性值,该属性值的key在遍历时,是不会被遍历到的
展开
1
2
3
4
5
6
7
8
9
10
11
12
13
< script >
let person = {
name : "test" ,
age : 18
};
/*这样定义的不会参与遍历*/
Object . defineProperty ( person , "sex" ,{
value : "男"
});
console . log ( person );
//遍历key
console . log ( Object . keys ( person ))
</ script >
当然了,我们也可以给他们配置属性,允许该操作。
1
2
3
4
5
6
7
8
9
10
/*允许被遍历*/
Object . defineProperty ( person , "sex" ,{
value : "男" ,
//控制属性可以被遍历,默认false
enumerable : true ,
//控制属性可以被修改,默认false
writable : true ,
//控制属性可以被删除,默认false。通过控制台delete person.sex测试
configurable : true
});
如果,我们想要动态修改对象中的值,可以这么玩
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
< script >
let sex = "男" ;
let person = {
name : "test" ,
age : 18
};
//让值为动态的
Object . defineProperty ( person , "sex" ,{
//读取值
get () {
console . log ( "读取sex" );
return sex ;
},
//修改值
set ( value ) {
console . log ( "修改sex" );
sex = value ;
}
});
console . log ( person );
</ script >
1.7 事件与事件修饰符 注意事项
使用v-on:xxx或者@xxx绑定事件,其中xxx是事件名,比如click 事件如果放在data中,会自动生成getter与setter,建议放在methods中 methods中如果用箭头函数,this就表示window。不用箭头函数,this表示vue对象 @click="function"与@click="function($event)"一样,前者是后者省略写法。 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
< div id = "root" >
< button v-on:click = "showInfo
<button @click=" showInfo " > @简
< button @ click = "showInfoWith
</div>
<script>
const app=new Vue({
el:" # root ",
data: {
name: " meethigher ",
address: " china "
},
methods: {
// showInfo () {
// alert (" test "
// }
showInfo ( a , b , c , d ) {
// 只有第一个参数 , a有值 , 也
console . log ( a , b
// 此时this是vue对象 ,
console . log ( thi
},
showInfoWithParam ( p
console . log ( eve
alert ( param );
}
}
});
</ script >
对于事件修饰符,拿阻止默认事件来说,我们从js的语法写vue可以这样
1
2
3
4
5
showInfo ( e ) {
//阻止默认行为,比如a标签点击跳转,阻止后就不用跳转了
e . preventDefault ();
alert ( "test" );
}
但是vue给提供了更方便的写法
1
2
3
< div id = "root" >
< a href = "https://meethigher.top" @ click . prevent = "showInfo" > test</ a >
</ div >
像这种还有很多,vue中常用的事件修饰符
prevent:阻止默认事件,常用 stop:阻止事件冒泡,常用 once:事件只触发一次,常用 capture:使用事件的捕获模式 self:只有event.target是当前操作的元素才会触发 passive:事件的默认行为立即执行,不需要等待事件回调完成 修饰符可以连写
.prevent.stop,先阻止默认事件,再阻止冒泡
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
< style >
. test {
margin : 10 px auto ;
background-color : #42b983 ;
}
. aaa {
height : 250 px ;
overflow : auto ;
}
. aaa > li {
margin : 10 px auto ;
height : 200 px ;
background-color : green ;
}
</ style >
< div id = "root" >
<!--阻止默认事件,不阻止会进行跳转-->
< a href = "https://meethigher.top" @ click . prevent = "showInfo" > test</ a >
<!--阻止冒泡,不阻止会执行方法两次-->
< div class = "test" @ click = "showInfo" >
< button @ click . stop = "showInfo" > 测试冒泡</ button >
</ div >
<!--设置事件只触发一次-->
< button @ click . once = "showInfo" > 事件只触发一次</ button >
<!--使用事件的捕获模式,就是在捕获阶段就开始执行。
js点击事件的触发,分两个阶段,
一个是捕获阶段,从dom树最外层找到最内层,
然后才是冒泡阶段,冒泡阶段是从内向外。
点击div2正常log顺序是2,1,如果对div1进行捕获,输出就成了1,2
-->
< div class = "test" @ click . capture = "showMsg('div1')" >
div1
< div class = "test" @ click = "showMsg('div2')" >
div2
</ div >
</ div >
<!--只有event.target是当前操作的元素才会触发-->
< div class = "test" @ click . self = "showTarget" >
< button @ click = "showTarget" > 测试只有当前元素才能触发</ button >
</ div >
<!--事件的默认行为立即执行,无须等待事件回调执行完毕
滚动事件有scroll,还有wheel
scroll指滚动条移动,先移动再执行事件
wheel指鼠标滚轮移动,执行完事件再移动
-->
< ul class = "aaa" @ wheel . passive = "calculate" >
< li > 向晚</ li >
< li > 贝拉</ li >
< li > 珈乐</ li >
< li > 嘉然</ li >
< li > 乃琳</ li >
</ ul >
</ div >
< script >
const app = new Vue ({
el : "#root" ,
data : {
name : "meethigher" ,
address : "china"
},
methods : {
showInfo ( e ) {
// e.preventDefault();//阻止默认事件
//e.stopPropagation();//阻止冒泡
alert ( "test" );
},
showMsg ( param ) {
console . log ( param );
},
showTarget ( e ) {
console . log ( e . target );
},
calculate () {
for ( let i = 0 ; i < 100000 ; i ++ ) {
console . log ( "a" );
}
console . log ( "算完了" );
}
}
});
</ script >
1.8 键盘事件 先看一个例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
< div id = "root" >
< input type = "text" placeholder = "按下回车提示输入" @ keydown = "showInfo" >
</ div >
< script >
new Vue ({
el : "#root" ,
methods : {
showInfo ( e ) {
if ( e . keyCode !== 13 ) return ;
console . log ( e . target . value );
}
}
})
</ script >
一般操作是上面这样进行的,但是在Vue中,提供了常用的按键别名
回车:enter 删除:delete 退出:esc 空格:space 换行:tab,必须与keydown使用 上:up 下:down 左:left 右:right ctrl alt shift meta:对应windows的win键 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
< div id = "root" >
< input type = "text" placeholder = "按下ctrl+enter提示输入" @ keydown . ctrl . enter = "showMsg" >
< input type = "text" placeholder = "按下ctrl+enter提示输入" @ keydown . ctrl . e = "showMsg" >
</ div >
< script >
// 自定义全局按键修饰符
Vue . config . keyCodes . e = 69 ;
new Vue ({
el : "#root" ,
methods : {
showInfo ( e ) {
console . log ( e . target . value );
}
}
})
</ script >
1.9 计算属性 需求
两个输入框,一个姓,一个名,下面文本框动态展示姓名。
占位符实现 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
< div id = "root" >
姓:< input type = "text" v-model = "xing" >< br >
名:< input type = "text" v-model = "ming" >< br >
全名:{{xing.slice(0,3)}}{{ming}}
全名:{{xing.slice(0,3)}}{{ming}}
</ div >
< script src = "js/vue.js" ></ script >
< script >
new Vue ({
el : "#root" ,
data : {
xing : '' ,
ming : ''
}
})
</ script >
修改一次,调用两次。
方法实现 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
< div id = "root" >
姓:< input type = "text" v-model = "xing" >< br >
名:< input type = "text" v-model = "ming" >< br >
全名:{{getFullName()}}
全名:{{getFullName()}}
</ div >
< script src = "js/vue.js" ></ script >
< script >
new Vue ({
el : "#root" ,
data : {
xing : '' ,
ming : ''
},
methods : {
getFullName () {
console . log ( "方法被调用" );
return this . xing . slice ( 0 , 3 ) + this . ming ;
}
}
})
</ script >
修改一次,方法调用两次。
计算属性实现 很明显,不管是占位符或是方法,都是在只要数据发生变化后,都要重新读取一下,效率不高。
Vue提供了计算属性,为了解决这个问题,计算属性里面用到了缓存,将数据缓存了起来,便于后续的复用。
何为属性,vue对象中的data里面的可以都是属性(属性名)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
< div id = "root" >
姓:< input type = "text" v-model = "xing" >< br >
名:< input type = "text" v-model = "ming" >< br >
全名:{{getFullName}}< br >
全名:{{getFullName}}
</ div >
< script src = "js/vue.js" ></ script >
< script >
const app = new Vue ({
el : "#root" ,
data : {
xing : '' ,
ming : ''
},
computed : {
getFullName : {
//有人读取fullName时,get就会被调用,并将其返回值作为getFullName的值
get (){
console . log ( "被调用了" );
return this . xing + this . ming ;
},
/*控制台通过app.getFullName=xxx即可执行*/
set ( value ) {
console . log ( "set被调用" );
this . xing = value ;
}
}
}
})
</ script >
修改一次,只调用一次。
计算方法实现 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
< script >
const app = new Vue ({
el : "#root" ,
data : {
xing : '' ,
ming : ''
},
computed : {
getFullName () {
console . log ( "被调用了" );
return this . xing + this . ming ;
}
}
})
</ script >
1.10 监视属性 需求
实现一个切换天气按钮,获取当前天气和上一次天气。
常规实现 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
< div id = "root" >
< h2 > 今天天气很{{weather}}</ h2 >
< button @ click = "changeWeather" > 切换天气</ button >
</ div >
< script src = "js/vue.js" ></ script >
< script >
const app = new Vue ({
el : "#root" ,
data : {
isHot : true
},
methods : {
changeWeather () {
this . isHot = ! this . isHot ;
}
},
computed : {
weather () {
return this . isHot ? "炎热" : "凉爽" ;
}
}
});
</ script >
监视属性实现 监视属性的两种实现
实例化Vue对象时,初始化配置watch 通过已有的Vue对象,obj.$watch监视 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
< div id = "root" >
< h2 > 今天天气很{{weather}}</ h2 >
< button @ click = "changeWeather" > 切换天气</ button >
</ div >
< script src = "js/vue.js" ></ script >
< script >
const app = new Vue ({
el : "#root" ,
data : {
isHot : true
},
methods : {
changeWeather () {
this . isHot = ! this . isHot ;
}
},
computed : {
weather () {
return this . isHot ? "炎热" : "凉爽" ;
}
},
// 实例化Vue对象时,初始化配置watch
// watch: {
// isHot: {
// //初始化时,令handler调用一次
// immediate:false,
// //当isHot这个值发生变化时,自动true
// handler(newValue,oldValue) {
// console.log("isHot被修改了",newValue,oldValue);
// }
// },
// weather: {
// immediate:true,
// handler(newValue, oldValue) {
// console.log("监测weather方法",newValue,oldValue);
// }
// }
// }
});
// 通过已有的Vue对象,obj.$watch监视
app . $watch ( "weather" ,{
immediate : true ,
handler ( newValue , oldValue ) {
console . log ( "监测weather方法" , newValue , oldValue );
}
})
</ script >
vue默认不监视多层级数据的变化,如果想要监视多层级监视,就要配置deep。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
< div id = "root" >
< button @ click = "number.a++" > a++</ button >
</ div >
< script >
const app = new Vue ({
el : "#root" ,
data : {
isHot : true ,
number : {
a : 1 ,
b : 2
}
},
watch : {
number : {
deep : true ,
/*多层次数据监视,vue默认不监视下面层次数据的变化*/
handler () {
console . log ( "number发生变化" );
}
}
}
});
</ script >
1.11 绑定样式 绑定class vue绑定样式需要使用:class,参数内容支持字符串、数组、对象(key的值需要是boolean类型)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
< div id = "root" >
< div id = "weather" class = "basic" :class = "[weatherClass,weatherValid]" > 今天的天气:{{weather}}</ div >
< button @ click = "changeWeather" > 查询当前天气</ button >
< button @ click = "addFont" > 添加字体样式</ button >
</ div >
< script src = "js/vue.js" ></ script >
< script >
const app = new Vue ({
el : "#root" ,
data : {
// weatherClass: ["basic","sunny"],//多样式时的写法
weatherClass : "sunny" ,
weather : "晴天" ,
/*为false时,表示:class的引用不生效,true表示生效*/
weatherValid : {
isValid : false
}
},
methods : {
changeWeather () {
const arr = [ "sunny" , "cloudy" , "rain" ];
const arrDesc = [ "晴天" , "多云" , "雨天" ];
const index = Math . floor ( Math . random () * 3 );
this . weatherClass = arr [ index ];
this . weather = arrDesc [ index ];
},
addFont () {
let weatherClass = this . weatherClass ;
if ( weatherClass instanceof Array ) {
console . log ( "是数组,追加" );
this . weatherClass . push ( "font" );
} else {
console . log ( "不是数组,拼接" );
this . weatherClass = this . weatherClass + " font" ;
}
}
}
})
</ script >