2019年实习时的 VueJS基础知识 备份
介绍
- Vue 是一套用于构建用户界面的渐进式框架,数据驱动视图,只关注视图层,采用自底向上增量开发的设计。
使用方式
1 | // 原生引入 |
开发规范
- 组件名为多个单词
- 私有 property 名使用 $_ 前缀,并附带一个命名空间以避免冲突。
- 单文件组件的文件名始终单词大写开头,或者横线链接。
- 特定样式和约定组件全部以一个特定的前缀开头
- 和父组件紧密耦合的子组件应该以父组件名作为前缀命名
- 组件名倾向完整单词,避免缩写。
生命周期
基本顺序
创建→挂载→更新→销毁
具体步骤
State | Description |
---|---|
beforeCreate | 创建前:此阶段为实例初始化,此时的数据观察和事件机制都未形成,不能获得 DOM 节点。 |
created | 创建后:实例初始化完毕,页面还没开始渲染,但可以操作数据(data,prop,发送请求获取数据)。 |
beforeMount | 挂载前:在这一阶段,我们虽然依然得不到具体的 DOM 元素,但 vue 挂载的根节点已经创建,之后对 DOM 的操作将围绕这个根元素继续进行,这个阶段是过渡性的,一般一个项目只能用到一两次。 |
mounted | 挂载后:在这个阶段,数据和 DOM 都已被渲染。 |
beforeUpdate | 更新前:这一阶段遵循数据驱动 DOM 的原则,函数在数据更新后虽然没立即更新数据,但是 DOM 中的数据会改变 |
updated | 更新后:在这一阶段 DOM 会和更改过的内容同步。 |
beforeDestroy | 销毁前:在上一阶段 vue 已经成功的通过数据驱动 DOM 更新,当我们不再需要 vue 操纵 DOM 时,就要销毁 vue ,也就是清除 vue 实例与 DOM 的关联,调 destroy 方法可以销毁当前组件,在销毁前会触发 beforeDestroy 钩子函数。(此时记得解除绑定事件,销毁定时器与全局变量等等。) |
destroyed | 销毁后:在销毁后,会触发 destroyed 钩子函数。 |
- 生命周期图示
父子组件执行顺序
- 加载渲染过程
父beforeCreate→父created→父beforeMount→子beforeCreated→子created→子beforeMount→子mounted→父mounted
- 更新过程
父beforeUpdate→子beforeUpdate→子updated→父updated
- 销毁过程
父beforeDestroy→子beforeDestroy→子destroyed→父destroyed
常用指令
v-text 文本填充
示例:
1 | <span v-text="msg"></span> |
v-html html填充
示例:
1 | <div v-html="rawHtml"></div> |
v-bind 动态地绑定一个或多个特性,或一个组件 prop 的表达式。
示例:
1 | <div id="app"> |
v-on 用于监听指定元素的 DOM 事件,绑定事件监听器。
- 常用 v-on 事件
Name | Description | Name | Description |
---|---|---|---|
click | 点击元素 | mouseenter | 鼠标移入元素 |
dbclick | 双击元素 | mouseleave | 鼠标移出元素 |
focus | 元素获得焦点 | mousemove | 鼠标在元素内移动 |
blur | 元素失去焦点 | mousedown | 在元素上按下鼠标 |
keydown | 按下键盘 | mouseup | 在元素上释放鼠标 |
keyup | 释放键盘 | submit | 提交元素 |
input | 在元素内输入内容 | scroll | 滚动元素 |
示例:
1 | <div id="app"> |
v-model 实现表单输入和应用状态之间的双向绑定。
示例:
原理:<input type="text" :value="datax" @input="datax = $event.target.value">
1 | <div id="app"> |
v-for 循环遍历,基于一个数组或者对象渲染一个列表。
示例:
有以下两种遍历方式
1 | <div v-for="(item,index) in items"></div> //使用in,index是一个可选参数,表示当前项的索引。 |
v-if 根据表达式的值的真假条件渲染元素
示例:
1 | <div v-if="ok">yes</div> |
v-else 搭配v-if使用
示例:
1 | <div v-if="ok">yes</div> |
v-show 根据表达式的真假值展示元素
示例:
1 | <h1 v-show="ok">hello world</h1> |
v-pre 跳过这个元素和它的子元素的编译过程
示例:
1 | <div id="app"> |
v-once 只渲染元素和组件一次
示例:
1 | <span v-once>This will never change:{{msg}}</span> //单个元素 |
常用于处理 DOM 事件的事件修饰符
Instructions | Description |
---|---|
.stop | 阻止事件继续传播 |
.prevent | 事件不再重载页面 |
.capture | 使用事件捕获模式,即元素自身触发的事件先在此处处理,然后才交由内部元素进行处理。 |
.self | 只当在 event.target 是当前元素自身时触发处理函数 |
.once | 事件将只会触发一次 |
.passive | 告诉浏览器你不想阻止事件的默认行为 |
@keyup.enter.native="toNextInput"
常用按键绑定
常用属性
- el:指示 vue 编译器从什么地方开始解析 vue 语法,相当于一个占位符。
- data:组织从 view 中抽象出来的属性,将视图的数据抽象出来存放在 data 中。
- template:设置模板,可以用于替换页面元素。
- method:放置页面中的业务逻辑,js 方法一般都放在 method 中。
- render:创建真正的 Virtual Dom。
- computed:根据已经存在的属性计算出新的属性,对于相同的数据会缓存,当依赖的属性值发生变化时,这个属性的值也会自动更新。
- watch:监听 data 中的数据变化。
过滤器
- 在两个大括号中
{{message | capitalize}}
- 在 v-bind 指令中
v-bind:id="rawId | formatId"
- 串联
{{message | filterA | filter}}
- 接受参数
{{message | filterA('arg1',arg2)}}
计算属性和监听器
计算属性
- computed
- 属性默认只有 getter,不过在需要的时候也可以提供一个 setter。
- computed 和 methods 的区别:computed 是基于依赖缓存,只有相关依赖发生改变时才会重新取值。methods 是在重新渲染的时候,函数总会重新调用执行。
示例:
1 | <template> |
监听属性
- watch 实时监听数据变化并改变自身的值。
- 允许执行异步操作,限制执行该操作频率。
示例:
1 | watch: { |
computed/watch 区别
computed
- 支持缓存,只有依赖数据发生改变,才会重新进行计算。
- 不支持异步,当 computed 内有异步操作时无效,无法监听数据的变化。
- computed 属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于 data 中声明过或者父组件传递的 props 中的数据通过计算得到的值。
- 如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个多对一或者一对一,一般用 computed
- 如果 computed 属性属性值是函数,那么默认会走 get 方法,函数的返回值就是属性的属性值。在 computed 中的,属性都有一个 get 和一个 set 方法(自己配置),当数据变化时,调用 set 方法。
watch
- 不支持缓存,发生改变,直接会触发监听事件。
- watch 支持异步;
- 监听的函数接收两个参数,第一个参数是最新的值,第二个参数是输入之前的值。
- 当一个属性发生变化时,需要执行对应的操作。
- 监听数据必须是data中声明过或者父组件传递过来的 props 中的数据,当数据变化时,触发其他操作,函数有两个参数:
- immediate:组件加载立即触发回调函数执行。
- deep:深度监听,为了发现对象内部值的变化,复杂类型的数据时使用,例如数组中的对象内容的改变(监听数组的变动不需要这么做)。注意:Vue 2 中 deep 无法监听到数组的变动和对象的新增,参考 Vue 数组更新检测,只有以响应式的方式触发才会被监听到。
响应式原理
- 官方文档介绍如下
当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data
选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty
把这些 property 全部转为 getter/setter。Object.defineProperty
是 ES5 中一个无法 shim 的特性,这也就是 Vue 不支持 IE8 以及更低版本浏览器的原因。
这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更。这里需要注意的是不同浏览器在控制台打印数据对象时对 getter/setter 的格式化并不同,所以建议安装 vue-devtools 来获取对检查数据更加友好的用户界面。
每个组件实例都对应一个 watcher
实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。
- 博主 BB
Vue 2
文档中提到:由于 JavaScript 的限制,Vue 不能检测数组和对象的变化。尽管如此我们还是有一些办法来回避这些限制并保证它们的响应性。
其实出现这个问题的主要原因就是 Object.defineProperty
,因为 Object.defineProperty
是采用数据劫持的方式进行数据监听,即必须提供监听数据的 key
,才能进行数据拦截并监听,但是数组对象是变化的,所以存在这个缺陷。而 ES6 中的 Proxy
,是通过直接代理数据的方式进行监听,所以没有此问题。
另外 Vue 3
中,Object.defineProperty
已改用为 ES6 Proxy
。官方文档说明,当我们从一个组件的 data
函数中返回一个普通的 JavaScript 对象时,Vue 会将该对象包裹在一个带有 get 和 set
处理程序的 Proxy
中。Proxy
是在 ES6 中引入的,它使 Vue 3
避免了 Vue 早期版本中存在的一些响应性问题。
虚拟 DOM
前面响应式原理中有提到虚拟 DOM(Virtual DOM),那么如何理解它呢?
虚拟 DOM 其实就是用普通 JavaScript 对象来描述 DOM 结构,因为不是真实DOM,所以称之为虚拟 DOM。
虚拟 DOM 是相对于浏览器所渲染出来的真实 DOM 而言的,在 React/Vue
等技术出现之前,我们要改变页面展示的内容只能通过遍历查询 DOM 树的方式找到需要修改的 DOM 然后修改样式行为或者结构,来达到更新页面的目的。
DOM 树的实现模块和 JavaScript 模块是分开的,这些跨模块的通讯增加了资源耗费成本,而且这种方式操作会引起浏览器的回流和重绘,使得性能开销巨大,同时每次查询 DOM 几乎都需要遍历整颗 DOM 树。
但若建立一个与 DOM 树对应的虚拟 DOM 对象( JavaScript 对象),以对象嵌套的方式来表示 DOM 树及其层级结构,那么每次 DOM 的更改就变成了对 DOM 对象的属性的增删改查,这样一来查找 JavaScript 对象的属性变化要比查询 DOM 树的性能开销小。
所以 React/Vue 都采用虚拟 DOM 的方式来渲染页面,当监测页面触发了渲染事件或者数据变化后,会重新生成一个新的虚拟 DOM,然后对比新旧虚拟 DOM 进行渲染,至于渲染方案与生成方案需要自己去了解啦。
nextTick
将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。它跟全局方法 Vue.nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上。
因为 Vue 实现响应式并不是数据发生变化之后 DOM 立即变化,所以若要在视图更新之后,基于新的视图进行操作,则需要用到 nextTick。
- 使用
1 | this.testText = '更新后文本'; |
组件
组件的定义使用
示例:
1 | //定义一个 <vue-demo> 组件 |
父子组件的传值方式
- props/$emit
- 父组件传值给子组件:父组件通过一个属性,将其 data 上的值于该属性进行绑定,子组件通过 props 接受这个属性,就能获取这个属性的值。
- 子组件传值给父组件:子组件通过实践触发的方式向父组件传值,当子组件的数值发生变化时,向外发射一个事件,然后父组件监听该事件名称,并在父组件的 data中去定义这个函数名的函数体
- 注册组件
- 全局组件:所有实例都能使用。
- 局部组件:只能在实例的选项中使用。
- Prop。
- Prop 验证:type 可以是原生构造器,也可以是自定义构造器。
- 自定义事件。
- 父组件使用 props 传递数据给子组件,子组件将数据传递回去则需要使用到自定义事件。
- 使用 v-on 绑定自定义事件,每个 Vue 实例都实现了事件接口(Events interface)。
- 父组件可以在使用子组件的地方直接用 v-on 监听子组件触发的事件。
- $children/$parent
- provide/inject
- $refs
- eventBus 思否、知乎
- Vuex
- html5Storage
- $attrs/$listeners
props/methods/data/computed/watch 优先级
1 | // 通过 src\core\instance\init.js 源码 |
我们可以看到优先级是
props > methods > data > computed > watch
自定义指令
除了默认设置的核心指令( v-model 和 v-show),Vue 也允许注册自定义指令。
钩子函数
Funtion | Description |
---|---|
bind | 只调用一次,指令第一次绑定到元素时调用. |
inserted | 被绑定元素插入父节点时调用 |
update | 被绑定元素所在的模板更新时调用 |
componentUpdated | 被绑定元素所在模板完成一次更新周期时调用 |
unbind | 只调用一次,指令与元素解绑时调用。 |
钩子函数参数
Parameter | Description |
---|---|
el | 指令所绑定的元素,可以直接用来操作 DOM。 |
binding | 一个对象 |
vnode | Vue 编译生成的虚拟节点 |
oldVnode | 上一个虚拟节点,仅在 update 和 componentUpdateed 中可用。 |
binding属性
Attribute | Description |
---|---|
name | 指令名 |
value | 指令的绑定值 |
oldValue | 指令绑定的前一个值 |
expression | 绑定值的表达式或变量名 |
arg | 传给指令的参数 |
modifiers | 一个包含修饰符的对象 |
路由(Route)
router-link 是一个用于设置一个导航链接的组件,实现路由的跳转。
相关属性
Attribute | Description |
---|---|
to | 目标路由的链接 |
replace/push | 调用 router.replace(),导航后不会留下 history 记录。 |
append | 在当前(相对)路径前添加其路径 |
tag | 将 |
active-class | 设置链接激活时使用的 CSS 类名 |
exact-active-class | 配置当链接被精确匹配的时候应该激活的 class |
event | 声明可以用来除法导航的事件 |
router-view 是一个用于渲染页面的组件,实现指定路由对应组件的渲染,相当于一个占位的作用,配合 router-link 使用
配置示例
1 | import Vue from 'vue'; |
使用模板
1 | <template> |
路由跳转
模板调用
1 | // 不带参数 |
函数调用
1 | // 不带参数 |
过渡与动画
语法格式
1 | <transition name="nameoftransition"> |
切换类
Class | Description |
---|---|
v-enter | 定义进入过渡的开始状态 |
v-enter-active | 定义进入过渡生效时的状态 |
v-enter-to | 定义进入过渡的结束状态 |
v-leave | 定义离开过渡的开始状态 |
v-leave-active | 定义离开过渡生效时的状态 |
v-leave-to | 定义离开过渡的结束状态 |
自定义过渡的类名
- enter-class
- enter-active-class
- enter-to-class (2.1.8+)
- leave-class
- leave-active-class
- leave-to-class (2.1.8+)
同时使用过渡和动画
- 必须设置相应的时间监听器来知道过渡的完成
- 监听器可以是 transitionend 或 animationend
- 同时设置两种过渡效果时,需使用 type 特性设置 animation 或 transition 来明确声明需要监听的类型
全局状态管理(Vuex)
基础示例
1 | import Vue from 'vue'; |
模块化示例
1 | //参考 [https://gitee.com/doubleam/biugle/tree/main/resources/js/store] |
引入与使用
1 | import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'; |
其他
main 模板
1 | import Vue from 'vue'; |
basic.vue 模板
1 | <template> |
待补充
- 自定义指令
- 更多传值方式(前面提到未[举栗子])
- 混入
- 插槽
- 路由钩子与鉴权机制实现
- SSR
- Vue-cli
篇幅有限,这些需自己深入了解啦。