第4章 深入理解Vue组件
4-1 使用组件细节点
1.is的使用
当我们写循环组件的时候,经常给
table中的tr
select中的option
ul中的li或者ol中的li
等等定义组件的时候,我们经常用is来定义组件的名称,为了让浏览器成功的渲染正确的dom结构
<div id="root">
<table>
<tbody>
<tr is="row"></tr>
<tr is="row"></tr>
<tr is="row"></tr>
</tbody>
</table>
<select name="" id="">
<option is="selectOption"></option>
<option is="selectOption"></option>
<option is="selectOption"></option>
</select>
<ul>
<li is="ulLi"></li>
<li is="ulLi"></li>
<li is="ulLi"></li>
</ul>
</div>
<script>
Vue.component('row', {
template: '<tr><td>this is a row</td></tr>'
});
Vue.component('selectOption',{
template: '<option>this is option</option>'
});
Vue.component('ulLi',{
template: '<li>this is li</li>'
});
var app = new Vue({
el: '#root',
data: {},
})
</script>
2.在子组件定义data的时候,必须是一个函数,而不能是一个对象,返回一个对象是为了每个子组件都能拥有一个独立的数据存储。这样子组件之间的数据不会互相影响
而在根组件中,data可以是一个对象。
<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: function () {//返回的是一个函数
return {
content: 'this is row'
}
},
template: '<tr><td>{{content}}</td></tr>'
});
var app = new Vue({
el: '#root',
data: {}
})
</script>
3.有时候我们在开发过程中,因为一些业务的需求,少不了对dom的操作,那么我们就可以借助ref来实现
//实例一
<div id="root">
<div ref="hello" @click="handleClick">hello world</div>
</div>
<script>
var app = new Vue({
el: '#root',
data: {},
methods: {
handleClick: function () {
console.log(this.$refs.hello.innerHTML);//通过refs属性 获取当前节点的文本
}
}
});
</script>
//案例二 counter求和
<div id="root">
<counter ref="one" @change="handleChange"></counter>
<counter ref="two" @change="handleChange"></counter>
<div>{{total}}</div>
</div>
<script>
Vue.component('counter', {
data: function () {
return {
number: 0
}
},
template: '<div @click="handleClick">{{number}}</div>',
methods: {
handleClick: function () {
this.number++;
this.$emit('change');//触发一个监听器
}
}
});
var app = new Vue({
el: '#root',
data: {
total: 0
},
methods: {
handleChange: function () {
this.total = this.$refs.one.number + this.$refs.two.number //通过refs 来回去组件的值
}
}
});
</script>
4-2父子组件之间的数据传递
父组件向子组件传值:是通过属性的方式
子组件向父组件传值:可以通过$emit
来触发一个事件
vue数据传递遵循的是单向数据流,
所以在下面的案例中我们并没有对content数据直接进行数据的累加,而是把content数据赋值给了number,对number进行数据的累加操作。
<div id="root">
<counter :content="1" @inc="handleInc"></counter><!--父组件通过属性向子组件传值-->
<counter :content="3" @inc="handleInc"></counter>
<div>{{total}}</div>
</div>
<script>
Vue.component('counter', {
props: ['content'],
data: function () {
return {
number: this.content //遵循单向数据流
}
},
template: '<div @click="handleClick">{{number}}</div>',
methods: {
handleClick: function () {
this.number += 2;
//子组件通过方法向父组件传值
this.$emit('inc', 2);
}
}
});
var app = new Vue({
el: '#root',
data: {
total: 4
},
methods: {
handleInc: function (step) {
this.total += step
}
}
})
</script>
4-3组件参数校验和非props特性
1.组件的的参数校验
<div id="root">
<child content="hello"></child>
</div>
<script>
Vue.component('child', {
props: {
content: {
type: String,
required: true,
default: 'default Value',
validator: function (value) {
return (value.length > 5)
}
}
},
template: '<div>{{content}}</div>'
});
var app = new Vue({
el: '#root',
})
</script>
2.props特性和非props特性的对比
props特性:
父组件传递属性,子组件要接受该属性
props属性不会显示在dom的标签之中
非props特性:
父组件传递属性,子组件没有去接受,而是直接调用
props属性会显示在dom的标签之中
4-4给组件绑定原生事件
通过.native
属性来绑定原生事件
<div id="root">
<child @click.native="handleClick"></child>
</div>
<script>
Vue.component('child', {
template: '<div>child</div>'
})
var app = new Vue({
el: '#root',
methods: {
handleClick: function () {
console.log('click');
}
}
})
</script>
4-5 非父子组件间的传值
非父子组件间的传值1.通过vuex
2.通过发布订阅模式(Bus/总线/发布订阅模式/观察者模式/)
<div id="root">
<child content="sunny"></child>
<child content="fan"></child>
</div>
<script>
Vue.prototype.bus = new Vue();//定义bus
Vue.component('child', {
data: function () {
return {
newContent: this.content //保证单向数据流
}
},
props: {
content: String
},
template: '<div @click="handleClick">{{newContent}}</div>',
methods: {
handleClick: function () {
this.bus.$emit('change', this.newContent); //在bus上发布一个事件,并且传值
}
},
mounted: function () {//通过这个钩子,来监听change的变化,通过回调拿到相对应的的值
var that = this;
this.bus.$on('change', function (msg) {
console.log(msg)
that.newContent = msg//this 指向发生变更,所以上面要从新获取一下this的指向
})
}
});
var app = new Vue({
el: '#root'
})
4-6 在vue中使用插槽
插槽只能有一个
而剧名插槽可以有多个
<div id="root">
<body-content>
<p slot="header">this is header</p>
<p slot="footer">this is footer</p>
</body-content>
</div>
<script>
Vue.component('body-content',{
template:
`<div>
<slot name="header">default header</slot> //设置默认值
<p>this is content</p>
<slot name="footer"></slot>
</div>`
})
var app = new Vue({
el:'#root'
})
</script>
4-7作用域插槽
父组件调用子组件的时候,给子组件传了一个插槽,这个插槽是一个作用域的插槽,这个插槽必须是一个<template slot-scope="props">{{props.item}}</template>
那什么时候使用作用插槽呢?
1.当子组件做循环
2.或者当子组件的dom结构由外部传递进来,或者有外部决定的时候
<div id="root">
<child>
<template slot-scope="props">
<li>{{props.item}}</li>
</template>
</child>
</div>
<script>
Vue.component('child', {
data: function () {
return {
list: [1, 2, 3, 4]
}
},
template: `<div>
<ul>
<slot v-for="item of list" :item=item></slot>
</ul>
</div>`
})
var app = new Vue({
el: '#root'
})
</script>
4-8 动态组件和v-once 指令
<div id="root">
<component :is="type"></component> <!--这就是动态组件-->
<child-one v-if="type==='child-one'"></child-one>
<child-two v-if="type==='child-two'"></child-two>
<button @click="hanleBtnClick">change</button>
</div>
<script>
Vue.component('child-one', {
template: '<div v-once>child-one</div>'
})
Vue.component('child-two', {
template: '<div v-once>child-two</div>'
})
var app = new Vue({
el: '#root',
data: {
type: 'child-one'
},
methods: {
hanleBtnClick: function () {
this.type = this.type === 'child-one' ? 'child-two' : 'child-one'
}
}
})
</script>
更多
上一篇:第3章 Vue 基础精讲
下一篇:第5章 Vue 表单
全篇文章:Vue学习总结
所有章节目录:Vue学习目录