基础
# MVVM模型
- M:模型(Model)对应data中的数据
- V:视图(View) 模版
- VM:视图模型(ViewModel) Vue中的实例对象
# 数据绑定
// 原数据
let p = {
name: '张三',
age: 20
}
let person = {}
Object.defineProperty(person,'age',{
value:"", // 值
enumerable:true, // 控制属性是否可以枚举,默认值为false
writable:true, // 控制属性是否可以被修改,默认值为false
configurable:true, // 控制属性是否可以被删除,默认值为false
// 当有设置person.age时,set(setter)就会被调用
set(value){
number = value;
},
// 当有读取person.age时, get函数(getter)就会被调用
get(value){
return number;
}
})
// vue中将data中的数据进行数据代理到vm下,且_data中进行了数据劫持,
// 当_data中改变则模版中引用该数据同时也发生变化
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 指令
- 内置指令
指令 | 说明 | 指令 | 说明 |
---|---|---|---|
v-bind | 单项绑定 | v-model | 双向数据绑定 |
v-for | 遍历数组/对象/字符串 | v-on | 绑定事件监听 |
v-if | 条件渲染 | v-show | 控制节点是否展示 |
v-text | 节点中渲染文本内容 | v-html | 渲染包含html结构的内容 有安全性问题 |
v-cloak | 隐藏尚未完成编译的DOM模板 | v-once | 仅渲染元素和组件一次,并跳过之后的更新 |
v-pre | 跳过该元素及其所有子元素的编译 |
# 事件修饰符
修饰符 | 描述 | 修饰符 | 描述 |
---|---|---|---|
.prevent | 阻止默认事件 | .stop | 阻止事件冒泡 |
.once | 事件只触发一次 | .capture | 使用事件的捕获模式 |
.self | 只有event.target是当前操作的元素时才会触发事件 | .passive | 事件的默认行为立即执行,无需等待事件回调执行完毕 |
.native | 组件的根元素上绑定事件 |
# v-model修饰符
修饰符 | 描述 | 修饰符 | 描述 | 修饰符 | 描述 |
---|---|---|---|---|---|
.number | 输入字符串转为有效数字 | .trim | 首尾空格过滤 | .lazy | 失去焦点再收集数据 |
# v-for
遍历数组 / 对象
- 对象
v-for="(item,key,index) in myObject"
- item ----- 值 -----
- key ----- key -----
- index ----- 索引 -----
key的作用
key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,之后Vue会进行【新旧虚拟DOM】的差异比较
- 比较规则
- 旧虚拟DOM中找到了与新虚拟DOM相同的key
(1) 若虚拟DOM中内容没变,直接使用之前真实的DOM
(2) 若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM - 旧虚拟DOM中未找到与新虚拟DOM相同的key
直接创建新的真实DOM,之后渲染到页面上
- 旧虚拟DOM中找到了与新虚拟DOM相同的key
- 应如何选择key
- 最好使用每条数据的唯一标识作为key
- 如果不存在对数据的逆序添加,逆序删除等破坏顺序操作,仅用于渲染列表用于展示,可以使用index作为key
# 自定义指令
// 局部指令
directives:{指令名,配置对象} directives:{指令名,回调函数}
// 全局指令
Vue.directive(指令名,配置对象) Vue.directive(指令名,回调函数)
// 配置对象中常用的回调函数
bind // 只调用一次,指令第一次绑定到元素时调用,可以定义一个在绑定时执行一次的初始化动作。
inserted // 被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。
update // 被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后的绑定值。
componentUpdated // 被绑定元素所在模板完成一次更新周期时调用。
unbind // 只调用一次, 指令与元素解绑时调用。
bind // 指令与元素成功绑定时调用
inserted // 指令所在元素被插入页面时调用
update // 指令所在模版结构被重新解析时调用
2
3
4
5
6
7
8
9
10
11
12
13
批量注册指令,新建index.js
文件
import copy from './copy'
const directives = {
copy,
}
export default {
install(Vue) {
Object.keys(directives).forEach((key) => {
Vue.directive(key, directives[key])
})
},
}
2
3
4
5
6
7
8
9
10
11
12
指令功能copy.js
点击查看
const copy = {
bind(el, { value }) {
el.$value = value
el.handler = () => {
if (!el.$value) {
// 值为空的时候,给出提示。可根据项目UI仔细设计
console.log('无复制内容')
return
}
// 动态创建 textarea 标签
const textarea = document.createElement('textarea')
// 将该 textarea 设为 readonly 防止 iOS 下自动唤起键盘,同时将 textarea 移出可视区域
textarea.readOnly = 'readonly'
textarea.style.position = 'absolute'
textarea.style.left = '-9999px'
// 将要 copy 的值赋给 textarea 标签的 value 属性
textarea.value = el.$value
// 将 textarea 插入到 body 中
document.body.appendChild(textarea)
// 选中值并复制
textarea.select()
const result = document.execCommand('Copy')
if (result) {
console.log('复制成功') // 可根据项目UI仔细设计
}
document.body.removeChild(textarea)
}
// 绑定点击事件,就是所谓的一键 copy 啦
el.addEventListener('click', el.handler)
},
// 当传进来的值更新的时候触发
componentUpdated(el, { value }) {
el.$value = value
},
// 指令与元素解绑的时候,移除事件绑定
unbind(el) {
el.removeEventListener('click', el.handler)
},
}
export default copy
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
在main.js
中引入并注册
import Vue from 'vue' import Directives from 'index.js' Vue.use(Directives)
页面中调用即可
```html
<button v-copy="copyText">复制</button>
2
3
# 键盘事件
- Vue中常用的键盘别名
别名 别名 别名 别名 回车 enter
删除 delete
空格 esc
空格 space
换行 tab
(需配合keydown去使用)上 up
下 down
左 left
右 right
- 注意
// 1.Vue中如捕获多个单词的键盘,需要用-隔开,如@keyup.caps-lock="mykey"
// 2.系统修饰键
ctrl、alt、shift、meta
(1).配合keyup使用:按下修饰键的同时,再按下其他键,之后释放其他键,事件才会触发。
(2).配合keydown使用:正常触发事件即可。
// 3.使用keyCode指定具体的按键(不推荐)
// 4.自定义键名
Vue.config.keyCodes.自定义键名 = 键名
2
3
4
5
6
7
8
# 计算属性
- 定义: 通过已有属性计算得来
- 原理 : 底层借助Object.defineproperty方法提供的getter和setting。
- get函数执行时机
- 初次读取会执行一次
- 依赖的数据发生变化时会再次被调用
- 优势
- 与methods实现相比,内部有缓存机制(复用,效率更高)
- 注意
- 计算属性会出现在vm上,点击读取即可
- 当计算属性要被修改,那必须些set函数去响应修改,且set函数中要引起计算时依赖的数据 发生变化才行
computed:{
count :{
// 调用触发
get(){},
// 改变触发
set(value){}
}
// 计算属性简写(只考虑读取可使用)
count(){ return 'content'}
},
2
3
4
5
6
7
8
9
10
# 监听属性
用于监听data中与computed中的属性,当监视的属性发生变化时,回调函数自动调用
watch:{
city:{
deep:true, // 深度监听对象内部值的改变
immediate:true, // 初始化时让handler调用一下
// handler发生变化时调用
handler(newValue,oldValue){}
},
// 也可单独监听对象中某个属性的变化
'number.a'(newVal,oldVal){},
// 简写
city(newValue,oldValue){}
}
// 组件实例中调用$watch
vm.$watch('city',{
immediate:true,
handler(newValue,oldValue){}
})
// 简写(不能使用其他属性)
vm.$watch('city', function(newValue,oldValue){})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 过滤器
对要显示的数据进行特定格式化后再显示(仅适用于一些简单逻辑)
filters:{
getTime(val){
return moment(val).format('YYYY年MM月DD HH:mm');
}
}
// 全局过滤器
Vue.filter(name,callback)
// 多个过滤器也可以串联
{{ time | 过滤器名1 | 过滤器名2 }} v-bind:属性=" xxx | 过滤器名"
2
3
4
5
6
7
8
9
# 绑定class
- 字符串绑定
<div class="box" :class="bg"></div>
- 数组绑定
<div :class="['a','b']"></div>
<div :class="[obj.isActive ? 'a1' : '','errorClass']"></div>
<!-- a1 和 'a1' 两种都可以 -->
<div :class="[{a1:obj.isActive},'errorClass']"></div>
2
3
4
- 对象绑定
<div :class="{ active: isActive ,'text-danger': hasError}"></div>
<div :class="classObject"></div>
2
data(){
return{
classObject: {
active: true,
'text-danger': false
}
}
}
2
3
4
5
6
7
8
- 计算属性绑定
<div :class="classObject"></div>
computed:{
classObject(){
return{
active:this.obj.isActive,
'selected':this.obj.status == 'error'
}
}
}
2
3
4
5
6
7
8
# 绑定style
注意
- 凡是有-的style属性名都要变成驼峰式,比如font-size要变成
fontSize
- 除了绑定值,其他的属性名的值要用引号括起来,比如color:
#00a2ff'
而不是 color:#00a2ff
- 数组绑定
<div :style="[baseStyles, overridingStyles]"></div>
<div :style="[{color:(index == 1 ? 'green':'red')},{fontSize:'18px'}]"></div>
2
- 对象绑定
<div :style="{color: activeColor, fontSize: fontSize + 'px' }"></div>
<div :style="{color:index == 1 ? 'blue' : 'red'}"></div>
2
- 三元表达式
<div :style="activeLayerName === 1?'font-weight:700' : 'font-weight:400'"></div>
# 生命周期
- beforeCreate
初始化生命周期、事件,但数据代理还未开始,无法访问data数据及methods中的方法
- created
初始化数据代理、数据监测,可以访问data数据及methods中的方法
- beforeMount
页面显示的是未经Vue编译的DOM结构,所有对DOM的操作,最终都没效果
- mounted
页面显示的是Vue编译的DOM结构,用于初始化操作
- beforeUpdate
数据是新的,页面是旧的,页面尚未和数据保持同步
- updated
页面和数据保持同步
- beforeDestroy
开始执行销毁过程
- destroyed
销毁已结束
# 组件
定义
用来实现局部功能效果的代码集合
- 定义组件
const school = Vue.extend({
template:`<div>{{user}}</div>`,
// 组件中的data必须写成函数,避免组件被复用时,数据存在引用关系
data(){
return{
user:"子组件"
}
}
})
2
3
4
5
6
7
8
9
- 注册组件
// 局部注册
new Vue({
el:"#root",
components:{
school
}
})
// 全局注册
Vue.component('组件名',组件)
2
3
4
5
6
7
8
9
this.$refs
是一个对象,持有已注册过的所有子组件。 ref为子组件指定一个名称,通过this.$refs.ref指定的子组件名称 即可获得对该子组件的操作 (包括data中定义的数据和methods中定义的方法)
this.$parent
可以访问到父组件上所有的数据在子组件中使用
注意
当遇到
this.$parent.
数据获取父组件的数据得到undefined的情况时,是因为父组件在调用子组件的时候,在子组件的外层包裹了一层UI组件的某个组件//外层包裹了几个组件就需要用几个$parent,即可解决 this.$parent.$parent.数据
1
2this.$root
可以直接操作当前组件的所有祖先组件的根组件
this.$children
是一个数组,可以操作当前组件的所有子组件
# 父传子
// 父组件
<Floating :title="str" ref="floating"></Floating>
// 子组件props接收的三种方式
props:['title']
props:{
// 表示传入的值是Number或者String类型
content: [Number, String],
// 传入布尔类型的值
content: Boolean,
}
props: {
title: {
type: String, // 传递的类型
required: true, // 值必传
default: "我是默认的", // 默认传递的值
},
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 子传父
自定义事件
// 子组件使用$emit()
valueTransfer(){
this.$emit('getValue','传递的值')
}
// 父组件接收
// @或v-on
<Floating :title="str" ref="floating" @getValue="getValue"></Floating>
methods:{
getValue(value){}
}
// 2.使用ref
<Floating ref="floating"></Floating>
mounted(){
// 这种方式更加灵活,如延迟几秒...
this.$refs.xxxx.$on('getValue',(value)=>{})
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 全局事件总线
组件的通信方式,适用于任意组件的通信(GlobalEventBus)
- 安装全局事件总线
new Vue({
render: h => h(App),
beforeCreate(){
Vue.prototype.$bus = this;
}
}).$mount('#app')
2
3
4
5
6
- 适用事件总线
// A组件想要接收数据,则A组件给$bus绑定自定义事件
mounted(){
this.$bus.$on('getData',(value)=>{})
},
// B组件提供数据
methods:{
this.$bus.$emit('getData',数据)
}
2
3
4
5
6
7
8
- 解绑当前使用的事件
// 哪个组件使用该事件接收的数据,哪个组件进行解绑
this.$off('事件名') // 解绑单个
this.$off(['事件名1','事件名2']) // 解绑多个
this.$off() // 全部解绑
beforeDestroy(){
this.$bus.$off('getData')
},
2
3
4
5
6
7
# 消息订阅与发布(pubsub)
用于组件通信,适用于任意组件
// 1.安装
npm i pubsub-js
import pubsub from 'pubsub-js'
// 2.A组件需要接收数据,则在A组件中订阅消息并取消订阅
mounted(){
const pubId = pubsub.subscribe('getData',(msgName,data)=>{
console.log(msgName,data)
})
}
beforeDestroy(){
pubsub.unsubscribe(pubId)
},
// 3.B组件用于提供数据
pubsub.publish('getData',数据)
2
3
4
5
6
7
8
9
10
11
12
13
14
# 动画
类名 | 说明 | 类名 | 说明 |
---|---|---|---|
v-enter | 进入的起点 | v-enter-to | 进入的终点 |
v-leave | 离开的起点 | v-leave-to | 离开的终点 |
v-enter-active | 进入过渡过程中 | v-leave-active | 离开过渡过程中 |
# 自定义过渡类名
- enter-class
- enter-active-class
- enter-to-class (2.1.8+)
- leave-class
- leave-active-class
- leave-to-class (2.1.8+)
# 配置
- mode 过渡模式
- in-out:新元素先进行过渡,完成之后当前元素过渡离开。
- out-in:当前元素先进行过渡,完成之后新元素过渡进入
- appear 初始渲染的过渡
<transition
mode="out-in"
appear
></transition>
2
3
4
# 插槽
作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于父组件 ===> 子组件
- 默认插槽
<!-- 子组件 -->
<div class="tion">
<slot>默认内容</slot>
</div>
<!-- 父组件调用 -->
<List>
<div>内容</div>
</List>
2
3
4
5
6
7
8
- 具名插槽
<!-- 子组件 -->
<div class="tion">
<!-- 指定插槽名 -->
<slot name="content">默认内容</slot>
</div>
<!-- 父组件调用 -->
<List>
<h3>标题</h3>
<div slot="content">内容</div>
<!-- template中可以使用v-slot:content这种写法 slot="content"也可以 -->
<template v-slot:content></template>
</List>
2
3
4
5
6
7
8
9
10
11
12
- 作用于插槽
数据在组件的自身,但数据生成的结构需要组件的使用者来决定。
<!-- 子组件 -->
<div class="tion">
<!-- 数据在组件内,也可以传多个 -->
<slot :cxd="books" :username="name"></slot>
</div>
<!-- 父组件调用 -->
<List>
<!--
scope 和 slot-scope语法都可以使用
scope="{book}" 也可以使用解构赋值
-->
<template slot-scope="book"></template>
</List>
2
3
4
5
6
7
8
9
10
11
12
13