Vue起步
1.下载核心库vue.js
bower info vue
npm init --yes
cnpm install vue --save
vue2.0和1.0相比,最大的变化就是引入了Virtual DOM(虚拟DOM),页面更新效率更高,速度更快
2.vue实现
js:
new Vue({
el:'#itany', //指定关联的选择器
data:{ //存储数据
msg:'Hello World',
name:'tom'
}
});
html:
<div id="itany">
{{msg}}
</div>
3. 安装vue-devtools插件,便于在chrome中调试vue
直接将vue-devtools解压缩,然后将文件夹中的chrome拖放到扩展程序中
//配置是否允许vue-devtools检查代码,方便调试,生产环境中需要设置为false
Vue.config.devtools=false;
Vue.config.productionTip=false; //阻止vue启动时生成生产消息
Vue常用指令
+ v-model
双向数据绑定,一般用于表单元素
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>常用指令:v-model</title> <script src="js/vue.js"></script> <script> window.onload=function(){ new Vue({ // el:'.itany', el:'div', //vue2.0中不允许将vue实例挂载到<html>或<body>元素,在vue1.0中是可以的 data:{ name:'', //即使没有值,也不能省略,报错 age:21, flag:true, nums:[12,4,23,5], user:{id:9527,name:'唐伯虎'} } }); } </script> </head> <body> <!-- <div id="itany"> --> <!-- <div class="itany"> --> <div> 用户名:<input type="text" v-model="name"> <br> {{name}} <br> {{age}} <br> {{flag}} <br> {{nums}} <br> {{user}} </div> </body> </html>
+ v-for
对数组或对象进行循环操作,使用的是v-for,不是v-repeat
注:在vue1.0中提供了隐式变量,如$index、$key,在vue2.0中去除了隐式变量,已被废除
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>常用指令:v-for</title> <script src="js/vue.js"></script> <script> window.onload=function(){ new Vue({ el:'#itany', data:{ arr:[12,4,5,34,2,11], user:{id:9527,name:'唐伯虎',age:25}, arr2:[12,4,5,34,2,11,12], users:[ {id:9527,name:'唐伯虎',age:25}, {id:1001,name:'秋香',age:22}, {id:1002,name:'石榴姐',age:24} ] } }); } </script> </head> <body> <div id="itany"> <!-- {{arr}} --> <ul> <!-- 普通循环 --> <li v-for="value in arr">{{value}}</li> <!--<li v-for="value in user">{{value}}</li>--> <!-- 键值循环 --> <!-- <li v-for="(v,k) in arr">{{k}}={{v}}</li> --> <!-- <li v-for="(v,k) in user">{{k}}={{v}}</li> --> <!-- 可以直接循环包含重复数据的集合,可以通过指定:key属性绑定唯一key,当更新元素时可重用元素,提高效率,类似于vue1.0中track-by --> <!-- <li v-for="(v,k) in arr2" :key="k">{{v}}</li> --> <!--<li v-for="(user,index) in users">--> <!--{{index+1}},{{user.id}},{{user.name}},{{user.age}}--> <!--</li>--> </ul> </div> </body> </html>
+ v-on
用来绑定事件,用法:v-on:事件="函数"
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>常用指令:v-on</title> <script src="js/vue.js"></script> <script> window.onload=function(){ let vm=new Vue({ el:'#itany', data:{ //存储数据 arr:[12,34,45,23,5] }, methods:{ //存储方法 show:function(){ console.log('show方法'); }, add(){ // console.log(this); //this表示当前vue实例 // console.log(this===vm); //true this.arr.push(666); //使用this访问当前实例中的成员 // this.show(); } } }); } </script> </head> <body> <div id="itany"> <!-- <button onclick="show()">点我</button> --> <button v-on:click="show">点我</button> <button v-on:click="add()">向数组中添加一个元素</button> <br> {{arr}} <hr> <button v-on:mouseover="show">鼠标经过</button> <button v-on:dblclick="show">鼠标双击</button> </div> </body> </html>
+ v-show/v-if
用来显示或隐藏元素,v-show是通过display实现,v-if是每次删除后再重新创建,与angular中类似
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>常用指令:v-show</title> <script src="js/vue.js"></script> <script> window.onload=function(){ let vm=new Vue({ el:'#itany', data:{ flag:true }, methods:{ change(){ this.flag=!this.flag; } } }); } </script> </head> <body> <div id="itany"> <!-- <button v-on:click="change">隐藏</button> --> <button v-on:click="flag=!flag">隐藏</button> <hr> <div style=" 100px;height: 100px; background-color: red" v-if="flag">欢迎来到南京网博</div> </div> </body> </html>
事件与属性
1.事件
事件简写
v-on:click="" 简写方式 @click=""
事件对象$event
包含事件相关信息,如事件源、事件类型、偏移量 target、type、offsetx
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>事件简写和事件对象$event</title> <script src="js/vue.js"></script> <script> window.onload=function(){ let vm=new Vue({ el:'#itany', methods:{ show(){ console.log(111); }, print(e){ // console.log(e); console.log(e.target.innerHTML); //DOM对象 console.log(this); } } }); } </script> </head> <body> <div id="itany"> <button v-on:click="show">点我</button> <button @click="show">点我</button> <hr> <button @click="print($event)">Click Me</button> </div> </body> </html>
事件冒泡
阻止事件冒泡:
a)原生js方式,依赖于事件对象
b)vue方式,不依赖于事件对象@click.stop
事件默认行为
阻止默认行为:
a)原生js方式,依赖于事件对象
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>事件冒泡和默认行为</title> <script src="js/vue.js"></script> <script> window.onload=function(){ let vm=new Vue({ el:'#itany', methods:{ show(){ console.log(111); // e.stopPropagation(); }, print(){ console.log(222); }, write(){ console.log(333); }, study(){ console.log(444); // e.preventDefault(); } } }); } </script> </head> <body> <div id="itany"> <div @click="write"> <p @click="print"> <!-- <button @click="show($event)">点我</button> --> <button @click.stop="show">点我</button> </p> </div> <hr> <!-- <a href="#" @click="study($event)">俺是链接</a> --> <a href="#" @click.prevent="study">俺是链接</a> </div> </body> </html>
键盘事件
回车:@keydown.13 或@keydown.enter
上:@keydown.38 或@keydown.up
默认没有@keydown.a/b/c...事件,可以自定义键盘事件,也称为自定义键码或自定义键位别名
事件修饰符
.stop - 调用 event.stopPropagation()。
.prevent - 调用 event.preventDefault()。
.{keyCode | keyAlias} - 只当事件是从特定键触发时才触发回调。
.native - 监听组件根元素的原生事件。
.once - 只触发一次回调。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>键盘事件</title> <script src="js/vue.js"></script> <script> /** * 自定义键位别名 */ Vue.config.keyCodes={ a:65, f1:112 } window.onload=function(){ let vm=new Vue({ el:'#itany', methods:{ show(e){ console.log(e.keyCode); if(e.keyCode==13){ console.log('您按了回车'); } }, print(){ // console.log('您按了回车'); // console.log('您按了方向键上'); console.log('11111'); } } }); } </script> </head> <body> <div id="itany"> <!-- 键盘事件:@keydown、@keypress、@keyup --> <!-- 用户名:<input type="text" @keydown="show($event)"> --> <!-- 简化按键的判断 --> <!-- 用户名:<input type="text" @keydown="show($event)"> --> <!-- 用户名:<input type="text" @keydown.13="print"> --> <!-- 用户名:<input type="text" @keydown.enter="print"> --> <!-- 用户名:<input type="text" @keydown.up="print"> --> 用户名:<input type="text" @keydown.f1="print"> <!-- 事件修饰符 --> <button @click.once="print">只触发一次</button> </div> </body> </html>
2.属性
属性绑定和属性的简写
v-bind 用于属性绑定, v-bind:属性=""
属性的简写:v-bind:src="" 简写为 :src=""
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>属性绑定和属性的简写</title> <script src="js/vue.js"></script> <script> window.onload=function(){ let vm=new Vue({ el:'#itany', data:{ url:'https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png', w:'200px', h:'100px' } }); } </script> </head> <body> <div id="itany"> <!-- <img src="{{url}}"> --> <!-- 可以直接访问vue中的数据,不需要使用{{}} --> <!-- <img v-bind:src="url"> --> <img :src="url" :width="w" :height="h"> </div> </body> </html>
class和style属性
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>class和style属性</title> <script src="js/vue.js"></script> <script> window.onload=function(){ let vm=new Vue({ el:'#itany', data:{ bb:'aa', dd:'cc', flag:true, num:-2, hello:{aa:true,cc:true}, xx:{color:'blue',fontSize:'30px'}, yy:{backgroundColor:'#ff7300'} } }); } </script> <style> .aa{ color:red; font-size:20px; } .cc{ background-color:#ccc; } </style> </head> <body> <div id="itany"> <!-- class属性 --> <!-- <p class="aa">南京网博</p> --> <!-- 可以访问,普通css方式 --> <!-- <p :class="aa">南京网博</p> --> <!-- 不可以,Vue的属性绑定时不能直接css样式 --> <!-- 方式1:变量形式 --> <!-- <p :class="bb">南京网博</p> --> <!-- 方式2:数组形式,同时引用多个 --> <!-- <p :class="[bb,dd]">南京网博</p> --> <!-- 方式3:json形式,常用!!! --> <!-- <p :class="{aa:true,cc:flag}">南京网博</p> --> <!-- <p :class="{aa:num>0}">南京网博</p> --> <!-- 方式4:变量引用json形式 --> <!-- <p :class="hello">南京网博</p> --> <!-- style属性 --> <p :style="[xx,yy]">itany</p> </div> </body> </html>
模板
Vue.js使用基于HTML的模板语法,可以将DOM绑定到Vue实例中的数据
模板就是{{}},用来进行数据绑定,显示在页面中,也称为Mustache语法
1. 数据绑定的方式
a.双向绑定
v-model
b.单向绑定
方式1:使用两对大括号{{}},可能会出现闪烁的问题,可以使用v-cloak解决
方式2:使用v-text、v-html
2. 其他指令
v-once 数据只绑定一次
v-pre 不编译,直接原样显示
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>模板</title> <script src="js/vue.js"></script> <script> window.onload=function(){ let vm=new Vue({ el:'#itany', data:{ msg:'welcome to itany' }, created:function(){ // alert(111); } }); } </script> <style> /* 必须配置css样式,否则不生效 */ [v-cloak]{ display:none; } </style> </head> <body> <div id="itany"> <input type="text" v-model="msg"> <h3>aaa<span v-cloak>{{msg}}</span></h3> <h3 v-text="msg"></h3> <h3 v-html="msg"></h3> <h3 v-once>{{msg}}</h3> <h3 v-pre>{{msg}}</h3> </div> </body> </html>
过滤器
用来过滤模型数据,在显示之前进行数据处理和筛选
语法:{{ data | filter1(参数) | filter2(参数)}}
1. 关于内置过滤器
vue1.0中内置许多过滤器,如:
currency、uppercase、lowercase
limitBy
orderBy
filterBy
vue2.0中已经删除了所有内置过滤器,全部被废除
如何解决:
a.使用第三方工具库,如lodash、date-fns日期格式化、accounting.js货币格式化等
b.使用自定义过滤器
2. 自定义过滤器
分类:全局过滤器、局部过滤器
自定义全局过滤器
使用全局方法Vue.filter(过滤器ID,过滤器函数)
自定义局部过滤器
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>自定义过滤器</title> <script src="js/vue.js"></script> <script> /** * 自定义全局过滤器 */ Vue.filter('addZero',function(data){ // console.log(data); return data<10?'0'+data:data; }); /*Vue.filter('number',(data,n) => { // console.log(data,n); return data.toFixed(n); });*/ Vue.filter('date',data => { let d=new Date(data); return d.getFullYear()+'-'+(d.getMonth()+1)+'-'+d.getDate()+' '+d.getHours()+':'+d.getMinutes()+':'+d.getSeconds(); }); window.onload=function(){ let vm=new Vue({ el:'#itany', data:{ currentTime:Date.now() }, filters:{ //局部过滤器 number:(data,n) => { return data.toFixed(n); } } }); } </script> </head> <body> <div id="itany"> <!-- <h3>{{3 | addZero}}</h3> --> <!-- 课后作业:自己实现toFiexed()四舍五入的功能 --> <h3>{{12.345678 | number(2)}}</h3> <!-- <h3>{{12.045 | number(2)}}</h3> --> <h3>{{currentTime | date}}</h3> </div> </body> </html>
Vue生命周期
vue实例从创建到销毁的过程,称为生命周期,共有八个阶段,分别为数据观测前,数据观测后,模板挂载前,模板挂载后,组件更新前,组件更新后,组件销毁前,组件销毁后
其中最常用的就是监测数据后(created)和模板挂载后(mounted)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Vue生命周期</title> <script src="js/vue.js"></script> <script> window.onload=function(){ let vm=new Vue({ el:'#itany', data:{ msg:'welcome to itany' }, methods:{ update(){ this.msg='欢迎来到南京网博!'; }, destroy(){ // this.$destroy(); vm.$destroy(); } }, beforeCreate(){ alert('组件实例刚刚创建,还未进行数据观测和事件配置'); }, created(){ //常用!!! alert('实例已经创建完成,并且已经进行数据观测和事件配置'); }, beforeMount(){ alert('模板编译之前,还没挂载'); }, mounted(){ //常用!!! alert('模板编译之后,已经挂载,此时才会渲染页面,才能看到页面上数据的展示'); }, beforeUpdate(){ alert('组件更新之前'); }, updated(){ alert('组件更新之后'); }, beforeDestroy(){ alert('组件销毁之前'); }, destroyed(){ alert('组件销毁之后'); } }); } </script> </head> <body> <div id="itany"> {{msg}} <br> <button @click="update">更新数据</button> <button @click="destroy">销毁组件</button> </div> </body> </html>
计算属性
1.基本用法
计算属性也是用来存储数据,但具有以下几个特点:
- 数据可以进行逻辑处理操作
- 对计算属性中的数据进行监视
2.计算属性 VS 方法
将计算属性的get函数定义为一个方法也可以实现类似的功能
- 计算属性是基于它的依赖进行更新的,只有在相关依赖发生改变时才能更新变化
- 计算属性是缓存的,只要相关依赖没有改变,多次访问计算属性得到的值是之前缓存的计算结果,不会多次执行
3.get和set
- 计算属性由两部分组成:get和set,分别用来获取计算属性和设置计算属性
- 默认只有get,如果需要set,要自己添加
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>计算属性</title> <script src="js/vue.js"></script> <script src="js/axios.min.js"></script> <script src="js/vue-resource.min.js"></script> </head> <body> <div id="itany"> <!--基本用法--> <h2>基本属性:{{ msg }}</h2> <h2>计算属性:{{ msg2 }}</h2> <!--对数据处理再显示--> <h2>基本属性:{{ msg.split(' ').reverse().join(' ') }}</h2> <h2>计算属性:{{ reverseMsg }}</h2> <button @click="change">修改值</button> <p>小结:如果涉及值运算,运用计算属性,提高代码可读性和可维护性</p> <br> <!--计算属性 vs 方法--> <h2>{{ num1 }}</h2> <h2>{{ num2 }}</h2> <h2>{{ getNum2() }}</h2> <button onclick="fn()">修改num2</button> <p>小结:依赖发生变化时,才会执行计算属性,否则取的是 之前缓存的结果</p> <!--get和set--> <h2>{{ num2 }}</h2> <button @click="change2">修改计算属性</button> </div> <script> var vm = new Vue({ el : '#itany', data : { msg : 'welcome to dasha', num1 : 8 }, computed : {//计算属性 msg2 : function(){//该函数必须有返回值,用来获取属性,称为get函数 return '欢迎来到南京网博' }, reverseMsg : function(){ //可以包含逻辑处理操作,同时reverseMsg依赖于msg return this.msg.split(' ').reverse().join(' ') }, num2 : { get : function(){ console.log('num2:' + new Date()); return this.num1 - 1; }, set : function(val){ console.log('修改num2值'); this.num1 = val; } } }, methods : { getNum2(){ console.log('基本方法'); console.log(new Date()); return this.num1 - 1; }, change(){ this.msg = 'i love you'; }, change2(){ this.num2 = 111; } } }); function fn(){ setInterval(function(){ //console.log(vm.num2); 计算属性触发 console.log(vm.getNum2()); //基本方法 },1000) } </script> </body> </html>
Vue实例的属性和方法
1.属性
-
vm.$el 获取vue实例关联的元素 DOM对象
-
vm.$data 获取数据对象data 也可以直接用vm.属性名取
-
vm.$options 获取自定义属性
-
vm.$refs 获取所有添加ref属性的元素
2.方法
-
vm.$mount() 手动挂载vue实例
-
vm.$destroy() 销毁实例
-
vm.$nextTick(callback) 在DOM更新完成后再执行回调函数,一般在修改数据之后使用该方法,以便获取更新后的DOM
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue实例的属性和方法</title> <script src="js/vue.js"></script> <script src="js/axios.min.js"></script> <script src="js/vue-resource.min.js"></script> </head> <body> <div id="itany"> {{ msg }} <h2 ref="hello">hello</h2> <h2 ref="world">world</h2> </div> <script> var vm = new Vue({ el : '#itany', data : { msg : 'welcome to itany' }, name : 'tom', age : 24, show : function(){ console.log('show'); } }); /*属性*/ //vm.属性名 获取data中的属性 //console.log(vm.msg); //vm.$el 获取ue实例关联的元素 //console.log(vm.$el); //DOM对象 //vm.$el.style.color = 'red'; //vm.$data //获取数据对象data //console.log(vm.$data); //console.log(vm.$data.msg); //vm.$options //获取自定义属性 //console.log(vm.$options); //console.log(vm.$options.name); //console.log(vm.$options.age); //console.log(vm.$options.show); //vm.$refs 获取所有添加ref属性的元素 //console.log(vm.$refs); //console.log(vm.$refs.hello); //DOM对象 //vm.$refs.hello.style.color = 'blue'; /*方法*/ //vm.$mount() 手动挂载vue实例 //vm.$mount('#itany'); //var vm = new Vue({ // data : { // msg : '欢迎来到南京网博', // name : 'tom' // } //}).$mount('#itany'); //vm.$destroy() 销毁实例 //vm.$destroy(); // vm.$nextTick(callback) 在DOM更新完成后再执行回调函数,一般在修改数据之后使用该方法,以便获取更新后的DOM //修改数据 vm.name='汤姆'; //DOM还没更新完,Vue实现响应式并不是数据发生改变之后DOM立即变化,需要按一定的策略进行DOM更新,需要时间!! // console.log(vm.$refs.title.textContent); vm.$nextTick(function(){ //DOM更新完成,更新完成后再执行此代码 console.log(vm.$refs.title.textContent); }); </script> </body> </html>
3.属性修改,添加,删除
- vm.$set(object,key,value) vm.set 添加
- vm.$delete(object,key) vm.delete 删除
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>添加和删除属性: $set、$delete</title> <script src="js/vue.js"></script> <script src="js/axios.min.js"></script> <script src="js/vue-resource.min.js"></script> </head> <body> <div id="itany"> <button @click="doUpdate">修改属性</button> <button @click="doAdd">添加属性</button> <button @click="doDelete">删除属性</button> <br> <h2>{{ user.name }}</h2> <h2>{{ user.age }}</h2> </div> <script> var vm = new Vue({ el : '#itany', data : { user : { id : 1001, name : 'tom' } }, methods : { doUpdate(){ this.user.name = '汤姆' }, doAdd(){ //通过普通方式为对象添加属性时 vue无法实时监控 //this.user.age = 25; //属性添加成功,但是页面不显示 this.$set(this.user,'age',18); //通过vue实例的$set方法为对象体添加属性,可以实时监控到 Vue.set(this.user,'age',22); //全局设置 if(this.user.age){ console.log(this.user.age); this.user.age++; }else{ Vue.set(this.user,'age',1) } }, doDelete(){ if(this.user.age){ Vue.delete(this.user, 'age'); } } } }) </script> </body> </html>
- vm.$watch(data,callback[,options]) 除了提供方法监控属性变化,还在 vue实例提供watch选项用于监控
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>监视数据的变化 $watch</title> <script src="js/vue.js"></script> <script src="js/axios.min.js"></script> <script src="js/vue-resource.min.js"></script> </head> <body> <div id="itany"> <input type="text" v-model="name"> <h3>{{ name }}</h3> <hr> <input type="text" v-model="age"> <h3>{{ age }}</h3> <hr> <input type="text" v-model="user.name"> <h3>{{ user.name }}</h3> </div> <script> var vm = new Vue({ el : '#itany', data : { name : 'tom', age : 23, user : { id : 1001, name : 'alice' } }, watch : {//方式2:使用vue实例提供的watch选项 age : (newValue,oldValue) => { console.log('age被修改啦,原值:'+oldValue+',新值:'+newValue); }, user : { handler : (newValue,oldValue) => { console.log('user被修改啦,原值:'+oldValue.name+',新值:'+newValue.name); }, deep : true //深度监视,当对象中的属性发生变化时也会监视 } } }); //方式1 使用vue实例提供的$watch()方法 vm.$watch('name',function(newValue,oldValue){ console.log('name被修改啦,原值:' + oldValue + ', 新值:' + newValue); }) </script> </body> </html>
自定义指令
分类:全局指令、局部指令
1.自定义全局指令
- 使用全局方法Vue.directive(指令ID,定义对象)
2.自定义局部指令
- vue实例中,directives选项中定义
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>自定义指令</title> <script src="js/vue.js"></script> <script src="js/axios.min.js"></script> <script src="js/vue-resource.min.js"></script> </head> <body> <div id="itany"> <!--<p>验证钩子函数 或者 说是指令执行的生命周期</p>--> <!--<h3 v-hello>{{ msg }}</h3>--> <!--<button @click="change">更新数据</button>--> <!--<hr>--> <!--<p>定义指令参数验证</p>--> <!--<h3 v-world:wbs17022.haha>{{ msg }}</h3>--> <p>自定义局部指令</p> <input type="text" v-model="msg" v-focus> </div> <script> /*自定义全局指令*/ /*注:使用指令时必须在指令名称前加前缀v-,即v-指令名称*/ Vue.directive('hello',{ bind(){//常用! alert('指令第一次绑定到元素上时调用,只调用一次,可执行初始化操作'); }, inserted(){ alert('被绑定元素插入到DOM中时调用'); }, update(){ alert('被绑定元素所在模板更新时调用'); }, componentUpdated(){ alert('被绑定元素所在模版完成一次更新周期时调用'); }, unbind(){ alert('指令与元素解绑时调用,只调用一次'); } }); //钩子函数的参数 Vue.directive('world',{ bind(el,binding){ console.log(el); el.style.color = 'red'; console.log(binding); //指令name console.log(binding.arg); //冒号后面的值 console.log(binding.modifiers); //后缀对象 {haha: true} } }); //传入一个简单的函数, bind 和 update时调用 Vue.directive('wbs',function(){ alert('wbs17022'); }); var vm = new Vue({ el : '#itany', data : { msg : 'welcome to itany' }, methods : { change(){ this.msg = 'hello world' } }, directives : {//自定义局部指令 focus : { //当被绑定元素插入到DOM中时获取焦点 inserted(el){ el.focus(); } } } }); </script> </body> </html>
动画
Vue 在插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡效果本质上还是使用CSS3动画:transition、animation
使用transition组件,将要执行动画的元素包含在该组件内<transition>运动的元素</transition> 过滤的CSS类名:6个,通过设置好这几个类就达到动画的效果,提供8个钩子函数在动画生命周期里写入触发事件函数
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>单个动画</title> <script src="js/vue.js"></script> <script src="js/axios.min.js"></script> <script src="js/vue-resource.min.js"></script> <style> p{ width : 300px; height : 300px; background-color : red; } .fade-enter-active,.fade-leave-active{ transition : all 3s ease; } .fade-enter-active{ opacity : 1; width : 300px; height : 300px; } .fade-leave-active{ opacity : 0; width : 50px; height : 50px; } /* .fade-enter需要放在.fade-enter-active的后面*/ .fade-enter{ opacity : 0; width : 100px; height : 100px; } </style> </head> <body> <div id="itany"> <button @click="flag=!flag">点我</button> <!--name可以随便取--> <transition name="fade" @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter" @before-leave="beforeLeave" @leave="leave" @after-leave="afterLeave"> <p v-show="flag">wang bo</p> </transition> </div> <script> var vm = new Vue({ el : '#itany', data : { flag : false }, methods : { beforeEnter(el){ alert('动画进入之前'); }, enter(){ alert('动画进入'); }, afterEnter(el){ alert('动画进入之后'); el.style.background='blue'; }, beforeLeave(){ alert('动画即将离开之前') }, leave(){ alert('动画离开'); }, afterLeave(el){ alert('动画离开之后'); el.style.background = 'red'; } }, }); </script> </body> </html>
当然你也可以结合第三方提供动画插件animate实现动画效果,只要使用它提供的样式就可以了
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>动画</title> <link rel="stylesheet" href="css/animate.css"> <script src="js/vue.js"></script> <style> p{ 300px; height: 300px; background-color:red; margin:0 auto; } </style> </head> <body> <div id="itany"> <button @click="flag=!flag">点我</button> <transition enter-active-class="animated fadeInLeft" leave-active-class="animated fadeOutRight"> <p v-show="flag">网博</p> </transition> </div> <script> var vm=new Vue({ el:'#itany', data:{ flag:false } }); </script> </body> </html>
上面transition标签也只能实现单个动画效果,如果想实现多个动画效果,就必须使用transition-group标签,并且每个动画标签都要给key属性绑定一个唯一值
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>多元素动画</title> <link rel="stylesheet" href="css/animate.css"> <script src="js/vue.js"></script> <style> p{ 100px; height: 100px; background-color:red; margin:20px auto; } </style> </head> <body> <div id="itany"> <button @click="flag=!flag">点我</button> <transition-group enter-active-class="animated bounceInLeft" leave-active-class="animated bounceOutRight"> <p v-show="flag" :key="1">itany</p> <p v-show="flag" :key="2">网博</p> </transition-group> </div> <script> var vm=new Vue({ el:'#itany', data:{ flag:false } }); </script> </body> </html>
组件component
组件的使用方法
组件(Component)是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码组件是自定义元素(对象)
定义组件的两种方式:
- 先创建组件构造器,然后由组件构造器创建组件
- 直接创建组件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>定义组件的两种方式</title> <script src="js/vue.js"></script> </head> <body> <div id="itany"> <hello></hello> <my-world></my-world> </div> <script> /*方式1:先创建组件构造器,然后由组件构造器创建组件*/ //1.使用Vue.extend()创建一个组件构造器 var MyComponent = Vue.extend({ template : '<h3>Hello World</h3>' }); //2.使用Vue.component(标签名,组件构造器) 根据组件构造器来创建组件 Vue.component('hello', MyComponent); /*方式2:直接创建组件(推荐)*/ Vue.component('my-world',{ template : '<h1>你好,世界</h1>' }) var vm = new Vue({//这里的vm也是一个组件 称为根组件Root el : '#itany', data : { msg : 'wang bo' } }) </script> </body> </html>
组件分为全局组件、局部组件,全局组件由Vue.component方法定义,而局部组件则是vue实例中的components里定义
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>组件的分类</title> <script src="js/vue.js"></script> </head> <body> <div id="itany"> <my-hello></my-hello> <my-world></my-world> </div> <script> /*全局组件,可以在所有vue实例中使用*/ Vue.component('my-hello',{ template : '<h3>{{ name }}</h3>', data : function(){//在组件中存储数据时,必须以函数形式,函数返回一个对象 return { name : 'alex' } } }); /*局部组件,只能在当前vue实例中使用,vue实例中提供components选项定义*/ vm = new Vue({ el : '#itany', data : { name : 'wang bo' }, components : { 'my-world' : { //vue实例本身也是组件,和当前my-world组件是父子组件关系,子组件是不能直接访问父组件的data数据的 //template : '<h3>{{ name }}</h3>', template : '<h3>{{ age }}</h3>', data(){ return { age : 25 } } } } }) </script> </body> </html>
引用模板:除了在组件里的template选项指定模板外,另外还提供了一种方式--将组件内容放到模板<template>中并引用
另外在用template标签定义模板时,需要保证template标签只有一个根元素
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>引用模板</title> <script src="js/vue.js"></script> </head> <body> <div id="itany"> <my-hello></my-hello> </div> <template id="wbs"> <!--template必须有且只有一个根元素--> <div> <h3>{{ msg }}</h3> <ul> <li v-for="value in arr">{{ value }}</li> </ul> </div> </template> <script> var vm = new Vue({ el : '#itany', components : { 'my-hello' : { name : 'wbs17022', //指定组件的名称,默认为标签名,可以不设置 template : '#wbs', data(){ return { msg : 'welcome to the world', arr : ['tom', 'jack', 'mike'] } } } } }) </script> </body> </html>
动态组件
- <component :is="">组件 多个组件使用同一个挂载点,然后动态的在它们之间切换,is属性绑定了哪个组件,哪个组件就处于挂载状态
- <keep-alive>组件 可以防止非活动组件重复渲染
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>动态组件</title> <script src="js/vue.js"></script> </head> <body> <div id="itany"> <button @click="flag='my-hello'">显示hello组件</button> <button @click="flag='my-world'">显示world组件</button> <!--使用keep-alive组件缓存非活动组件,可以保留状态,避免重新渲染,默认每次都会销毁非活动组件并重新创建--> <keep-alive> <component :is="flag"></component> </keep-alive> </div> <script> var vm = new Vue({ el : '#itany', data : { flag : 'my-hello' }, components : { 'my-hello' : { template : '<h2>我是hello组件{{x}}</h2>', data(){ return { x : Math.random() } } }, 'my-world' : { template : '<h3>我是world组件{{y}}</h3>', data(){ return { y : Math.random() } } } } }) </script> </body> </html>
组件间数据传递
在一个组件内部定义另一个组件,称为父子组件,子组件只能在父组件内部使用,默认情况下,子组件无法访问父组件中的数据,每个组件实例的作用域是独立的
子组件访问父组件的数据:
- 在调用子组件时,通过自定义属性绑定想要获取的父组件中的数据
- 在子组件内部,使用props选项声明获取的数据,即接收来自父组件的数据
总结:父组件通过props向下传递数据给子组件
注:组件中的数据共有三种形式:data、props、computed
父组件访问子组件的数据:
- 在子组件中使用vm.$emit(事件名,数据)触发一个自定义事件,事件名自定义
- 父组件在使用子组件的地方监听子组件触发的事件,并在父组件中定义方法,用来获取数据
总结:子组件通过events给父组件发送消息,实际上就是子组件把自己的数据发送到父组件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>父子组件及组件间数据传递</title> <script src="js/vue.js"></script> </head> <body> <div id="itany"> <my-hello></my-hello> <!--嵌套的子组件是不可以直接访问的,只能在父组件的模板下访问--> <!--<my-world></my-world>--> </div> <template id="hello"> <div> <h3>我是hello父组件</h3> <h3>访问自己的数据:{{ msg }},{{ name }},{{ age }},{{ user.username }}</h3> <br> <h4>子组件只能在父模板下访问</h4> <my-world :message="msg" :name="name" :age="age" @e-world="getData"></my-world> <!--<my-world :message="msg" :name="name" :age="age" :user="user"></my-world>--> <h3>访问子组件的数据:{{ sex }},{{ height }}</h3> </div> </template> <template id="world"> <div> <h4>我是world子组件</h4> <h4>访问自己的数据:{{ sex }},{{ height }}</h4> <br> <h4>访问父组件中的数据:{{ message }},{{ name }},{{ age }},{{ user.username}}</h4> <button @click="send">将子组件的数据向上传递给父组件</button> </div> </template> <script> var vm = new Vue({//根组件 el : '#itany', components : { 'my-hello' : { //父组件 methods : { getData(sex,height){ this.sex = sex; this.height = height; } }, data(){ return { msg : 'wang bo', name : 'tom', age : 23, user : {id:9527,username:'唐伯虎'}, sex : '', height : '' } }, template : '#hello', components : { 'my-world' : {//子组件 data(){ return { sex : 'male', height : 180.5 } }, template : '#world', //props : ['message','name','age','user'] //简单的字符串数组 props : {//也可以是对象形式 message : String, name : { type : String, required : true, }, age : { type : Number, default : 18, validator : function(value){ return value >= 0; } }, user : { type : Object, default : function(){//对象或数组的默认值必须使用函数的形式来返回 return {id:3306,username:'秋香'}; } } }, methods : { send(){//如果你希望在加载就被父组件访问到,可以用vue生命周期中挂载事件 //console.log(this); //此处的this表示当前子组件实例 this.$emit('e-world',this.sex,this.height); //使用$emit()触发一个事件,发送数据 } } } } } } }) </script> </body> </html>
单向数据流
- props是单向绑定的,当父组件的属性变化时,将传导给子组件,但是不会反过来
- 子组件不允许直接修改父组件中的数据,报错
子组件修改父组件解决方案:
- 如果子组件想把它作为局部数据来使用,可以将数据存入另一个变量中再操作,不影响父组件中的数据
- 如果子组件想修改数据并且同步更新到父组件,两个方法:
-
使用.sync(1.0版本中支持,2.0版本中不支持,2.3版本又开始支持) 需要$emit显式地触发一个更新事件
- 可以将父组件中的数据包装成对象,然后在子组件中修改对象的属性(因为对象是引用类型,指向同一个内存空间),推荐
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>单向数据流</title> <script src="js/vue.js"></script> </head> <body> <div id="itany"> <h2>父组件:{{ name }}</h2> <h4>双向绑定,改变父组件的数据,子组件传入的数据也会跟着改</h4> <input type="text" v-model="name"> <h2>父组件{{ user.age }}</h2> <hr> <!--在调用子组件时,通过.sync允许子组件修改指定名称父组件传递的数据--> <my-hello :name.sync="name" :user="user"></my-hello> </div> <template id="hello"> <div> <h3>子组件{{ name }}</h3> <!--变量赋值修改--> <!--<h3>子组件{{ username }}</h3>--> <h3>子组件{{ user.age }}</h3> <h4>而子组件想修改父组件的数据,是不能直接修改的,修改报错</h4> <!--方式1:赋值给新的变量--> <button @click="change">修改数据</button> </div> </template> <script> var vm = new Vue({ el : '#itany', data : { name : 'tom', user : { name : 'zhangsan', age : 24 } }, components : { 'my-hello' : { template : '#hello', props : ['name','user'], data(){ return { username : this.name //方式1:将数据存入另一个变量中再操作 } }, methods : { change(){ //this.name = 'alex'; 直接修改 报错 //this.username = 'alex'; 赋值修改 this.$emit('update:name','alex'); //方式2:a.使用.sync,需要用$emit显式触发更新事件 this.user.age = 10000; //方式2:b.利用对象是引用类型,修改属性时,不会改变内存地址 } } } } }) </script> </body> </html>
非父子组件间的通信
- var Event=new Vue(); 创建一个空实例,相当于中介者
- 发送组件发送数据:Event.$emit(事件名,数据)
- 接收组件接收数据:Event.$on(事件名,data => {})
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>非父子组件通信</title> <script src="js/vue.js"></script> </head> <body> <div id="itany"> <my-a></my-a> <my-b></my-b> <my-c></my-c> </div> <template id="a"> <div> <h3>A组件{{ name }}</h3> <button @click="send">将数据发送给C组件</button> </div> </template> <template id="b"> <div> <h3>B组件{{ age }}</h3> <button @click="send">将数组发送给C组件</button> </div> </template> <template id="c"> <div> <h3>C组件{{ name }}{{ age }}</h3> </div> </template> <script> //定义一个空的Vue实例 var Event = new Vue({ name : 'yes' }); var A = { template : '#a', data(){ return { name : 'tom' } }, methods : { send(){ Event.$emit('data-a', this.name); } } }; var B = { template : '#b', data(){ return { age : '2555' } }, methods : { send(){ Event.$emit('data-b', this.age); } } }; var C = { template : '#c', data(){ return { name : '', age : '' } }, mounted(){//在模板编译完成后执行 //Event.$on('data-a',function(name){ // console.log(name); // console.log(this); //此时的this是Event,也就是空Vue实例 //}); Event.$on('data-a',name => { this.name = name; console.log(this); //此时this是C组件,和上面的函数调用方式有所区别 }); Event.$on('data-b',age => { this.age = age; }) } }; var vm = new Vue({ el : '#itany', components : { 'my-a' : A, 'my-b' : B, 'my-c' : C } }) </script> </body> </html>
slot内容分发
- 本意:位置、槽
- 作用:用来获取组件中的原内容,可以在模板中实现对原内容进行排版,类似angular中的transclude指令
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>slot内容分发</title> <script src="js/vue.js"></script> </head> <body> <div id="itany"> <!--<my-hello></my-hello>--> <!--<my-hello>456</my-hello>--> <my-hello> <ul slot="s1"> <li>aaa</li> <li>bbb</li> <li>ccc</li> </ul> <ol slot="s2"> <li>111</li> <li>222</li> <li>333</li> </ol> </my-hello> </div> <template id="hello"> <div> <h3>welcome to itany</h3> <!--如果my-hello标签间没有内容,则用默认值123--> <!--<slot>123</slot>--> <slot name="s2"></slot> <hr> <slot name="s1"></slot> </div> </template> <script> var vm = new Vue({ el : '#itany', components : { 'my-hello' : { template : '#hello' } } }); </script> </body> </html>
vue-router路由
使用Vue.js开发SPA(Single Page Application)单页面应用,根据不同url地址,显示不同的内容,但显示在同一个页面中,称为单页面应用 [参考](https://router.vuejs.org/zh-cn)
cnpm install vue-router -S
基本用法
路由配置分四步走
- 定义组件 就是链接跳转时,显示的内容
- 配置路由 就是把url和组件添加映射关系
- 创建路由实例 提供配置路由参数,包括上面的路由映射关系,和显示样式等
- 注入路由 路由内容应该在哪个vue实例下显示
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>路由基本用法</title> <script src="js/vue.js"></script> <script src="js/vue-router.js"></script> <style> .active{ font-size : 20px; color : #ff7300; text-decoration : none; } </style> </head> <body> <div id="itany"> <div> <router-link to="/home">主页</router-link> <router-link to="/news">新闻</router-link> </div> <div> <router-view></router-view> </div> </div> <script> //1.定义组件 var Home = { template : '<h3>我是主页</h3>' }; var News = { template : '<h3>我是新闻</h3>' }; //2.配置路由 const routes = [ {path:'/home',component:Home}, {path:'/news',component:News}, {path:'*',redirect:'/home'} //重定向 ]; //3.创建路由实例 const router = new VueRouter({ routes, //简写,相当于routes:routes //mode : 'history', //更改模式 linkActiveClass : 'active' //更新活动链接的class类名 }); //4.创建根实例并将路由挂载到Vue实例上 new Vue({ el : '#itany', router //注入路由 }) </script> </body> </html>
路由嵌套和参数传递
传参的两种方式
- 查询字符串:login?name=tom&pwd=123 {{$route.query}}
- rest风格url:regist/alice/456 {{$route.params}}
路由实例方法
- router.push() 添加路由,功能上与<route-link>相同
- router.replace() 替换路由,不产生历史记录
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>路由嵌套和参数传递</title> <link rel="stylesheet" href="css/animate.css"> <script src="js/vue.js"></script> <script src="js/vue-router.js"></script> <style> .active{ font-size : 20px; color : #ff7300; text-decoration : none; } </style> </head> <body> <div id="itany"> <div> <router-link to="/home">主页</router-link> <router-link to="/user">用户</router-link> </div> <div> <transition enter-active-class="animated bounceInLeft" leave-active-class="animated bounceOutRight" > <router-view></router-view> </transition> <hr> <button @click="push">添加路由</button> <button @click="replace">替换路由</button> </div> </div> <template id="user"> <div> <h3>用户信息</h3> <ul> <!--router-link里还提供tag选项 用指定生成什么标签--> <router-link to="/user/login?username=alex&age=89" tag="li">用户登录</router-link> <router-link to="/user/regist/alex/89" tag="li">用户注册</router-link> </ul> <router-view></router-view> </div> </template> <script> var Home = { template : '<h3>我是主页</h3>' }; var User = { template : '#user' }; var Login = { template : '<h4>用户登录....获取参数:{{ $route.query }},{{ $route.path }}</h4>', mounted : function(){ alert(this.$route.query.username); } }; var Regist = { template : '<h4>用户注册 获取参数:{{ $route.params }},{{ $route.path }}</h4>' }; const routes = [ { path : '/home', component : Home }, { path : '/user', component : User, children : [ { path : 'login', component : Login }, { path : 'regist/:username/:password', component : Regist } ] }, { path : '*', redirect : '/home' } ]; const router = new VueRouter({ routes, linkActiveClass : 'active' }); new Vue({ el : '#itany', router, methods : { push(){ router.push({path:'home'}); //添加路由, 本质上就是在触发时 切换路由 这里切换到home }, replace(){ router.replace({path:'user'}); //替换路由 还是切换路由 没有历史记录 } } }) </script> </body> </html>