key属性,template占位符,v-for数组,v-for对象
当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。
为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性。理想的 key 值是每项都有的且唯一的 id。
建议尽可能在使用 v-for 时提供 key,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。
案发现场1:key
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
</head>
<body>
<div id="root">
<!-- 当页面加载时会首先显示邮箱名当我们输入邮箱时,在浏览器控制台上改变show的值为true时,为了减少DOM操作,
vue会复用input元素,会导致input的内容未被清空,这时需要阻止复用使用key属性,key的值确保是唯一的且不重复 -->
<div v-if="show">
用户名:<input type="text" key="userName">
</div>
<div v-else>
邮箱名:<input type="text" key="userEmail">
</div>
</div>
<script>
var vm=new Vue({
el:"#root",
data:{
show:false
}
});
</script>
</body>
</html>
案发现场2:key/template/v-for数组/变异方法
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
</head>
<body>
<div id="root">
<!-- 一般为了提升循环的性能会在循环项上添加唯一的key值 -->
<div v-for="(item,index) of list" :key="item.id"><!--在循环表达式中in和of都可以使用,'蛋'更推荐of-->
{{item.text}}---{{index}}
</div>
<!-- 当循环体需要包裹其他标签时使用template占位符,template占位符 只会包裹不会显示到页面上 -->
<template v-for="(text,idx) of list">
<span>{{idx}}</span>
<h1>{{text.text}}</h1>
</template>
</div>
<script>
var vm=new Vue({
el:"#root",
data:{
/*
对数组进行操作时,只能使用push pop shift unshift splice sort reverse变异方法否则页面和数据之间
无法实现响应式
其他响应式的操作数组的方法
1还可以通过改变数组的引用来实现数据和页面之间的响应式
list=[
{
id:'010120201',
text:'Iphone'
},
{
id:'010120202',
text:'OPPO'
},
{
id:'010120203',
text:'VIVO'
},
{
id:"010120204",
text:'HUIWEI'
},
{
id:"010120205",
text:"NOKIA"
}
]
2.Vue.set(vm.list,下标,值)
Vue.set(vm.list,4,{id:"010120205",text:"NOKIA"});
3.vm.$set(vm.list,下标,值)
vm.$set(vm.list,4,{id:"010120205",text:"NOKIA"});
*/
list:[
{
id:'010120201',
text:'Iphone'
},
{
id:'010120202',
text:'OPPO'
},
{
id:'010120203',
text:'VIVO'
},
{
id:"010120204",
text:'HUIWEI'
}
]
}
});
</script>
</body>
</html>
案发现场3:v-for对象
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
</head>
<body>
<div id="root">
<!-- 其实js中对象的底层就是一个关联数组,查看页面item key index 分别表示什么 -->
<div v-for="(item,key,index) of userInfo">
{{key}}:{{item}}---{{index}}
</div>
</div>
<script>
var vm=new Vue({
/*
响应式的操作对象中的数据
1.修改引用
vm.userInfor={
name:'Tom',
age:18,
car:'BYD',
girlFriend:false
}
2.Vue.set(vm.userInfor,"address","beijing")
3.vm.$set(vm.userInfor,"address","beijing")
*/
el:"#root",
data:{
userInfo:{
name:'Dell',
age:28,
gender:'male',
salary:'secret'
}
}
});
</script>
</body>
</html>
is属性
用于动态组件且基于 DOM 内模板的限制来工作。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
</head>
<body>
<div id="root">
<table border="1">
<tbody>
<!-- 如果直接使用子组件语法会不符合html5语法规范,会出现bug
可在页面审查元素查看tbody里并无tr -->
<!--
<row></row>
<row></row>
-->
<!-- 使用is属性使其标签指向组件,ul,ol.select标签同理 -->
<tr is="row"></tr>
<tr is="row"></tr>
<tr is="row"></tr>
</tbody>
</table>
</div>
<script>
Vue.component('row',{
template:`
<tr>
<td>this is a row</td>
</tr>
`
});
var vm=new Vue({
el:"#root"
});
</script>
</body>
</html>
组件参数校验
我们可以为组件的 prop 指定验证要求,例如你知道的这些类型。如果有一个需求没有被满足,则 Vue 会在浏览器控制台中警告你。这在开发一个会被别人用到的组件时尤其有帮助。
为了定制 prop 的验证方式,你可以为 props 中的值提供一个带有验证需求的对象,而不是一个字符串数组。例如:
案发现场:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!-- content通过:绑定传递数字类型,因为绑定:表示js表达式 -->
<child :content="123"></child>
</div>
<script>
Vue.component('child',{
props:{
//1.基础校验
// 对父组件content传递过来的数据进行校验必须为String类型
// content:String
// content:Number
// content:Object
// content:[String,Number]
// content:null 匹配任意类型
//2.更为严格的校验
content:{
type:String,
// 父组件必须传入该类型的值
required:true,
// 如果父组件没有传入该类型的值时,使用默认的值
default:"default value",
// 自定义校验器:对父组件传入的值进行校验,字符长度大于5
validator:function (value) {
return (value.length>5)
}
}
},
template:`
<div>{{content}}</div>
`
});
var vm=new Vue({
el:"#app"
});
</script>
</body>
</html>
组件绑定原生事件
案发现场:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 通过事件修饰符.native给组件绑定原生事件 -->
<!-- 不加.native 监听的是自定义事件 -->
<child @click.native="handleClick"></child>
</div>
<script>
Vue.component('child',{
template:`
<div>Child</div>
`
});
var vm=new Vue({
el:"#app",
methods:{
handleClick:function () {
alert("click");
}
}
});
</script>
</body>
</html>
非父子组件传值
案发现场:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>非父子组件间传值(Bus/总线/发布订阅模式/观察者模式)</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
</head>
<body>
<div id="root">
<child content='Dell'></child>
<child content='Lee'></child>
</div>
<script>
// 向Vue的prototype中加入bus方法,其他组件就可以借助bus来传递数据
Vue.prototype.bus=new Vue();
Vue.component('child',{
props:{
content:String,
required:true,
default:'Default Value'
},
data:function(){
//父组件传递过来的数据子组件无法直接修改,所以保存副本
return {selfContent:this.content}
},
template:`
<div @click="sendData">{{selfContent}}</div>
`,
methods:{
sendData:function(){
//触发事件并发送数据
this.bus.$emit('change',this.selfContent);
}
},
mounted:function(){
// 监听事件并响应
var this_=this;
this.bus.$on('change',function(msg){
this_.selfContent=msg;
});
}
});
var vm=new Vue({
el:"#root"
});
</script>
</body>
</html>
插槽
案发现场:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue中的插槽(slot)</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
</head>
<body>
<div id="root">
<child>
<h1>Dell</h1>
</child>
<body-content>
<!-- 具名插槽 -->
<div class="header" slot="header">header</div>
<div class="footer" slot="footer">footer</div>
</body-content>
</div>
<script>
Vue.component('child',{
template:`
<div>
<p>Hello Slot</p>
<slot>当父组件没有传递插槽内容,使用此处默认内容</slot>
</div>
`
});
Vue.component('body-content',{
template:`
<div>
<slot name="header">default header</slot>
<div class="content">content</div>
<slot name="footer">default footer</slot>
</div>
`
});
var vm=new Vue({
el:"#root"
});
</script>
</body>
</html>
作用域插槽
案发现场:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue中的作用域插槽(slot)</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
</head>
<body>
<div id="root">
<child>
<!-- template必须写固定语法 -->
<template slot-scope="content">
<!-- <li>{{content.item}}</li> -->
<h1>{{content.item}}</h1>
</template>
</child>
</div>
<script>
Vue.component('child',{
data:function(){
return {list:[1,2,3,4,5]}
},
template:`
<div>
<ul>
<slot v-for="item of list" :item=item></slot>
</ul>
</div>
`
});
var vm=new Vue({
el:"#root"
});
</script>
</body>
</html>