Vue基础知识

本文最后更新于:2021年11月10日 凌晨

Vue基础知识

安装

Vue实例

1
2
3
4
5
6
<script>
// 一个 Vue 应用由一个通过 new Vue 创建的根 Vue 实例;
var vm = new Vue({
// 选项
})
</script>

模板语法

v-cloak

1
2
3
<div v-cloak>
{{ message }}
</div>

当加载加载vue资源过慢,当么界面会出现的模板,v-cloak可以等待编译完成在显示,就不会直接闪烁出现;

v-text

1
2
3
<span v-text="msg"></span>
<!-- 和下面的一样 -->
<span>{{msg}}</span>

加上v-test就不会出现没加v-cloak的闪烁问题,效果与插值表达式基本一致;但是v-test会覆盖掉标签内部的内容;

v-html

1
2
<!-- html是一个变量 -->
<div v-html="html"></div>

内容按普通 HTML 插入 - 不会作为 Vue 模板进行编译;既然都使用html引入了,尤大建议考虑提成组件;

在单文件组件里,scoped 的样式不会应用在 v-html 内部,因为那部分 HTML 没有被 Vue 的模板编译器处理;可以定义全局样式设置或者行内样式;

v-bind

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<img v-bind:src="imageSrc">

<!-- 缩写 -->
<img :src="imageSrc">

<!-- 动态 attribute 名 (v2.6.0+) -->
<button v-bind:[key]="value"></button>

<!-- class 绑定 -->
<div :class="{ red: isRed }"></div>
<div :class="[classA, classB]"></div>
<div :class="[classA, { classB: isB, classC: isC }]"></div>

<!-- style 绑定 -->
<div :style="{ fontSize: size + 'px' }"></div>
<div :style="[styleObjectA, styleObjectB]"></div>

<!-- 绑定一个全是 attribute 的对象 -->
<div v-bind="{ id: someProp, 'other-attr': otherProp }"></div>

<!-- 通过 prop 修饰符绑定 DOM attribute -->
<div v-bind:text-content.prop="text"></div>

<!-- prop 绑定。“prop”必须在 my-component 中声明。-->
<my-component :prop="someThing"></my-component>

<!-- 通过 $props 将父组件的 props 一起传给子组件 -->
<child-component v-bind="$props"></child-component>

<!-- XLink -->
<svg><a :xlink:special="foo"></a></svg>

动态地绑定一个或多个 attribute,或一个组件 prop 到表达式。

v-bind绑定class
1
<div v-bind:class="{ active: isActive }"></div>

这里绑定了class, class-active的存在取决于isActive;

1
<div v-bind:class="[activeClass, errorClass]"></div>

或者是数组,其中activeClass, errorClass 都是变量;

v-bind绑定style
1
2
3
4
5
6
7
8
9
10
11
12
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>

<!-- 或者直接写成一个对象 -->
<div v-bind:style="styleObject"></div>
<!--
data: {
styleObject: {
color: 'red',
fontSize: '13px'
}
}
-->

v-on

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<!-- 方法处理器 -->
<button v-on:click="doThis"></button>

<!-- 动态事件 (2.6.0+) -->
<button v-on:[event]="doThis"></button>

<!-- 内联语句 -->
<button v-on:click="doThat('hello', $event)"></button>

<!-- 缩写 -->
<button @click="doThis"></button>

<!-- 动态事件缩写 (2.6.0+) -->
<button @[event]="doThis"></button>

<!-- 停止冒泡 -->
<button @click.stop="doThis"></button>

<!-- 阻止默认行为 -->
<button @click.prevent="doThis"></button>

<!-- 阻止默认行为,没有表达式 -->
<form @submit.prevent></form>

<!-- 串联修饰符 -->
<button @click.stop.prevent="doThis"></button>

<!-- 键修饰符,键别名 -->
<input @keyup.enter="onEnter">

<!-- 键修饰符,键代码 -->
<input @keyup.13="onEnter">

<!-- 点击回调只会触发一次 -->
<button v-on:click.once="doThis"></button>

<!-- 对象语法 (2.4.0+) -->
<button v-on="{ mousedown: doThis, mouseup: doThat }"></button>

<!-- 除此之外还有 -->
<!--
.stop - 调用 event.stopPropagation()。
.prevent - 调用 event.preventDefault()。
.capture - 添加事件侦听器时使用 capture 模式。
.self - 只当事件是从侦听器绑定的元素本身触发时才触发回调。
.{keyCode | keyAlias} - 只当事件是从特定键触发时才触发回调。
.native - 监听组件根元素的原生事件。
.once - 只触发一次回调。
.left - (2.2.0) 只当点击鼠标左键时触发。
.right - (2.2.0) 只当点击鼠标右键时触发。
.middle - (2.2.0) 只当点击鼠标中键时触发。
.passive - (2.3.0) 以 { passive: true } 模式添加侦听器
-->

