vue父子组件间数据传递
父组件传子组件
父组件可以通过属性的方式,单向传递数据给子组件,但是子组件接收到的数据不能直接修改,这会影响其他父组件的数据。子组件可通过克隆的方式,将父组件传过来的值在data里克隆一份,然后修改克隆后的数据,这样不会影响父组件的数据。
<body>
<div id="root">
<counter :count="1"></counter>
<counter :count="1"></counter>
</div>
<script>
// 点击子组件,数字自增
// 父组件向子组件传值,子组件通过data将父组件传过来的值复制一遍再使用
var counter = {
props: ['count'],
data: function() {
return {
num: this.count
};
},
template: "<div @click='handleClick'>{{num}}</div>",
methods: {
handleClick: function() {
this.num ++;
}
}
}
var vm = new Vue({
el: "#root",
components: {
counter: counter
}
})
</script>
</body>
子组件传父组件
子组件通过事件触发的形式,向父组件传值。$emit(事件名, 参数)。
<body>
<div id="root">
<counter :count="2" @change="handleChange"></counter>
<counter :count="3" @change="handleChange"></counter>
{{total}}
</div>
<script>
// 父组件向子组件传值,子组件通过data将父组件传过来的值复制一遍再使用
var counter = {
props: ['count'],
data: function() {
return {
num: this.count
};
},
template: "<div @click='handleClick'>{{num}}</div>",
methods: {
handleClick: function() {
this.num = this.num + 2;
this.$emit("change", 2); // change事件名、2传递参数,单词累加步长
}
}
}
var vm = new Vue({
el: "#root",
components: {
counter: counter
},
data: {
total: 5
},
methods: {
handleChange: function(step) { // step接收子组件传递过来的参数2
this.total += step;
}
}
})
</script>
</body>
组件参数校验与非Props特性
props特性
父组件传递给子组件的数据,可以通过pros设置参数类型、是否必传、默认值、长度要求等,达到校验的目的。
<body>
<div id="root">
<child count="1"></child>
</div>
<script>
Vue.component("child", {
props: {
// count: [Number, String] // 参数校验,只能是数字或字符串类型
count: {
type: Number, // 类型为字符串
required: true, // true表示 count为必传属性
default: 'default value', // 默认参数,如果count未传,则为默认值
validator: function(val) { // 长度须大于5
return (val.length > 5)
}
}
},
template: '<div>{{count}}</div>'
})
var vm = new Vue({
el: "#root"
})
</script>
</body>
非Props特性
- 非props特性,即父组件传递的参数,子组件不使用props声明,这时直接使用会报错。
- 父组件传递参数的属性,会加入到子组件最外地标签上,同样以属性的方式存在。props特性则不会显示在子组件标签上
给组件绑定原生事件
在父组件自定义事件名后加上native修饰符即可,将自定义事件变为原生事件。
<body>
<div id="root">
<child @click.native="handleClick"></child>
</div>
<script>
Vue.component("child", {
template: '<div>child</div>'
})
var vm = new Vue({
el: "#root",
methods: {
handleClick: function() {
alert('click');
}
}
})
</script>
</body>
非父子组件间传值问题
- Vuex
- 总线机制(Bus/总线/发布订阅模式/观察着模式)
<body>
<div id="root">
<child content="2019"></child>
<child content="2020"></child>
</div>
<script>
// 兄弟组件传值:点击组件a,组件b的内容也变成a的,点击b同理
Vue.prototype.bus = new Vue()
Vue.component("child", {
data: function() {
return {
selfContent: this.content
}
},
props:{
content: String
},
template: '<div @click="handleClick">{{selfContent}}</div>',
methods: {
handleClick: function() {
// alert(this.content)
this.bus.$emit("change", this.selfContent) // 事件发布
}
},
mounted: function() {
var _this = this;
this.bus.$on('change', function(msg) { // 事件订阅
// alert(msg)
_this.selfContent = msg;
})
}
})
var vm = new Vue({
el: "#root",
})
</script>
</body>
slot插槽
具名插槽
元素可以用一个特殊的属性name,来配置如何分发内容。多个插槽可以有不同的名字,具名插槽将匹配内容片段中有对应 slot 特性的元素。
<body>
<div id="root">
<child>
<div slot="header">header</div>
<div slot="footer">footer</div>
</child>
</div>
<script>
Vue.component("child", {
template:
`<div>
<slot name="header"></slot>
<div>content</div>
<slot name="footer"></slot>
</div>`
})
var vm = new Vue({
el: "#root",
})
</script>
</body>

作用域插槽
使用场景:当子组件的部分DOM结构需要外部传入的时候,或者子组件内部循环。 当使用作用域插槽的时候,子组件可以向父组件插槽传递数据,父组件接收传递的数据需要在外层包裹template标签,同时使用slot-scoped="属性名",接收传递过来的数据,然后使用数据。
<body>
<div id="root">
<child>
<!-- 父组件调用子组件的时候,给子组件传了一个作用域插槽,以template标签包裹,并且在其插槽上声明slot-scope="props" 要从子组件接收的数据 放在props里 -->
<template slot-scope="props">
<!-- li标签 展示从子组件接收的数据 -->
<li>{{props.item}}</li>
</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>

动态组件与v-once指令
动态组件component
v-once
如果有多个组件,需要在页面切换展示,如果不使用v-once,每次页面重新渲染的时候,都需要重新加载组件。而组件上加v-once,当组件第一次被渲染的时候,会将组件缓存,下次渲染的时候,无须重新加载。
<body>
<div id="root">
<!-- 动态组件component,通过:is="属性名"切换队形组件 -->
<!-- <component :is="type"></component> -->
<child-one v-if="type === 'child-one'"></child-one>
<child-two v-if="type === 'child-two'"></child-two>
<!-- 点击change 实现child-one和child-two的切换 -->
<button @click="btnClick">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 vm = new Vue({
el: "#root",
data: function() {
return {
type: "child-one"
}
},
methods: {
btnClick: function() {
this.type = this.type === "child-one" ? "child-two" : "child-one";
}
}
})
</script>
</body>