vue 高级特性

一 自定义v-model属性

vue在表单等domm模型中默认绑定了v-model的特性,而父组件中封装了有input的子组件,那么如何使父子组件都能进行双向绑定呢?这里提供一个案例:

父组件有一个custom-model子组件:

<template>
    <div>
        <p>{{name}}</p>
        <custom-model v-model="name" />
    </div>
</template>

<script>
import customModel from './CustomModel';
export default {
    components: {
        customModel
    },
    data() {
        return {
            name: ''
        }
    }
}
</script>

子组件custom-model:

<template>
    <input type="text" 
      :value="text1" 
      @input="$emit('change1', $event.target.value)" 
    />
    <!-- 上面的input使用了:value而非v-model -->
    <!-- 上面的change1和model.event对应起来 -->
    <!-- text1属性对应起来 -->
</template>

<script>
export default {
    model: {
        prop: 'text1',
        event: 'change1'
    },
    props: {
        text1: String,
        default() {
            return ''
        }
    }
}
</script>

父组件中的子组件自定义v-model,该值会与子组件model中的prop进行双向数据绑定,同时提供event作为事件名进行事件注册。

二 $nextTick

由于vue是异步渲染的,所以在修改vue的data等数据之后,等所有函数执行完才会进行dom渲染,所以在函数执行中,要在dom渲染后执行外面要包裹一层$nextTick,下面有一个案例:

<template>
    <div>
        <ul ref="ul1">
            <li v-for="(item,index) in list" :key="index">
                {{item}}
            </li>
        </ul>
        <button @click="add">add</button>
    </div>
</template>

<script>
export default {
    data() {
        return {
            list: ['a', 'b', 'c']
        }
    },
    methods: {
        add() {
            this.list.push(`${Date.now()}`)
            this.list.push(`${Date.now()}`)
            this.list.push(`${Date.now()}`)
            // 异步渲染  $nextTick等待dom渲染完成后执行
            // 页面渲染时将会对data的修改做整合,多次data修改只会修改一次
            this.$nextTick(() => {
                const ul1 = this.$refs.ul1
                console.log(ul1.childNodes.length)
            })
        }
    }
}
</script>

如果去掉this.$nextTick,在函数中打印的dom长度就不是6而是3,可以尝试一下。

三 slot插槽

高级的插槽使用作用域插槽和具名插槽,案例:

父组件

<template>
    <slot-name>
        <!-- 作用域插槽 -->
        <template v-slot="slotProps">
            {{slotProps.slotData.name}}
        </template>
        <!-- 具名插槽 -->
        <template v-slot:footer>
            <p>aaa</p>
        </template>
    </slot-name>
</template>

<script>
import slotName from './slotName';
export default {
    components: {
        slotName
    }
}
</script>

子组件

<template>
    <div>
        <a :href="website.url">
            <slot :slotData="website">
                哈哈哈
            </slot>
        </a>
        <slot name="footer"></slot>
    </div>
</template>

<script>
export default {
    data() {
        return {
            website: {
                url: 'http://www.baidu.com',
                name: '百度'
            }
        }
    }
}
</script>

子组件在slot中传入slotData属性和对应的value,到父组件v-slot的名称.slotData属性就是子组件website的值,这里注意一下在具名插槽footer里的插槽不能使用slotData的值,所以交作用域插槽,只是在这个slot内可以使用的变量

四 动态组件,异步组件

动态组件:

<Component :is="'text'" />

在子组件不确定的情况下,通过字符串传参表示所对应的类的名称,组件能够直接渲染出来,照常引用、注册组件,使用component标签并添加:is属性,属性值为组件名

异步组件:

普通组件采用import xx from xx的方式加载,为同步加载,当项目需要引入很大的组件时,同步加载性能会十分差,体验也很不理想,所以此时需要采用异步加载组件的方法。
方法:直接在components里定义组件名,使用import()方法

export default{
    components:{
        ${组件名}:()=>import(${组件路径})
    }
}

能够在组件初始化时不用渲染而等到需要使用的时候再进行渲染,在路由的配置中经常使用。

五 keep-alive

使用场景:频繁切换,不需要重复渲染的组件
被包裹的组件会被缓存,在频繁切换但不需要重复渲染的情况下使用,通常是vue其中一个性能优化的方向
用法:需要频繁切换的组件外层添加keep-alive标签,添加后组件切换时不会被销毁,会缓存起来,大幅提高渲染性能。
案例:
这是父组件,会同时切换两个组件

<template>
    <div>
        <keep-alive>
            <template v-if="data === 'c'">
                <c /> 
            </template>
            <template v-if="data === 'd'">
                <d />
            </template>
        </keep-alive>
        <button @click="handle">提交</button>
    </div>
