(syntax)vue2
2022-10-20 10:31:20

Vue2

API

两种API

  • Option API Vue2 vs Compition API Vue3(也可以用Option API 推荐前者)

两种文件

  • HTML vs Vue

Option API

  • data:{} computed:{} methods:{} watch(){}
  • beforeCreate\Mounted\Update\Destory\ 、created\mounted\updated\desotryed

指令

-

组件

概念

  • 是什么:Web界面的前端框架、响应式编程、组件化、关注视图层、构建用户界面的渐进式框架、自底向上逐层应用
  • 优点:小、高效(虚拟DOM)、双向数据绑定、生态丰富、学习成本低

安装

cdn && npm/yarn vue-cli

1
2
3
4
5
6
// vue-cli vue -V @vue/cli版本
npm install @vue/cli // 安装 vue-cli
yarn global add @vue/cli
vue create my-project // 创建项目
// webpack
vue init webpack my-project

定义

data computed methods watch

  • data 数据
  • computed:{ }解决模板过重的问题 把模板中的复杂逻辑进行抽取出来 computed 是计算属性,数据的逻辑运算 可以理解为经过计算的 data的属性 计算属性是基于它们的响应式依赖进行缓存的
    • get(){ return } 和 set(val){ }
  • methods 事件
  • watch 侦听属性 观察和响应Vue实例上的数据变动 每时每刻监听数据或者动作的变化 一个数据依赖于其他数据,那么把这个数据设计为 computed 的 如果你需要在某个数据变化时做一些事情,使用 watch 来观察这个数据变化

前缀 $ : Vue 实例还暴露了一些有用的实例 property 与方法

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// html
{{ msg }}
{{ reversed }}
// html
var obj = { }
Object.freeze(obj) // 阻止修改现有的 property
var vm = new Vue({
el:"#app",
// data:obj
data:{
// data():{ }
firstName: "ZSH",
msg:"Message",
newTodoText: '',
visitCount: 0,
hideCompletedTodos: false,
todos: ['zs','sz','wo'],
error: null,
items:[
{ name:'zs',age:20 },
{ name:'sh',age:30 }
]
},
watch:{
// 没有输出
firstName: function (newval, oldval) {}
},
computed:{ // 计算属性
// 写法一 :默认使用get
// 没有getter
// 输出到模块
num(){
return 1000
},
// vm.num = 1000 ==> set
num:{
// get:function(){}
get(){
return 100
}
set(newVale){
}
},
reversed(){
return this.msg.reserve()
}
},
methods:{ // 方法
//alert:function(){ }
// 或者 推荐
alert(){},
show(){}
},
watch:{ //侦听器

},
filters:{},
directives:{},
components:{
login:{
template:'#tpl2'
}
},
// 八个生命周期
beforeCreate(){},
// beforeCreate:function(){},
created(){},
beforeMount(){},
mounted(){},
beforeUpdate(){},
update(){},
beforeDestroy(){},
destroyed(){},
})

