vue 的指令

目录

一、vue 的指令

1、v-text

2、v-html

3、v-show

4、v-if/v-esle-if/v-else

(1)、v-if

(2)、v-if 与 v-show

5、v-for

(1)、v-for 渲染一个数组

(2)、 v-for 渲染一个对象

(3)、v-if 与 v-for

(4)、v-for 之 key

(5)、显示过滤/排序后的结果

6、v-on

(1)、v-on 指令的修饰符

(2)、在内联事件处理器中访问事件参数

(3)、vue 中的特殊事件

7、v-bind

8、v-model

(1)、双向绑定的语法糖

(2)、v-model 的修饰符——表单

9、v-slot

10、v-pre(使用频率很低)

11、v-once(使用频率很低)

二、自定义指令 与 指令的生命周期

1、注册自定义指令

(1)、注册全局指令——Vue.directive() 方法

(2)、注册局部指令——directives 属性

2、案例


一、vue 的指令

指令的本质:语法糖,标志位。在编译阶段 render 函数里,会把指令编译成 JavaScript 代码。

vue 的指令:

  • v-text
  • v-html(不建议使用)
  • v-show
  • v-if / v-else-if / v-else
  • v-for
  • v-bind
  • v-on
  • v-model
  • v-slot
  • v-pre(使用频率很低)
  • v-once(使用频率很低)
  • v-cloak(使用频率极低,不细介绍)

1、v-text

v-text 指令,会把该元素下面的所有内容替换掉。

hello world

现实结果是:hello vue

2、v-html

v-html 指令,会用一个HTML标签字符串,替换该元素下面的所有内容。

但是,不建议使用v-html指令,因为它会导致被恶意者进行XSS攻击的潜在风险。

hello vue'">

  hello world

现实结果是:字体颜色为红色的 hello vue

3、v-show

v-show 指令,控制元素的显示隐藏,元素存在并占据空间。

元素隐藏时,相当于给该元素添加了 CSS 样式:display:none;

hello vue
changeShow

4、v-if/v-esle-if/v-else

(1)、v-if

v-if指令,控制元素是否加载。

v-esle-if/v-else指令不能单独使用,必须配合v-if一起使用。

hello vue {{number}}
hello world {{number}}
hello someone {{number}}

(2)、v-if 与 v-show

  • v-if:有更高的切换开销;
  • v-show:有更高的初始化开销。

若需要频繁的切换则使用 v-show 比较好,否则使用 v-if 比较好。

5、v-for

v-for 指令,for循环,基于源数据多次渲染元素或模板块。

v-for 既可以渲染一个数组,也可以渲染一个对象。

(1)、v-for 渲染一个数组



    {{item}}

// 渲染的结果: // 1 // 2 // 3

(2)、 v-for 渲染一个对象



    {{key}}: {{val}}

// 渲染的结果: // one: 1 // two: 2

(3)、v-if 与 v-for

同时使用 v-if 和 v-for 是不推荐的,因为这样二者的优先级不明显。请查看风格指南获得更多信息。

当 v-if 与 v-for 一起使用时:

vue3 官网之 v-for 与 v-if

(4)、v-for 之 key

①、为什么需要给 v-for 设置 key?

这牵扯到 vue 的 vnode 的 Diff 算法的特点,请参见此文。

②、在 v-for 中直接用 index 作为 key 的值有什么不好?

例如:


此时,删除 “Person4” 是正常的,但是如果我删除 “Person2” 就会出现问题。

删除前

id index name
1 0 Person1
2 1 Person2
3 2 Person3
4 3 Person4

删除后

id index name
1 0 Person1
3 1 Person3
4 2 Person4

可见,数组的 index 下标始终是从 0 开始依次递增不间断的,当其中某一项被删除后,被删节点之后的 index 下标会自动全部做减 1 更新。所以,删除了 id 是 2 的节点时,被删节点之后的 index 下标全部做减 1 更新了。所以,当 DOM 内容比较复杂时,建议设置并使用唯一的 id 属性,来作为 key 的值。

(5)、显示过滤/排序后的结果

显示过滤/排序后的结果

6、v-on

v-on指令,可简写为“@”,绑定事件监听器。

number++

(1)、v-on 指令的修饰符

v-on指令有一系列的修饰符:

...
// 滚动事件的默认行为 (即滚动行为) 将会立即触发,而不会等待 `onScroll` 完成。
...
...

(2)、在内联事件处理器中访问事件参数

有时我们需要在内联事件处理器中访问原生 DOM 事件。你可以向该处理器方法传入一个特殊的 $event 变量,或者使用内联箭头函数:



(3)、vue 中的特殊事件

vue 监听页面滚动事件 

export default {
  mounted () {
    window.addEventListener('scroll', this.handleScroll)
  },
  beforeDestroy () {
    window.removeEventListener('scroll', this.handleScroll)
  },
  methods: {
    // 监听页面滚动
    handleScroll (e) {
      // ...
    }
  }
}

7、v-bind

v-bind 指令,可简写为“:”,动态地绑定一个或多个属性,或一个来自父组件的 prop 里的表达式。

在自定义组件时,若要对 prop 进行“双向绑定”,可以用“v-bind 指令与 .sync 修饰符”相结合来实现。