</template>

<script>
import c from './c';
import d from './d';
export default {
    components: {
        c,
        d
    },
    data() {
        return {
            data: 'c'
        }
    },
    methods: {
        handle() {
            this.data === 'c' ? this.data = 'd' : this.data = 'c'
        }
    }
}
</script>

其中c组件和d组件基本相同只展示其中一个

<template>
  <div>c</div>
</template>

<script>
export default {
    mounted() {
        console.log('c mounted')
    },
    destroyed() {
        console.log('c destoryed')
    }
}
</script>
test

如果没有keep-alive,那么切换的时候destoryed函数也会执行,但是有的情况destoryed函数就不执行了,原因就在于keep-alive会缓存组件,组件在其中不会销毁。

六 mixin

组件抽离公共逻辑
多个组件有相同的逻辑可以抽离出来的时候就可以使用。但是目前mixin并不是完美的解决方案,会有一些问题。现在的Vue3意在解决这些问题。
案例:

<template>
   <div>
       {{a}}--{{b}}
       <button @click="handle">提交</button>
   </div>
</template>

<script>
import myMixins from './mixins';
export default {
   mixins: [ myMixins ],
   data() {
       return {
           a: 'aaa'
       }
   }
}
</script>

export default {
    data() {
        return {
            b: 'bbb'
        }
    },
    methods: {
        handle() {
            console.log(this.b)
        }
    }
}

mixin目前存在的缺点:

  • 变量来源不明确,不利于阅读。
  • 多mixin可能会造成命名冲突。
  • mixin可能存在多对多的关系,复杂度较高。

七 watch进阶

从我们刚开始学习Vue的时候,对于侦听属性,都是简单地如下面一般使用:

watch:{
    a(){
     //doSomething
    }
}

实际上,Vue对watch提供了很多进阶用法。

handler函数

以对象和handler函数的方式来定义一个监听属性,handler就是处理监听变动时的函数:

watch:{
    a:{
        handler:'doSomething'
    }
},
methods:{
    doSomething(){
        //当 a 发生变化的时候,做些处理
    }
}

handler有啥用?是多此一举么?用途主要有两点:

  • 将处理逻辑抽象出去了,以method的方式被复用
  • 给定义下面两个重要属性留出了编写位置

deep属性

当watch的是一个Object类型的数据,如果这个对象内部的某个值发生了改变,并不会触发watch动作!

也就是说,watch默认情况下,不监测内部嵌套数据的变动。但是很多情况下,我们是需要监测的!

为解决这一问题,就要使用deep属性:

watch:{
    obj:{
        handler:'doSomething',
        deep:true
    }
},
methods:{
    doSomething(){
        //当 obj 发生变化的时候,做些处理
    }
}

deep属性默认为false,也就是我们常用的watch模式。

immediate属性

watch 的handler函数通常情况下只有在监听的属性发生改变时才会触发。

但有些时候,我们希望在组件创建后,或者说watch被声明和绑定的时候,立刻执行一次handler函数,这就需要使用immediate属性了,它默认为false,改为true后,就会立刻执行handler。

watch:{
    obj:{
        handler:'doSomething',
        deep:true,
        immediate:true
    }
},
methods:{
    doSomething(){
        //当 obj 发生变化的时候,做些处理
    }
}

同时执行多个方法

使用数组可以设置多项,形式包括字符串、函数、对象

watch: {
   // 你可以传入回调数组,它们会被逐一调用
   a: [
       
     'handle1',
       
     function handle2 (val, oldVal) { /* ... */ },
       
     {
       handler: function handle3 (val, oldVal) { /* ... */ },
       /* ... */
     }
       
   ],
   
 }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • 本文使用的Vue版本:2.6.10 Vue为我们提供了很多高级特性,学习和掌握它们有助于提高你的代码水平。 一、w...
    liujiangblog阅读 357评论 1 1
  • Vue高级特性 未经同意 禁止转载 自定义v-model $nextTick 1. vue是异步渲染 2. dat...
    吾名刘斩仙阅读 309评论 0 0
  • v-model $nextTick 汇总data的修改,一次性做视图更新减少DOM操作次数,提高性能 slot 父...
    卷村队队员阅读 112评论 0 0
  • 1、使用v-model进行父子传值 2、nextTick()异步加载dom元素 3、使用slot,分为匿名插槽、作...
    枸杞_7422阅读 109评论 0 0
  • 基本使用 父组件在引用的子组件中添加内容 子组件 slotDemo.vue 作用域插槽 父组件可以拿到子组件的数据...
    loushumei阅读 743评论 0 6