使用组件的细节:
细节一:子组件的基本使用
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue中组件使用的细节1</title> <script src="./vue.js"></script> </head> <body> <div id="root"> <table> <tbody> <tr is="row"></tr> <tr is="row"></tr> <tr is="row"></tr> </tbody> </table> </div> <script> Vue.component('row',{ template: `<tr><td>this is row</td></tr>` }) var vm = new Vue({ el : '#root', }) </script> </body> </html>
细节二:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue中组件使用的细节1</title> <script src="./vue.js"></script> </head> <body> <div id="root"> <table> <tbody> <tr is="row"></tr> <tr is="row"></tr> <tr is="row"></tr> </tbody> </table> </div> <script> Vue.component('row',{ //子组件中的数据 data 需要用函数来表示 函数返回一个对象 data: function (){ return { name : '小明' } }, template: `<tr><td>{{name}}</td></tr>` }) var vm = new Vue({ el : '#root', }) </script> </body> </html>
ref 的用法:vue中使用 ref 获取 dom 节点
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue中组件使用的细节1</title> <script src="./vue.js"></script> </head> <body> <div id="root"> <div ref="hello" @click="fun" >hello world</div> </div> <script> var vm = new Vue({ el : '#root', methods : { fun : function(){ alert(this.$refs.hello.innerHTML) } } }) </script> </body> </html> 弹出了 指定div 的内容 hello world
ref 综合案例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue中组件使用的细节1</title> <script src="./vue.js"></script> </head> <body> <div id="root"> <counter ref="one" @change="handleChange"></counter> <counter ref="two" @change="handleChange"></counter> <div>{{total}}</div> </div> <script> Vue.component('counter',{ template: `<div @click="handleClick">{{number}}</div>`, data: function () { return{ number : 0 } }, methods: { handleClick : function(){ this.number++; this.$emit('change') } } }) var vm = new Vue({ el : '#root', data : { total : 0 }, methods : { handleChange : function(){ this.total = this.$refs.one.number + this.$refs.two.number } } }) </script> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue中组件使用的细节1</title> <script src="./vue.js"></script> </head> <body> <div id="root"> <counter ref="one" @change="handleChange"></counter> <counter ref="two" @change="handleChange"></counter> <div>{{total}}</div> </div> <script> let count ={ template: `<div @click="handleClick">{{number}}</div>`, data: function () { return{ number : 0 } }, methods: { handleClick : function(){ this.number++; this.$emit('change') } } } var vm = new Vue({ el : '#root', data : { total : 0 }, components:{ counter : count // 子组件 }, methods : { handleChange : function(){ this.total = this.$refs.one.number + this.$refs.two.number } } }) </script> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>父子组件传值</title> <script src="./vue.js"></script> </head> <body> <div id="root"> <counter :count="1" @change="handleChange"></counter> <counter :count="2" @change="handleChange"></counter> <div>{{total}}</div> </div> <script> //父组件向子组件传值 子组件不能直接修改父组件传递的值 // 可以定义一个属性存放父组件传递的值 然后进行修改自己定义的属性 let counter = { props : ['count'], template : `<div @click="hendleClick">{{number}}</div>`, data : function(){ return { number : this.count } }, methods : { hendleClick : function(){ this.number = this.number + 2; this.$emit('change',2);//向外触发一个自定义事件 第二个参数改变的步长 } } } let vm = new Vue({ el:'#root', data:{ total: 3 }, components:{ counter : counter, //子组件 }, methods : { handleChange : function(step){ //参数为监听事件传出的步长 this.total += step } } }) </script> </body> </html>
以上三个案例的结果一样: 点击前两个数字会自加1 触发第三个数字改变 第三个数字等于前两个数字的和 (不同的是子组件的写法不同)
ref 练习:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>父子组件传值</title> <script src="./vue.js"></script> </head> <body> <div id="root"> <one ref="one" :count="1" @first="Change"></one> <two ref="two" :count="2" @second="Change"></two> <div>{{total}}</div> </div> <script> let one = { props : ['count'], template : `<div @click="hendleClick">{{number}}</div>`, data : function(){ return { number : this.count } }, methods : { hendleClick : function(){ this.number = this.number + 2; this.$emit('first',2); } } } let two = { props : ['count'], template : `<div @click="hendleClick">{{number}}</div>`, data : function(){ return { number : this.count } }, methods : { hendleClick : function(){ this.number = this.number + 3; this.$emit('second',3); } } } let vm = new Vue({ el:'#root', data:{ total: 3 }, components:{ one : one, two : two }, methods : { Change : function(){ this.total = this.$refs.one.number + this.$refs.two.number } } }) </script> </body> </html>
组件参数校验:
需求:校验父组件传递过来的必须是个字符串
<div id='root'> <child content='hello world'></child> </div> <script> Vue.component('child',{ props:{ content:String }, template:'<div>{{content}}</div>' }) var vm = new Vue({ el:'#root' }) </script>
将接收的props定义成对象,并指定类型,不以数组的形式接收参数
接收的数据是字符串类型 或者 数字类型都可以
props:{
content:[String, Number]
}
复杂的校验:
<div id='root'> <child content='hello world'></child> </div> <script> Vue.component('child',{ props:{ content:{ type:String,//数据类型 required:false,//是否是必传 default:'default content',//如果没传值,默认值 validator:function(val){//自定义校验器,数据长度必须 > 5 参数为传入的数据 return (val.length>5) } } }, template:'<div>{{content}}</div>' }) var vm = new Vue({ el:'#root' }) </script>
非props特性
父组件向子组件传递参数,子组件没有props这块内容,所以就会报错,不去接收,就没法使用这个content
第二个特点是,子组件没接收,对应的属性值会显示在标签中,props特性不会显示
Vue给组件绑定原生事件:组件生成的元素绑定原生事件需要在事件的后面加上native
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Vue给组件绑定原生事件</title> <script src="./vue.js"></script> </head> <body> <div id="root"> <child @click.native="handleClick"></child>组件生成的元素绑定原生事件需要在事件的后面加上native
</div>
<script>
Vue.component('child',{ template : `<div>Child</div> ` }) let vm = new Vue({ el : '#root', methods : { handleClick : function(){ alert('click') } } }) </script> </body> </html>
非父子组件间的传值(如何在vue重使用 bus/总线/发布订阅模式/观察者模式):
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>非父子组件之间的传值(bus/总线/发布订阅模式/观察者模式)</title> <script src="./vue.js"></script> </head> <body> <div id="root"> <child content="Dell"></child> <child content="Lee"></child> </div> <script> //在vue的原型链上挂载一个bus的属性 只要之后调用new Vue()或者创建组件 每一个组件都会有bus这个属性 Vue.prototype.bus = new Vue(); Vue.component('child',{ props : { content : String }, data : function(){ return { selfContent : this.content } }, template : `<div @click="hendleClick">{{selfContent}}</div>`, methods : { hendleClick : function(){ this.bus.$emit('change',this.selfContent) } }, //借助生命周期钩子监听bus的改变 mounted : function(){ this.bus.$on('change',(msg) => { this.selfContent = msg; }) } }) let vm = new Vue({ el : '#root', }) </script> </body> </html>
vue中的插槽:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue中的插槽</title> <script src="./vue.js"></script> </head> <body> <div id="root"> <child> <!--需要插槽才能渲染的内容--> <p>Dell</p> <p>Lee</p> </child> </div> <script> //slot语法:slot标签显示的内容是父组件向子组件插入的内容 插槽 也就是上面的 child 标签包住的 p 标签 //slot中可以放置默认内容 当父组件没有传入内容则显示默认内容 Vue.component('child',{ template : `<div> <p>hello</p> <slot><p>默认内容,当子组件没有传如任何内容时默认显示</p></slot> </div>`, }) let vm = new Vue({ el : '#root', }) </script> </body> </html>
假如使用多个插槽的时候,就需要用具名插槽:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue中的插槽</title> <script src="./vue.js"></script> </head> <body> <div id="root"> <child> <div slot="footer">footer</div> </child> </div> <script> Vue.component('child',{ template : `<div> <slot name="header"> <h1>default header</h1> </slot> <div>content</div> <slot name="footer"></slot> </div>`, }) let vm = new Vue({ el : '#root', }) </script> </body> </html>
作用域插槽:作用域插槽必须是由template标签包起来的 并且插槽要声明从子组件接收的数据放在哪(slot-scope) 以及告诉子组件模板的信息(接收到的数据应该怎么展示)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>作用域插槽</title> <script src="./vue.js"></script> </head> <body> <div id="root"> <child> <template slot-scope="props"><!--定义一个插槽,该插槽必须放在template标签内--> <em>{{props.item}}</em><!--定义使用渲染方式--> </template> </child> <child> <template slot-scope="props"> <h1>{{props.item}}</h1><!--定义不同的渲染方式--> </template> </child> </div> <script> let count = { data : function(){ return { list : [1, 2, 3, 4] } }, template : `<div> <slot v-for="item of list" :item=item></slot> </div>` } let vm = new Vue({ el : '#root', components : { child : count } }) </script> </body> </html>
动态组件案例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue中的动态组件</title> <script src="./vue.js"></script> </head> <body> <div id="root"> <component :is="type"></component> <button @click="handlechange">change</button> </div> <script> //v-once指令 对数据进行缓存 提高性能 let childone = { template : `<div v-once>child-one</div>` } let childtwo = { template : `<div v-once>child-two</div>` } let vm = new Vue({ el : '#root', data : { type: childone }, methods : { handlechange : function(){ this.type === childone ? this.type=childtwo : this.type=childone } } }) </script> </body> </html>