Vue 常用修饰符

209 阅读5分钟

Vue 中,修饰符处理了许多 DOM 事件的细节,让我们不再需要花大量的时间去处理这些烦恼的事情,而能有更多的精力专注于程序的逻辑处理。

vue 中修饰符分为以下五种:

  • 表单修饰符
  • 事件修饰符
  • 鼠标按键修饰符
  • 键值修饰符
  • v-bind修饰符

1、表单修饰符

在我们填写表单的时候用得最多的是input标签,指令用得最多的是v-model

关于表单的修饰符有如下:

  • lazy
  • trim
  • number

1.1、lazy

顾名思义,lazy 修饰符作用是,改变输入框的值时绑定的lazyValue不会改变,当光标离开输入框时,v-model 绑定的值lazyValue才会改变。

<input type="text" v-model.lazy="value">
<p>{{value}}</p>

1.2、trim

trim 修饰符的作用是把v-model绑定的值的首尾空格给去掉。在实际开发中我们一般用于搜索框的内容修饰,过滤掉用户多输入前后空格导致内容查不出来的情况。

<input type="text" v-model.trim="value">

1.3、number

number修饰符的作用是将值转成数字,但是先输入字符串和先输入数字,是两种情况。先输入数字的话,只取前面数字部分。先输入字母的话,number修饰符无效

<input v-model.number="age" type="number">

2、事件修饰符

事件修饰符是对事件捕获以及目标进行了处理,有如下修饰符:

  • stop
  • prevent
  • self
  • once
  • capture
  • passive
  • native

2.1、stop

阻止了事件冒泡,相当于调用了 event.stopPropagation 方法,单击事件将停止传递。

<template>
  <div @click="shout(2)">
    <button @click.stop="shout(1)">ok</button> 
  </div> 
</template>

<script>
export default {
  methods: {       
    shout(num) {        
      console.log(num); //只输出1
    },
  },
};
</script>

2.2、prevent

阻止了事件的默认行为,相当于调用了 event.preventDefault 方法(例如表单的提交、a标签的跳转就是默认事件)。

<form @submit.prevent="onSubmit"></form>

2.3、self

仅当 event.target 是元素本身时才会触发事件处理器,例如:事件处理器不来自子元素。

<div @click.self="shout(2)" >
  <button @click="shout(1)">按钮</button>
</div>

<!-- 不加 self 点击按钮输出 1 2 -->
<!-- 加了 self 点击按钮输出 1 点击div才会输出 2 -->

上面例子中,一个 div 里面有个按钮,div 和按钮都有事件,我们点击按钮,div 绑定的方法也会触发。如果 divclick 加上 self,只有点击到 div 的时候才会触发,算是变相的阻止冒泡了。

使用修饰符时需要注意调用顺序,因为相关代码是以相同的顺序生成的。因此使用 @click.prevent.self 会阻止元素及其子元素的所有点击事件的默认行为而 @click.self.prevent 则只会阻止对元素本身的点击事件的默认行为

2.4、once

绑定了事件以后只能触发一次,第二次就不会触发。

<button @click.once="shout(1)">ok</button>

2.5、capture

事件默认是由里往外冒泡capture修饰符的作用是反过来,由外向里捕获,例如:指向内部元素的事件,在被内部元素处理前,先被外部处理,使事件触发从包含这个元素的顶层开始往下触发。

<div @click.capture="shout(2)">
  <button @click.capture="shout(1)">按钮</button>
</div>

<!-- 不加 capture 点击按钮输出 1 2 -->
<!-- 加了 capture 点击按钮输出 2 1 -->

2.6、passive

当我们在监听元素滚动事件的时候,会一直触发 onscroll 事件,在 pc端 是没啥问题的,但是在移动端,会让我们的网页变卡,因此我们使用这个修饰符的时候,相当于给 onscroll 事件整了一个 .lazy 修饰符。

滚动事件的默认行为 (scrolling) 将立即发生而非等待 onScroll 完成,以防其中包含 event.preventDefault()

<!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 -->
<!-- 而不会等待 `onScroll` 完成  -->
<!-- 这其中包含 `event.preventDefault()` 的情况 -->
<div @scroll.passive="onScroll">...</div>

.passive 修饰符一般用于触摸事件的监听器,可以用来改善移动端设备的滚屏性能

请勿同时使用 .passive 和 .prevent,因为 .passive 已经向浏览器表明了你不想阻止事件的默认行为。如果你这么做了,则 .prevent 会被忽略,并且浏览器会抛出警告。

2.7、native

native 修饰符是加在自定义组件的事件上,保证事件能执行。

<!-- 子组件要是没有emit click事件 就执行不了 -->
<Child @click="clickEvent(1)"></Child>

<!-- 可以执行 -->  
<Child @click.native="clickEvent(1)"></Child>

使用 .native 修饰符来操作普通 HTML 标签是会令事件失效的。

3、鼠标按钮修饰符

鼠标按钮修饰符针对的就是左键、右键、中键点击,有如下:

  • left 监听鼠标左键点击
  • right 监听鼠标右键点击
  • middle 监听鼠标中键点击
<button @click.left="shout(1)" @click.right="shout(2)" @click.middle="shout(3)">鼠标各键触发</button>

4、键盘修饰符

