vue基本使用
1. 文本插值
- JS表达式 yes(只能是表达式,不能是 js 语句)
- 动态属性 id
2. watch
watch如何深度监听
watch监听引用类型,拿不到oldVal
<template>
<div>
<input v-model="name"/>
<input v-model="info.city"/>
</div>
</template>
<script>
export default {
data() {
return {
name: '哈哈',
info: {
city: '北京'
}
}
},
watch: {
name(oldVal, val) {
// eslint-disable-next-line
console.log('watch name', oldVal, val) // 值类型,可正常拿到 oldVal 和 val
},
info: {
handler(oldVal, val) {
// eslint-disable-next-line
console.log('watch info', oldVal, val) // 引用类型,拿不到 oldVal 。因为指针相同,此时已经指向了新的 val
},
deep: true // 深度监听
}
}
}
</script>
3. computed
computed有缓存,data不变则不会重新计算
<template>
<div>
<p>num {{num}}</p>
<p>double1 {{double1}}</p>
<input v-model="double2"/>
</div>
</template>
<script>
export default {
data() {
return {
num: 20
}
},
computed: {
double1() {
return this.num * 2
},
double2: { // 双向绑定必须有get和set方法
get() {
return this.num * 2
},
set(val) {
this.num = val/2
}
}
}
}
</script>
4. class和style
<template>
<div>
<p :class="{ black: isBlack, yellow: isYellow }">使用 class</p>
<p :class="[black, yellow]">使用 class (数组)</p>
<p :style="styleData">使用 style</p>
</div>
</template>
<script>
export default {
data() {
return {
isBlack: true,
isYellow: true,
black: 'black',
yellow: 'yellow',
styleData: {
fontSize: '40px', // 转换为驼峰式
color: 'red',
backgroundColor: '#ccc' // 转换为驼峰式
}
}
}
}
</script>
<style scoped>
.black {
background-color: #999;
}
.yellow {
color: yellow;
}
</style>
4. 条件渲染
- v-if v-else 的用法,可使用变量,也可使用 === 表达式
- v-if 和 v-show的区别?
v-if是通过控制dom节点的存在与否来控制元素的显隐;v-show是通过设置DOM元素的display样式,block为显示,none为隐藏。
- 使用场景
如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
5. 循环(列表)渲染
可以用v-for遍历对象和数组
key的重要性 (尽量和业务相关)
v-for 和v-if 不能一起使用
6. 事件
自定义传参
事件修饰符:
7. 表单
常见表单项 textarea checkbox radio select
修饰符 lazy number trim
8. vue组件使用
- 父子组件间通讯 props 和 $emit
- 兄弟之间通讯: 自定义事件
在外面新建一个名字叫 event.js 的文件,里面写
import Vue from 'vue'
export default new Vue()
创建一个vue的实例 就可以调用 event.on 最后卸载时执行event.$off销毁
- 生命周期(单个组件)
created是vue实例已经初始化完成了,但是还没有渲染 mounted是页面已经渲染完毕 -
生命周期(父子组件)
9. vue高级特性
- 自定义v-model
// 父组件
<p>{{name}}</p>
<CustomVModel v-model="name"/>
// 子组件
<template>
<!-- 例如:vue 颜色选择 -->
<input type="text"
:value="text1"
@input="$emit('change1', $event.target.value)"
>
<!--
1. 上面的 input 使用了 :value 而不是 v-model
2. 上面的 change1 和 model.event1 要对应起来
3. text1 属性对应起来
-->
</template>
<script>
export default {
model: {
prop: 'text1', // 对应 props text1
event: 'change1'
},
props: {
text1: String,
default() {
return ''
}
}
}
</script>
- $nextTick
vue是异步渲染,data改变后dom不会立刻渲染,$nextTick会在DOM渲染后在回调,以获取最新的dom节点。页面渲染时会将data的修改做整合,多次data修改只能渲染一次
- slot 基本使用
作用域插槽
// 父组件使用名字叫ScopedSlotDemo的子组件 在父组件里展示子组件的website的title
<ScopedSlotDemo :url="website.url">
<template v-slot="slotProps">
{{slotProps.slotData.title}}
</template>
</ScopedSlotDemo>
<template>
<a :href="url">
<slot :slotData="website">
{{website.subTitle}} <!-- 默认值显示 subTitle ,即父组件不传内容时 -->
</slot>
</a>
</template>
具名插槽
在slot上绑定一个name=“名字”,在父组件里在template里写v-slot:名字
-
动态、异步组件
- 动态组件:需要根据数据,动态渲染的场景。即组件类型不确定
<component :is= "子组件的名字" />
- 异步组件:用法
<demo v-if="showDemo"/> <button @click=" showDemo = true "></button> 当点击按钮时,显示demo组件时,加载demo组件 components: { demo: () => import('组件路径') }
-
keep-alive (缓存组件): 需要频繁切换且不需要重复渲染的时候
将需要缓存的组件用<keep-alive>标签包裹起来
-
mixin 可以将多个组件的相同的逻辑抽离出来
将共同的逻辑抽离出来放在一个JS文件里,在需要的页面通过import引用,在和data同级的位置写
mixins: [引用的js文件的名字] 可以添加多个,会自动合并起来 这样就可以在当前页面用引入来的js文件里的data、方法
缺点:
-
变量来源不明确,不利用阅读
- 多 mixin 可能会造成命名冲突
- mixin 和组件可能出现多对多的关系,复杂度较高
-
10. vuex
- state
- getters
- mutation
- action
api
- dispatch
- commit
- mapState
- mapGetters
- mapActions
- mapMutations
11. vue-router
- 路由模式(hash、history)
- 路由配置(动态路由、懒加载)
vue原理
1. 如何理解MVVM模型
数据驱动视图,不用我们操作DOM,只需要关注数据,数据变了,视图就会变
MVVM分为三个部分:分别是M(Model,模型层 ),V(View,视图层),VM(ViewModel,V与M连接的桥梁,也可以看作为控制器)
1、 M:模型层,主要负责业务数据相关;
2、 V:视图层,顾名思义,负责视图相关,细分下来就是html+css层;
3、 VM:V与M沟通的桥梁,负责监听M或者V的修改,是实现MVVM双向绑定的要点;
MVVM支持双向绑定,意思就是当M层数据进行修改时,VM层会监测到变化,并且通知V层进行相应的修改,反之修改V层则会通知M层数据进行修改,以此也实现了视图与模型层的相互解耦;
2. vue响应式
核心API - Object.defineProperty
深度监听对象的时候需要用到 for in 定义一个方法 ,遍历对象,通过判断遍历出来的属性是一个值还是对象,如果是对象的话,就需要再次调用这个方法,再次遍历,直到遍历到底。
Object.defineProperty 的缺点
- 深度监听,需要递归到底,一次性计算量大
- 无法监听新增属性/删除属性(vue.set vue.delete)
- 无法监听数组,需要特殊处理
3. 虚拟DOM(vdom)和 diff
vodm:用js模拟DOM结构,计算出最小的变更,操作DOM
用js模拟DOM结构
vdom核心概念: h vnode patch diff key 等
- patch:path(elem, vnode) 和 patch(vnode, newvnode)
vdom存在的价值:数据驱动试图,控制DOM操作
你知道Vue中key的作用和工作原理吗?说说你对它的理解。
- key的主要作用是为了高效的更新虚拟DOM,其原理是vue在patch过程中通过key可以精准判断两个节点是否是同一个,从而避免频繁更新不同元素,使得整个patch过程更加高效,减少DOM操作量,提高性能。
- 另外,若不设置key还可能在列表更新时引发一些隐藏的bug
- vue中在使用相同标签名元素的过渡切换时,也会使用到key属性,其目的也是为了让vue可以区分它们,否则vue只会替换其内部属性而不会触发过渡效果。
4. 模板编译
- 会将template编译成一个 render函数,里面是with语法的函数体(类似于h函数),最后返回vnode。
- 基于vnode在执行patch和diff。
- 使用webpack-vue-loader,会在开发环境编译模板
const template = `
<div id="div1" class="container">
<img :src="imgUrl"/>
</div>`
with(this){return _c('div', // 标签
{staticClass:"container",attrs:{"id":"div1"}}, // 属性
[
_c('img',{attrs:{"src":imgUrl}})])} // 子元素
5. 组件渲染/更新过程
- 初次渲染过程
- 解析模板为render函数(或在开发环境已完成, vue-loader)
- 触发响应式,监听data属性getter,setter
- 执行render函数,生成vnode,path(elem, vnode)
- 更新过程
- 修改data,触发setter(此前在getter中已被监听)
- 重新执行render函数,生成newVnode
-
patch(vnode, newvnode)
6. 异步渲染
- $nextTick
- 汇总data的修改,一次性更新视图
- 减少DOM操作次数,提高性能