前端基础
HTML:结构
CSS:表现
JavaScript:行为(js API 获取元素 CRUD) —> jQuery ----> VUE (MVVM)
do…getElementById(“id”) — $("#id")
MVVM:
Model:模型层,在这里表示JavaScript对象(更多的指的是JSON对象)
View:视图层,在这里表示DOM(HTML元素)
ViewModel:连接视图和数据的一个中间件
view的变化会自动更新到ViewModel中,而viewModel的变化也会自动更新到View上进行显示.
(DOM view之间的监听 数据绑定)
VUE
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
特点:
轻量级框架,体积小(20K),开发移动端更适合移动端Touch事件…
易上手,学习方便,文档相对比较齐全
组件:一切皆组件
轻量级的,数据库绑定,应用指令的,插件化开发.
JSON格式对象:
{
key1:value1,
key2:value2
}
VUE起步案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>欢迎学习VUE</title>
<!-- <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>-->
<script src="../lib/vue.js"></script>
</head>
<body>
<div id="app">
<h3>名称:{{name}}</h3>
<h3>地址:{{url}}</h3>
<h3>{{showInfo()}}</h3>
</div>
<script>
//每个VUE.js的应用都需要通过构造函数来创建VUE实例
//构造函数都需要传入一个选项对象,包含挂载元素,数据,方法,生命周期....
// var vm = new Vue({
// el:'#app',//为VUE对象指定挂载对象
// data:{//data对象定义的属性---响应式属性
// name:"",
// url:""
// }//数据定义
// })
var data={name:"",url:""};
var vm = new Vue({
el:'#app',//为VUE对象指定挂载对象
data:data, //数据定义
methods:{
showInfo:function () {
return this.name+"||"+this.url;
}
}
})
//vue.js中提供了有效的实例属性和方法,这些属性和方法名称都有前缀$,以便与用户的属性进行区分
document.write(vm.$data===data);
document.write(vm.$el);
// vm.$data={name:"aaa",url:"bbb"};//无法修改
// data={name:"aaa",url:"bbb"};//无法修改
vm.name="aaa";
vm.url='bbb';
</script>
</body>
</html>
VUE生命周期钩子函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../lib/vue.js"></script>
</head>
<body>
<div id="app">
</div>
<script>
//vue生命周期钩子函数:监听vue整个的生命过程,vue的一系列初始化步骤
var vm = new Vue({
el:'#app',
//vue实例开始初始化时调用
beforeCreate:function () {
console.log('beforeCreate')
},
//vue在创建实例之后进行调用,此时DOM尚未开始编译
created:function () {
console.log('created')
},
//在DOM文档渲染完毕之后立即调用(window.onload)
mounted:function () {
console.log('mounted')
},
beforeDestroy:function () {
console.log('beforeDestroy')
},
destroyed:function () {
console.log('destroyed')
}
});
</script>
</body>
</html>
数据的绑定:
- 文本绑定 ----{{}}
- HTML插值 ---- v-html
- 属性绑定 ---- v-bind 可以简写为 : (对象的绑定形式简单了解)
- 在双大括号中可以书写表达式,常量或者变量,或者运算符组成的式子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../lib/vue.js"></script>
<style>
.title{
color: #FF0000;
border: 1px solid red;
padding: 5px;
}
</style>
</head>
<body>
<div id='app'>
<h3>文本插值:{{name}}</h3>
<h3 v-once>文本插值(只插入一次):{{name}}</h3>
HTML插值<h3 v-html="message"></h3>
为元素绑定属性,比如class
<h3 v-bind:class="value">天津中德应用技术大学</h3>
绑定属性时,还可以以对象的形式赋值
<h3 v-bind:class="{'title':flag}">天津中德应用技术大学</h3>
由于属性绑定比较频繁,所以可以简写为 :
<a v-bind:href="url">进入百度</a>
<a :href="url">进入百度</a><br>
在双大括号中可以书写表达式,常量或者变量,或者运算符组成的式子<br>
{{number+10}}<br>
{{flag?"真":"假"}}<br>
{{str.toLowerCase()}}<br>
{{email}}<br>
qq:{{email.substr(0,email.indexOf('@'))}}
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
name:'lzp',
value:"title",
message:"<h1>科技是第一生产力</h1>",
flag:true,
url:"http://www.baidu.com",
number:100,
str:"My Love",
email:'21462092482@qq.com'
}
})
</script>
</body>
</html>
v-if(v-show)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../lib/vue.js"></script>
</head>
<body>
<div id='app'>
<h1 v-if="type==='A'">A</h1>
<h1 v-else-if="type==='B'">B</h1>
<h1 v-else-if="type==='C'">C</h1>
<h1 v-else>who</h1>
<input type="button" :value="bText" @click="toggle()">
v-show与v-if区别:if会进行判断,决定标签是否存在.show判断之后进行标签的显示和隐藏(标签不会消失)
<div v-show="show">
<img src="../imgs/a.jpg">
</div>
</div>
<script>
//可以在template标签中使用v-if,本标签不会渲染任何的结果
var vm = new Vue({
el: '#app',
data: {
type:'D',
show:true,
bText:"隐藏图片"
},
methods:{
toggle:function () {
this.show=!this.show;
this.bText=="隐藏图片"?this.bText="显示图片":this.bText="隐藏图片";
}
}
})
</script>
</body>
</html>
v-on
用来绑定事件的指令,v-on:可以简写为@符号,事件需要定义在VUE对象中的methods选项中.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../lib/vue.js"></script>
</head>
<body>
<div id='app'>
<button v-on:click="sayHi">sayHi1</button>
<button @click="sayHi">sayHi2</button>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
message:'hello'
},
methods:{
sayHi:function (event) {
//事件源对象
console.log(event);
alert(this.message);
}
}
})
</script>
</body>
</html>
v-for
用法:
- {{item.name}}
- {{index+1}}--{{item.name}}
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="../lib/vue.js"></script> <style> ul{ list-style: none; line-height: 30px; height: 30px; } li{ float: left; margin: auto 30px; } .item{ font-family: 微软雅黑; font-size: 20px; font-weight: 600; } .separator:not(:last-child){ width: 3px; height: 20px; background: #999999; margin: 9px auto; } </style> </head> <body> <div id='app'> <ul> <li v-for="item in items">{{item.name}}</li> <li v-for="(item,index) in items">{{index+1}}--{{item.name}}</li> </ul> <ul> <template v-for="menu in menulist"> <li class="item">{{menu}}</li> <li class="separator"></li> </template> </ul> <div v-for="n in 9"> <span v-for="m in n"> {{m}}*{{n}}={{m*n}} </span> </div> </div> <script> var vm = new Vue({ el: '#app', data: { items:[ {name:'张三'}, {name:'李四'}, {name:'翠花'} ], menulist:['首页','闪购','生鲜','团购','全球购'] } }) //局部方式向数组添加内容 vm.menulist.push('大甩卖'); //全局设置 Vue.set(vm.menulist,6,'随便'); //v-for 遍历 数组,对象,整数 // 对象 (value 为属性值 key为属性名 index为索引) // v-for="value in Object" // v-for="(value,key) in Object" // v-for="(value,key,index) in Object" // v-for="n in 5" 12345 //练习: 99乘法表 </script> </body> </html>
过滤器
在经过复杂的计算进行数据绑定时,可以通过过滤器进行处理,自定义过滤器对文本进行格式化
用法:
1.{{message | myfilter}} 在
v-bind
中2.定义
全局:Vue.filter(过滤器名称,过滤器函数)
局部:Vue构造中 增加 filters
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="../lib/vue.js"></script> </head> <body> <div id='app'> <ul> <li><span>特惠</span>{{title1 | subStr}}</li> <li><span>公告</span>{{title2 | subStr}}</li> <li><span>特惠</span>{{title3 | subStr}}</li> <li><span>公告</span>{{title4 | subStr}}</li> <li><span>特惠</span>{{title5 | subStr}}</li> <li><span>公告</span>{{title6 | subStr}}</li> </ul> {{date | nowDate}} </div> <script> //如果文本超过10字符,...省略显示 不足10个的 全部显现 Vue.filter('nowDate',function (value) { var year = value.getFullYear(); var month = value.getMonth()+1; var date = value.getDate(); var day = value.getDay(); var week = ''; switch (day) { case 1: week="星期一"; break; case 2: week="星期二"; break; case 3: week="星期三"; break; case 4: week="星期四"; break; case 5: week="星期五"; break; case 6: week="星期六"; break; case 7: week="星期日"; break; } return "今天是:"+year+"年"+month+"月"+date+"日"+week; }) var vm = new Vue({ el: '#app', data: { title1:'商品爆品1分秒杀', title2:'茅台酒年末促销,低价两件五折', title3:'商品爆品1分秒杀', title4:'茅台酒年末促销,低价两件五折', title5:'商品爆品1分秒杀', title6:'茅台酒年末促销,低价两件五折', date:new Date() }, filters:{ subStr:function (value) { if(value.length>10){ return value.substr(0,10)+"..."; }else { return value; } } } }) //时间过滤器 -- 今天是: 2021年5月10日 星期一 全局 </script> </body> </html>
计算属性
计算属性的重点–属性(名词),具有计算能力的属性(计算是动词),在这里计算就是一个函数.
它就是一个能够将计算结果缓存起来的属性
使用:
定义—computed
当计算属性依赖的数据发生变化时,这个属性的值会自动的更新.
每个计算属性里面都包含了getter 和 setter方法,当我们没有指明用的方法时,默认是getter
由于缓存的特性,则相对于方法而言,反复的计算过程必定产生系统的开销,那么如果这个结果不是经常改变的,就可以利用计算属性的特性(缓存)去实现更好.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="../lib/vue.js"></script> </head> <body> <div id='app'> <table border="1"> <thead> <th>商品名称</th> <th>商品单价</th> <th>商品数量</th> <th>商品金额</th> </thead> <template v-for="item in shop"> <tr> <td>{{item.name}}</td> <td>{{item.price}}</td> <td>{{item.count}}</td> <td>{{item.count*item.price | twoDecimal}}</td> </tr> </template> <tr> <td colspan="3">合计</td> <td>{{totalPrice | twoDecimal}}</td> </tr> </table> <p>姓名:{{fullName}}</p> </div> <script> var vm = new Vue({ el: '#app', data: { shop:[ { name:'iphone 12', price:5999, count:3 }, { name:'华为 P30', price:6999, count:4 } ], name:'李', Cname:'忠鹏' }, filters:{ twoDecimal:function (value) { return value.toFixed(2); } }, //每个计算属性里面都包含了getter 和 setter方法,当我们没有指明用的方法时,默认是getter computed:{ totalPrice:function () { var total=0; this.shop.forEach(function (s) { total+=s.count*s.price; }) return total; }, fullName:{ get:function () { return this.name+this.Cname; }, set:function (value) { this.name=value.substr(0,1); this.Cname=value.substr(1); } } } }) </script> </body> </html>
监听属性
每当属性发生改变时都会触发监听属性
可以通过watch选项进行监听,或者可以通过实例方法vm.$watch(),
函数使用:可以传递两个参数,第一个代表新值,第二个代表旧值
监听---- 数值 , 对象 ,数组
如果监听对象时,想要监听到对象的内部,需要增加deep属性为true才可以监听到
watch:{ shop:{ deep:true, handler:function(val){ .... } } }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="../lib/vue.js"></script> </head> <body> <div id='app'> 人民币:<input v-model="rmb"><br> 美元:<input v-model="dollar"><br> {{rmb | twoDecimal}}元人民币={{dollar | twoDecimal}}美元 </div> <script> var vm = new Vue({ el: '#app', data: { rate:0.68, rmb:0, dollar:0 }, watch:{ rmb: function (newValue,oldValue) { alert(newValue+":"+oldValue); this.dollar=this.rmb*this.rate; }, dollar: function () { this.rmb = this.dollar/this.rate; } }, filters:{ twoDecimal:function (val) { return val.toFixed(2); } } }) </script> </body> </html>
样式绑定
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="../lib/vue.js"></script> <style> .active{ color: red; } .size{ font-size: 30px; } .line{ text-decoration: line-through; } </style> </head> <body> <div id='app'> class的内联绑定 <h3 :class="{active:isActive}">{{name}}</h3> class 非内联 将元素的class 属性绑定在对象上,data中定义 <h3 :class="classObject">{{name}}</h3> 使用计算属性返回样式对象 <h3 :class="show">{{name}}</h3> 数组的绑定语法 <h3 :class="[lineClass,sizeClass]">{{name}}</h3> <h3 :class="[isLine?lineClass:'',sizeClass]">{{name}}</h3> <h3 :class="[{line:isLine},sizeClass]">{{name}}</h3> style的内联样式绑定 <h3 :style="{fontWeight:weight,'font-size':fontSize+'px'}">{{name}}</h3> style非内联 <h3 :style="styleObject">Vue.js样式绑定</h3> 使用计算属性返回样式对象 <h3 :style="showStyle">Vue.js样式绑定</h3> 数组语法 <div :style="[{fontWeight:weight},{'font-size':fontSize+'px'},{'text-decoration':'underline'}]">Vue.js样式绑定</div> </div> <script> var vm = new Vue({ el: '#app', data: { styleObject:{ fontWeight:'bold', 'font-size':'40px' }, fontSize:40, name: 'aaa', isActive:true, classObject:{ size:true, active:true }, lineClass:'line', sizeClass:'size', isLine:true }, computed:{ show:function () { return { active:true, size:this.classObject.size }; }, showStyle:function () { return { fontWeight:'bold', 'font-size':'40px' } } } }) </script> </body> </html>
事件总结
事件修饰符
对于常用的事件操作行为从而定义的一系列的快捷方法
1.prevent :阻止浏览器的默认行为 相当于 event.preventDefault()
2.stop:阻止冒泡行为,相当于event.stopPropagation
3.once:只触发一次
4.self:只当事件从监听器绑定的元素本身触发时才会触发回调
keyup事件:按下之后的抬起键盘事件
enter --13
space --32
左37 上38 右 39 下 40
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="../lib/vue.js"></script> </head> <body> <div id='app'> <h3 @click="show">{{name}}</h3> <img id="pic" src="../imgs/a.jpg" @mouseover="visible(1)" @mouseout="visible(0)"> <a href="http://www.baidu.com" @click="showA('百度',$event)">百度</a> <a href="http://www.baidu.com" @click.prevent="showA('百度',$event)">百度</a> <input @keyup.enter="submit"> <input @keyup.13="submit"> </div> <script> var vm = new Vue({ el: '#app', data: { name: 'lzp' }, methods:{ show:function (event) {//当不传递任何参数时,默认可以接收事件源对象,从而获取信息 alert(event.target.tagName); }, visible:function (value) { //获取event对象 var event = window.event || arguments.callee.caller.arguments[0]; // var pic = document.getElementById("pic"); //判断是鼠标移入还是移出 if(value==1){ event.target.style.opacity=0.5; // pic.style.opacity=0.5; }else { event.target.style.opacity=1; // pic.style.opacity=1; } }, showA:function (val,event) { // event.preventDefault();//阻止浏览器的默认跳转行为 alert(val+event.target.tagName); } } }) </script> </body> </html>
表单控件绑定
通过v-model指令对于表单的元素进行双向的数据绑定,在修改表单时,vue实例对应的属性应该更新,反之亦然.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="../lib/vue.js"></script> </head> <body> <div id='app'> <p>单行文本框当前输入:{{message}}</p> <input type="text" v-model.number="message" placeholder="单击此处编辑"> <p>多行文本框当前输入:{{message}}</p> <textarea v-model="message"></textarea> <p>单个复选框:{{checked}}</p> <input type="checkbox" v-model="checked"> <p>多个复选框:{{brand}}</p> <input type="checkbox" v-model="brand" value="iphone">苹果 <input type="checkbox" v-model="brand" value="华为">华为 <input type="checkbox" v-model="brand" value="小米">小米 <p>单选按钮框:{{sex}}</p> <input type="radio" value="1" v-model="sex">男 <input type="radio" value="0" v-model="sex">女 <p>下拉选:{{type}}</p> <select v-model="type"> <option value="">请选择种类</option> <option value="1">平板</option> <option value="2">手机</option> <option>电脑</option> </select> <p>多选下拉选:{{filmtype}}</p> <select multiple="multiple" v-model="filmtype" size="6"> <option>武侠片</option> <option>动作片</option> <option>爱情片</option> <option>科幻片</option> <option>喜剧片</option> <option>恐怖片</option> </select> <p>多选框的值的绑定:{{toggle}},所有的值绑定都可以使用:value的形式</p> <input type="checkbox" v-model="toggle" :true-value="yes" :false-value="no"> </div> <script> var vm = new Vue({ el: '#app', data: { message:'', checked:false, brand:["iphone", "华为", "小米" ], sex:'', type:'', filmtype:[], toggle:'', yes:"选中", no:"取消" } }) </script> </body> </html>
练习
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="../lib/vue.js"></script> </head> <body> <div id='app'> <h3>爱好</h3> <input type="checkbox" value="打游戏" v-model="checkedNames">打游戏 <input type="checkbox" value="看电影" v-model="checkedNames">看电影 <input type="checkbox" value="读书" v-model="checkedNames">读书 <input type="checkbox" value="写书" v-model="checkedNames">写书 <input type="checkbox" value="旅游" v-model="checkedNames">旅游 <input type="checkbox" value="睡觉" v-model="checkedNames">睡觉<br> <p v-if="checked"> 您的爱好是:{{checkedNames}} </p> <button @click="allChecked">全选</button> <button @click="reverseChecked">反选</button> <button @click="noChecked">全不选</button> </div> <script> var vm = new Vue({ el: '#app', data: { checkedNames:[], checked:false, checkedArr:[ "打游戏", "看电影", "读书", "写书", "旅游", "睡觉" ], tempArr:[] }, methods:{ allChecked:function () { this.checkedNames=this.checkedArr; }, reverseChecked:function () { this.tempArr=[]; for(var i=0;i<this.checkedArr.length;i++){ if(!this.checkedNames.includes(this.checkedArr[i])){ this.tempArr.push(this.checkedArr[i]); } } this.checkedNames=this.tempArr; }, noChecked:function () { this.checkedNames=[]; } }, watch:{ checkedNames:function () { if(this.checkedNames.length>0){ this.checked=true; }else { this.checked=false; } } }, computed:{ result:function () { var show=''; for(var i=0;i<this.checkedNames.length;i++){ show+=this.checkedNames[i]+" ,"; } return show; } } }) </script> </body> </html>
自定义指令
1.全局注册指令
Vue.directive(id,definition)
id:指令的id
definition:定义对象 (是定义指令的钩子函数)
2.局部注册指令
directives选项实现局部的自定义指令
钩子函数
bind:只调用一次,在指令第一次绑定在元素上时调用(初始化)
unbind:只调用一次,在指令从元素上解绑时调用inserted:当前被绑定的元素插入DOM中时执行
update:在bind之后进行一次调用,后期每次值发生改变时调用(可以接收新值和旧值)2
componentUpdate:指令所在组件以及子组件更新时调用
参数说明
el:element元素本身
binding:一个对象,包含属性如下
name:指令名
value:指令绑定的值
oldValue:旧值…
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="../lib/vue.js"></script> </head> <body> <div id='app'> 利用全局自定义指令,页面加载完成时,自动获取焦点(在调用自己写的指令前面需要加v-) <input type="text" v-focus><br> 局部注册指令 自动添加外边框 <p v-add-border>局部的自定义指令</p> 测试钩子函数参数以及相关属性 <div v-demo:hello.a.b="message"></div> 自定义指令数字传值 <p v-set-position="50">绑定数值:固定定位 向右偏移50px</p> 自定义指令 有个文本框 有个图片 框中输入数字 --- 图片的边框宽度 <input type="text" v-model="width"> <p> <img src="../imgs/b.jpg" v-set-border="width"> </p> </div> <script> Vue.directive('setBorder',{ update:function (el,binding) { el.border=binding.value; } }) Vue.directive('setPosition',function (el,binding) { el.style.position='fixed'; el.style.left=binding.value+'px'; }) Vue.directive("demo",{ inserted:function (el,binding,vnode) { el.innerHTML= "name:"+binding.name+ "value:"+binding.value+ "vnode:"+Object.keys(vnode).join(","); } }) Vue.directive("focus",{ //当前被绑定的元素插入DOM中时执行 inserted:function (el) { el.focus();//使元素获得焦点 } }); var vm = new Vue({ el: '#app', data: { message:'11', width:'' }, directives:{ addBorder:{ inserted:function (el) { el.style.border='1px solid red'; } } } }) </script> </body> </html>
组件
1.注册全局组件
Vue.component(name,options)
2.注册局部组件
Vue实例中components选项注册一个局部的组件,属性名—组件名,属性值–组件的选项对象
组件中的数据传递(父-子)
通过定义prop属性实现父子组件之间的数据传递,prop是父组件用来传递数据的一个自定义属性,这样的属性定义在组件选项对象中的props选项中.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="../lib/vue.js"></script> </head> <body> <div id='app'> 传递纯文本的数据 <my-component message="别想他"></my-component> 传递动态的数据 <my-component :myname="name"></my-component> <button-count></button-count> <button-count></button-count> <button-count></button-count> <my-component2></my-component2> <my-movie :img="imgUrl" :title="title" :description="description"></my-movie> 传递数组和对象数据类型 <my-item :list="type" :shop="shop" v-bind="shop"></my-item> </div> <script> Vue.component("my-item",{ props:['list','shop','name','price'], template:` <ol> <li v-for="item in list">{{item}}</li> <li>{{shop.name}}</li> <li>{{shop.price}}</li> <li>{{shop.number}}</li> <li>{{name}}</li> <li>{{price}}</li> </ol> ` }) Vue.component('my-movie',{ props:['img','title','description'], template:` <div> <img :src="img"> <p>{{title}}</p> <P>{{description}}</P> </div> ` }) Vue.component("my-component",{ //组件的模板:只能有一个根元素,如果想有多个需要被包裹在根元素的内部 props:['message','myname'], template:`<div><span>多个元素</span><h3>注册全局组件{{message}}{{myname}}</h3></div>` }) //对与组件的数据声明,要以函数的返回值形式实现,防止各个组件之间的数据冲突 Vue.component("button-count",{ data:function(){ return { count:0 } }, template: `<button @click="count++">{{count}}</button>` }) var vm = new Vue({ el: '#app', data: { name: 'lzp', imgUrl:'../imgs/a.jpg', title:'你的婚礼', description:'爱情电影', type:['HTML','CSS','JS'], shop:{name:'华为P40',price:4000,number:500} }, components:{ "my-component2":{ template:`<div><h3>注册局部组件</h3><button-count></button-count></div>` } } }) </script> </body> </html>
组件中的数据传递(子-父)
通过自定义事件实现
通过父的v-on监听子组件的自定义事件,子组件内部通过$emit()方法传入事件名称来触发自定义事件
$emit(eventName,[…args])
eventName:传入事件的名称
[…args]:触发事件传递的参数,该参数是可选的
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="../lib/vue.js"></script> </head> <body> <div id='app'> <div :style="{fontSize:fontSize+'px'}"> <!-- <my-font :text="text" @enlarge="fontSize+=$event"></my-font>--> <my-font :text="text" @enlarge="fontBig"></my-font> </div> 在某个组件的根元素上监听一个原生事件可以使用v-on的.native修饰符 <my-component @click.native="openDialog"></my-component> </div> <script> Vue.component("my-component",{ template: '<button>请点击</button>' }) Vue.component('my-font',{ props:['text'], template:` <div> <button @click="action(5)">放大文本</button> <p>{{text}}</p> </div> `, methods:{ action:function (value) { this.$emit('enlarge',value);//触发enlarge自定义事件 } } }) var vm = new Vue({ el: '#app', data: { text:'你是谁的谁,为谁流眼泪,不需要安慰,也不需要有人陪', fontSize:10 }, methods: { fontBig:function (value) { alert(value); this.fontSize+=value; }, openDialog:function () { alert("我可以抱着你吗?"); } } }) </script> </body> </html>
内容分发
在开发中,一般子组件提供基本的交互功能,而内容由父组件提供,为此Vue提供了一种混合父组件内容和子组件模板的方式,这种方式称为内容分发.
内容分发通过作为原始内容的插槽
动态组件
多个组件使用同一个挂载点,根据条件的不同,组件之间进行切换,通过component元素动态绑定到is属性上的值进行判断
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="../lib/vue.js"></script> <style> .mainmenu{ list-style: none; line-height: 30px; height: 30px; margin-bottom: 40px; } .mainmenu>li{ float: left; border: 1px solid red; padding: 15px 30px; } </style> </head> <body> <div id='app'> <div> <ul class="mainmenu"> <li @click="current='music'">音乐</li> <li @click="current='videos'">视频</li> <li @click="current='news'">新闻</li> </ul> <component :is="current"></component> </div> </div> <script> var vm = new Vue({ el: '#app', data: { name: 'lzp', current:'music' }, components: { music:{ data:function(){ return{ subcur:'popular' } }, template: ` <div> <div> <ul> <li @click="subcur='popular'">流行音乐</li> <li @click="subcur='national'">民族音乐</li> <li @click="subcur='classical'">古典音乐</li> </ul> </div> <component :is="subcur"></component> </div> `, components: { popular:{ template: '<div>流行音乐内容</div>' }, national:{ template: '<div>流行民族内容</div>' }, classical:{ template: '<div>流行古典内容</div>' } } }, videos:{ template:`<div>视频内容</div>` }, news:{ template:'<div>新闻内容</div>' } } }) </script> </body> </html>
动态组件的缓存(keep-alive)
在多个组件切换时,有时需要保持这个组件的状态,将切换后的状态保存在内存中,以避免重复操作
通过keep-alive标签将动态数组将包裹起来即可
<keep-alive> <component :is="current"></component> </keep-alive>
路由
vue-router插件可以提供路由的管理功能(刚刚引入的router.js)
利用路由可以创建简单的单页面应用,使用vue可以通过多个组件来组成应用程序,而vue-router可以将每个路径映射到对应的组件中,进而实现组件之间的切换.
通过不同的URL访问不同的内容,需要用到标签,该标签可以设置一个导航链接(最终会生成一个a标签),通过to属性设置目标的地址,从而切换不同的html内容,通过定义路由的出口,实现组件的渲染位置.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="../lib/vue.js"></script> <script src="../lib/vue-router.js"></script> </head> <body> <div id='app'> <!-- 通过router-link标签进行导航--> <!-- 通过to属性指定URL--> <p> <router-link to="/first">页面一</router-link> <router-link to="/second">页面二</router-link> <router-link to="/third">页面三</router-link> </p> <!-- 路由的出口,路由匹配到组件的渲染的位置--> <router-view></router-view> </div> <script> //定义路由 每个路由---一个组件(1.component的Vue.extend()创建组件构造器实现 2.给一个组件的对象) var routes=[ { path:'/first', component:{ template:'<div>这是第一个页面</div>' } }, { path:'/second', component:{ template:'<div>这是第二个页面</div>' } }, { path:'/third', component:{ template:'<div>这是第三个页面</div>' } } ]; //创建路由的实例 传入routes配置参数 , 还可以传入其他的参数 var router = new VueRouter({ routes//相当于routes:routes的缩写 }); //通过router参数配置路由,让整个应用都有路由功能 var vm = new Vue({ el: '#app', router }) </script> </body> </html>
动态路由
在实际的开发过程中经常需要某种匹配模式匹配到的所有的路由映射到同一组件,例如,对与不同用户的ID,都可以用一个User来渲染,那么vue-router路径中就可以使用动态路由参数实现:
path:’/user/:id’,component:user
以上的代码 /user/1 /user/2 都可以进入当前组件
获取路径上的动态参数:通过this.$route.params.参数名 获取
路由嵌套
因为界面中通过由多个组件嵌套而成,比如二级导航菜单,这时需要用到路由的嵌套
使用路由嵌套的时候,动态路由会对应的嵌套各个组件,router-view为最顶级出口,用来渲染最高级的路由匹配组件.
(同样渲染的组件模板也可以嵌套router-view)(使用children参数时,注意嵌套的层级)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="../lib/vue.js"></script> <script src="../lib/vue-router.js"></script> </head> <body> <div id='app'> <p> <router-link to="/user/1">访问用户1</router-link> <router-link to="/user/2/age">访问用户2</router-link> <router-link to="/user/3/sex">访问用户3</router-link> <router-link to="/user/4">访问用户4</router-link> </p> <router-view></router-view> </div> <script> var user={ template:`<div><span>用户内容:用户的id为{{$route.params.id}}<router-view></router-view></span></div>` }; var UserSex={ template:`<div>用户性别</div>` }; var UserAge={ template:`<div>用户年龄</div>` } var router = new VueRouter({ routes:[ { path:'/user/:id', component:user, children:[ {//如果访问 /user/:id/sex 匹配成功 --- UserSex组件就会被渲染在上一级(User的router-view标签中) path:'sex', component: UserSex }, { path:'age', component: UserAge }, {//一般在写路由嵌套时,保证初始化时有内容,则会给一个空路径,默认会有空路径的渲染 path:'', component:UserSex } ] } ] }) var vm = new Vue({ el: '#app', router }) </script> </body> </html>
路由的push方法
用户是通过页面上的router-link切面导航链接的
还可以在Vue内部通过$router访问路由实例,调用push方法
路由的重定向
利用routes完成
例如:当前访问的是/a 时,将URL替换为/b并匹配对应的路由
routes:[{path:’/a’,redirect:’/b’}]
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="../lib/vue.js"></script> <script src="../lib/vue-router.js"></script> </head> <body> <div id='app'> <button @click="go">go</button> <p> <router-link to="/user/3">页面1</router-link> <router-link :to="{name:'user',params:{id:666}}">页面2</router-link> <router-link to="/a">页面5</router-link> </p> <router-view></router-view> </div> <script> var user={ template:`<div><span>用户内容:用户的id为{{$route.params.id}}</span></div>` }; var router = new VueRouter({ routes:[ { path:'/user/:id', name:'user', component:user }, { path:'/a', redirect:'/user/10000' } ] }) var vm = new Vue({ el: '#app', data: { }, router, methods:{ go:function () { //在js中跳转导航链接 // this.$router.push('/user/5'); this.$router.push({path:'/user/888'}) // this.$router.push({name:'user',params:{id:666}}); } } }) </script> </body> </html>
路由的命名视图
有些的页面分布分为顶部,左部,主体内容区,那么每个部分都要定义一个视图,然后通过名字进行对应组件的渲染,界面中可以有多个单独命名的视图
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="../lib/vue.js"></script> <script src="../lib/vue-router.js"></script> </head> <body> <div id='app'> <router-view></router-view> <router-view name="left"></router-view> <router-view name="main"></router-view> </div> <script> var Top={ template:'<div>顶部</div>' }; var Left={ template:'<div>左部</div>' }; var Main={ template:'<div>主体内容</div>' }; var router = new VueRouter({ routes:[ { path:'/', components:{ default:Top, left:Left, main:Main } } ] }) var vm = new Vue({ el: '#app', data: { name: 'lzp' }, router }) </script> </body> </html>
练习:路由实现
足球
篮球
意甲联赛 — AC米兰稳居三甲
西甲联赛 — 梅西上演帽子戏法
CBA — 易建联PK四大外援
NBA — 库里三分大赛夺冠
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="../lib/vue.js"></script> <script src="../lib/vue-router.js"></script> </head> <body> <div id='app'> <div> <ul> <li><router-link to="/football">足球</router-link></li> <li><router-link to="/basketball">篮球</router-link></li> </ul> </div> <div> <router-view></router-view> </div> </div> <script> var FootBall={ template:` <div> <ul> <li><router-link to="/football/italy">意甲联赛</router-link></li> <li><router-link to="/football/spain">西甲联赛</router-link></li> </ul> <router-view></router-view> </div> ` }; var BasketBall={ template:` <div> <ul> <li><router-link to="/basketball/cba">CBA</router-link></li> <li><router-link to="/basketball/nba">NBA</router-link></li> </ul> <router-view></router-view> </div> ` }; var routes=[ { path:'', component:FootBall }, { path:'/football', component: FootBall, children:[ { path:'italy', component:{ template:'<h3>AC米兰稳居三甲</h3>' } }, { path:'spain', component:{ template:'<h3>梅西上演帽子戏法</h3>' } } ] }, { path:'/basketball', component: BasketBall, children:[ { path:'cba', component:{ template:'<h3>易建联PK四大外援</h3>' } }, { path:'nba', component:{ template:'<h3>库里三分大赛夺冠</h3>' } } ] } ]; var router = new VueRouter({ routes }); var vm = new Vue({ el: '#app', data: { name: 'lzp' }, router }) </script> </body> </html>