vm.message == data.message
vm.message = 100
data.message = 200
vm.$data === data
vm.$el === el === document.getElementById("app")
vm.$watch("a", function (newValue, oldValue) {}
1
2
3
4
5
6
7
8
9
10
11
12
// main.js
import vue from 'vue'
import app from './App'
// vue2
new Vue({
el:"app"
})

// App.vue
export default{

}

指令

内置指令

  • v-html/text/module/bind/once/for/if/else-if/else/show/on/pre/clock

双大括号

{{}}

  • Mustache”语法 (双大括号) 的文本插值{数据绑定}

v-html

  • 插入 HTML 需要绑定在某个元素上且能避免编译前闪现问题
  • 不建议在网站上直接动态渲染任意 HTML 片段,很容易导致 XSS 攻击

v-text

  • 插入文本 没有闪烁问题 解决{{ text }} 中闪现的问题 会覆盖元素中原本的内容
  • 插值表达式 {{}} 只会替换自已的这个占位符,不会把整个元素的内容清空

v-model

  • 表单绑定

  • input textarea select

  • v-modul 指令在表单 input textarea select 元素上创建双向数据绑定
    它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但 v-model 本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
    v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件:

    • text 和 textarea 元素使用 value property 和 input 事件;
    • checkbox 和 radio 使用 checked property 和 change 事件;
    • select 字段将 value 作为 prop 并将 change 作为事件
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
<textarea/input v-model="message" placeholder="输入内容"></textarea>
// 多选 data: toggle:[]
<input type="checkbox" id="jack" value="Jack" v-model="toggle">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="toggle">
<label for="john">John</label>
// 当选中时
vm.toggle === 'yes'
// 当没有选中时
vm.toggle === 'no'

// 单选 picked
<input type="radio" id="one" value="One" v-model="picked" v-bind:value="a"> //绑定值
// vm.picked === vm.a
<label for="one">One</label>
<input type="radio" id="two" value="Two" v-model="picked">
<label for="two">Two</label>

// 选项卡
<select v-model="selected" multiple>
<option disabled>请选择</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>

<select v-model="selected">
<option v-for="option in options" v-bind:value="option.value"> // v-bind:value绑定
{{ option.text }}
</option>
</select>
options: [
{ text: 'One', value: 'A' },
{ text: 'Two', value: 'B' },
{ text: 'Three', value: 'C' }
]

v-once

  • 标明元素或组件只能渲染一次 文本插值不可改变,执行一次插值 数据改变时 插值的内容不会更新

v-bind

  • 属性绑定 :id="id" :src="xxx" :class=""

  • 绑定 DOM 元素属性 缩写::href="url" 绑定属性值

  • 动态参数的缩写(2.6.0+) :[key]=url

  • class(类) 和 style(内联样式)绑定 两种方法动态绑定css

    • class 类
      • :class="[' ',' ']"
      • :class="{ active: isActive }" + data控制ture或false +style样式

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
data:{ 
classObject:{
active:true,
'text-danger':false
}
}

// [] 绑定的都是类名 {} 中的true或false改变值
:class="['red', 'thin']"

:class="['red', 'thin', isactive?'active':'']">

// 数组中嵌套对象
:class="['red', 'thin', {'active': isactive}]"
// 使用对象
:class="{ red:true, italic:false, active:true, thin:true }"
:class="{ active:isActive,Error:hasError }"

.active {
color: red;
font-size: 20px;
}

// 组件中使用
Vue.component('my-component',{
template:'<p class="foo bar"></p>'
})
<my-component class="bar boo" :class="{ active:isActive }"></my-component>
data{ isActive:true }
<p class="foo bar boo active"></p>
  • style 内联样式 对象 { } data中的对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 直接定义样式
:style="{color: 'red', 'font-size': '40px'}"

// data中定义样式
data:{
h1StyleObj: {
color: 'red',
'font-size': '40px',
'font-weight': '200'
}
}
:style="h1StyleObj"

// 数组绑定多个样式
:style="[h1StyleObj,h1StyleObj2]"

v-on

事件绑定 @

  • 动态参数的缩写 (2.6.0+) @[event]="doSomething"

v-for 列表循环 和v-bind:key key属性

  • 不推荐同时在同一元素中使用 v-ifv-for。当 v-ifv-for 一起使用时,v-for 具有比 v-if 更高的优先级 v-for > v-if v-if 将分别重复运行于每个 v-for 循环中。当你只想为部分项渲染节点时,这种优先级的机制会十分有用
  • 如果你的目的是有条件地跳过循环的执行,那么可以将 v-if 置于外层元素 (或 [`) 上
  • 在组件上使用 v-for
1
2
3
4
5
6
7
8
9
10
11
12
13
<ul v-if="todos.length">
<li v-for="todo in todos">{{ todo }}</li>
</ul>
<p v-else>No todos left!</p>

<my-component v-for="item in items" :key="item.id"></my-component>

<my-component
v-for="(item, index) in items"
v-bind:item="item"
v-bind:index="index"
v-bind:key="item.id"
></my-component>

key:vue用v-for正在更新已渲染过的元素列表时,默认用就地复用的策略。如果数据项的顺序被改变,Vue 将不是移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。(DOM 改变顺序,不是修改 DOM,而是重新渲染每一个元素)
这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出
为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性。

尽可能在使用 v-for 时提供 key attribute,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。
因为它(key)是 Vue 识别节点的一个通用机制,key 并不仅与 v-for 特别关联

不要使用对象或数组之类的非基本类型值作为 v-forkey。请用字符串或数值类型的值

  • in 后面我们放过普通数组 对象数组 对象 数字
  • of 替代 in 作为分隔符,接近 JavaScript 迭代器的语法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
data:{
items:[
{},{},{}
],
object: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
<div v-for="item in items"> {{ item.name }} </div>
<div v-for="item of items"></div>
<li v-for="(item,key,index) in items" :key="item.id">{{item}}+{{index}}</li>
// index是当前选项的索引值
<p v-for="i in 10">{{i}}</p>
<li v-for="(value,name,index) in object"> {{index}} {{value}} {{ name }}</li>

数组更新

  • push pop shift unshift splice sort reverse
  • filter concat slice 替换数组

v-if and v-show 切换元素的显示和隐藏

v-if

  • / v-else /v-else-if

  • 控制元素的显隐、运行条件不大时、更高的切换消耗、操作 DOM(true/false)的增删来显隐

  • 惰性的、初始渲染时条件为假,则什么都不用做,为真开始局部编译(编译会被缓存起来)

  • 真实的条件渲染

  • 通过操作 DOM(true/false)的增删来显隐、

  • 更高的切换消耗(元素的创建与销毁)

  • 运行条件不大时

  • 切换、更高的切换消耗、运行时条件不大可能改变时用 v-if 每次都会重新删除或创建元素,是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建 惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块

1
2
3
4
5
6
7
8
<h1 v-if="hidden">Vue is awesome!</h1>
<h1 v-else>这是第二段文字</h1>
data:{ hidden:true }
<div v-if="type === 'A'">A</div>
<div v-else-if="type === 'B'">B</div>
<div v-else-if="type === 'C'">C</div>
<div v-else>NOT A/B/C</div>
<template v-if="loginType === 'username'">

v-show

  • 元素始终被编译并保留,只是简单地基于 CSS 切换
  • 通过切换 Css 的 display 的属性(style=”display:none”)来显隐、
  • 更高的初始渲染消耗(display 属性控制元素的显示与消失)
  • 不支持 template 语法
  • 控制元素的显隐、更高的初始渲染消耗 频繁切换、切换 Css 的 display 的属性(style=”display:none”)来显隐 显隐、更高的初始渲染消耗、元素始终会被渲染并保留在 DOM 中、不会重新进行 DOM 的删除和创建操作,简单地切换元素的 CSS property display、不支持 <template> 元素,也不支持 v-else、更高的初始渲染消耗、频繁切换 v-show 不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换

v-el 、v-ref 废弃

  • vue1.0中的v-el和v-ref在2.0中被废弃了。

  • v-el 为 DOM 元素注册了一个索引,可以直接访问 DOM 元素(通过v-el我们可以获取到DOM对象)

  • 可以通过实例的$els属性调用

  • v-el:some-el

  • this.$els.some-el

  • 通过 this.$els获取相应的 DOM 元素

v-ref 通过v-ref获取到整个组件(component)的对象

  • 可以通过实例的$refs属性调用
  • 父组件注册子组件索引方便访问
    • v-ref:some-ref
    • this.$refs.some-ref

v-cloak

1
解决双大括号闪烁 在元素上添加了一个[v-cloak]的属性,直到关联的实例结束编译 解决 插值表达式闪烁的问题(网速慢,页面会出现插入表达式{{ }} 的问题

v-pre

编译时跳过当前元素和它的子元素。可以用来显示原始 Mustache 标签。跳过大量没有指令的节点会加快编译,作用显示出{{双大括号}}

1
2
3
4
5
6
7
8
9
10
11
// v-el 、v-ref `vue1.0中的属性 v-el和v-ref在2.0中被废弃了。`
<h1 v-cloak>Yout input is{{ message }}</h1>
<div v-el:demo>这是一段话</div>
vm.$els.demo.innerText // 这是一段话
<template id="demo">
<h2>组件对象</h2>
</template>
<demo v-ref:mycom></demo>
<button @click="getCom">获取组件对象</button>
vm.$refs.mycom
<h1 v-text="HH"></h1>

自定义指令

  • 全局: Vue.directive('name',{ })
    • bind/unbind(el, binding, vnode){}
    • inserted/componentUpdated(el, binding, vnode) {}
    • update(el, binding, vnode, oldVnode)
  • 局部
    • directives:{ name:{ } }

注册v-*自定义指令,以便封装对 DOM 元素的重复处理行为,提高代码的复用效率
复用 JS 代码,指令方便 将 JS 代码挂载具体的 DOM 元素上
创建、注册自定义指令,以及讲述指令相关属性钩子函数

  • 全局的自定义指令
  • 局部的自定义指令
1
2
3
4
5
6
7
Vue.directive("Vuedemo", {
bind(el, binding, vnode) {},
inserted(el, binding, vnode) {},
update(el, binding, vnode, oldVnode) {},
componentUpdated(el, binding, vnode) {},
unbind(el, binding, vnode) {},
});

自定义全局指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 自定义指令的使用方式
<input type="text" v-model="searchName" v-focus v-color="'red'" v-font-weight="900">
// 自定义全局指令 v-focus,为绑定的元素自动获取焦点:
Vue.directive('focus', {
inserted: function (el) { // inserted 表示被绑定元素插入父节点时调用
el.focus();
console.log(el);
}
});

Vue.directive(id,definition)
<div v-global-directive></div>
Vue.directive("focus", {
inserted: function (el) {
el.fouce;
},
});

自定义局部指令

局部注册
组件的directions选项注册一个局部的自定义指令,该指令只能在当前组件中通过v-local-direactive的方式调用

1
2
3
4
5
6
7
8
9
10
11
    // 自定义局部指令 v-color 和 v-font-weight,为绑定的元素设置指定的字体颜色 和 字体粗细:
directives: {
color: { // 为元素设置指定的字体颜色
bind(el, binding) {
el.style.color = binding.value;
}
},
'font-weight': function (el, binding2) { // 自定义指令的简写形式,等同于定义了 bind 和 update 两个钩子函数
el.style.fontWeight = binding2.value;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 局部注册
var comp = Vue.extend({
directives: {
localDirective: {}, // 采用驼峰式命名
},
});

var vm = new Vue({
el: "#app",
data: {},
directives: {
color: {
bind(el) {
el.style.backgroundColor = "red";
},
},
},
});

钩子函数

事件(function)

钩子函数(hook 函数)[监听函数]

钩子函数和回调函数都是事件处理函数

钩子函数其实和回调是一个概念,当系统执行到某处时,检查是否有 hook,有则回调

钩子函数:js 派函数监听事件 => 监听函数就是所谓的钩子函数 => 函数钩取事件 (函数自动找事件 => 钩子函数)自动

回调函数:js 预留函数给 dom 事件,dom 事件调用 js 预留的函数 => 事件派发给函数:(事件调用函数=>回调函数) 手动

dom 通过事件通知 js 的过程即是回调,对应的函数就是回调函数

js 通过监听函数得知事件的过程即是钩取,对应的函数就是钩子函数
一个指令定义对象可以提供了五个钩子函数(可选)可以理解成指令的(生命周期的)
bind (绑定)==> inserted(插入) ==> update(更新) ==> componentUpdated(组件和子组件 全部更新调用) ==> unbind(解绑)

绑定、插入、更新、VNode更新、解绑

  • bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
  • inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)
  • update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
  • componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
  • unbind:只调用一次,指令与元素解绑
1
2
3
4
5
6
7
Vue.directive("demo", {
bind() {},
inserted() {},
update() {},
componentUpdated() {},
unbind() {},
});

钩子函数参数

  • 三个参数:el(DOM 元素)、binding、vnode(vue 虚拟节点)
  • el:指令所绑定的元素,可以用来直接操作 DOM。
  • binding:一个对象 与动态钩子参数
  • {name、value、oldValue、expression、arg、modifiers }
  • name 指令名
  • value 指令的绑定值 binding.value 数字
  • oldValue 指令绑定的前一个值
  • expression 字符串形式的指令表达式 binding.expression 字符串
  • arg 传给指令的参数 binding.arg
  • modifiers 一个包含修饰符的对象
  • vnode:Vue 编译生成的虚拟节点。
  • oldVnode:上一个虚拟节点,仅在 updatecomponentUpdated 钩子中可用。

除了 el 之外,其它参数都应该是只读的,切勿进行修改。如果需要在钩子之间共享数据,建议通过元素的 dataset 来进行。

value 和 expression 的区别

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
<div id="hook-arguments-example" v-demo:foo.a.b="message"></div>
// v-demo:foo.a.b="message" v-demo:[argument].a.b="value"
// .a.b modifiers 一个包含修饰符的对象
Vue.directive("demo",{
bind(el,binding,vnode){
//el.innerText = ‘’
console.log(el)
console.log(binding)
console.lg(vnode)
var s = JSON.stringify
el.innerHTML =
'name: ' + s(binding.name) + '<br>' +
'value: ' + s(binding.value) + '<br>' +
'expression: ' + s(binding.expression) + '<br>' +
'argument: ' + s(binding.arg) + '<br>' +
'modifiers: ' + s(binding.modifiers) + '<br>' +
'vnode keys: ' + Object.keys(vnode).join(', ')
},
inserted(){},
update(){},
componentUpdated(){},
unbind(){}
}
new Vue({
el: '#hook-arguments-example',
data: {
message: 'hello!'
}
})
1
2
3
4
5
6
7
name: "demo"
// message: 'hello!'
value: "hello!"
expression: "message"
argument: "foo" // 参数
modifiers: {"a":true,"b":true}
vnode keys: tag, data, children, text, elm, ns, context, fnContext, fnOptions, fnScopeId, key, componentOptions, componentInstance, parent, raw, isStatic, isRootInsert, isComment, isCloned, isOnce, asyncFactory, asyncMeta, isAsyncPlaceholde

动态参数

指令的参数可以是动态的。例如,在 v-mydirective:[argument]="value" 中,
argument 参数可以根据组件实例数据进行更新!这使得自定义指令可以在应用中被灵活使用。
格式

  • arg
  • value 可以是对象
1
2
3
4
5
6
<h1 v-pin:[arg]="value"></h1>
`v-mydirective:[argument]="value"` binding.value = 100 binding.expression = 参数
:[arg] binding.arg = message // 重点 arg 要注册到data中 data:{ arg:'message' }

<p v-pin:[direction]="200"></p>
// v-pin:[参数]

修饰符

v-on:click.xxx="" Or @click.xxx="" @click.事件修饰符="btnHandler"

v-on:事件修饰符是由点开头的指令后缀来表示的、修饰符可以串联

  • 事件修饰符: .stop 阻止冒泡 .prevent 默认事件 .capture 捕获 .self 事件不是从内部元素触发 .once 触发一次 .passive 修饰符尤其能够提升移动端的性能
  • 按钮修饰符:@keyup +.enter .tab .delete .esc .space .up .down .left .right
    • 自定义按键修饰符别名:全局 config.keyCodes 对象
  • 系统修饰符: .ctrl .alt .shift .meta
  • 鼠标按键修饰符:.left .right .middle

v-model:修饰符 .lazy 在鼠标离开输入框时进行同步 .number .trim debounce 延时

  • v-model.lazy/.number/.trim=”msg”
  • .number 自动将用户的输入值转为数值类型、没有办法输入字符,只能输入数字
  • .trim 自动过滤用户输入的首尾空白字符 自动在鼠标离开input框时
修饰符作用
.sync双向绑定
.once单次绑定
.camel将绑定的特性名字转换回驼峰命名

v-model

修饰符作用
number用户输入自动转换为 Number 类型
lazy添加一个 lazy 特性,从而将数据改到 change 事件中发生
debounce设置一个最小的延时,每次敲击之后延时同步输入框的值域数据
1
<input v-model="msg" number lazy debounce="5000" />

事件修饰符

在事件处理程序中调用 event.preventDefault()event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。

  • 修饰符是由点开头的指令后缀来表示的
  • 修饰符可以串联
事件修饰符作用
.stop阻止单击事件继续传播 阻止冒泡 事件 默认从里到外 阻止外层事件
.prevent阻止默认事件 a 链接的跳转行为 提交事件不再重载页面
.capture添加事件监听器时使用事件捕获模式、即内部元素触发的事件先在此处理,然后才交由内部元素进行处理
.self只当在 event.target 是当前元素自身时触发处理函数 即事件不是从内部元素触发的 只当事件在该元素本身(比如不是子元素)触发时触发回调 阻止了当前元素的冒泡事件
.once2.1.4 新增、点击事件将只会触发一次
.passive2.3.0 新增、Vue 还对应 addEventListener 中的 passive 选项提供了 .passive 修饰符。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>
<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>
<!-- 点击事件将只会触发一次 -->
<a v-on:click.once="doThis"></a>
// 不像其它只能对原生的 DOM 事件起作用的修饰符,.once 修饰符还能被用到自定义的组件事件上。
<!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 -->
<!-- 而不会等待 `onScroll` 完成 -->
<!-- 这其中包含 `event.preventDefault()` 的情况 -->
<div v-on:scroll.passive="onScroll">...</div>
// 这个 .passive 修饰符尤其能够提升移动端的性能。
// 不要把 .passive 和 .prevent 一起使用,因为 .prevent 将会被忽略,同时浏览器可能会向你展示一个警告。请记住,.passive 会告诉浏览器你不想阻止事件的默认行为。

按钮修饰符

修饰键与常规按键不同,在和 keyup 事件一起用时,事件触发时修饰键必须处于按下状态。换句话说,只有在按住 ctrl 的情况下释放其它按键,才能触发 keyup.ctrl。而单单释放 ctrl 也不会触发事件。如果你想要这样的行为,请为 ctrl 换用 keyCodekeyup.17
常规按键
按键码 @keyup.

  • .enter 回车键
  • .tab制表键
  • .delete (捕获“删除”和“退格”键)
  • .esc 逃逸键
  • .space 空格键
  • 方向键
    • .up
    • .down
    • .left
    • .right
1
2
3
4
5
6
7
 <input type="text" v-on:keyup.enter="greet" @keyup.up="up">
greet(){
console.log('msg');
}
up(){
console.log('upup')
}

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

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

系统修饰键

  • .ctrl
  • .alt
  • .shift
  • .meta
1
2
3
4
<!-- Alt + C -->
<input v-on:keyup.alt.67="clear">
<!-- Ctrl + Click -->
<div v-on:click.ctrl="doSomething">Do something</div>

鼠标按键修饰符

  • .left
  • .right
  • .mideele

事件

监听事件

  • v-on:click=“func” @click="func"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@click="greet('Hi')"
v-on:click="warn('Message',$event)"

methods:{
greet(event){
console.log(event.target.tagName)
console.log(message);
},
warn(message,event){
if(event){
event.preventDefault()
}
}
}

过滤器

  • filters:{}
  • Vue.filter(“name”, function (value) {})

Vue.js 允许你自定义过滤器,可被用作一些常见的文本格式化
过滤器可以用在两个地方:

  • mustache 插值
  • v-bind 表达式
    过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符指示|
1
2
{{  message | capitalize; }}
<div v-bind:id="rawId | formatId"></div>;

当全局过滤器和局部过滤器重名时,会采用局部过滤器

局部过滤器

私有 filters 定义方式:

1
2
3
4
5
6
7
filters:{
capitalize:function(value){
if(!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
}
}
1
<td>{{item.ctime | dataFormat('yyyy-mm-dd')}}</td>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
filters: { // 私有局部过滤器,只能在 当前 VM 对象所控制的 View 区域进行使用
dataFormat(input, pattern = "") { // 在参数列表中 通过 pattern="" 来指定形参默认值,防止报错
var dt = new Date(input);
// 获取年月日
var y = dt.getFullYear();
var m = (dt.getMonth() + 1).toString().padStart(2, '0');
var d = dt.getDate().toString().padStart(2, '0');
// 如果 传递进来的字符串类型,转为小写之后,等于 yyyy-mm-dd,那么就返回 年-月-日
// 否则,就返回 年-月-日 时:分:秒
if (pattern.toLowerCase() === 'yyyy-mm-dd') {
return `${y}-${m}-${d}`;
} else {
// 获取时分秒
var hh = dt.getHours().toString().padStart(2, '0');
var mm = dt.getMinutes().toString().padStart(2, '0');
var ss = dt.getSeconds().toString().padStart(2, '0');
return `${y}-${m}-${d} ${hh}:${mm}:${ss}`;
}
}
}

使用 ES6 中的字符串新方法 String.prototype.padStart(maxLength, fillString=’’) 或 String.prototype.padEnd(maxLength, fillString=’’)来填充字符串;

全局过滤器

1
2
3
4
5
Vue.filter("capitalize", function (value) {
if (!value) return "";
value = value.toString();
return value.charAt(0).toUpperCase() + value.slice(1);
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 定义一个全局过滤器
Vue.filter("dataFormat", function (input, pattern = "") {
var dt = new Date(input);
// 获取年月日
var y = dt.getFullYear();
var m = (dt.getMonth() + 1).toString().padStart(2, "0");
var d = dt.getDate().toString().padStart(2, "0");
// 如果 传递进来的字符串类型,转为小写之后,等于 yyyy-mm-dd,那么就返回 年-月-日
// 否则,就返回 年-月-日 时:分:秒
if (pattern.toLowerCase() === "yyyy-mm-dd") {
return `${y}-${m}-${d}`;
} else {
// 获取时分秒
var hh = dt.getHours().toString().padStart(2, "0");
var mm = dt.getMinutes().toString().padStart(2, "0");
var ss = dt.getSeconds().toString().padStart(2, "0");
return `${y}-${m}-${d} ${hh}:${mm}:${ss}`;
}
});

注意:当有局部和全局两个名称相同的过滤器时候,会以就近原则进行调用,即:局部过滤器优先于全局过滤器被调用!

过滤器传递参数

多个过滤器串联

过滤器可以串联 过滤

1
{{  message | filterA | filterB; }}

message ==> filterA ==> filterB
filterA 被定义为接收单个参数的过滤器函数,表达式 message 的值将作为参数传入到函数中。然后继续调用同样被定义为接收单个参数的过滤器函数 filterB,将 filterA 的结果传递到 filterB 中。

过滤器多个参数

过滤器是 JavaScript 函数

1
2
3
4
{{ message | filterA("args1", "args2"); }}
// message 第一个参数
// args1 第二个参数
// args2 第三个参数

生命周期

什么是生命周期:从 Vue 实例创建、运行、到销毁期间,总是伴随着各种各样的事件,这些事件,统称为生命周期

生命周期钩子:就是生命周期事件的别名
生命周期钩子 = 生命周期函数 = 生命周期事件

创建(create) ==> 挂载(mounted) ==> 更新(updated) ==> 销毁(destroy)

  • beforeCreate created
  • beforeMount mounted
  • beforeUpdate updated
  • beforeDestory destroyed

==创建期间的生命周期函数==:

  • beforeCreate:实例刚在内存中被创建出来,此时,还没有初始化好 data 和 methods 属性(调用报错 )组件刚刚被创建
  • created:实例已经在内存中创建 OK,此时 data 和 methods 已经创建 OK,此时还没有开始 编译模板
  • beforeMount:此时已经完成了模板的编译,但是还没有挂载到页面·中 挂载之前
  • mounted:此时,已经将编译好的模板,挂载到了页面指定的容器中显示 挂载之后

==运行期间的生命周期函数==:

  • beforeUpdate:状态更新之前 执行此函数, 此时 data 中的状态值是最新的,但是界面上显示的 数据还是旧的,因为此时还没有开始重新渲染 DOM 节点
  • updated:实例更新完毕之后调用此函数,此时 data 中的状态值 和 界面上显示的数据,都已经完成了更新,界面已经被重新渲染好了!

==销毁期间的生命周期函数==:

  • beforeDestroy:实例销毁之前调用。在这一步,实例仍然完全可用。组件销毁前调用
  • destroyed:Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。组件销毁后调用

不要在选项 property 或回调上使用箭头函数 并没有 this

1
2
3
4
5
6
7
8
9
10
11
var vm = new Vue({
el: "#app",
beforeCreate(){},
created(){},
beforemount(){},
mounted(){},
beforeupdate(){},
update(){},
beforeDestroy(){},
destroyed(){},
});

动画 && 过渡

使用过渡类名实现动画

  • .v-enter-active 和 .v-leave-active 设置动画过渡的时间
  • .v-enter 和 .v-leave-to 设置动画进入和离开
  • transition 设置过渡的动画元素
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* 定义进入和离开时候的过渡状态 */
.v-enter-active,
.v-leave-active {
transition: all 0.2s ease;
position: absolute;
}
/* 定义进入过渡的开始状态 和 离开过渡的结束状态 */
.v-enter,
.v-leave-to {
opacity: 0;
transform: translateX(100px);
}

<transition>
<div v-show="isshow">动画哦</div>
</transition>

通过可以给`transtion标签添加name属性设置自定义v-前缀

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* 定义进入和离开时候的过渡状态 */
.fade-enter-active,
.fade-leave-active {
transition: all 0.2s ease;
position: absolute;
}
/* 定义进入过渡的开始状态 和 离开过渡的结束状态 */
.fade-enter,
.fade-leave-to {
opacity: 0;
transform: translateX(100px);
}
<transition name="fade">
<div v-show="isshow">动画哦</div>
</transition>

钩子函数 定义 transition 组件以及三个钩子函数 动画钩子函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<transition
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter"
>
<div class="ball" v-show="flag"></div>
</transition>

methods:{
beforeEnter(el){
el.style.transform="translate(0,0)";
};
enter(el,done){
el.offsetWidth
el.style.transform="translate(150px,450px)"
el.style.transition="all 1s ease"
done()
//这里的done ,起始就是 afterEnter这个函数,也就是 done 是 afterEnter函数的引用
},
afterEnter(el){
this.flag = !this.flag
}
}
}

transition-group

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.v-enter,
.v-leave-to {
transform: translateY(150px);
opacity: 0;
}
.v-enter-active,
.v-leave-active {
transition: all 1s ease;
}
<transition-group>
<li v-for="item in list" :key="item.id">
id:{{item.id}} name:{{item.name}}
</li>
</transition-group>

trasition-group 中 appear

1
2
3
4
5
6
7
8
9
10
11
// 给trasition-group 添加appear属性,实现页面展示出来时候,入场时候的效果
同岗位transition-group元素,设置tag属性,指定transition-group渲染为指定的元素,如果不指定tag属性,默认,渲染为span
标签 //
<ul>
<transition-group appear tag="ul">
<li v-for="(item,index) in list" :key="item.id" @click="del(index)">
id:{{item.id}} name:{{item.name}}
</li>
</transition-group>
//
</ul>

列表的排序过渡
<transition-group> 组件还有一个特殊之处。不仅可以进入和离开动画,还可以改变定位。要使用这个新功能只需了解新增的 v-move 特性,它会在元素的改变定位的过程中应用

  • v-movev-leave-active 结合使用,能够让列表的过渡更加平缓柔和:
1
2
3
4
5
6
.v-move{
transition: all 0.8s ease;
}
.v-leave-active{
position: absolute;
}

组件

  • 拆分vue实例代码量 不同组件划分不同的功能模块
  • 模块化: 是从代码逻辑的角度进行划分的;方便代码分层开发,保证每个功能模块的职能单一;
  • 组件化: 是从 UI 界面的角度进行划分的;前端的组件化,方便 UI 组件的重用;
  • 组件命令方式
    • kebab-case kebab-case (短横线分隔命名)
    • PascalCase PascalCase (首字母大写命名)
  • 注册方式
    • 全局注册:·
    • 局部注册:components:{ } 进行局部注册
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
54
// html
// 使用
<component-name></component-name>

// 注册方法
// 方法一 直接使用 Vue.component
Vue.component('component-name',{
data(){
return{

}
}
props: ['Message'],
template:'<h1>Hello {{ Message }} Vue2!!!<h1>'
})

// 方法二 Vue.extend 配合 Vue.component 方法
var Message = Vue.extend({
props: ["content"],
template: "<h1>{{ content }}</h1>",
});
Vue.component("message", Message);

Vue.component('register', Vue.extend({
template: '<h1>注册</h1>'
}));
// 方法三 将模板字符串,定义到 script 标签中
// JS中
<script id="tmpl" type="x-template">
<div><a href="#">登录</a> | <a href="#">注册</a></div>
</script>

// HTML中
<template id="tpl">
<div>
<h1>这是通过template元素,在定义</h1>
<h4>这是一个或</h4>
</div>
</template>

Vue.component("account", {
template: "#tpl",
});

new Vue({
data:{}, xxx:{}
components:{
son:{
data(){
return { }
}
}
}
})
1
2
3
4
5
6
7
8
9
10
// vue
#app
export default{
data(){
return{}
},
computed(){},
watch(){},
methods(){}
}

组件系统

1
2
3
4
5
6
7
8
9
ComponentB.js/.vue
import ComponentA from './ComponentA'
import ComponentB from './ComponentC'
export default{
components:{
ComponentA,
ComponentC
}
}

插槽

1
<slot></slot>

动态组件

在不同组件之间进行动态切换:特殊的 is attribute 来实现

1
2
<component v-bind:is="currentTabComponent"></component> // currentTabComponent
// 已注册组件的名字,或 一个组件的选项对象

组件通信

  • 父 => 子
    • 子 props: [‘finfo’]
    • <son :finfo="msg">

prop 与 data 的区别

  • data 组件或实例的数据
  • prop 传递的数据 newVue ==> 子组件
1
2
3
4
5
6
Vue.component('blog-post',{ props:['title'], template:'
<h3>{{ title }}</h3>
' })
<blog-post title="My journey with Vue"></blog-post>
<blog-post title="Blogging with Vue"></blog-post>
<blog-post title="Why Vue is so fun"></blog-post>
  • 子父
      • sendMsg() { this.$emit('func', 'OK'); }
      • <son @func="getMsg"></son>
      • <input type="button" value="向父组件传值" @click="sendMsg" />
      • getMsg(val){}
  • this.$refs 来获取元素和组件
1
2
3
4
<h1 ref="myh1">
<my-com ref="mycom">
console.log(this.$refs.myh1.innerText); //元素
console.log(this.$refs.mycom.name); // 组件

复用 && 组合

  • var myMixin = { } // 选项api
  • Vue.extend({ minxins:[myMixin] })
  • var component = new Component()
  • 什么是混入(Mixin):提供了一种非常灵活的方式,来分发Vue组件中的可复用功能
  • 一个混入对象可以包含任意组件选项。
  • 当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 定义一个混入对象
var myMixin = {
created:function(){
this.hello()
}
methods:{
hello:function(){
console.log('hello from mixin!')
}
}
}
var Component = Vue.extend({
minxins:[myMixin]
})
var component = new Component()

防抖和节流

1
2
3
4
5
methods:{
click:_.debounce(function(){
xxx
},500)
}

vue-preview

一个 Vue 集成 PhotoSwipe 图片预览插件

上一页
2022-10-20 10:31:20
下一页