例如:在一个包含 title prop 的自定义组件中,若想让其父组件可以监听那个事件并根据需要更新一个本地的数据 property,可以这样来实现:

注意: 注意带有 .sync 修饰符的 v-bind 不能和表达式一起使用 (例如 v-bind:title.sync=”doc.title + ‘!’” 是无效的)。取而代之的是,你只能提供你想要绑定的 property 名,类似 v-model。

当我们用一个对象同时设置多个 prop 的时候,也可以将这个 .sync 修饰符和 v-bind 配合使用:

这样会把 doc 对象中的每一个 property (如 title) 都作为一个独立的 prop 传进去,然后各自添加用于更新的 v-on 监听器。

注意:将 v-bind.sync 用在一个字面量的对象上,例如 v-bind.sync=”{ title: doc.title }”,是无法正常工作的,因为在解析一个像这样的复杂表达式的时候,有很多边缘情况需要考虑。 

8、v-model

(1)、双向绑定的语法糖

v-model 指令,是双向绑定的语法糖。

双向绑定:当数据变化视图同步更新,当视图更新数据也会同步更新。

双向绑定的原理请戳此链接:vue 的双向绑定原理_青蛙king的博客-CSDN博客_vue数据双向绑定原理一句话概括

v-model 实际上是 value 属性和 input 事件结合的简写形式。它等同于:


(2)、v-model 的修饰符——表单


【拓展】

v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件:

9、v-slot

v-slot 指令,用来定义一个 具名插槽 或 作用域插槽。可以缩写为 #。

插槽:用来分发内容,传递复杂的内容。

具体请戳这里:vue 插槽 slot_青蛙king的博客-CSDN博客

10、v-pre(使用频率很低)

v-pre 指令,跳过这个元素和它的子元素的编译过程。

{{ this will not be compiled }}

11、v-once(使用频率很低)

v-once 指令,只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。

This will never change: {{msg}}

二、自定义指令 与 指令的生命周期

指令的周期: 5个 (bind、inserted、update、componentUpdated、unbind)。

1、注册自定义指令

(1)、注册全局指令——Vue.directive() 方法

(2)、注册局部指令——directives 属性

2、案例

【案例一】

// 注册一个局部的自定义指令v-append-text:不替换原来的内容,直接插入其后。

【案例二】

也可以这样定义一个指令:

import Vue from 'vue'

const ctx = 'clickOutsideContext'
const nodeList = []
const isServer = Vue.prototype.$isServer // 当前 Vue 实例是否运行于服务器
let seed = 0
let startClick

const on = (function () {
  if (!isServer && document.addEventListener) {
    return function (element, event, handler) {
      if (element && event && handler) {
        element.addEventListener(event, handler, false)
      }
    }
  } else {
    return function (element, event, handler) {
      if (element && event && handler) {
        element.attachEvent('on' + event, handler)
      }
    }
  }
})()

function createDocumentHandler (el, binding, vnode) {
  return function (mouseup = {}, mousedown = {}) {
    // node.contains( otherNode ) 如果 otherNode 是 node 的后代节点或是 node 节点本身.则返回true , 否则返回 false.
    if (
      !vnode ||
      !vnode.context ||
      !mouseup.target ||
      !mousedown.target ||
      el.contains(mouseup.target) ||
      el.contains(mousedown.target) ||
      el === mouseup.target || (vnode.context.focusElment &&
        (vnode.context.focusElment.contains(mouseup.target) ||
        vnode.context.focusElment.contains(mousedown.target)))
    ) {
      return
    }
    if (binding.expression &&
      el[ctx].methodName &&
      vnode.context[el[ctx].methodName]) {
      vnode.context[el[ctx].methodName]()
    } else {
      el[ctx].bindingFn && el[ctx].bindingFn()
    }
  }
}

if (!isServer) {
  on(document, 'mousedown', e => (startClick = e))
  on(document, 'mouseup', e => {
    nodeList.forEach(node => node[ctx].documentHandler(e, startClick))
  })
}

export default {
  // 只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置
  bind (el, binding, vnode) {
    nodeList.push(el)
    const id = seed++
    el[ctx] = {
      id,
      documentHandler: createDocumentHandler(el, binding, vnode),
      methodName: binding.expression,
      bindingFn: binding.value
    }
  },
  // 所在组件的 VNode 更新时调用
  update (el, binding, vnode) {
    el[ctx].documentHandler = createDocumentHandler(el, binding, vnode)
    el[ctx].methodName = binding.expression
    el[ctx].bindingFn = binding.value
  },
  // 只调用一次,指令与元素解绑时调用
  unbind (el, binding, vnode) {
    const len = nodeList.length
    for (let i = 0; i < len; i++) {
      if (nodeList[i][ctx].id === el[ctx].id) {
        nodeList.splice(i, 1)
        break
      }
    }
    delete el[ctx]
  }
}

将指令统一导出: 

import clickoutside from './modules/clickoutside'

export { clickoutside }

然后在main.js里注册指令:

Object.keys(directives).forEach(k => Vue.directive(k, directives[k]))

在vue组件中使用自定义指令:


你可能感兴趣的:(#,Vue.js,vue指令,自定义指令,指令的生命周期)