键盘修饰符是用来修饰键盘事件(onkeyuponkeydown)的,有如下:

keyCode 存在很多,但 vue 为我们提供了别名,分为以下两种:

  • 普通键(entertabdeletespaceescupdownleftright...)
  • 系统修饰键(ctrlaltmetashift...)
<!-- 当我们这么写事件的时候,无论按什么按钮都会触发事件 -->
<input type="text" @keyup="shout(4)">

<!-- 只有按键为keyCode的时候才触发 -->
<input type="text" @keyup.keyCode="shout()">

也可以通过键码去触发,具体键码:

image.png

可以通过全局 config.keyCodes 对象自定义按键修饰符别名:

// 可以使用 `v-on:keyup.f1` 
Vue.config.keyCodes.f1 = 112

举例🌰:

<!-- 按 ctrl 才会触发 -->
<input type="text" @keyup.ctrl="shout(4)">

<!-- 也可以鼠标事件+按键 -->
<input type="text" @mousedown.ctrl.="shout(4)">

<!-- 可以多按键触发 例如 ctrl + 67 -->
<input type="text" @keyup.ctrl.67="shout(4)">

5、v-bind修饰符

v-bind修饰符主要是为属性进行操作,用来分别有如下:

  • sync
  • prop
  • camel

5.1、sync

当我们想要在父组件子组件之间对某个属性值进行双向绑定时,用 .sync 修饰符即可办到。

一般情况下,当父组件传值进子组件,子组件想要改变这个值时,可以这么做:

<!-- 父组件里 -->
<Child :childValue="trimValue" @changeChildValue="value=> trimValue = value"></Child>

<!-- 子组件里 -->
this.$emit('changeChildValue', newValue);

这种情况比较常见但写法比较复杂,于是我们引出 .sync。相当于多了一个事件监听,事件名是 update:属性名,回调函数中,会把接收到的值赋值给属性绑定的数据项中。

<!-- 父组件里 -->
<Child :childValue.sync="trimValue"></Child>
<!-- 以上这种方法相当于以下的简写 -->
<Child :childValue="trimValue" @update:childValue="value=> trimValue = value"></Child>

<!-- 子组件里 -->
this.$emit('update:childValue', newValue);

这里面的传值与接收与正常的父向子传值没有区别,唯一的区别在于往回传值的时候 $emit 所调用的事件名必须是 update:属性名,事件名写错不会报错,但是也不会有任何的改变,这点需要多注意。

使用 sync 需要注意以下两点:

  • 使用 sync 的时候,子组件传递的事件名格式必须为 update:value,其中 value 必须与子组件中 props 中声明的名称完全一致。
  • 注意带有 .sync 修饰符的 v-bind 不能和表达式一起使用。
  • 将 v-bind.sync 用在一个字面量的对象上,例如 v-bind.sync="{ title: doc.title }",是无法正常工作的。

.syncv-model 的区别

  • 相同点:都是语法糖,都可以实现父子组件中的数据的双向通信。

  • 不同点:格式不同:v-model="num":num.sync="num"

  • v-model@input + value

  • :num.sync@update:num

另外需要特别注意的是:v-model 只能用一次,.sync 可以有多个。

5.2、prop

设置自定义标签属性,避免暴露数据,防止污染HTML结构。

<template>
  <div class="prop">
    <div class="prop-item" :my-name="prop"></div>
    <!-- 最终变成了 -->
    <!-- <div my-name="hello prop" class="prop-item"></div> -->
    
    <div class="prop-item" :my-name.prop="prop2"></div>
    <!-- 最终变成了 -->
    <!-- <div class="prop-item"></div> -->
    
    <button @click="onGetResult">获取结果</button>
  </div>
</template>

<script>
export default {
  name: 'prop',
  data () {
    return {
      prop: 'hello prop',
      prop2: 'hello prop2'
    }
  },
  methods: {
    onGetResult () {
      const $refProp = this.$refs.prop;
      const $refProp2 = this.$refs.prop2;

      console.log($refProp.getAttribute('my-name')); // hello prop
      console.log($refProp2.getAttribute('my-name')); // null
    }
  }
}
</script>

image.png

从示例上可以看出未使用 .prop 修饰符的 my-name 属性会绑定到 dom 节点的 attribute,从而出现暴露的情况。

5.3、camel

由于 HTML 特性是不区分大小写的,.camel 修饰符允许在使用 DOM 模板时将 v-bind 属性名称驼峰化,例如 SVG 的 viewBox 属性,实际会被渲染为:

<!-- 不加camel,viewBox会被识别成viewbox --> 
<svg :viewBox="viewBox"></svg>

这将导致渲染失败,因为 SVG 标签只认 viewBox,却不知道 viewbox 是什么。

<!-- 加了canmel,viewBox才会被识别成viewBox --> 
<svg :viewBox.camel="viewBox"></svg>

6、应用场景

根据每一个修饰符的功能,我们可以得到以下修饰符的应用场景:

  • .stop:阻止事件冒泡
  • .native:绑定原生事件
  • .once:事件只执行一次
  • .self :将事件绑定在自身身上,相当于阻止事件冒泡
  • .prevent:阻止默认事件
  • .capture:用于事件捕获
  • .keyCode:监听特定键盘按下
  • .right:右键