前言
vue简洁好用体现在很多个中央,比方其内置了32+修饰符,能够很不便咱们阻止冒泡、阻止默认事件、鼠标事件处理、零碎键盘事件等等,让咱们能够疾速搞定业务,几乎不要太不便噢!!!
耽搁您15分钟您能够播种:
- 32+修饰符(包含事件修饰符、鼠标修饰符、表单修饰符、零碎修饰符等等)的含意和应用
- 如何利用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
的配置大略长上面这个样子,每个配置最重要的局部别离是path
、name
和component
[ { "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(/^\./, '')}`).default return { path, name, component } }) return routes}
成果
通过下面的简略解决,动静注册路由就实现啦!您也能够点击vue-demos查看成果
事件修饰符
1. 阻止冒泡的两种形式
<template> <div class="parent" @click="onClickParent"> 我是爸爸 <div class="child" @click="onClickChild"> 我是儿子 </div> </div> </template>export default { name: 'stop', methods: { onClickParent () { console.log('我是爸爸') }, onClickChild () { console.log('我是儿子') } }}
点击子节点的时候因为事件冒泡的缘故不仅会打印出我是儿子
还会打印我是爸爸
。有什么方法能够阻止子节点的事件冒泡呢?
1 .stop
只有加.stop修饰符即可,阻止事件冒泡的及简形式,很不便是不是。
当增加上.stop
修饰符时,只会呈现我是儿子
<template> <div class="parent" @click="onClickParent"> 我是爸爸 <div class="child" @click.stop="onClickChild"> 我是儿子 </div> </div> </template>
2. event.stopPropagation
当然了,咱们也能够通过调用event.stopPropagation
来阻止冒泡。不过更加举荐修饰符的做法,这样你的函数会更加专一在逻辑解决上,而不必关怀DOM事件细节
export default { name: 'stop', methods: { onClickChild (event) { console.log('我是儿子') event.stopPropagation() } }}
2. 阻止默认事件的两种形式
vue中阻止冒泡有两种形式,那阻止默认事件呢?
1 .prevent
<template> <div class="prevent"> <a href="https://juejin.cn/" @click="onNoPrevent">点击跳转掘金</a> <br /> <br /> <a href="https://juejin.cn/" @click.prevent="onPrevent">阻止默认事件,无奈跳转掘金</a> </div></template>export default { name: 'prevent', methods: { onNoPrevent () { console.log('未阻止默认事件') }, onPrevent () { console.log('阻止默认事件') } }}
只有增加.prevent
轻松实现阻止默认事件
2.event.preventDefault()
和阻止冒泡一样,咱们也能够通过调用事件对象的preventDefault
办法来阻止默认事件
export default { name: 'prevent', methods: { onPrevent (event) { console.log('阻止默认事件') event.preventDefault() } }}
3 .capture
默认状况下,事件流是以冒泡
(由里向外)的模式传递的,如果想以捕捉(由内向里)
的模式应该怎么办呢?
<template> <div class="capture parent" @click.capture="onClickParent"> 父节点 <div class="child" @click.capture="onClickChild">自节点</div> </div></template>export default { name: 'capture', methods: { onClickParent () { console.log('我是父节点') }, onClickChild () { console.log('我是子节点') } }}
不加catpture
修饰符,点击子节点会陆续打印我是父节点以及我是子节点,加了之后,则是反过来了
4 .self
只有当event.target
是以后元素本身时才会触发事件回调函数
<template> <div class="self" @click.self="onClickSelf"> <div class="inner" @click="onClickInner"></div> </div></template>export default { name: 'self', methods: { onClickSelf () { console.log('我是self节点') }, onClickInner () { console.log('我是inner节点') } }}
不加self
修饰符的话,点击inner
节点也会触发self
的事件,加了之后只有触发事件的元素自身是self
,才会打印出我是self节点
暂停一下:修饰符的程序如何了解?
曾经回顾了4个修饰符,独自应用的时候很容易了解,然而留神官网有这么一句话
怎么了解呢?咱们来看两个栗子
<template> <div class="order"> <div class="order-0"> <a href="https://juejin.cn/" class="order-parent" @click.self.prevent="onClickParent"> 我是父节点,会跳转掘金 <br /> <span class="order-child" @click="onClickChild"> 我是子节点 </span> </a> <hr /> </div> <div class="order-2"> <a href="https://juejin.cn/" class="order-parent" @click.prevent.self="onClickParent"> 我是父节点,无奈跳转掘金 <br /> <span class="order-child" @click="onClickChild"> 我是子节点 </span> </a> </div> </div> </template>export default { name: 'order', methods: { onClickParent () { console.log('我是父节点') }, onClickChild () { console.log('我是子节点') } }}
您能够猜一下,下面的代码会产生什么,以下三点是能够明确的?
- 首先能够明确的是点击下面和上面的子节点都不会触发父节点的点击事件
- 点击上面的父节点会打印出我是父节点,然而不会跳转掘金
- 点击下面的父节点会打印出我是父节点,也不会跳转掘金
然而点击下面的子节点,父节点会不会跳转至掘金呢?答案是会
为什么?
a@click.self.prevent="onClickParent"
的意思是当点击的元素是a元素自身时,会阻止默认事件(能够解释3,不会产生跳转),并且执行onClickParent
回调。
而点击span元素时,因为冒泡的缘故,点击事件会传递给a,然而此时a会判断出该事件不是由本身触发的也就不会阻止默认事件
(此时也就产生跳转了),当然也不会触发onClickParent
回调
同理来咱们剖析一下a@click.prevent.self="onClickParent"
不论是子节点还是本身点击,都是先阻止默认事件,只有当触发点击事件是a元素自身时才会执行onClickParent
回调函数。
回过头看,你了解事件的程序含意了吗?
5. once
顾名思义,事件只会触发一次
<template> <div class="once" @click.once="onClickOnce"> 只触发一次 </div></template>export default { name: 'once', methods: { onClickOnce () { console.log('once,我只会触发一次点击事件回调') } }}
触发一次点击之后,任我再怎么点,回调怎也不会触发了。
6 .native
咱们晓得在自定义组件上,只能监听自定义事件,一些原生事件(比方click)是没有方法间接触发的,然而应用.native
修饰符能够帮咱们办到这点
native.vue
<template> <div class="native-custom"> <input type="text" @keydown="onKeydown"> </div></template>export default { name: 'nativeCustom', methods: { onKeydown () { this.$emit('onKeydown') } }}
custom.vue
<template> <div class="native"> <!-- 加上.native之后原生事件才得以监听胜利 --> <NativeCustom @onKeydown="onKeydown" @click.native="onClick" /> </div></template>import NativeCustom from '../../components/native.vue'export default { name: 'native', components: { NativeCustom }, methods: { onKeydown () { console.log('onKeydown') }, onClick () { console.log('onClick') } }}
7 .passive
vue对应addEventListener
中的passive
选项提供了.passive
修饰符
<!-- 滚动事件的默认行为 (即滚动行为) 将会立刻触发 --> <!-- 而不会期待 `onScroll` 实现 --> <!-- 这其中蕴含 `event.preventDefault()` 的状况 --> <div v-on:scroll.passive="onScroll">...</div>
这个修饰符对于滚动性能的晋升,始终没找到适合的例子,跪求宽广掘友有例子啊
这个修饰符对于滚动性能的晋升,始终没找到适合的例子,跪求宽广掘友有例子啊
这个修饰符对于滚动性能的晋升,始终没找到适合的例子,跪求宽广掘友有例子啊
v-bind修饰符
8 .sync
当咱们想要在父组件
和子组件
之间对某个属性值进行双向绑定时,有什么便捷的形式?是的只有.sync
修饰符即可办到
父组件
<template> <div class="sync-parent"> 我是父组件: {{ text }} <Child :text.sync="text" /> </div></template>import Child from './child.vue'export default { name: 'SyncParent', data () { return { text: 'parent' } }, components: { Child, }}
子组件
<template> <div class="child"> 我是子组件: <input type="text" v-model="value" @input="onInput"> </div></template>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) } }}
9 .camel
.camel
修饰符容许在应用 DOM 模板时将v-bind
property 名称驼峰化,例如 SVG 的viewBox
property:
<svg :view-box.camel="viewBox"></svg>
10 .prop
对于.prop修饰符官网只有这句话 .prop
作为一个 DOM property 绑定而不是作为 attribute 绑定。`。
有啥作用?
- 通过自定义属性存储变量,防止裸露数据
- 避免净化 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>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 } }}
从示例上能够看出未应用.prop
修饰符的my-name
属性会绑定到dom节点的attribute,从而呈现裸露的状况。
鼠标修饰符
当咱们想监听用户点击了左键
、右键
或者中键
时也有修饰符能够快捷应用,别离是.left
、.right
、middle
,来看个例子试试
依据MDN MouseEvent.button,介绍。
在最外层div.mouse
监听mousedown
事件,看下用户点击的是鼠标哪个键,三个button
别离用三个修饰符快捷方式监听左键
、中键
、右键
并打印出left
、middle
、right
<template> <div class="mouse" @mousedown="onMousedown"> <button @click.left="onClickBtn('left')">left</button> <button @click.middle="onClickBtn('middle')">middle</button> <button @click.right="onClickBtn('right')">right</button> </div></template>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
对于输出的内容,心愿能够过滤首尾空格
应该怎么做呢?
<template> <div class="trim"> <div class="trim-item"> <input type="text" v-model="name"> <p>用户名:<span>{{ name }}</span></p> </div> <div class="trim-item"> <input type="text" v-model.trim="name2"> <p>用户名2:<span>{{ name2 }}</span></p> </div> </div></template>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
修饰符即可达到成果
<template> <div class="lazy"> <div class="lazy-item"> <input type="text" v-model="text"> <p>无.lazy: {{ text }}</p> </div> <div class="lazy-item"> <input type="text" v-model.lazy="text2"> <p>.lazy: {{ text2 }}</p> </div> </div></template>export default { name: 'lazy', data () { return { text: '', text2: '' } }}
能够看到增加了.lazy修饰符之后,第二个输入框输出的值不会实时反馈在上面,而是光标来到实,text2
的数据才更新了
16 .number
咱们晓得input
输入框的type
哪怕是number
失去的值的类型也是string
,如果咱们想间接拿到number
类型的数据,有不想麻烦的手动转换应该怎么办呢?
<template> <div class="number"> <div class="number-item"> <p>无.number </p> <input type="number" v-model="number"> </div> <div class="number-item"> <p>type:text .number </p> <input type="text" v-model.number="number1"> </div> <div class="number-item"> <p>type:number .number </p> <input type="number" v-model.number="number2"> </div> </div></template>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) }, }}
- 第一个输入框的类型是number,然而失去的值是string
- 第二个输入框的类型是text,然而增加了number修饰符,失去的值能够是number(如果这个值无奈被
parseFloat()
解析,则会返回原始的值。) - 第三个输入框的类型是number,最初失去的值也是number
零碎修饰符
当点击事件或者键盘事件须要零碎键同时按下才触发时.ctrl
、.alt
、.shift
、.meta
能够帮大忙噢!
如下代码
- 全局监听keydown事件,尝试看
.ctrl
、.alt
、.shift
、.meta
是否被按下 - 别离给四个按钮加上
.ctrl
、.alt
、.shift
、.meta
修饰符并配合点击事件,验证是否同时按下指定按键,再点击才会失效
注明:电脑ctrl键 + 点击预计和浏览器快捷配置抵触了,导致没触发
<template> <div class="system"> <p>{{ msg }}</p> <div class="buttons"> <button @click.ctrl="onClickButon('ctrl')">ctrl</button> <button @click.alt="onClickButon('alt')">alt</button> <button @click.shift="onClickButon('shift')">shift</button> <button @click.meta="onClickButon('meta')">meta</button> </div> </div> </template>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,对应的两个事件都能够触发
- 只想某个零碎润饰键按下时才触发点击
- 没有任何零碎修饰符被按下的时候才触发点击
要实现下面的需要.exact
就派上用场了,用下面的例子稍作革新
<template> <div class="extra"> <p>{{ msg }}</p> <div class="buttons"> <button @click.ctrl.exact="onClickButon('ctrl')">ctrl</button> <button @click.alt.exact="onClickButon('alt')">alt</button> <button @click.shift.exact="onClickButon('shift')">shift</button> <button @click.meta.exact="onClickButon('meta')">meta</button> <button @click.exact="onClickButon('非零碎键')">非零碎键</button> </div> </div> </template>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+的按键修饰符。
如下代码,咱们别离给enter
、tab
、delete
等按键指定了keydown
事件,当在指定的输入框中按下指定的键盘,会打印出enter
、tab
、delete
等,其余按键在输入框中无奈触发该console
<template> <div class="key-modifiers"> <div class="key-modifiers-item"> enter: <input type="text" @keydown.enter="onKeydown('enter')"> </div> <div class="key-modifiers-item"> tab: <input type="text" @keydown.tab="onKeydown('tab')"> </div> <div class="key-modifiers-item"> delete: <input type="text" @keydown.delete="onKeydown('delete')"> </div> <div class="key-modifiers-item"> esc: <input type="text" @keydown.esc="onKeydown('esc')"> </div> <div class="key-modifiers-item"> space: <input type="text" @keydown.space="onKeydown('space')"> </div> <div class="key-modifiers-item"> up: <input type="text" @keydown.up="onKeydown('up')"> </div> <div class="key-modifiers-item"> down: <input type="text" @keydown.down="onKeydown('down')"> </div> <div class="key-modifiers-item"> left: <input type="text" @keydown.left="onKeydown('left')"> </div> <div class="key-modifiers-item"> right: <input type="text" @keydown.right="onKeydown('right')"> </div> <div class="key-modifiers-item"> page-down: <input type="text" @keydown.page-down="onKeydown('page-down')"> </div> <div class="key-modifiers-item"> page-up: <input type="text" @keydown.page-up="onKeydown('page-up')"> </div> </div></template>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}<div class="custom"> <input type="text" @keydown.q="f1Keydown"></div>export default { name: 'custom', methods: { f1Keydown () { console.log('按下了q') } }}
不说再见
以上就是胖头鱼对vue修饰符学习和理解的内容啦!欢送大家补充和评论交换。O(∩_∩)O哈哈~
文章中例子都放在了github源码上,也能够点击间接看例子