【建议收藏】面试官贼喜欢问的|【建议收藏】面试官贼喜欢问的 32+ vue 修饰符,你掌握几种啦()

前言

vue简洁好用体现在很多个地方,比如其内置了32+修饰符,可以很方便我们阻止冒泡、阻止默认事件、鼠标事件处理、系统键盘事件等等,让我们可以快速搞定业务,简直不要太方便噢!!!
耽误您15分钟您可以收获:
  1. 32+修饰符(包括事件修饰符、鼠标修饰符、表单修饰符、系统修饰符等等)的含义和使用
  2. 如何利用webpack动态注册vue路由,再也不手写路由配置啦!
文章中例子都放在了github源码上,也可以点击直接看例子
如何动态注册路由?
文中的每个修饰符例子都由一个页面承载,聪明的你肯定不想手动引入几十个.vue文件并配置路由.
有什么办法可以帮我们自动完成路由注册呢?
1. 文件目录结构
目录结构(已去除其他文件目录)大概如下
├── package.json └── src ├── App.vue ├── main.js ├── router.js └── views ├── About.vue ├── Home.vue └── modifiers ├── capture.vue ├── once.vue ├── order.vue ├── passive.vue ├── prevent.vue ├── self.vue └── stop.vue └── ...

2. 期望的路由配置
最终给到 vue-router的配置大概长下面这个样子,每个配置最重要的部分分别是 pathnamecomponent
[ { "path": "/home", "name": "home", "component": { "name": "Home", "methods": {}, "staticRenderFns": [], "_compiled": true, "_scopeId": "data-v-fae5bece", "beforeCreate": [ null ], "beforeDestroy": [ null ], "__file": "src/views/Home.vue" } }, { "path": "/modifiers/capture", "name": "modifiersCapture", "component": { "name": "capture", "methods": {}, "staticRenderFns": [], "_compiled": true, "_scopeId": "data-v-63b4eeee", "beforeCreate": [ null ], "beforeDestroy": [ null ], "__file": "src/views/modifiers/capture.vue" } }, ... // 其他路由配置 ]

3. require.context实现动态注册路由
借助 webpack require.context 的能力,可以非常方便地实现上面目录到路由配置的映射工作,源码如下
const registerRoutes = () => { const contextInfo = require.context('./views', true, /.vue$/) const routes = contextInfo.keys().map((filePath) => { // filePath 形如 ./Home.vue、./modifiers/capture.vue // path我们希望是/home、/modifiers/capture // 所以需要把开头的./和.vue都替换为空 const path = filePath.toLowerCase().replace(/^\.|\.vue/g, '') // name的话将/home、/modifiers/capture转成小驼峰即可 // 把开头的/先替换掉,再把第一个/后的单词变成大写就可以了 const name = path.replace(/^\//, '').replace(/\/(\w)/, ($0, $1) => $1.toUpperCase()) // 通过require去读取.vue文件内容 const component = require(`./views${filePath.replace(/^\./, '')}`).defaultreturn { path, name, component } })return routes }

效果
经过上面的简单处理,动态注册路由就完成啦!您也可以点击 vue-demos查看效果

事件修饰符 1. 阻止冒泡的两种方式
export default { name: 'stop', methods: { onClickParent () { console.log('我是爸爸') }, onClickChild () { console.log('我是儿子') } } }

点击子节点的时候因为事件冒泡的缘故不仅会打印出我是儿子还会打印我是爸爸。有什么办法可以阻止子节点的事件冒泡呢?
【建议收藏】面试官贼喜欢问的|【建议收藏】面试官贼喜欢问的 32+ vue 修饰符,你掌握几种啦()
文章图片

1 .stop
只要加.stop修饰符即可,阻止事件冒泡的及简方式,很方便是不是。
当添加上.stop修饰符时,只会出现我是儿子

【建议收藏】面试官贼喜欢问的|【建议收藏】面试官贼喜欢问的 32+ vue 修饰符,你掌握几种啦()
文章图片

2. event.stopPropagation
当然了,我们也可以通过调用 event.stopPropagation来阻止冒泡。不过更加推荐修饰符的做法,这样你的函数会更加专注在逻辑处理上,而不用关心DOM事件细节
export default { name: 'stop', methods: { onClickChild (event) { console.log('我是儿子') event.stopPropagation() } } }

【建议收藏】面试官贼喜欢问的|【建议收藏】面试官贼喜欢问的 32+ vue 修饰符,你掌握几种啦()
文章图片

2. 阻止默认事件的两种方式
vue中阻止冒泡有两种方式,那阻止默认事件呢?
1 .prevent
export default { name: 'prevent', methods: { onNoPrevent () { console.log('未阻止默认事件') }, onPrevent () { console.log('阻止默认事件') } } }

只要添加.prevent轻松实现阻止默认事件
【建议收藏】面试官贼喜欢问的|【建议收藏】面试官贼喜欢问的 32+ vue 修饰符,你掌握几种啦()
文章图片

2.event.preventDefault()
和阻止冒泡一样,我们也可以通过调用事件对象的 preventDefault方法来阻止默认事件
export default { name: 'prevent', methods: { onPrevent (event) { console.log('阻止默认事件') event.preventDefault() } } }

3 .capture
默认情况下,事件流是以 冒泡(由里向外)的形式传递的,如果想以 捕获(由外向里)的形式应该怎么办呢?
export default { name: 'capture', methods: { onClickParent () { console.log('我是父节点') }, onClickChild () { console.log('我是子节点') } } }

不加catpture修饰符,点击子节点会陆续打印我是父节点以及我是子节点,加了之后,则是反过来了
【建议收藏】面试官贼喜欢问的|【建议收藏】面试官贼喜欢问的 32+ vue 修饰符,你掌握几种啦()
文章图片

4 .self
只有当 event.target是当前元素自身时才会触发事件回调函数
export default { name: 'self', methods: { onClickSelf () { console.log('我是self节点') }, onClickInner () { console.log('我是inner节点') } } }

不加self修饰符的话,点击inner节点也会触发self的事件,加了之后只有触发事件的元素本身是self,才会打印出我是self节点
【建议收藏】面试官贼喜欢问的|【建议收藏】面试官贼喜欢问的 32+ vue 修饰符,你掌握几种啦()
文章图片

暂停一下:修饰符的顺序如何理解?
已经回顾了4个修饰符,单独使用的时候很容易理解,但是注意官网有这么一句话
【建议收藏】面试官贼喜欢问的|【建议收藏】面试官贼喜欢问的 32+ vue 修饰符,你掌握几种啦()
文章图片

怎么理解呢?我们来看两个栗子
export default { name: 'order', methods: { onClickParent () { console.log('我是父节点') }, onClickChild () { console.log('我是子节点') } } }

【【建议收藏】面试官贼喜欢问的|【建议收藏】面试官贼喜欢问的 32+ vue 修饰符,你掌握几种啦()】您可以猜一下,上面的代码会发生什么,以下三点是可以明确的?
  1. 首先可以明确的是点击上面和下面的子节点都不会触发父节点的点击事件
  2. 点击下面的父节点会打印出我是父节点,但是不会跳转掘金
  3. 点击上面的父节点会打印出我是父节点,也不会跳转掘金
但是点击上面的子节点,父节点会不会跳转至掘金呢?答案是会
为什么?
a@click.self.prevent="onClickParent"的意思是当点击的元素是a元素本身时,会阻止默认事件(可以解释3,不会发生跳转),并且执行onClickParent回调。
而点击span元素时,由于冒泡的缘故,点击事件会传递给a,但是此时a会判断出该事件不是由自身触发的也就不会阻止默认事件(此时也就发生跳转了),当然也不会触发onClickParent回调
同理来我们分析一下a@click.prevent.self="onClickParent"
不管是子节点还是自身点击,都是先阻止默认事件,只有当触发点击事件是a元素本身时才会执行onClickParent回调函数。

回过头看,你理解事件的顺序含义了吗?
【建议收藏】面试官贼喜欢问的|【建议收藏】面试官贼喜欢问的 32+ vue 修饰符,你掌握几种啦()
文章图片

5. once
顾名思义,事件只会触发一次
export default { name: 'once', methods: { onClickOnce () { console.log('once,我只会触发一次点击事件回调') } } }

触发一次点击之后,任我再怎么点,回调怎也不会触发了。
【建议收藏】面试官贼喜欢问的|【建议收藏】面试官贼喜欢问的 32+ vue 修饰符,你掌握几种啦()
文章图片

6 .native
我们知道在自定义组件上,只能监听自定义事件,一些原生事件(比如click)是没有办法直接触发的,但是使用 .native修饰符可以帮我们办到这点
native.vue
export default { name: 'nativeCustom', methods: { onKeydown () { this.$emit('onKeydown') } } }

custom.vue
import NativeCustom from '../../components/native.vue'export default { name: 'native', components: { NativeCustom }, methods: { onKeydown () { console.log('onKeydown') }, onClick () { console.log('onClick') } } }

【建议收藏】面试官贼喜欢问的|【建议收藏】面试官贼喜欢问的 32+ vue 修饰符,你掌握几种啦()
文章图片

7 .passive
vue对应 addEventListener 中的 passive 选项提供了 .passive 修饰符
...

这个修饰符对于滚动性能的提升,一直没找到合适的例子,跪求广大掘友有例子啊
这个修饰符对于滚动性能的提升,一直没找到合适的例子,跪求广大掘友有例子啊
这个修饰符对于滚动性能的提升,一直没找到合适的例子,跪求广大掘友有例子啊
v-bind修饰符 8 .sync
当我们想要在 父组件子组件之间对某个属性值进行双向绑定时,有什么便捷的方式?是的只要 .sync修饰符即可办到
父组件
import Child from './child.vue'export default { name: 'SyncParent', data () { return { text: 'parent' } }, components: { Child, } }

子组件
export default { name: 'child', props: { text: { type: String } }, data () { return { value: this.text } }, methods: { onInput () { // 注意这里,必须是update:xxx的形式xxx即属性prop this.$emit('update:text', this.value) } } }

【建议收藏】面试官贼喜欢问的|【建议收藏】面试官贼喜欢问的 32+ vue 修饰符,你掌握几种啦()
文章图片

9 .camel
.camel 修饰符允许在使用 DOM 模板时将 v-bind property 名称驼峰化,例如 SVG 的 viewBox property:

10 .prop
关于.prop修饰符官网只有这句话 .prop作为一个 DOM property 绑定而不是作为 attribute 绑定。`。
有啥作用?
  1. 通过自定义属性存储变量,避免暴露数据
  2. 防止污染 HTML 结构
比如有以下代码
export default { name: 'prop', data () { return { prop: 'hello prop', prop2: 'hello prop2' } }, methods: { onGetResult () { const $refProp = this.$refs.prop const $refProp2 = this.$refs.prop2console.log($refProp.getAttribute('my-name')) // hello prop console.log($refProp2.getAttribute('my-name')) // null } } }

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

鼠标修饰符
当咱们想监听用户点击了 左键右键或者 中键时也有修饰符可以快捷使用,分别是 .left.rightmiddle,来看个例子试试
根据MDN MouseEvent.button,介绍。
【建议收藏】面试官贼喜欢问的|【建议收藏】面试官贼喜欢问的 32+ vue 修饰符,你掌握几种啦()
文章图片

在最外层div.mouse监听mousedown事件,看下用户点击的是鼠标哪个键,三个button分别用三个修饰符快捷方式监听左键中键右键并打印出leftmiddleright
export default { name: 'mouse', mounted () {}, methods: { onClickBtn (msg) { console.log(msg) }, onMousedown (event) { const mosueMsgMap = { 0: '鼠标左键', 1: '鼠标中键', 2: '鼠标右键' } console.log('点击了', mosueMsgMap[event.button]) } } }

没有带鼠标回来,中键点击暂时不能演示,后续会补上

11 .left
同上例子,监听鼠标左键点击
12 .right
同上例子,监听鼠标右键点击
13 .middle
同上例子,监听鼠标中键点击
表单相关修饰符 14 .trim
对于输入的内容,希望可以 过滤首尾空格应该怎么做呢?
export default { name: 'trim', data () { return { name: '', name2: '', } }, watch: { name (newVal) { console.log(`'----${newVal}----'`) }, name2 (newVal) { console.log(`'----${newVal}----'`) }, } }

.trim修饰符可以很方便做到

15 .lazy
v-model大家都很熟悉,默认情况下,每次 input事件触发的时候都会将输入框的值与其绑定的数据进行实时同步。但是如果想要实现光标离开的时候再更新数据如何实现呢?
思路1: 绑定change事件,在事件回调中手动获取target的值
思路2: 直接使用.lazy修饰符即可达到效果
export default { name: 'lazy', data () { return { text: '', text2: '' } } }

可以看到添加了.lazy修饰符之后,第二个输入框输入的值不会实时反应在下面,而是光标离开实,text2的数据才更新了
【建议收藏】面试官贼喜欢问的|【建议收藏】面试官贼喜欢问的 32+ vue 修饰符,你掌握几种啦()
文章图片

16 .number
我们知道 input输入框的 type哪怕是 number得到的值的类型也是 string,如果我们想直接拿到 number类型的数据,有不想麻烦的手动转换应该怎么办呢?
export default { name: 'lazy', data () { return { number: 0, number1: '', number2: '', } }, watch: { number (newVal) { console.log(typeof newVal, newVal) }, number1 (newVal) { console.log(typeof newVal, newVal) }, number2 (newVal) { console.log(typeof newVal, newVal) }, } }

  1. 第一个输入框的类型是number,但是得到的值是string
  2. 第二个输入框的类型是text,但是添加了number修饰符,得到的值可以是number(如果这个值无法被 parseFloat() 解析,则会返回原始的值。)
  3. 第三个输入框的类型是number,最后得到的值也是number

系统修饰符
当点击事件或者键盘事件需要系统键同时按下才触发时 .ctrl.alt.shift.meta可以帮大忙噢!
如下代码
  1. 全局监听keydown事件,尝试看.ctrl.alt.shift.meta是否被按下
  2. 分别给四个按钮加上 .ctrl.alt.shift.meta修饰符并配合点击事件,验证是否同时按下指定按键,再点击才会生效
注明:电脑ctrl键 + 点击估计和浏览器快捷配置冲突了,导致没触发
export default { name: 'system', data () { return { msg: '' } }, mounted () { this.onListenSystemKeyDown() }, methods: { onListenSystemKeyDown () { document.addEventListener('keydown', (event) => { let msg = '按下了'if (event.ctrlKey) { msg += 'ctrl键' } else if (event.altKey) { msg += 'alt键' } else if (event.shiftKey) { msg += 'shift键' } else if (event.metaKey) { msg += 'meta键' } else { msg += '其他键' }this.msg = msg }, false) }, onClickButon (key) { console.log(`只有同时按下${key}键,点击事件才会发生`) } } }


17 .ctrl
仅在按下ctrl按键时才触发鼠标或键盘事件的监听器,详细例子请看上面
18 .alt
仅在按下alt按键时才触发鼠标或键盘事件的监听器,详细例子请看上面
19 .shift
仅在按下shift按键时才触发鼠标或键盘事件的监听器,详细例子请看上面
20 .meta
仅在按下meta按键时才触发鼠标或键盘事件的监听器,详细例子请看上面
21 .exact
严格来说这 .exact不属于系统修饰符,只是上面例子的写法有一个现象,同时按下几个系统修饰键(例如alt和shift)既可以触发 .alt也可以触发 .shift
还是用上面的例子,看一下下面的gif, 此时我同时按下了alt和shift,对应的两个事件都可以触发
【建议收藏】面试官贼喜欢问的|【建议收藏】面试官贼喜欢问的 32+ vue 修饰符,你掌握几种啦()
文章图片

  1. 只想某个系统修饰键按下时才触发点击
  2. 没有任何系统修饰符被按下的时候才触发点击
要实现上面的需求.exact就派上用场了,用上面的例子稍作改造
export default { name: 'extra', data () { return { msg: '' } }, mounted () { this.onListenSystemKeyDown() }, methods: { onListenSystemKeyDown () { document.addEventListener('keydown', (event) => { let msg = '按下了'if (event.ctrlKey) { msg += 'ctrl键' } else if (event.altKey) { msg += 'alt键' } else if (event.shiftKey) { msg += 'shift键' } else if (event.metaKey) { msg += 'meta键' } else { msg += '其他键' }this.msg = msg }, false) }, onClickButon (key) { console.log(`只有同时按下${key}键,点击事件才会发生`) } } }


按键修饰符
在监听键盘事件时,我们经常需要检查详细的按键再执行对应的逻辑,vue也为我们内置了至少11+的按键修饰符。
如下代码,我们分别给entertabdelete等按键指定了keydown事件,当在指定的输入框中按下指定的键盘,会打印出entertabdelete等,其他按键在输入框中无法触发该console
export default { name: 'keyModifiers', methods: { onKeydown (keyName) { console.log(keyName) } } }


22 .enter
在按下enter按键时才触发鼠标或键盘事件的监听器,详细例子请看上面
23 .tab
在按下tab按键时才触发鼠标或键盘事件的监听器,详细例子请看上面
24 .delete
在按下delete按键时才触发鼠标或键盘事件的监听器,详细例子请看上面
25 .esc
在按下esc按键时才触发鼠标或键盘事件的监听器,详细例子请看上面
26 .space
在按下space按键时才触发鼠标或键盘事件的监听器,详细例子请看上面
27 .up
在按下up按键时才触发鼠标或键盘事件的监听器,详细例子请看上面
28 .down
在按下down按键时才触发鼠标或键盘事件的监听器,详细例子请看上面
29 .left
在按下left按键时才触发鼠标或键盘事件的监听器,详细例子请看上面
30 .right
在按下right按键时才触发鼠标或键盘事件的监听器,详细例子请看上面
31 .page-down
在按下(fn + down)按键时才触发鼠标或键盘事件的监听器,详细例子请看上面
32 .page-up
在按下(fn + up)按键时才触发鼠标或键盘事件的监听器,详细例子请看上面
如何自定义按键修饰符
vue本身给我们内置了很多实用的按键修饰符,大部分情况下可以满足我们的日常需求了,那么有没有办法可以自定义按键修饰符呢?
通过以下配置即可定义一个属于我们自己的按键修饰符, 比如我们定义q为按下q的快捷键。
Vue.config.keyCodes = { q: 81 }export default { name: 'custom', methods: { f1Keydown () { console.log('按下了q') } } }

【建议收藏】面试官贼喜欢问的|【建议收藏】面试官贼喜欢问的 32+ vue 修饰符,你掌握几种啦()
文章图片

不说再见
以上就是胖头鱼对vue修饰符学习和了解的内容啦!欢迎大家补充和评论交流。O(∩_∩)O哈哈~
文章中例子都放在了github源码上,也可以点击直接看例子

    推荐阅读