组件用于封装页面的部分功能,将功能的结构、样式、逻辑代码封装为整体。
提高功能的复用性与可维护性,更好的专注于业务逻辑。
组件使用时为自定义 HTML 标签形式,通过组件名作为自定义标签名。
Vue.component('组件名',{ 选项对象 })
父子组件间所有的prop都是单向下行绑定的。
Vue 的单向数据流:指数据一般从父组件传到子组件,子组件没有权利直接修改父组件传来的数据,即子组件从 props 中直接获取的数据,只能请求父组件修改数据再传给子组件。父级属性值的更新会下行流动到子组件中。
为什么不能子组件直接修改父组件传来的值呢?父组件的值可能会不断发生变化,那么如果我们子组件对父组件传来的值比如说 props 有一个 number,子组件收到了 number=1,在收到后,子组件直接改变number 的值为 5,去做些事情,但还未做时父组件数据更新了,传过来一个值 3,也就是说子组件刚将其变为 5,父组件又把它变成了 3,可能影响子组件的使用。说的官方一些,就是父组件的值更新时,子组件中 props 的值也会发生更新。
在子组件中直接用 v-model 绑定父组件传过来的数据是不合理的,如果希望修改父组件传给子组件的值:
(1)在子组件 data 中创建一个变量获取 props 中的值,再改变这个 data 中的值。
(2)子组件使用 $emit 发出一个事件,让父组件接收去修改这个值。
new Vue({
el: '#myApp',
data: {
},
methods: {
},
components: {
'my-com-a': {
template: `
{{title}}
{{content}}
`,
data() {
return {
title: '组件 A 标题',
content: '组件A 内容'
}
}
},
MyComB: {
template: `
{{title}}
{{content}}
`,
data() {
return {
title: '组件 B 标题',
content: '组件 B 内容'
}
}
}
}
})
var MyComA = {}
var MyComB = {}
new Vue({
el:'#app',
components:{
'my-com-a':MyComA,
'my-com-b':MyComB
}
})
new Vue({
el:'#app',
components:{
MyComA,
MyComB
}
})
子组件的本质是一个名为VueComponent的构造函数,且不是程序员定义的。是Vue.extend生成的。
我们只需要写<子组件名/>或<子组件名><子组件名/>,Vue解析时会帮我们创建子组件的实例对象,及Vue帮我们执行的:new VueComponent(options)。
特别注意:每次调用Vue.extend。返回的都是一个全新的VueComponent!!!!!
关于this指向:
(1)组件配置中
data函数、methods中的函数、watch中的函数、computed中的函数 他们的this均是【VueComponent实例对象】。
(2)new Vue(options)配置中:
data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】
Vue.component('my-component',{
props:['title'],
template:'{{title}}
'
})
子向父传值需要通过自定义事件实现。
购物车案例:
商品为子组件,购物车为父组件,父组件需要统计商品个数,就需要在子组件个数变化时传值给父组件。
子组件数据变化时,通过$emit()触发自定义事件。
Vue.component('product-item',{
...
methods:{
countIns(){
this.$emit('count-change');
this.count++;
}
}
})
<div id="app">
...
<product-item
...
@count-change="totalCount++"
>product-item>
div>
// 方案一 直接传数据
<div id="app">
...
<product-item
...
@count-change="totalCount += $event"
>product-item>
div>
// 方案二 通过处理程序
<div id="app">
...
product-item>
div>
new Vue({
...
methods:{
onCountChange(productCount){
this.totalCount += productCount // 这个productCount只是一个形参用来接 收this.$emit()传来的数据,它可以随意 写
}
}
})
非父子组件指的是兄弟组件或完全无关的两个组件。
兄弟组件可以通过父组件进行数据中转
<body>
<script src='https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js'>script>
<div id='myApp'>
<my-com-a @value-change=" value = $event">my-com-a>
<my-com-b :value="value">my-com-b>
div>
<template id='myTem1'>
<div>
组件a的内容:{{value}}
<button @click="$emit('value-change',value)">发送button>
div>
template>
<template id='myTem2'>
<div>
组件B接收到:{{value}}
div>
template>
<script>
// 子组件A,发送数据
Vue.component('myComA', {
template: '#myTem1',
data() {
return {
value: "这是组件a的数据"
}
},
})
// 子组件B,接收数据
Vue.component('myComB', {
props: ['value'],
template: '#myTem2',
data() {
return {
}
}
})
new Vue({
el: '#myApp',
data: {
// 用于数据中转
value: ''
},
methods: {
}
})
script>
body>
当组件嵌套关系复杂时,根据组件关系传值会比较繁琐。
组件为了数据中转,data中会存在许多与当前组件功能无关的数据。
操作步骤: