第一章
注意点
let app=new Vue({
el:"#app",
data:{
msg:'Vue!'
}
});
setTimeout(() => {
// app.msg="Heelo";
app.$data.msg="Heelo";
}, 1000);
简化的todolist
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model='msg'>
<button @click='addList'>添加</button>
<ul>
<li v-for='item in arrs'>{{item}}</li>
</ul>
</div>
</body>
</html>
<script>
let app=new Vue({
el:"#app",
data:{
msg:'',
arrs:[]
},
methods:{
addList(){
this.arrs.push(this.msg);
this.msg='';
}
}
});
</script>
全局组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model='msg'>
<button @click='addList'>添加</button>
<ul>
<todo-item v-bind:content='item' v-for='item in arrs'></todo-item>
</ul>
</div>
</body>
</html>
<script>
Vue.component('TodoItem',{
props:['content'],
template:`<li>{{content}}</li>`,
})
let app=new Vue({
el:"#app",
data:{
msg:'',
arrs:[]
},
methods:{
addList(){
this.arrs.push(this.msg);
this.msg='';
}
}
});
</script>
局部组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model='msg'>
<button @click='addList'>添加</button>
<ul>
<todo-item v-bind:content='item' v-for='item in arrs'></todo-item>
</ul>
</div>
</body>
</html>
<script>
let TodoItem={
props:['content'],
template:`<li>{{content}}</li>`,
}
let app=new Vue({
el:"#app",
data:{
msg:'',
arrs:[]
},
components:{
TodoItem
},
methods:{
addList(){
this.arrs.push(this.msg);
this.msg='';
}
}
});
</script>
组件传值(子组件修改父组件数据)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model='msg'>
<button @click='addList'>添加</button>
<ul>
<todo-item
v-bind:content='item'
:index='index'
v-for='(item,index) in arrs'
@delete='deleteIndex'
></todo-item>
</ul>
</div>
</body>
</html>
<script>
let TodoItem={
props:['content','index'],
template:`<li @click='hehe'>{{content}}</li>`,
methods:{
hehe(){
this.$emit('delete',this.index);
}
}
}
let app=new Vue({
el:"#app",
data:{
msg:'',
arrs:[]
},
components:{
TodoItem
},
methods:{
addList(){
this.arrs.push(this.msg);
this.msg='';
},
deleteIndex(index){
this.arrs.splice(index,1);
}
}
});
</script>
第二章
条件渲染
<body>
<div id="app">
<div v-if='show'>
用户名:<input key="username">
</div>
<div v-else>
密码:<input key="password">
</div>
</div>
</body>
</html>
<script>
let app=new Vue({
el:"#app",
data:{
show:false
}
});
</script>
说明: <input key="username">中key的用处,比如在默认显示用户名输入框时候,
如果此时不加key则修改show值使之显示密码输入框,此时之前输入框输入内容还在
virtualdom的diff算法,会尽量少的修改dom,复用了input,vi是加上key代表input
是独一无二的,则可以达到之前输入内容清除的效果。
列表渲染
<body>
<div id="app">
<template v-for='item in arrs'>
<div :key='item.id'>
{{item.info}}
</div>
<span>
{{item.info}}
</span>
</template>
<div v-for='(item,key,index) of objs'>
{{item}}--{{key}}--{{index}}
</div>
</div>
</body>
</html>
<script>
let app=new Vue({
el:"#app",
data:{
arrs:[
{id:"0001",info:"1"},
{id:"0002",info:"2"},
{id:"0003",info:"3"},
{id:"0004",info:"4"}
],
objs:{
name:"qiang",
age:12
}
}
});
</script>
说明:
一、列表渲染的时候,上面div和span被template包裹,tempalte作用就是:
在span和div(类似多个标签)内部数据来源一样,为了避免写两次循环,必须最外部
再用div包裹,但是这样在html源码里面多出来一个无意义的div,此时tempalte就是
起一个占位符的作用,即满足包裹还在生成的html里面不存在一个无意义的div。
二、:key='item.id'其实就是针对的绑定key属性(上面条件渲染说明了key一些的作用),
一般不要使用index直接当key,而是使用后台返回数据,保证唯一性和高效性。
三、在针对数组的时候,直接去修改数组内容dom视图不变化。
但是直接修改此时app.arrs[0].info的值,即具体值会更新视图
方案:① 使用js提供的数组操作方法(push,sort等)
② 直接改数组的引用(即重新赋值) ③ set方法
四、针对对象遍历使用of,<div v-for='(item,key,index) of objs'>,其中item是属性值,key是属性名,index是索引
第三章(组件)
组件使用的细节
<body>
<div id="app">
<ul>
<li ref='one' is='itemli' @change='addTotal'></li>
<li ref='two' is='itemli' @change='addTotal'></li>
<li>{{total}}</li>
</ul>
</div>
</body>
</html>
<script>
Vue.component('itemli',{
template:`<li @click='add'>{{msg}}</li>`,
data(){
return{
msg:1
}
},
methods:{
add(){
this.msg++;
this.$emit('change');
}
}
});
let app=new Vue({
el:"#app",
data:{
total:0
},
methods:{
addTotal(){
this.total=this.$refs.one.msg+this.$refs.two.msg;
}
}
});
</script>
说明:
一、组件中,data必须是函数形式,是因为,每个组件应该数据是独立的,互不影响,从当前案例可以看出,同样都是itemli组件,两者的点击事件加msg值互不影响。
二、例如在ul中放入组件,有些浏览器会存在兼容性问题,必须放入li,形成ul>li结构,
此时可以使用is='组件名称'达到效果。
三、注意this.$emit('change');括号内部参数是 change对应的是<li ref='one' is='itemli' @change='addTotal'></li>中的v-on的属性,这个属性值change是随意的,也可以是click等.然后触发是父级的在vue构造器内部的方法addTotal
四、ref属性作用:在组件中ref代表的是组件的引用(可以打印看到各种内部属性),在dom中代表该dom节点。this.$refs代表所有的ref,根据相关引用,可以得到各种所需的dom中的值或者其他属性。、
补充:<counter :count='1'></counter>
上面是父组件给子组件传递参数方式的一种,此时反是:修饰的属性内部的''中都是表达式
所以此时传递是数字,如果不加:直接count也可以传递参数,但是传递的是字符串。
补充:同理在子组件中,也可以不通过传递参数直接使用父组件的数据,方法等
this.$parent.数据名称
单项数据流
单向数据流:父组件可以传递参数给子组件,但是子组件不能修改该参数,因为传递过来的参数可能是一个对象的引用,可能不光是该子组件在使用,可能会影响其他子组件。
解决方案:
<body>
<div id="app">
<ul>
<li is='itemli' :count='1' @change='addTotal'></li>
<li is='itemli' :count='2' @change='addTotal'></li>
<li>{{total}}</li>
</ul>
</div>
</body>
</html>
<script>
Vue.component('itemli',{
props:['count'],
template:`<li @click='add'>{{num}}</li>`,
data(){
return{
num:this.count
}
},
methods:{
add(){
this.num++;
this.$emit('change',2);
}
}
});
let app=new Vue({
el:"#app",
data:{
total:0
},
methods:{
addTotal(step){
this.total+=step;
}
}
});
</script>
说明::count='1'是父组件传递的number类型的参数,如果在子组件中直接修改count会报错,此时解决方案是num:this.count,相当于复制有一份在当前子组件中,即可。
组件参数校验
一、
<itemli :count='1+3'></itemli>:在界面上显示的是4
<itemli count='1+3'></itemli>:在界面上显示的是1+3
二、
Vue.component('itemli',{
props:{
count:Number
},
template:<li>{{count}}</li>
,
});
说明:props一般是数组形式,但是如果需要对父组件传递的参数进行校验需要如上的写法
意思是必须是Number类型,也可以这么写[String,Number],就是字符串或者数字类型都可以。
三、针对二的更完整复杂写法
<body>
<div id="app">
<itemli count='afasad'></itemli>
</div>
</body>
</html>
<script>
Vue.component('itemli',{
props:{
count:{
type: String,
required:false,
defalut:'hello',
validator:function(value){
return (value.length>5);
}
}
},
template:`<li>{{count}}</li>`,
});
let app=new Vue({
el:"#app",
data:{
},
});
</script>
说明:required代表(是否,布尔值)必须传递count参数,defalut代表允许不传递时候的默认值,validator是一个判断函数,此时意思是传递的参数长度必须大于5.注意这种详细判断和上面的一二的写法不同count后面跟的也是对象
非付子组件之间传值(总线,发布订阅,观察者模式)
<body>
<div id="app">
<itemli count='1'></itemli>
<itemli count='2'></itemli>
</div>
</body>
</html>
<script>
Vue.prototype.bus=new Vue();
Vue.component('itemli',{
props:['count'],
template:`<li @click='hehe'>{{info}}</li>`,
data(){
return{
info:this.count
}
},
methods:{
hehe(){
this.bus.$emit('change',this.info);
}
},
mounted(){
//如果此处不用箭头函数,内部的this指向不是vue
this.bus.$on('change',(msg)=>{
this.info=msg;
})
}
});
let app=new Vue({
el:"#app"
});
</script>
说明:
一、Vue.prototype.bus=new Vue();是在vue原型上增加bus属性,并且赋值为一个Vue对象。
二、this.bus.$emit('change',this.count);触发bus上面的change
三、this.bus.$on('change',(msg)=>{this.info=msg;})监听bus上面的change事件
四、data(){return{info:this.count}},解决子组件逆向修改父组件值的报错问题
Vue的插槽(slot)
使用场景:当父组件向子组件传递大量信息时候,例如:dom,使用上面的props不方便维护代码,此时slot(插槽)作用就显现出来了。
<body>
<div id="app">
<itemli>
<div slot='A'>slot A </div>
<div slot='B'>slot B </div>
</itemli>
<itemli><div>如果不写slot则itemli内部整体被当作插槽</div></itemli>
</div>
</body>
</html>
<script>
Vue.prototype.bus=new Vue();
Vue.component('itemli',{
// template:`<li>
// <slot name='A'></slot>
// <h1>中间内容</h1>
// <slot name='B'></slot>
// <slot name='C'><h2>默认内容,在指定的插槽没有传递时候,显示出来</h2></slot>
// </li>`,
template:`<li>
<slot></slot>
</li>`,
});
let app=new Vue({
el:"#app",
});
</script>
说明:
一、第二个itemli内部整体直接被当作slot,不区分名称,直接替换template:`<li><slot></slot></li>`,中的<slot></slot>。
二、第一个slot中的name='A'对应上面的slot='A',这样可以避免整体替换,而且没有传递对应slot(不见的一定要name),则会显示默认,否则不显示默认内容。
作用于插槽
使用场景:显示细节是由父组件确定情况下,例如此时li内部可以是h2或者p
<body>
<div id="app">
<itemli>
<template slot-scope='props'>
<h2>{{props.item}}</h2>
</template>
</itemli>
<itemli>
<template slot-scope='props'>
<p>{{props.item}}</p>
</template>
</itemli>
</div>
</body>
</html>
<script>
Vue.component('itemli',{
template:`<li>
<slot v-for='item in arrs' :item=item></slot>
</li>`,
data(){
return{
arrs:[1,2,3,4]
}
}
});
let app=new Vue({
el:"#app",
});
</script>
说明:作用于插槽在父组件中,必须是template包裹,slot-scope='props'代表数据来源也是固定写法,所有子组件传递给父组件的数组都在props中。
在子组件的模板中<slot v-for='item in arrs' :item=item></slot>的:item=item是固定写法,代表数据
动态组件的切换性能问题
<body>
<div id="app">
<one v-if='show==1'></one>
<two v-if='show==2'></two>
<button @click='change'>切换</button>
</div>
</body>
</html>
<script>
Vue.component('one',{
template:`<li v-once>one</li>`,
});
Vue.component('two',{
template:`<li v-once>two</li>`,
});
let app=new Vue({
el:'#app',
data:{
show:1
},
methods:{
change(){
this.show=(this.show==1?2:1);
}
}
})
</script>
说明:在组件的template中添加v-once属性,可以提高性能,因为动态切换组件的时候,是加载之后销毁在加载别的组件,但是加上v-once属性后,除了第一次是加载,其他切换时候都是加载内存中保存的实例,可以极大的提高性能。
网友评论