Vue高级特性
@ 姜波 | 星期二,六月 30 日,2020 年 | 2 分钟阅读 | 更新于 星期二,六月 30 日,2020 年

自定义v-model

Index.vue

<p>{{name}}</p>
<CustomVModel v-model="name"/>

CustomVModel.vue

<template>
    <!-- 例如:vue 颜色选择 -->
    <input type="text"
        :value="text1"
        @input="$emit('change1', $event.target.value)"
    >
    <!--
        1. 上面的 input 使用了 :value 而不是 v-model
        2. 上面的 change1 和 model.event1 要对应起来
        3. text1 属性对应起来
    -->
</template>

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

$nextTick

  • Vue是异步渲染
  • data改变之后,DOM不会立刻渲染
  • $nextTick会在DOM渲染之后被触发,以获取最新DOM节点
<template>
  <div id="app">
    <ul ref="ul1">
        <li v-for="(item, index) in list" :key="index">
            {{item}}
        </li>
    </ul>
    <button @click="addItem">添加一项</button>
  </div>
</template>

<script>
export default {
  name: 'app',
  data() {
      return {
        list: ['a', 'b', 'c']
      }
  },
  methods: {
    addItem() {
        this.list.push(`${Date.now()}`)
        this.list.push(`${Date.now()}`)
        this.list.push(`${Date.now()}`)

        // 1. 异步渲染,$nextTick 待 DOM 渲染完再回调
        // 2. 页面渲染时会将 data 的修改做整合,多次 data 修改只会渲染一次
        this.$nextTick(() => {
          // 获取 DOM 元素
          const ulElem = this.$refs.ul1
          // eslint-disable-next-line
          console.log( ulElem.childNodes.length )
        })
    }
  }
}
</script>

slot

  • 基本使用

Index.vue

<SlotDemo :url="website.url">
  {{website.title}}
</SlotDemo>

SlotDemo.vue

<template>
    <a :href="url">
        <slot>
            默认内容,即父组件没设置内容时,这里显示
        </slot>
    </a>
</template>

<script>
export default {
    props: ['url'],
    data() {
        return {}
    }
}
</script>
  • 作用域插槽

Index.vue

<ScopedSlotDemo :url="website.url">
  <template v-slot="slotProps">
  	{{slotProps.slotData.title}}
  </template>
</ScopedSlotDemo>

ScopedSlotDemo.vue

<template>
    <a :href="url">
        <slot :slotData="website">
            {{website.subTitle}} <!-- 默认值显示 subTitle ,即父组件不传内容时 -->
        </slot>
    </a>
</template>

<script>
export default {
    props: ['url'],
    data() {
        return {
            website: {
                url: 'http://wangEditor.com/',
                title: 'wangEditor',
                subTitle: '轻量级富文本编辑器'
            }
        }
    }
}
</script>
  • 具名插槽

Index.vue

<NamedSlot>
  <template v-slot:header>
  	header
  </template>
  <template v-slot:footer>
  	footer
  </template>
</NamedSlot>

NamedSlot.vue

<div>
  <slot name="header"></slot>
	<slot name="footer"></slot>
</div>

动态、异步组件

动态组件

<component :is="NextTickName"/>

<script>
import NextTick from './NextTick'

export default {
    components: {
        NextTick
    },
    data() {
        return {
            NextTickName: "NextTick",
        }
    }
}
</script>

异步组件

<FormDemo v-if="showFormDemo"/>
<button @click="showFormDemo = true">show form demo</button>

<script>
export default {
    components: {
        FormDemo: () => import('./FormDemo')
    },
    data() {
        return {
            showFormDemo: false,
        }
    }
}
</script>

keep-alive

缓存组件

<keep-alive> <!-- tab 切换 -->
  <KeepAliveStageA v-if="state === 'A'"/> <!-- v-show -->
  <KeepAliveStageB v-if="state === 'B'"/>
  <KeepAliveStageC v-if="state === 'C'"/>
</keep-alive>

mixin

  • 变量来源不明确
  • 多mixin可能会造成命名冲突
  • mixin和组件可能出现多对多的关系,复杂度较高

Mixin.vue

<template>
    <div>
        <p>{{name}} {{major}} {{city}}</p>
        <button @click="showName">显示姓名</button>
    </div>
</template>

<script>
import myMixin from './mixin'

export default {
    mixins: [myMixin], // 可以添加多个,会自动合并起来
    data() {
        return {
            name: 'wilber',
            major: 'web 前端'
        }
    },
    methods: {
    },
    mounted() {
        // eslint-disable-next-line
        console.log('component mounted', this.name)
    }
}
</script>

mixin.js

export default {
    data() {
        return {
            city: '上海'
        }
    },
    methods: {
        showName() {
            // eslint-disable-next-line
            console.log(this.name)
        }
    },
    mounted() {
        // eslint-disable-next-line
        console.log('mixin mounted', this.name)
    }
}
vue
保存为图片

公众号

Image text

QQ

Image text

微信

Image text

微信打赏

Image text

社交链接