组件间的通信
$ref
可以获取到组件实例
// 父组件 this.$ref.blog // 子组件 <blog ref="blog"><blog/>
插槽
父组件给子组件传值
基本语法
// 子组件 <!-- blog组件 --> <div> <p>博文的标题</p> <div> <p>博文的内容</p> <slot></slot> </div> </div>
在父组件中使用
// 父组件 <template> <div id="app"> <blog> 1 <!-- 可以插入文案 --> 今天是一个好天气 2 <!-- 可以插入标签 --> <h1>我是一个大帅哥{{man}}</h1> 3 <!-- 也可以插入组件 --> <hello-world></hello-world> </blog> </div> </template> <script> import Blog from './components/Blog.vue' export default { name: 'App', components: { Blog, }, data() { return { man: 'pd' } }, mounted() { } } </script> ========================
编译作用域
父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。在子组件中不能使用父组件的data
插槽的后备内容
可以在slot中提前设置一段内容作为默认值,当父组件提供插槽内容时将会被覆盖
具名插槽
// 子组件 <template> <!-- layout组件 --> <div class="container"> <header> <!-- 页头放这里 --> <slot name="header"></slot> </header> <main> <!-- 主要内容放这里 --> <slot></slot> </main> <footer> <!-- 页脚放这里 --> <slot name="footer"></slot> </footer> </div> </template> <script> export default { data() { return {} } } </script> // 父组件 <template> <div id="app"> <layout> <template v-slot:header> // div里的内容会插入到lay组件中的slot位置 <div >我是头部内容</div> </template> <div>我是主要内容</div> <template v-slot:footer> <div>我是尾部内容</div> </template> </layout> </div> </template> <script> </script>
作用域插槽
作用域插槽能够实现在父组件中获取子组件的数据,从数据流向
的角度来讲就是将子组件的数据传递到父组件。
v-slot
在vue2.6中。上述的API被软废弃(3.0正式废弃),取而代之的是内置指令v-slot,可以缩写为【#】 子组件用法保持不变,父组件中
slot属性弃用,具名插槽通过指令参数v-slot:插槽名的形式传入,可以简化为#插槽名 slot-scope属性弃用,作用域插槽通过v-slot:xxx="slotProps"的slotProps来获取子组件传出的属性 v-slot属性只能在template上使用,但在只有默认插槽时可以在组件标签上使用
1 <!-- 子组件中 --> <template> <span> <slot v-bind:user="user">{{ user.lastName }}</slot> </span> </template> <script> export default { data() { return { user: { firstName: '张', lastName: '三' } } } } </script> 2 <!-- 父组件中 --> <current-user> <template v-slot:default="slotProps"> 这里自定义一个变量 我们传的数据会到这个对象下面,使用的时候是slotProps.user {{ slotProps.user.firstName }} </template> </current-user>
计算属性
计算属性在页面首次加载的时候就会执行,而且是深度监视,watch需要加两个属性才能实现。
计算属性和watch的区别?
Watch 和 computed的区别
computed支持缓存,只有依赖数据发生改变,才会重新进行计算;而watch不支持缓存,数据变,直接会触发相应的操作 computed不支持异步,当computed内有异步操作时无效,无法监听数据的变化,而watch支持异步 computed属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data中声明过或者父组件传递的props中的数据通过计算得到的值;而watch监听的函数接收两个参数,第一个参数是最新的值,第二个参数是输入之前的值 computed:一个属性受到多个属性影响,如:购物车商品结算。 watch:一个数据影响多条数据,如:搜索数据。数据变化响应,执行异步操作,或高性能消耗的操作,watch为最佳选择
watch
写法
<template> <div></div> </template> <script> export default { data(){ variable:null, }, watch:{ // 此处监听variable变量,当期有变化时执行 variable(item1,item2){ // item1为新值,item2为旧值 } } ==================================== 也可以这样写 watch:{ variable:{ // 此处监听variable变量,当期有变化时执行 handler(item1,item2){ // item1为新值,item2为旧值 } } } } </script>
immediate
watch:{ // 此处监听variable变量,当期有变化时执行 variable(item1,item2){ // item1为新值,item2为旧值 }, immediate:true // watch侦听操作内的函数会立刻被执行 }
deep深度监听
侦听普通变量的变化使用以上方法,当侦听的某个变量值是对象时则不起作用,这时需要使用deep深度监听。该回调会在任何被侦听的对象的 property 改变时被调用,不论其被嵌套多深
对象和数组都是引用类型,引用类型变量存的是地址,地址没有变,所以不会触发watch。这时我们需要进行深度监听,就需要加上一个属性 deep,值为 true。
<script> export default { data(){ obj:{ a:{ c } }, }, watch:{ // 此处监听obj属性c值变量 'obj.a.c'(item1,item2){ // item1为新值,item2为旧值 }, deep:true } } </script>
如果对象内有多个属性,并采用以下写法,则对象内每个属性都会被侦听,每个属性的变化都会执行一次侦听操作。
<template> <div></div> </template> <script> export default { data(){ obj:{ a:'', b:'', c:'' }, }, watch:{ obj:{ handler(item1,item2){ // item1为新值,item2为旧值 }, deep:true } } } </script>
习题
父子组件通信的方式?
1 props $emit
2 v-model
3 $ref
4 v-slot
5 provide和 inject
$refs用于通信时的弊端?
会导致逻辑混乱,因为此时,修改子组件数据的逻辑写在了父组件内
具名插槽和作用域插槽的区别?
数据的流向不同,具名插槽是父组件向子组件传递数据,作用域插槽是子组件向父组件传递数据。
watch如何实现深度监听和页面加载后触发
深度监听
给watch加一条
deep;true
页面加载后触发
给watch加一条
immediate:true
计算属性和watch的区别?
computed支持缓存,只有依赖数据发生改变,才会重新进行计算;而watch不支持缓存,数据变,直接会触发相应的操作 computed不支持异步,当computed内有异步操作时无效,无法监听数据的变化,而watch支持异步
vuex的store中包含的内容?
state Mutation Action getter
vuex如何实现页面获取state和修改state?
获取:可以使用mapState,也可以直接调用 this.$store.state.数据
修改:在store.js的Mutation , Action中定义修改state的逻辑,在页面中分别使用commit 和diapatch调用。
页面刷新后vuex中state是否存在,如何实现持久化?
不会存在,因为Vuex的state是保存在内存中的,而不是持久化到本地存储。
实现持久化:
1 使用插件 vuex-persistedstate
2 使用localStorage或sessionStorage实现持久化