在面试过程中,经常会被面试官问的鸦雀无言,但是如果我们日常积累些知识点,等到被面试的时候,就可以和面试官来交流技术。
父子组件通信
绝大部分vue本身提供的通信方式,都是父子组件通信
prop
最常见的组件通信方式之一,由父组件传递到子组件
父组件
<template> <div id="app"> <HelloWorld msg="Welcome to Your Vue.js App" /> </div> </template> <script> import HelloWorld from "./components/HelloWorld.vue"; export default { components: { HelloWorld, }, }; </script> 复制代码
子组件
<template> <div> <h1>{{msg}}</h1> </div> </template> <script> export default { name: "HelloWorld", props: { msg: String, }, created(){ console.log(this.msg) // 打印出父组件给子组件传递的值 Welcome to Your Vue.js App } }; </script> 复制代码
event(emit)
最常见的组件通信方式之一,当子组件发生了某些事,可以通过event通知父组件
父组件
<template> <div id="app" :style="{fontSize: postFontSize + 'em'}"> <HelloWorld msg="Welcome to Your Vue.js App" @enlarge-text="postFontSize += 0.1" /> </div> </template> <script> import HelloWorld from "./components/HelloWorld.vue"; export default { components: { HelloWorld, }, data(){ return { postFontSize: 1 } } }; </script> 复制代码
子组件
<template> <div> <h1>{{msg}}</h1> // 点击按钮后,子组件会触发事件,传递到父组件中,放大字体 <button @click="$emit('enlarge-text')">放大字号</button> </div> </template> <script> export default { name: "HelloWorld", props: { msg: String, }, }; </script> 复制代码
style和class
父组件可以向子组件传递style和class,它们会合并到子组件的根元素中
示例
父组件
<template> <div id="app"> <HelloWorld style="color:red" class="hello" msg="Welcome to Your Vue.js App" /> </div> </template> <script> import HelloWorld from "./components/HelloWorld.vue"; export default { components: { HelloWorld, }, }; </script> 复制代码
子组件
<template> <div class="world" style="text-align:center"> <h1>{{msg}}</h1> </div> </template> <script> export default { name: "HelloWorld", props: { msg: String, }, }; </script> 复制代码
渲染结果:
<div id="app"> <div class="hello world" style="color:red; text-aling:center"> <h1>Welcome to Your Vue.js App</h1> </div> </div> 复制代码
attribute
如果父组件传递了一些属性到子组件,但子组件并没有声明这些属性,则它们称之为attribute,这些属性会直接附着在子组件的根元素上
不包括style和class,它们会被特殊处理
示例
父组件
<template> <div id="app"> <!-- 除 msg 外,其他均为 attribute --> <HelloWorld data-a="1" data-b="2" msg="Welcome to Your Vue.js App" /> </div> </template> <script> import HelloWorld from "./components/HelloWorld.vue"; export default { components: { HelloWorld, }, }; </script> 复制代码
子组件
<template> <div> <h1>{{msg}}</h1> </div> </template> <script> export default { name: "HelloWorld", props: { msg: String, }, created() { console.log(this.$attrs); // 得到: { "data-a": "1", "data-b": "2" } }, }; </script> 复制代码
渲染结果:
<div id="app"> <div data-a="1" data-b="2"> <h1>Welcome to Your Vue.js App</h1> </div> </div> 复制代码
子组件可以通过inheritAttrs: false配置,禁止将attribute附着在子组件的根元素上,但不影响通过$attrs获取
natvie修饰符
在注册事件时,父组件可以使用native修饰符,将事件注册到子组件的根元素上
示例
父组件
<template> <div id="app"> <HelloWorld @click.native="handleClick" /> </div> </template> <script> import HelloWorld from "./components/HelloWorld.vue"; export default { components: { HelloWorld, }, methods: { handleClick() { console.log(1); }, }, }; </script> 复制代码
子组件
<template> <div> <h1>Hello World</h1> </div> </template> 复制代码
渲染结果
<div id="app"> <!-- 点击该 div,会输出 1 --> <div> <h1>Hello World</h1> </div> </div> 复制代码
$listeners
子组件可以通过$listeners获取父组件传递过来的所有事件处理函数, 爷爷组件
<template> <div class="father-page"> <div>这是父组件</div> <child-1 @child2Info="getInfo"></child-1> </div> </template> <script> import child1 from './Child1' export default { name: 'Father', components:{child1}, methods: { getInfo:function(data){ console.log(data) //这是子组件1-1-1发送的信息 } } } </script> 复制代码
父亲组件 child-1
<template> <div class="child1-page"> <div>这是子组件-1</div> <child-2 v-on="$listeners"></child-2> </div> </template> <script> import child2 from "./Child2" export default { name: 'Child1', components:{child2}, } </script> 复制代码
孙子组件
<template> <div>这是子组件1-1</div> </template> <script> export default { mounted: function() { this.$emit("child2Info","这是子组件1-1-1发送的信息") } }; </script> 复制代码
可以在子孙组件中执行祖先组件的函数,从而实现数据传递。 demo或小型项目可以使用listeners进行数据传递,中大型项目不推荐,数据流会变的难于理解。‘listeners进行数据传递,中大型项目不推荐,数据流会变的难于理解。 `listeners`的真正目的是将所有的事件监听器指向这个组件的某个特定的子元素。
v-model
v-model 实际上是vue给表单做单的一个双向数据绑定
<input v-model="aaa" /> 复制代码
等价于
<input :value="aaa" @input="aaa = $event.target.value" > 复制代码
sync修饰符
和v-model的作用类似,用于双向绑定,不同点在于v-model只能针对一个数据进行双向绑定,而sync修饰符没有限制
示例
子组件
<template> <div> <p> <button @click="$emit(`update:num1`, num1 - 1)">-</button> {{ num1 }} <button @click="$emit(`update:num1`, num1 + 1)">+</button> </p> <p> <button @click="$emit(`update:num2`, num2 - 1)">-</button> {{ num2 }} <button @click="$emit(`update:num2`, num2 + 1)">+</button> </p> </div> </template> <script> export default { props: ["num1", "num2"], }; </script> 复制代码
父组件
<template> <div id="app"> <Numbers :num1.sync="n1" :num2.sync="n2" /> <!-- 等同于 --> <Numbers :num1="n1" @update:num1="n1 = $event" :num2="n2" @update:num2="n2 = $event" /> </div> </template> <script> import Numbers from "./components/Numbers.vue"; export default { components: { Numbers, }, data() { return { n1: 0, n2: 0, }; }, }; </script> 复制代码
v-model VS .sync
先明确一件事情,在 vue 1.x 时,就已经支持 .sync 语法,但是此时的 .sync 可以完全在子组件中修改父组件的状态,造成整个状态的变换很难追溯,所以官方在2.0时移除了这个特性。然后在 vue2.3时,.sync又回归了,跟以往不同的是,现在的.sync完完全全就是一个语法糖的作用,跟v-model的实现原理是一样的,也不容易破环院有的数据模型,所以使用上更安全也更方便。
- 两者都是用于实现双向数据传递的,实现方式都是语法糖,最终通过 prop + 事件 来达成目的。
- vue 1.x 的 .sync 和 v-model 是完全两个东西,vue 2.3 之后可以理解为一类特性,使用场景略微有区别
- 当一个组件对外只暴露一个受控的状态,切都符合统一标准的时候,我们会使用v-model来处理。.sync则更为灵活,凡是需要双向数据传递时,都可以去使用。
$parent和$children
在组件内部,可以通过$parent和$children属性,分别得到当前组件的父组件和子组件实例
$slots 插槽
Vue.compopnent('my-cmp', { template: ` <div class="container"> <header> <slot name="header"></slot> </header> <main> <slot></slot> </main> <footer> <slot name="footer"></slot> </footer> </div> ` }) 复制代码
使用时
<my-cmp> <template v-slot:header> <h1>头部</h1> </template> <p>内容</p> <p>内容</p> <template v-slot:footer> <p>底部</p> </template> </my-cmp> 复制代码
ref
父组件可以通过ref获取到子组件的实例
$parent
可以在子组件中访问父实例的数据。
对于 demo 或非常小型的有少量组件的应用来说这是很方便的。中大型项目不适用。会使应用难于调试和理解。
$children
可以在父组件中访问子实例的数据。
对于 demo 或非常小型的有少量组件的应用来说这是很方便的。中大型项目不适用。会使应用难于调试和理解
跨组件通信
Provide和Inject
示例
// 父级组件提供 'foo' var Provider = { provide: { foo: 'bar' }, // ... } // 组件注入 'foo' var Child = { inject: ['foo'], created () { console.log(this.foo) // => "bar" } // ... } 复制代码
详见:cn.vuejs.org/v2/api/?#pr…
router
如果一个组件改变了地址栏,所有监听地址栏的组件都会做出相应反应
最常见的场景就是通过点击router-link组件改变了地址,router-view组件就渲染其他内容
vuex
适用于大型项目的数据仓库
store模式
适用于中小型项目的数据仓库
// store.js const store = { loginUser: ..., setting: ... } // compA const compA = { data(){ return { loginUser: store.loginUser } } } // compB const compB = { data(){ return { setting: store.setting, loginUser: store.loginUser } } } 复制代码
eventbus
组件通知事件总线发生了某件事,事件总线通知其他监听该事件的所有组件运行某个函数
Vue.prototype.$bus = new Vue(); 复制代码
Vue.component(‘cmp-a’, { data () { return { a: ‘a’ } }, methods: { onClick () { this.b u s . bus.bus.on(‘click’, this.a) } }, template: <div> <button @click="onClick">点击</button> </div>, }) 复制代码
Vue.component('cmp-a', { mounted () { this.$bus.$on('click', data => { console.log(data); // 拿到a的数据 }) }, template: ` <div>b</div> `, }) 复制代码 ```