绑定事件监听器。事件类型由参数指定。表达式可以是一个方法的名字或一个内联语句,如果没有修饰符也可以省略。

用在普通元素上时,只能监听原生 DOM 事件。用在自定义元素组件上时,也可以监听子组件触发的自定义事件

按键修饰符

在监听键盘事件时,我们经常需要检查详细的按键。Vue 允许为 v-on 在监听键盘事件时添加按键修饰符:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- 只有在 `key``Enter` 时调用 `vm.submit()` -->
<input v-on:keyup.enter="submit">

<!--
.enter
.tab
.delete (捕获“删除”和“退格”键)
.esc
.space
.up
.down
.left
.right
.ctrl
.alt
.shift
.meta --- 这个键对应的是mac上面的command,win上是win键
-->

除了这些如果需要使用其他按钮可使用自定义按键修饰符别名:

1
2
3
4
5
<input type="text" @keyup.f1="doSomething"/>
<script>
// 可以使用 `v-on:keyup.f1`
Vue.config.keyCodes.f1 = 112
</script>

v-model

1
2
<input v-model="message" placeholder="edit me">
<p>Message is: {{ message }}</p>

v-bind是单向绑定,v-model是数据的双向绑定;

v-for

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!-- items = [{text: 1, id: 0}, {text: 2, id:1}, {text: 3, id: 3}] -->
<div v-for="item in items">
{{ item.text }}
</div>

<!-- 数组只有item和下标,遍历对象中包含key-value-index三个值 -->
<div v-for="(item, index) in items"></div>
<div v-for="(val, key) in object"></div>
<div v-for="(val, name, index) in object"></div>
<!--
为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,
你需要为每项提供一个唯一 `key` attribute,
`v-for` 的默认行为会尝试原地修改元素而不是移动它们;
要强制其重新排序元素,你需要用特殊 attribute key 来提供一个排序提示;
重复的 key 会造成渲染错误。
-->
<div v-for="item in items" v-bind:key="item.id">
<!-- 内容 -->
</div>

基于源数据多次渲染元素或模板块。此指令之值,必须使用特定语法 alias in expression,为当前遍历的元素提供别名;

除了数组和对象,从2.6开始,支持原生的Map和Set;

v-if 和v-show

1
2
<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no 😢</h1>

根据表达式的值的 truthiness 来有条件地渲染元素。在切换时元素及它的数据绑定 / 组件被销毁并重建。如果元素是 <template>,将提出它的内容作为条件块。

1
<h1 v-show="true">Hello!</h1>

不同的是带有 v-show 的元素始终会被渲染并保留在 DOM 中。v-show 只是简单地切换元素的 CSS property display

v-if和v-show的区别在于,前者是删除或者新增dom元素,但是v-show只是简单的添加display: none这个css属性;

全局指令

注册或获取全局指令。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script>
// 命名需要加上v-前缀,但是使用的时候需要加上v-前缀[v-自定义指令名称]
// 每个方法第一个参数el,都表示绑定了指令的那个元素
Vue.directive('自定义指令名称', {
// bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置
bind: function () {},
// inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
inserted: function () {},
// 所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
update: function () {},
// 指令所在组件的 VNode 及其子 VNode 全部更新后调用。
componentUpdated: function () {},
// 只调用一次,指令与元素解绑时调用。
unbind: function () {}
})
</script>

自定义私有指令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script>
new Vue({
// ...
directive: {
"指令名称": {
bind: function() {},
inserted: function() {},
update: function() {},
componentUpdated: function () {},
unbind: function () {}
}
}
})
</script>

过滤器

定义全局的过滤器:

1
2
3
4
5
6
7
8
9
10
<p>{{ msg | 过滤器名称(arg) }}</p>

<script>
// 过滤器的function第一个参数是管道符传递过来的数据
vue.filter("过滤器名称", function(data, arg) {
...
})

// 在这里function中第一个参数data默认是管道函数前 的数据,后面的参数是传递过来的;
</script>

定义局部的过滤器:

1
2
3
4
5
6
7
8
9
10
11
12
<script>
var vm = new Vue({
el: "#app",
data: {},
methods: {},
filter: {
// 私有过滤器,参数与上述一样
// 调用规则就近,如果私有和全局名称一样,那么会调取私有过滤器;
dataFormat: function(data, argments) {}
}
})
</script>

生命周期

生命周期图例

组件

