Vue学习笔记07:ref 、动态组件、插槽、自定义指令

文章目录

  • 一、ref 引用
    • 1. 什么是 ref 引用
    • 2. 引用 DOM 和组件实例
    • 3. this.$nextTick(cb) 方法
  • 二、动态组件
    • 1. 什么是动态组件
    • 2. 动态组件渲染和 keep-alive
  • 三、插槽
    • 1. 什么是插槽
    • 2. 插槽的基础用法
    • 3. 具名插槽
    • 4. 作用域插槽
      • 4.1 表格使用作用域插槽
  • 四、自定义指令
    • 1. 什么是自定义指令
    • 2. 声明私有自定义指令的语法
    • 3. 声明全局自定义指令的语法
    • 4. updated 函数
    • 5. 指令的参数值
  • 五、table 案例
    • 1. 案例效果
    • 2. 实现步骤
    • 3. 搭建项目基本结构
      • 3.1 初始化项目
      • 3.2 梳理项目结构
    • 4. 请求商品列表的数据
    • 5. 封装 MyTable 组件
      • 5.1 创建并使用 MyTable 组件
      • 5.2 封装 MyTable 的模板结构
      • 5.3 预留名称为 body 的作用域插槽
    • 6. 实现删除功能
    • 7. 实现添加标签的功能
      • 7.1 渲染标签
      • 7.2 输入框的焦点事件
      • 7.3 为商品添加新的 tag 标签
      • 7.4 添加回车和 esc 键盘事件
  • 总结

一、ref 引用

1. 什么是 ref 引用

ref 用来辅助开发者在不依赖于 jQuery 的情况下,获取 DOM 元素或组件的引用

每个 vue 的组件实例上,都包含一个 $refs 对象,里面存储着对应的 DOM 元素或组件的引用。默认情况下,组件的 $refs 指向一个空对象

<template>
  <h1>App 根组件h1>
  <button type="button" @click="getRefs">获取 $refs 引用button>
template>

<script>
export default {
  methods: {
    getRefs() {
      // this 表示当前组件的实例对象 Proxy
      console.log(this)
      // this.$refs 默认指向空对象 {}
      console.log(this.$refs)
    },
  },
}
script>

2. 引用 DOM 和组件实例

如果想要使用 ref 引用页面上的 DOM 元素或组件实例,则可以按照如下的方式进行操作:

<template>
  
  <h1 ref="myr1">App 根组件h1>
  <button type="button" @click="getRefs">获取 $refs 引用button>
  <my-counter ref="counterRef">my-counter>
template>

<script>
import MyCounter from './Counter.vue'

export default {
  methods: {
    getRefs() {
      // 通过 this.$refs.引用名称,获取到 DOM 元素的引用
      console.log(this.$refs.myr1)
      // 操作 DOM 元素,把文本颜色改成红色
      this.$refs.myr1.style.color = 'red'

      // 通过 this.$refs.引用名称,可以获取到组件的实例
      console.log(this.$refs.counterRef)
      // 获取到组件实例后,就可以调用组件上的 methods 方法
      this.$refs.counterRef.reset()
    },
  },
  components: { MyCounter },
}
script>

Counter 组件:

<template>
  <h3>Counter 组件 --- {{ count }}h3>
  <button type="button" @click="count += 1">+1button>
template>

<script>
export default {
  name: 'MyCounter',
  data() { return { count: 0 } },
  methods: {
    reset() { this.count = 0 },
  },
}
script>

3. this.$nextTick(cb) 方法

需求:控制文本框和按钮的按需切换,然后让文本框自动获得焦点

通过布尔值来控制文本框与按钮的切换。当文本框展示出来之后,添加 ref 引用,并调用原生 DOM 的 .focus() 方法让它立即获得焦点,示例代码如下:

<template>
  <input type="text" v-if="inputVisible" ref="ipt" />
  <button type="button" v-else @click="showInput">展示 input 输入框button>
template>

<script>
export default {
  data() {
    return { inputVisible: false }
  },
  methods: {
    showInput() {
      this.inputVisible = true
      // 打印这个 DOM 引用,会发现此时根本没有这个 DOM 元素,如果调用 focus() 则报错
      console.log(this.$refs.ipt); // undefined

      // 把对 input 的操作,推迟到下次 DOM 更新之后,这样页面上就有这个 DOM 元素了
      this.$nextTick(() => {
        console.log(this.$refs.ipt)
        // 获取到文本框的引用对象,然后调用 focus() 方法
        this.$refs.ipt.focus()
      })
    },
  },
}
script>

