Preface
Vue is simple and easy to use in many places. For example, it has built-in 32+ modifiers, which can easily prevent bubbling, prevent default events, mouse event processing, system keyboard events, etc., so that we can quickly get business done. It's so convenient! ! !
If you delay you for 15 minutes, you can gain:
- The meaning and use of 32+ modifiers (including event modifiers, mouse modifiers, form modifiers, system modifiers, etc.)
- How to use webpack to dynamically register vue routing, no more handwriting routing configuration!
The examples in the article are all on the github source code , or you can click to see the example
How to dynamically register routes?
Each modifier example in the article is carried by a page, so smart you don’t want to manually import dozens of .vue files and configure routing.
Is there any way to help us automatically complete the route registration?
1. File directory structure
The directory structure (other file directories have been removed) is roughly as follows
├── 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. Desired routing configuration
The finalvue-router
looks like this, the most important parts of each configuration arepath
,name
andcomponent
[
{
"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 realizes dynamic registration routing
With webpack require.context , you can easily realize the mapping from the above directory to the routing configuration. The source code is as follows
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
}
effect
After the above simple processing, the dynamic registration of routing is complete! You can also click vue-demos view the effect
Event modifier
1. Two ways to stop bubbling
<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('我是儿子')
}
}
}
When you click hit the child node , it will not only print I am a son, but also
I am a father, because of the bubbling event. Is there any way to prevent the event of the ?
1 .stop
Just add the .stop modifier to prevent the event from bubbling in a simple way, which is very convenient, isn't it?
When the .stop
modifier is added, only will appear. I am a son
<template>
<div class="parent" @click="onClickParent">
我是爸爸
<div class="child" @click.stop="onClickChild">
我是儿子
</div>
</div>
</template>
2. event.stopPropagation
Of course, we can also prevent bubbling event.stopPropagation
However, the practice of modifiers is more recommended, so that your function will focus more on logical processing, without worrying about the details of DOM events
export default {
name: 'stop',
methods: {
onClickChild (event) {
console.log('我是儿子')
event.stopPropagation()
}
}
}
2. Two ways to prevent default events
There are two ways to prevent bubbling in vue. What about preventing default events?
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('阻止默认事件')
}
}
}
Just add .prevent
easily prevent default events
2.event.preventDefault()
Like preventing bubbling, we can also prevent default events preventDefault
export default {
name: 'prevent',
methods: {
onPrevent (event) {
console.log('阻止默认事件')
event.preventDefault()
}
}
}
3 .capture
By default, the event stream is in the form of 161849e41ee8a1 bubbling (from the inside to the outside). What if you want to capture (from the outside to the inside) in the form of
<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('我是子节点')
}
}
}
Without the catpture
modifier, click on the child node will successively print that I am the parent node and I am the child node. After adding it, it will be the other way around
4 .self
The event callback function will only be triggered 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节点')
}
}
}
Without the self
modifier, clicking on the inner
node will also trigger the self
event. After adding it, only the element that triggered the event itself is self
, will print out I am a self node
Pause: How to understand the order of modifiers?
I have reviewed 4 modifiers, they are easy to understand when used alone, but pay attention to the sentence on the official website
How to understand Let's take a look at two chestnuts
<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('我是子节点')
}
}
}
You can guess what will happen to the above code. Are the following three points clear?
- First of all, it is clear that clicking on the child nodes above and below will not trigger the click event of the parent node.
- Clicking on the parent node below will print out I am the parent node , but will not jump to Nuggets
- Click on the parent will print out I am a parent , not jump Nuggets
But click on the child node above, will the parent node jump to the Nuggets? The answer is will
Why?
a@click.self.prevent="onClickParent"
means that when the clicked element is the a element itself, the default event will be blocked (can explain 3, no jump will occur), and the onClickParent
callback will be executed.
When the span element is clicked, due to bubbling, the click event will be passed to a, but at this time a will determine that the event is not triggered by itself, so will not prevent the default event (the jump will also occur at this time) ), of course, it will not trigger the
onClickParent
callback
In the same way, let’s analyze a@click.prevent.self="onClickParent"
Regardless of whether it is a child node or its own click, the default event is blocked first, and the onClickParent
callback function will be executed only when the triggering click event is the a element itself.
Looking back, do you understand the meaning of the sequence of events?
5. once
As the name suggests, the event will only be triggered once
<template>
<div class="once" @click.once="onClickOnce">
只触发一次
</div>
</template>
export default {
name: 'once',
methods: {
onClickOnce () {
console.log('once,我只会触发一次点击事件回调')
}
}
}
After a click is triggered, no matter what I click, the callback will not be triggered.
6 .native
We know that on custom components, we can only listen to custom events. Some native events (such as click) cannot be triggered directly, but using the .native
modifier can help us do this.
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 correspondaddEventListener
inpassive
option provides.passive
modifiers
<!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 -->
<!-- 而不会等待 `onScroll` 完成 -->
<!-- 这其中包含 `event.preventDefault()` 的情况 -->
<div v-on:scroll.passive="onScroll">...</div>
has not found a suitable example for the improvement of scrolling performance, so I beg your friends to have examples
has not found a suitable example for the improvement of scrolling performance, so I beg your friends to have examples
has not found a suitable example for the improvement of scrolling performance, so I beg your friends to have examples
v-bind modifier
8 .sync
When we want to bind a certain property value two-way between the parent component and the child component, what is a convenient way? Yes, as long as .sync
modifier can be done
parent component
<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,
}
}
subcomponent
<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
v-bind
property name to be camelized when using DOM templates, such as theviewBox
property of SVG:
<svg :view-box.camel="viewBox"></svg>
10 .prop
Regarding the official website of the .prop modifier, there is only this sentence .prop
as a DOM property binding instead of an attribute binding. `.
do?
- Store variables through custom attributes to avoid exposing data
- Prevent pollution of HTML structure
For example, the following code
<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
}
}
}
It can be seen from the example that the my-name
.prop
modifier will be bound to the attribute of the dom node, which will be exposed.
Mouse modifier
I want to listen when the user clicks on the left, right or there are modifiers can quickly use, are the key when .left
, .right
, middle
, look at an example to try
According to MDN MouseEvent.button , introduction.
In the outermost div.mouse
listen mousedown
event, look at the user clicks a mouse button which, three button
were listening with three modifiers shortcut left,
button,
right and print out
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])
}
}
}
did not bring the mouse back, the middle-click cannot be demonstrated temporarily, and
11 .left
Same as the above example, monitor left mouse click
12 .right
Same as the above example, monitor the right-click of the mouse
13 .middle
Same as the above example, monitor the middle mouse button click
Form related modifiers
14 .trim
For the input content, I hope that can filter the leading and trailing spaces. What should I do?
<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 modifier can be easily done
15 .lazy
v-model
familiar to everyone. By default, every time theinput event is triggered, the value of the input box will be synchronized with the data bound to it in real time. But what if you want to update the data when the cursor leaves?
Idea 1: binds the change event, and manually obtains the value of the target in the event callback
Idea 2: can be achieved by directly using the .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: ''
}
}
}
It can be seen that after adding the .lazy modifier, the value entered in the second input box will not be reflected below in real time, but the cursor will leave the real state, and text2
will be updated.
16 .number
We knowinput
input boxtype
evennumber
type of the value obtained isstring
, if we want to get directlynumber
types of data, there do not want the trouble of manual conversion should be how to do it?
<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)
},
}
}
- The type of the first input box is number, but the value obtained is string
- The type of the second input box is text, but with the number modifier added, the value obtained can be number (if this value cannot be
parseFloat()
, the original value will be returned.) - The type of the third input box is number, and the final value is also number
System modifier
When the click event or keyboard event needs to be triggered when the system keys are pressed at the same time,.ctrl
,.alt
,.shift
,.meta
can help a lot!
as follows code
- Monitor keydown events globally, try to see if
.ctrl
,.alt
,.shift
,.meta
are pressed .ctrl
,.alt
,.shift
,.meta
modifiers to the four buttons respectively and cooperate with the click event to verify whether the specified keys are pressed at the same time, and then clicks will take effect
Note: Computer ctrl key + click estimate conflicts with the browser shortcut configuration, resulting in not triggering
<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
The listener for mouse or keyboard events is triggered only when the ctrl button is pressed. For a detailed example, please see above
18 .alt
The listener for mouse or keyboard events is triggered only when the alt button is pressed. For a detailed example, please see above
19 .shift
The listener for mouse or keyboard events is triggered only when the shift button is pressed. For a detailed example, please see above
20 .meta
The listener for mouse or keyboard events is triggered only when the meta button is pressed. For a detailed example, please see above
21 .exact
Strictly speaking,.exact
not a system modifier, but there is a phenomenon in the above example. Pressing several system modifier keys (such as alt and shift) at the same time can trigger.alt
or.shift
.
Still use the above example, take a look at the gif below, at this time I press alt and shift at the same time, the corresponding two events can be triggered
- Only want to trigger a click when a certain system modifier key is pressed
- is triggered when no system modifier is pressed. Click
To achieve the above requirements .exact
will come in handy, use the above example to make a slight modification
<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}键,点击事件才会发生`)
}
}
}
Key modifier
When listening to keyboard events, we often need to check detailed keystrokes and then execute the corresponding logic. Vue also has built-in at least 11+ key modifiers for us.
In the following code, we assign the keydown
enter
, tab
, delete
etc. When the specified keyboard is pressed in the specified input box, it will print enter
, tab
, delete
etc. Other keys cannot trigger the event in the input box. 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
The listener for mouse or keyboard events is triggered when the enter button is pressed. For a detailed example, please see the above
23 .tab
The mouse or keyboard event listener is triggered when the tab button is pressed. For a detailed example, please see the above
24 .delete
The mouse or keyboard event listener is triggered when the delete button is pressed. For a detailed example, please see the above
25 .esc
The mouse or keyboard event listener is triggered when the esc button is pressed, please see the above for a detailed example
26 .space
The mouse or keyboard event listener is triggered when the space button is pressed. For a detailed example, please see the above
27 .up
The mouse or keyboard event listener is triggered when the up button is pressed. For a detailed example, please see the above
28 .down
The mouse or keyboard event listener is triggered when the down button is pressed. For a detailed example, please see the above
29 .left
The mouse or keyboard event listener is triggered when the left button is pressed. For a detailed example, please see the above
30 .right
The mouse or keyboard event listener is triggered when the right button is pressed. For a detailed example, please see the above
31 .page-down
The listener for mouse or keyboard events is triggered when the (fn + down) button is pressed. For a detailed example, please see above
32 .page-up
The listener for mouse or keyboard events is triggered when the (fn + up) button is pressed. For a detailed example, please see above
How to customize key modifiers
Vue itself has built-in many practical key modifiers for us, which can meet our daily needs in most cases, so is there a way to customize key modifiers?
Through the following configuration, we can define a key modifier of our own. For example, we define q as a shortcut key to press 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')
}
}
}
do not say goodbye
The above is the content that Fathead Fish has learned and understood about vue modifiers! Everyone is welcome to add and comment. O(∩_∩)O haha~
The examples in the article are all placed on the github source code , or you can click to see the example
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。