Vue.component和Vue.extend

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<script>
// Vue.extend, Vue 构造器,创建一个“子类”
const com = Vue.extend({
template: "<div>moki</div>"
})
// Vue.component,第一个参数是组件名称, 第二个参数是组件模板
const com = Vue.component("myCom", com);
// 当不使用vue.extend构造,直接传入一个对象到Vue.components到第二个参数自动调用Vue.extend
const com_1 = Vue.component("MyCom", {
template: "<div>moki</div>",
// 每个对象必须是一个方法返回一个对象,因此每个实例可以维护一份被返回对象的独立的拷贝:
data() {
return {
/.../
}
}
})
</script>

组件名称的kebab-case和PascalCase

在我们定义组件的时候可以使用PascalCase,去定义:

1
2
3
4
5
<script>
Vue.component('MyComponentName', { /* ... */ })
// 同样也可以使用kebab-case定义
Vue.component('my-component-name', { /* ... */ })
</script>

但是在dom中使用的时候只能是kebab-case这种方式:

1
2
3
<template>
<my-component-name></my-component-name>
</template>

template

在自定义根节点,如

,之外使用template标签书写组件内容;然后使用Vue.component注册;

1
2
3
4
5
6
7
8
9
<template id="template_1">
<div>hello</div>
</template>

<script>
Vue.component("myCom", {
template: "#template_1"
})
</script>

私有组件定义

1
2
3
4
5
6
7
8
9
10
11
<script>
new Vue({
el: '#app',
components: {
// ComponentA, ComponentB 定义可以如上定义一个对象{ template: "", date() {return {}} }
// 也可以使用import使用引入
'component-a': ComponentA,
'component-b': ComponentB
}
})
</script>

全局注册一个基础组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import Vue from 'vue'
import upperFirst from 'lodash/upperFirst'
import camelCase from 'lodash/camelCase'

const requireComponent = require.context(
// 其组件目录的相对路径
'./components',
// 是否查询其子目录
false,
// 匹配基础组件文件名的正则表达式
/Base[A-Z]\w+\.(vue|js)$/
)

requireComponent.keys().forEach(fileName => {
// 获取组件配置
const componentConfig = requireComponent(fileName)

// 获取组件的 PascalCase 命名
const componentName = upperFirst(
camelCase(
// 获取和目录深度无关的文件名
fileName
.split('/')
.pop()
.replace(/\.\w+$/, '')
)
)

// 全局注册组件
Vue.component(
componentName,
// 如果这个组件选项是通过 `export default` 导出的,
// 那么就会优先使用 `.default`,
// 否则回退到使用模块的根。
componentConfig.default || componentConfig
)
})

组件占位

1
2
<!-- is后面跟的组件的名称,可以绑定上变量  -->
<component is="compoentName"></component>

Prop

子组件使用外部的传递的数据使用prop去定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<script>
Vue.component('blog-post', {
// 在 JavaScript 中是 camelCase 的
props: ['postTitle'],
template: '<h3>{{ postTitle }}</h3>'
})
// props可以写成数组
props: ['title', 'likes', 'isPublished', 'commentIds', 'author']
// props也可以写成对象
props: {
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object,
callback: Function,
contactsPromise: Promise // or any other constructor
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!-- 传递参数的时候使用v-bind绑定,事件还是使用v-on -->
<com1 :parentname="name" ></com1>

<!-- 在my-com内部需要去接受 parentName -->
<script>
new Vue({
el: "#app",
// 变量
data() {
return {
msg: "这是一个测试数据;"
}
},
components: {
com1: {
template: "<div>{{parentname}}</div>",
props: ["parentname"],
}
},
methods: {
clickItem() {}
},

})
</script>

props的属性大小写也会影响;

在vue内部props中或者模版语法中使用camelCase props是没有问题的,但是在dom中会把所有的camelCase 转换成 kebab-case,所有在dom中需要把camelCase转换一下书写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- 传递参数的时候使用v-bind绑定 -->
<!-- 但是这里需要转换成 kebab-case书写 -->
<com1 :parent-name="name"></com1>

<script>
new Vue({
/.../
components: {
com1: {
// 例如这里是camelCase
template: "<div>{{parentName}}</div>",
props: ["parentName"],
}
}
})
</script>

Prop传入自定义事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!-- 使用了v-on -->
<com1 @clickItem="click" ></com1>
<script>
new Vue({
components: {
com1: {
template: "<button @click="click">{{parentname}}</button>",
props: ["parentname"],
methods: {
click() {
// 通过$emit的方式去出发传进来的方法事件,后面可以跟上参数
this.$emit("clickItem")
}
}
}
},
methods: {
click() {}
},

})
</script>

Vue基础知识
http://www.clearluv.com/2020/11/10/vue基础知识/
发布于
2020年11月10日
许可协议