组件的 $nextTick(cb) 方法,会把 cb 回调推迟到下一个 DOM 更新周期之后执行。通俗的理解是:等组件的 DOM 异步地重新渲染完成后,再执行 cb 回调函数。从而能保证 cb 回调函数可以操作到最新的 DOM 元素。


二、动态组件

1. 什么是动态组件

动态组件指的是动态切换组件的显示与隐藏。vue 提供了一个内置的 组件,专门用来实现组件的动态渲染。 是组件的占位符,通过 is 属性动态指定要渲染的组件名称。

使用示例:


2. 动态组件渲染和 keep-alive

默认情况下,切换动态组件时无法保持组件的状态。此时可以使用 vue 内置的 组件保持动态组件的状态。当组件在 内被切换时,它的 mountedunmounted 生命周期钩子不会被调用,取而代之的是 activateddeactivated。示例代码如下:

更多参数查看官网文档:https://v3.cn.vuejs.org/api/built-in-components.html#keep-alive

<template>
  
  <button type="button" @click="comName = 'MyHome'">首页button>
  <button type="button" @click="comName = 'MyMovie'">电影button>

  
  <keep-alive>
    <component :is="comName">component>
  keep-alive>
template>

<script>
import MyHome from './Home.vue'
import MyMovie from './Movie.vue'

export default {
  data() {
    return { comName: 'MyHome' } // 1.表示当前需要渲染的组件名称
  },
  components: { MyHome, MyMovie },
}
script>

Home.vue

<template>
  <h3>Home 组件 --- {{ count }}h3>
  <button type="button" class="btn btn-primary" @click="count += 1">+1button>
template>

<script>
export default {
  name: 'MyHome',
  data() { return { count: 0 } },
  // 如果不使用 keep-alive 会发现,每次组件切换都会进行创建或销毁
  created() { console.log('created') },
  unmounted() { console.log('unmounted') }
}
script>

Movie.vue

<template>
  <h3>Movie 组件h3>
template>

三、插槽

1. 什么是插槽

插槽(Slot)是 vue 为组件的封装者提供的能力。允许开发者在封装组件时,把不确定的、希望由用户指定的部分定义为插槽。可以把插槽认为是组件封装期间,为用户预留的内容的占位符
Vue学习笔记07:ref 、动态组件、插槽、自定义指令_第1张图片


2. 插槽的基础用法

在封装组件时,可以通过 元素定义插槽,从而为用户预留内容占位符。示例代码如下:

<template>
  
  <my-com>
    <img src="../../assets/logo.png" alt />
  my-com>
template>

组件:

<template>
  <p>这是第一个 p 标签p>
  
  <slot>slot>
  
  <slot>这是后备内容slot>
  <p>这是最后一个 p 标签p>
template>

注意:

  • 在封装组件时没有预留任何插槽,那用户提供的任何自定义内容都会被丢弃
  • 可以为插槽提供后备内容(默认内容)。如果使用者没有为插槽提供任何内容,则后备内容会生效。

3. 具名插槽

如果在封装组件时需要预留多个插槽节点,则需要为每个 插槽指定具体的 name 名称。这种带有具体名称的插槽叫做具名插槽。示例代码如下:

<template>
  <my-article>
    
    <template v-slot:header>
      <h1>滕王阁序h1>
    template>
    
    <template v-slot:default>
      <p>豫章故郡,洪都新府。p>
      <p>星分翼轸,地接衡庐p>
      <p>襟三江而带五湖,控蛮荆而引瓯越。p>
    template>
    
    <template #footer>
      <p>落款:王勃p>
    template>
  my-article>
template>

组件:

<template>
  
  <header>
    <slot name="header">slot>
  header>
  
  <main>
    <slot>slot>
  main>
  
  <footer>
    <slot name="footer">slot>
  footer>
template>

注意:

  • 没有指定 name 名称的插槽,会有隐含的名称叫做 default
  • 向具名插槽提供内容时,可以在