美文网首页
Vue高级特性复习

Vue高级特性复习

作者: miao8862 | 来源:发表于2021-06-07 23:57 被阅读0次

    梳理vue的高级特性的使用场景和用法,做一个简单的复习,这里只是列举了我们日常常用的一些高级特性,欢迎食用,如果是在面试时问到这些问题,同学们最好和自己的项目经验结合起来哟

    1. vue如何自己实现v-model

    实现步骤:

    1. 父组件使用v-model='xxx'设置绑定的值
    2. 子组件,正常接收父组件的属性props: { xxx: {}}
    3. 子组件使用model对象来绑定
    model: {
      prop: 'xxx',  // 得跟父组件的的v-model保持一致
      event: 'change'  // 这个命名随意,不影响
    }
    
    1. 子组件通过$emit来回调修改父组件绑定的值xxx,第一个参数是model.event命名的事件名,第二个参数是我们要返回的新值,即调用这句,等同于在父组件中赋值xxx = newVal
      this.$emit('change', newVal)

    举个栗子1

    <template>
      <!-- useModel.vue -->
     <div>
       {{myText}}
       <!-- 下面是自定义组件 -->
       <myModel v-model="myText" />
     </div>
    </template>
    
    <script>
    import myModel from './myModel.vue'
    export default {
     name: 'useVModel',
     components:{
       myModel
     },
     data() {
       return {
         myText: ''
       }
     }
    }
    </script>
    
    <template>
      <!-- 自定义组件 -->
      <input
        type="text"
        :value="myText"
        @input="$emit('change', $event.target.value)"
      />
    </template>
    
    <script>
    export default {
      name: "myVModel",
      props: {
        // 接收父组件的v-model属性
        myText: {
          type: String,
          default: ''
        },
      },
      // 这里,定义要绑定的属性和事件
      model: {
        prop: "myText", // 跟父组件的v-model值、自身的value值命名保持一致
        event: "change", // 自定义方法名,但要跟emit方法中的方法名保持一致
      }
    };
    </script>
    

    栗子2

    <template>
     <div>
       {{myText}}
       <!-- 下面是自定义组件 -->
       <myModel2 v-model="myText" />
     </div>
    </template>
    <script>
    import myModel2 from './myModel2.vue'
    
    export default {
     name: 'useVModel',
     components:{
      //  myModel,
       myModel2
     },
     data() {
       return {
         myText: ''
       }
     }
    }
    </script>
    
    <template>
      <!-- 自定义组件 -->
      <div>
        <input type="text" :value="text1" @input="changeValue($event.target.value, 1)">
        <input type="text" :value="text2" @input="changeValue($event.target.value, 2)">
      </div>
    </template>
    
    <script>
    export default {
      name: "myVModel",
      props: {
        // 接收父组件的v-model属性
        myText: {
          type: String,
          default: ''
        },
      },
      // 这里,定义要绑定的属性和事件
      model: {
        prop: "myText", // 跟父组件的v-model值、自身的value值命名保持一致
        event: "myEvent", // 自定义方法名,但要跟emit方法中的方法名保持一致
      },
      data() {
        return {
          text1: '',
          text2: ''
        }
      },
      methods: {
        changeValue(val, type) {
          if(type === 1) {
            this.text1 = val
          }else {
            this.text2 = val
          }
          this.$emit('myEvent', this.text1 + this.text2)
        }
      }
    };
    </script>
    
    实现v-model自定义组件

    2. nextTick

    我们知道vue是异步渲染的,我们在修改值后,并不能立马拿到更新后的dom,而nextTick可以等到渲染完后再执行回调,且页面渲染时,会将data的修改做整合,多次data修改只会渲染一次

    <ul ref="list">
      <li v-for="item in list" :key="index">
        {{item}}
      </li>
    </ul>
    
    this.list.push(1)
    this.list.push(2)
    this.list.push(3)
    this.$nextTick(() => {
      const list = this.$refs['list']
      console.log(list.childNodes.length)
    })
    

    3. slot

    之前写过,这里不再介绍:可以查看 slot

    4. 动态组件:is

    使用component包裹动态组件,:is是动态的组件名

     <!-- useDynamic.vue -->
    <template>
     <div>
        <!-- is中的组件名要和导入的组件名一致 -->
       <component :is="compName"></component>
       <button @click="changeComp">changeComp</button>
     </div>
    </template>
    
    <script>
    import aa from './aa.vue'
    import bb from './bb.vue'
    import cc from './cc.vue'
    export default {
     name: 'useVModel',
     components:{
       aa,
       bb,
       cc
     },
     data() {
       return {
         compName: 'aa'
       }
     },
     methods: {
       changeComp() {
         this.compName == 'aa' ? this.compName = 'bb' : this.compName =='bb' ? this.compName = 'cc' : this.compName = 'aa'
       }
     }
    }
    </script>
    
    <!-- aa.vue -->
    <template>
      <span>aa</span>
    </template>
    
    <!-- bb.vue -->
    <template>
      <span>bb</span>
    </template>
    
    <!-- cc.vue -->
    <template>
      <span>cc</span>
    </template>
    
    动态组件1

    点击后,更改为:


    动态组件2

    5. 异步组件

    平常我们写代码是这样的,也就是使用import aa from './aa.vue'方式导入的组件都是同步的,即使它在页面最初加载时不显示;
    当导入的组件比较小时,这没什么问题,但当组件体积较大时,这样会使页面最初加载时速度慢,所以可以使用异步加载组件的方式来优化,这样,页面最初进来时不会加载这个组件,当showComptrue时,才会加载这个组件

     <!-- useAsyncCom.vue -->
    <template>
     <div>
       <aa v-if="showComp"/>
       <button @click="showComp = true">show or hide</button>
     </div>
    </template>
    
    <script>
    
    import aa from './aa.vue'
    
    export default {
     name: 'useAsyncCom',
     components:{
       aa
     },
     data() {
       return {
         showComp: false
       }
     }
    }
    </script>
    
    // 同步加载
    // import aa from './aa.vue'
    
    export default {
     name: 'useAsyncCom',
     components:{
       // 修改成异步加载组件  
       aa: () => import('./aa')
     }
     //...
    }
    

    6. keep-alive

    • 缓存组件
    • 频繁切换,不需要重复渲染
    • 是vue常见的性能优化
     <!-- useKeepalive.vue -->
    <template>
     <div>
       <button @click="showName = 'aa'">a</button>
       <button @click="showName = 'bb'">b</button>
       <button @click="showName = 'cc'">c</button>
       <!-- <keep-alive> -->
         <aa v-if="showName == 'aa'"/>
         <bb v-if="showName == 'bb'"/>
         <cc v-if="showName == 'cc'"/>
       <!-- </keep-alive> -->
     </div>
    </template>
    
    <script>
    import aa from './aa.vue'
    import bb from './bb.vue'
    import cc from './cc.vue'
    export default {
     name: 'useKeepalive',
     components:{
       aa,
       bb,
       cc
     },
     data() {
       return {
         showName: 'aa'
       }
     }
    }
    </script>
    
    
    <!-- aa.vue, bb和cc组件相同 -->
    <template>
      <span>aa</span>
    </template>
    
    <script>
    export default {
      mounted() {
        console.log('mounted AA');
      },
      beforeDestroy() {
        console.log('destroy AA');
      }
    }
    </script>
    
    

    下面是未用keep-alive时的效果,可以看到,当切换组件时,组件都要进行销毁和重新渲染:

    image.png

    aa, bb, cc组件加上keep-alive后,查看效果,组件不再进行销毁操作,多次切换也只会进行一次渲染:

       <keep-alive>
         <aa v-if="showName == 'aa'"/>
         <bb v-if="showName == 'bb'"/>
         <cc v-if="showName == 'cc'"/>
       </keep-alive>
    
    image.png
    当切换时,会调用另外两个生命周期activateddeactivated,给aa, bb, cc添加上这两个生命周期打印
    <!-- aa.vue -->
    <template>
      <span>aa</span>
    </template>
    
    <script>
    export default {
      mounted() {
        console.log('mounted AA');
      },
      activated() {
        console.log('AA activated');
      },
      deactivated() {
        console.log('AA deactivated');
      },
      beforeDestroy() {
        console.log('destroy AA');
      }
    }
    </script>
    

    结果:


    activated和deactivated

    7. mixin

    当多个组件有共同逻辑,需要抽离出来,可以考虑使用mixin
    虽然它并不是最完美的解决方案,比如会存在以下问题:

    1. 变量来源不明确,难以追溯调试;
    2. 多个mixin文件,可能会造成命名冲突;
    3. mixin和组件可能会出现多对多关系(一个组件引用多个mixin,一个mixin引入多个组件),复杂度较高。

    vue3中的composition api针对这些,会有更好的解决方案。但这里,主要还是介绍下mixin,如果业务比较简单,且较多页面复用时,还是可以考虑使用它。

    它对生命周期中的执行,会做混合操作;但对变量或方法等,会进行覆盖,优先级是 左边mixin < 右边mixin < 当前组件

    <!-- useMixins.vue -->
    <template>
     <div>
       {{name}}今年{{age}}岁了
       <button @click="age++">加一岁</button>
     </div>
    </template>
    
    <script>
    import mixinA from './mixinA'
    import mixinB from './mixinB'
    export default {
     name: 'useMixins',
     mixins: [mixinA, mixinB],
     data() {
       return {
         name: '小花'
       }
     },
     mounted() {
       console.log('引用mixin的组件 mounted');
     }
    }
    </script>
    
    // mixinA.js
    export default {
     name: 'mixinA',
     data() {
       return {
         age: 11
       }
     },
     mounted() {
       console.log('mixinA的组件 mounted');
     }
    }
    
    // mixinB.js
    export default {
     name: 'mixinB',
     data() {
       return {
         age: 12
       }
     },
     mounted() {
       console.log('mixinB的组件 mounted');
     }
    }
    

    可以看到结果,mixinB中的age覆盖了mixinA的,mounted中混合了三个组件的内容,从左到右优化的顺序混合

    mixin

    相关文章

      网友评论

          本文标题:Vue高级特性复习

          本文链接:https://www.haomeiwen.com/subject/ltzreltx.html