🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] > 参考 [https://juejin.im/post/5c776ee4f265da2da53edfad](https://juejin.im/post/5c776ee4f265da2da53edfad) ## 父组件传递props属性给子组件 子组件要想得到父组件的数据,只需要在子组件内部通过props显示的声明自己想要什么属性。声明之后父组件将数据传递给子组件就ok了,如下: ~~~ Vue.component('child',{ props: ['message','myMessage'], template: '<span>{{ message }}</span>' }) ~~~ 在父组件中使用 `<child message="hello!" :my-message="parentMsg"></child> `即可 > 注意:在子组件中不能修改父组件传递过来的数据,只能做备份来修改,并且引用类型要深拷贝 <br> <br> ## 父组件传递非props属性给子组件 在父组件中通过传递非props属性,将自动添加到子组件根元素上面,如下 ~~~ <bs-date-input data-3d-date-picker="true"></bs-date-input> ~~~ 如果子组件上面已经存在了同名属性,一般都是直接替换的,但是class和style是和子组件的class和style合并的 。 <br> <br> ## 子组件通知父组件 ~~~ // 父组件 <aaa v-on:somefunction="parentfunction"></aaa> ~~~ ~~~ // 子组件 export default { methods: { childfunction () { this.$emit('somefunction') } } } ~~~ 在子组件中触发某个事件同时`v-on:click="childfunciton"`,可以通过在 childfunction 内部添加`this.$emit('somefunction')`通知触发父组件中的事件,在父组件中通过 `v-on:somefunction="parentfunction"` 接受到通知,然后触发父组件中的 parentfunction 事件,也就是说在父组件中,将 `v-on` 用在子组件标签上面并不是给子组件绑定事件而是监听子组件内部的消息。 但是如果确实想绑定一个事件给子组件可以通过添加.native修饰符,如下 ~~~ <my-component v-on:click.native="doTheThing"></my-component> ~~~ 这个事件将直接绑定到子组件的根元素 。 <br> <br> ## 子组件父组件数据双向绑定 在一个包含 title prop 的假设的组件中,我们可以用以下方法表达对其赋新值的意图: ~~~ this.$emit('update:title', newTitle) ~~~ 然后父组件可以监听那个事件并根据需要更新一个本地的数据属性。例如: ~~~ <text-document v-bind:title="doc.title" v-on:update:title="doc.title = $event" ></text-document> ~~~ 为了方便起见,我们为这种模式提供一个缩写,即 .sync 修饰符: ~~~ <text-document v-bind:title.sync="doc.title"></text-document> ~~~ > 注意带有 `.sync` 修饰符的 `v-bind` 不能和表达式一起使用 (例如 `v-bind:title.sync=”doc.title + ‘!’”` 是无效的)。取而代之的是,你只能提供你想要绑定的属性名,类似 `v-model`。 当我们用一个对象同时设置多个 prop 的时候,也可以将这个 `.sync` 修饰符和 `v-bind` 配合使用: ~~~ <text-document v-bind.sync="doc"></text-document> ~~~ 这样会把 `doc` 对象中的每一个属性 (如 `title`) 都作为一个独立的 `prop` 传进去,然后各自添加用于更新的 `v-on` 监听器。 <br> <br> ## 自定义组件通信 ~~~ <input v-model="something"> ~~~ v-model其实,就是下面的简写形式: ~~~ <input v-bind:value="something" v-on:input="something = $event.target.value"> ~~~ 同样v-model也可以用在组件身上,就是如下的样子了。 ~~~ <custom-input :value="something" @input="value => { something = value }"></custom-input> ~~~ 所以知道这上面两点就可以实现自定义组件v-model功能了。 <br> 下面是child.vue的代码 ~~~ <div> <input type="text" :value="value" @input="updateValue($event.target.value)"> {{value}} </div> export default { props: ['value'], methods: { updateValue(value){ this.$emit('input',value) } }, } ~~~ 下面是father.vue的代码 ~~~ <child v-model="price"></child> data () { return { price: '' } } ~~~ 在子组件中的input中输入数据,可以动态的反应到父组件中,实现双向绑定 由于默认是value和input如果想改变这个默认的,可以在子组件中,使用model如下: ~~~ model: { prop: 'checked', event: 'change' }, props: { checked: Boolean, value: String } ~~~ 所以使用 `<my-checkbox v-model="foo" value="some value"></my-checkbox>` 其实就是下面的简写 ~~~ <my-checkbox :checked="foo" @change="val => { foo = val }" value="some value"></my-checkbox> ~~~ <br> <br> ## 非父子组件之间的通信 非父子组件之间的通信就要使用$on了。首先要有一个空的vue实例 ~~~ var bus = new Vue(); ~~~ 如果你使用vue的webpack项目的话,这个东西你要单独的加在一个js文件中以store.js为例,添加如下代码 : ~~~ import Vue from 'vue' window.bus = new Vue(); ~~~ 并且还要在main.js中通过import './store.js'导入,这时就可以在vue项目全局使用bus了 如果在一个组件中需要传递消息,就使用bus.$emit('fn', 1)传递数据 在要接受数据的组件中使用,bus.$on('fn',function(value){...})即可 讲到这儿,vue最核心的部分也就将完了,弄懂这块儿东西,相信后面的学习就易如反掌了 <br> <br> ## 使用slot实现内容分发 实际工作中组件的组成大多数是类似下面的 : ~~~ <parent> <child> <someother-component></someother-component> </child> </parent> ~~~ slot的作用就是用来处理嵌套在组件标签内部的内容 <br> <br> ## 单一slot 如果只有一个slot标签并且没有任何属性,slot标签将会被全部替换成嵌套在组件标签内部的内容,如果slot标签自身包裹内容,这个内容只会在组件标签内部不包含任何东西的时候展示,demo如下 如果一个child组件的模板内容如下 ~~~ <div> <h2>I'm the child title</h2> <slot> 这里面的内容只会在没有插入内容时显示 </slot> </div> ~~~ 然后`<child>hahahhahahah</child> `,那么hahahhahahah就会替换 `slot` 成为 `child` 模板的一部分 。 <br> <br> ## 命名slot 可以给slot起个名字,比如`<slot name="header"></slot> ` 然后给组件标签内容添加slot属性,属性值和上面的名字相同,就可以实现特殊指派了,如 ~~~ <child> <h1 slot="header">指定的内容</h1> </child> ~~~ 这样就实现的需求导入了 。 <br> <br> ## 局部slot 上面讲的 `slot` 都是可以实现父组件传递数据到子组件中,现在想实现将子组件中的数据传递到 `slot` 要替换的内容中 。 可以在子组件中的 `slot` 插槽中添加任意属性,如 '<slot text="子组件child中的数据"></slot> '。 然后,在子组件标签内部,如下 : ~~~ <parent> <child> // 必须使用template标签,并且添加scope属性,属性值props就是包含slot传递的数据对象 <template scope="props"> <span>父组件parent中的数据</span> <span>{{props.text}}</span> </template> </child> </parent> ~~~ <br> <br> ## 动态组件 可以使用同一个绑定点,动态的切换渲染不同的组件,要实现这个功能要借助component标签和is属性 。 ~~~ <component :is="currentView"></component> ~~~ vue实例代码如下 : ~~~ var vm = new Vue({ el: "#example", data: { currentView: 'home' }, components: { home,posts,archive } }) ~~~ 通过改变currentView的值,可以实现动态切换组件。 上面这种写法可以满足局部组件,也就是你自己定义的组件的切换,但是如果你使用全局组件,比如某些UI组件库中的组件,那么就要像下面这样用 : ~~~ var Home = { template: ... }; var vm = new Vue({ el: "#example", data: { currentView: Home } }); ~~~ 如果你想将切换渲染过的组件保留在内存中可以使用keep-alive将动态组件包裹 ~~~ <keep-alive> <component :is="currentView"> ... </component> <keep-alive> ~~~