Vue自定义指令 和 插槽

238 阅读3分钟

Vue自定义指令 和 插槽

自定义指令

除了核心功能默认内置的指令 (v-modelv-show),Vue 也允许注册自定义指令。 v-xxx

注意,代码复用和抽象的主要形式是组件。

然而,有的情况下,仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令。

自定义指令 - 局部注册

当页面加载时,让元素将获得焦点 , (autofocus 在 safari 浏览器有兼容性)

<template>
  <div>
    <h3>自定义指令</h3>
    <input ref="inp" type="text" v-focus>
  </div>
</template><script>
export default {
  directives: {
    // 自定义一个局部指令
    focus: {
      inserted (el) {
        el.focus()
      }
    }
  }
}
</script>

自定义指令 - 全局注册

// 注册全局自定义指令
Vue.directive('focus', {
  inserted (el) {
    el.focus()
  }
})

自定义指令 - 指令的值

在绑定指令时,可以通过“等号”的形式为指令绑定具体的参数值

需求: v-color="color" 给对应的颜色, 就能改对应的字体颜色

<div v-color="color">我是内容</div>

实现:

directives: {
  // 自定义一个局部指令
  color: {
    // 指令所在的元素渲染的时候
    inserted (el, {value}) {
      el.style.color = value
    },
    // update指令的值改变时触发, binding.value指令的值修改触发
    update (el, binding) {
      el.style.color = binding.value
    }
  }
}

插槽

插槽(Slot)是 vue 为组件的封装者提供的能力。

允许开发者在封装组件时,把不确定的、希望由用户指定的部分定义为插槽。

默认插槽 slot

通过父传子, 固然可以完成一定层面的组件的定制, 但是自定义性较差,

如果希望能够自定义组件内部的一些结构 => 就需要用到插槽

插槽作用: 用于实现组件的内容分发, 通过 slot 标签, 可以接收到写在组件标签内的内容

插槽:slot 作用:占位置

基本示例:

<my-dialog>
  <p>请输入正确的手机号码</p>
</my-dialog>

my-dialog.vue

<template>
  <div class="my-dialog">
    <div class="header">
      <h3>友情提示</h3>
    </div>
    <div class="content">
      <slot></slot>
    </div>
    <div class="footer">
      <button>关闭</button>
    </div>
  </div>
</template>

后备内容 (默认值)

封装组件时,可以为预留的 <slot> 插槽提供后备内容(默认内容)。

如果组件的使用者没有为插槽提供任何内容,则后备内容会生效。

<template>
  <div class="my-dialog">
    <div class="header">
      <h3>友情提示</h3>
    </div>
    <div class="content">
      <slot>这是后备内容</slot>
    </div>
    <div class="footer">
      <button>关闭</button>
    </div>
  </div>
</template>

具名插槽

插槽的分类:

1 默认插槽(匿名插槽)

<slot></slot> 只要没有具体分发的内容, 都会给到默认插槽

<slot name="default"></slot> 是默认插槽完整的写法 和 <slot></slot> 完全等价

2 具名插槽: 具有名字的插槽 (配置了名字), 可以实现定向分发

一旦配置了名字, 只会接收对应的内容, 不是分发给他的, 就不要

具名插槽的使用步骤

(1) 给插槽起名字

<div class="header">
  <slot name="header"></slot>
</div>
<div class="content">
  <slot>这是后备内容</slot>
</div>
<div class="footer">
  <slot name="footer"></slot>
</div>

(2) 需要使用 template 标签, 将内容包裹成一个整体

(3) 通过 v-slot:插槽名, 指定具体分发给谁

<my-dialog>
  <template v-slot:header>
    <h3>这是大标题</h3>
  </template>

  <template v-slot:default>
    <p>这是内容</p>
  </template>

  <template v-slot:footer>
    <button>确认</button>
    <button>取消</button>
  </template>
</my-dialog>

具名插槽的简写

跟 v-on 和 v-bind 一样,v-slot 也有缩写,即把参数之前的所有内容 (v-slot:) 替换为字符 #。

例如 v-slot:header 可以被简写为 #header

<my-dialog>
  <template #header>
    <h3>这是大标题</h3>
  </template>

  <template #default>
    <p>这是内容</p>
  </template>

  <template #footer>
    <button>确认</button>
    <button>取消</button>
  </template>
</my-dialog>

作用域插槽

作用域插槽: 定义 slot 插槽的同时, 是可以传值的, 将来在分发内容时, 可以使用

  1. 给 slot 标签, 以 添加属性的方式传值
<slot name="bottom" :yes="yes" :no="no" money="100"></slot>
  1. 所有添加的属性, 都会被收集到一个对象中
{ yes: '确认', no: '取消', money: '100' }
  1. 在template中, 通过 v-slot:插槽名= "obj" 接收
<template #bottom="obj">
  <!-- {{ obj }} -->
  <button>{{ obj.yes }}</button>
  <button>{{ obj.no }}</button>
  <button>{{ obj.money }}</button>
</template>
  1. 可以使用解构赋值简化数据的接收
<template #bottom="{ yes, no, money }">
  <button>{{ yes }}</button>
  <button>{{ no }}</button>
  <button>{{ money }}</button>
</template>