# 技术栈知识点巩固——Vue
Posted 爱码代码的喵
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了# 技术栈知识点巩固——Vue相关的知识,希望对你有一定的参考价值。
技术栈知识点巩固——Vue
Vue 概念
Vue
是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue
被设计为可以自底向上逐层应用。Vue
的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue
也完全能够为复杂的单页应用提供驱动。
Vue核心
Vue.js
的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进DOM
的系统。
MVVM 模型
Mode-View-ViewModel
Model
代表数据模型、View
代表UI
组件、ViewModel
是View
和Model
层的桥梁,数据会绑定到viewModel
层并自动将数据渲染到页面中,视图变化的时候会通知viewModel
层更新数据
Vue 生命周期
Vue
实例有⼀个完整的⽣命周期,也就是从开始创建、初始化数据、编译模版、挂载Dom
-> 渲染、更新 -> 渲染、卸载 等⼀系列过程,称这是Vue
的⽣命周期。
beforeCreate(创建前)
- 组件实例被创建之初,组件的属性生效之前
created(创建后)
- 组件实例已经完全创建,属性也绑定,真实
dom
还没有生成,$el
还不可用
beforeMount(挂载前)
- 在挂载开始之前被调用:相关的
render
函数被首次调用
mounted(挂载后)
- 在
el
被新创建的vm.$el
替换,并挂载到实例上去之后调用该钩子
beforeUpdate(更新前)
- 组件数据更新之前调用,真实
DOM
还没被渲染
updated(更新后)
- 组件数据更新之后
activated(激活前)
keep-alive
专属,组件被激活时调用
deactivated(激活后)
keep-alive
专属,组件被销毁时调用
beforeDestory(销毁前
- 组件销毁前调用
destoryed(销毁后)
- 组件销毁前调用
Vue 父向子传值
-
遵守单向数据流原则
-
prop
向下传递
Vue 子向父传值
-
遵守单向数据流原则
-
事件
向上传递,使用$on(evntName)
监听事件;使用$emit(eventName,optionalPayload)
触发事件。另外,父组件可以在使用子组件的地方直接用v-on
来监听子组件触发的事件。
父子组件生命周期顺序
- 执行顺序:父组件先创建,然后子组件创建;子组件先挂载,然后父组件挂载,即
父beforeCreate-> 父create -> 子beforeCreate-> 子created -> 子mounted -> 父mounted
非父子组件通信
-
使用
EventBus
-
EventBus.js
import Vue from 'vue'
export default new Vue()
- 发送数据
import eventBus from './EventBus'
methods:
pushMsg()
// 通过事件总线发送消息
eventBus.$emit('pushMsg',this.childNum++)
- 接收数据
mounted()
// 通过事件总线监听消息
eventBus.$on('pushMsg', (children1Msg) =>
this.msg = children1Msg
)
Vue.$nextTick()
- 参数:
Function[callback]
- 用法:将回调延迟到下次
DOM
更新循环之后执行。在修改数据之后立即使用它,然后等待DOM
更新。它跟全局方法Vue.nextTick
一样,不同的是回调的this
自动绑定到调用它的实例上。
示例
<!DOCTYPE html>
<html>
<body>
<head>
<script src="./js/vue.js"></script>
</head>
<div id="app">
<p id="msg">message</p>
<button @click="change">更新</button>
</div>
</body>
</html>
<script>
var app = new Vue(
el: '#app',
data:
message: 'Hello Vue!'
,
methods:
change()
this.message = 'This is new message!';
console.log('not nextTick():', document.getElementById("msg").innerHTML);
)
</script>
-
console.log
预期应该输出not nextTick():This is new message!
但是输出的是not nextTick(): Hello Vue!
-
Vue
在更新DOM
的时候,是异步执行的。只要监听到数据变化,vue
将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个watcher
被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和DOM
操作是非常重要的。然后,在下一个的事件循环tick
中,Vue
刷新队列并执行实际 (已去重的) 工作。
使用
- 立即输出更新后的值
change()
this.message = 'This is new message!';
this.$nextTick(()=>
console.log('use nextTick():',document.getElementById("msg").innerHTML);
)
console.log('not nextTick():',document.getElementById("msg").innerHTML);
- 使用
this.$nextTick()
之所以能获取到更新后的值,并不是改变了vue
的渲染流程,而是改变了获取最新值的时间,并不是立即获取,而是等vue
渲染完后再获取,即异步获取
Computed
- 支持缓存,只有依赖的数据发生变化,才会重新计算
- 不支持异步,当
Computed
中有异步操作时,无法监听数据的变化 Computed
的值默认会走缓存- 如果一个属性是由其他属性计算而来的,这个属性依赖其他的属性,一般会使用
computed
- 如果
computed
属性的属性值是函数,那么默认使用get
方法,函数的返回值就是属性的属性值;在computed
中,属性有一个get
方法和一个set
方法,当数据发生变化时,会调用set
方法。
Watch
- 不支持缓存,数据变化时,触发相应的操作
- 支持异步监听
- 监听的函数接收两个参数,第一个时参数的新值,第二个是变化之前的值
- 监听数据必须是
data
中声明的或者父组件传递过来的props
中的数据,当发生变化时,会触发其他操作,函数有两个的参数:immediate
:组件加载立即触发回调函数deep
:深度监听,发现数据内部的变化,在复杂数据类型中使用,例如数组中的对象发生变化。需要注意的是,deep
无法监听到数组和对象内部的变化。
// 监听基本数据类型
watch:
value ()
// do something
// 监听引用数据类型
watch:
obj:
handler () // 执行回调
// do something
,
deep: true, // 是否进行深度监听
immediate: true // 是否初始执行handler函数
常见的事件修饰符
.stop
:等同于javascript
中的event.stopPropagation()
,防止事件冒泡;.prevent
:等同于JavaScript
中的event.preventDefault()
,防止执行预设的行为(如果事件可取消,则取消该事件,而不停止事件的进一步传播);.capture
:与事件冒泡的方向相反,事件捕获由外到内;.self
:只会触发自己范围内的事件,不包含子元素;.once
:只会触发一次。
v-show、v-if
-
v-show
隐藏则是为该元素添加css--display:none
,dom
元素依旧还在。v-if
显示隐藏是将dom
元素整个添加或删除 -
v-if
切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件;v-show
只是简单的基于css
切换 -
v-if
是真正的条件渲染,它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。只有渲染条件为假时,并不做操作,直到为真才渲染 -
v-show
由false
变为true
的时候不会触发组件的生命周期 -
v-if
由false
变为true
的时候,触发组件的beforeCreate
、create
、beforeMount
、mounted
钩子,由true
变为false
的时候触发组件的beforeDestory
、destoryed
方法 -
v-if
有更高的切换消耗;v-show
有更高的初始渲染消耗;
Vue 动态组件
Vue.js
提供了一个特殊的元素<component>
用来动态地挂载不同的组件 使用is
属性来选择要挂载的组件。
<template>
<div>
<h1>vue 动态组件使用</h1>
<button @click="changeView('A')">切换到组件A</button>
<button @click="changeView('B')">切换到组件B</button>
<button @click="changeView('C')">切换到组件C</button>
<component :is="currentView"></component>
</div>
</template>
<script>
export default
components:
componentA:
template: '<div>组件A</div>'
,
componentB:
template: '<div>组件B</div>'
,
componentC:
template: '<div>组件C</div>'
,
data ()
return
currentView: 'componentA'
,
methods:
changeView (val)
this.currentView = 'component' + val
</script>
keep-alive
keep-alive
可以实现组件缓存,当组件切换时不会对当前组件进行卸载。- 常用的两个属性
include/exclude
,允许组件有条件的进行缓存。 - 两个生命周期
activated/deactivated
,用来得知当前组件是否处于活跃状态。 keep-alive
的中还运用了LRU(Least Recently Used)
算法。
不需要响应式的数据应该怎么处理
// 方法一:将数据定义在data之外
data ()
this.list1 = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
return
// 方法二:Object.freeze()
data ()
return
list1: Object.freeze(xxxxxxxxxxxxxxxxxxxxxxxx),
Vue中双向数据绑定实现
vue
双向数据绑定是通过 数据劫持 结合 发布订阅模式的方式来实现的, 也就是说数据和视图同步,数据发生变化,视图跟着变化,视图变化,数据也随之发生改变;核心:关于VUE
双向数据绑定,其核心是Object.defineProperty()
方法。- 使用
Object.defineProperty()
来定义属性的set函数,属性被赋值的时候,修改Input
的value
值以及span
中的innerHTML
;然后监听input
的keyup
事件,修改对象的属性值,即可实现这样的一个简单的数据双向绑定。
<!DOCTYPE html>
<html>
<head>
<script src="./js/vue.js"></script>
</head>
<body>
<h2>Vue 双向绑定</h2>
<input type="text" id="textInput" />
输入:<span id="textSpan"></span>
</body>
<script>
let obj = ;
let textInput = document.getElementById("textInput");
let textSpan = document.getElementById("textSpan");
Object.defineProperty(obj, "foo",
set: function (newValue)
textInput.value = newValue;
textSpan.innerHTML = newValue;
,
);
textInput.addEventListener("keyup", function (e)
obj.foo = e.target.value;
);
</script>
</html>
Vue 优化
编码阶段
-
尽量减少
data
中的数据,data
中的数据都会增加getter
和setter
,会收集对应的watcher
-
v-if
和v-for
不能连用 -
如果需要使用
v-for
给每项元素绑定事件时使用事件代理 -
SPA
页面采用keep-alive
缓存组件 -
在更多的情况下,使用
v-if
替代v-show
-
key
保证唯一 -
使用路由懒加载、异步组件
-
防抖、节流
-
第三方模块按需导入
-
长列表滚动到可视区域动态加载
-
图片懒加载
SEO优化
- 预渲染
- 服务端渲染
SSR
打包优化
- 压缩代码
Tree Shaking
/Scope Hoisting
- 使用
cdn
加载第三方模块 - 多线程打包
happypack
splitChunks
抽离公共文件sourceMap
优化
v-model
v-model
用于表单数据的双向绑定,是一个语法糖v-bind
绑定一个value
属性v-on
指令给当前元素绑定input
事件
<input v-model="sth" />
<input v-bind:value="sth" v-on:input="sth = $event.target.value" />
vue组件中data是一个函数
- 组件中的
data
是一个函数数据以函数返回值的形式定义,这样每次复用组件的时候,都会返回一份新的data
,每个组件都会有自己私有的数据空间,他们只负责各自维护的数据,不会造成混乱。
vue-router 钩子
全局路由钩子
router.beforeResolve
: 在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,该钩子函数就被调用router.afterEach
: 路由改变后的钩子
beforeEach(to,from,next)
afterEach(to,from,next)
单个路由钩子
- 可以在路由配置上直接定义
beforeEnter
cont router = new Router(
routes: [
path: '/file',
component: File,
beforeEnter: (to, from ,next) =>
// do someting
]
);
组件内路由钩子
beforeRouteEnter
不能获取组件实例this
,因为当守卫执行前,组件实例被没有被创建出来,剩下两个钩子则可以正常获取组件实例this
methods: ,
beforeRouteLeave (to, from, next)
beforeRouteEnter
在进入当前组件对应的路由前调用beforeRouteUpdate
在当前路由改变,但是该组件被复用时调用beforeRouteLeave
在离开当前组件对应的路由前调用
单向数据流和双向数据流
-
单向数据流是指数据只能从父级向子级传递数据,子级不能改变父级向子级传递的数据。
-
双向数据流是指数据从父级向子级传递数据,子级可以通过一些手段改变父级向子级传递的数据。
-
比如用
v-model
、.sync
来实现双向数据流。
vue-loader
- 基于
webpack
的一个的loader
,解析和转换.vue
文件,提取出其中的逻辑代码script
、样式代码style
、以及HTML
模版template
,再分别把它们交给对应的Loader
去处理,核心的作用,就是提取,划重点。
Vue属性改变页面不刷新
-
Vue
不允许在已经创建的实例上动态添加新的响应式属性若想实现数据与视图同步更新,可采取下面三种解决方案: -
Vue.set()
-
Object.assign()
-
$forcecUpdated()
-
如果为对象添加少量的新属性,可以直接采用
Vue.set()
-
如果需要为新对象添加大量的新属性,则通过
Object.assign()
创建新对象 -
如果你实在不知道怎么操作时,可采取
$forceUpdate()
进行强制刷新 (不建议)
Vue mixin 使用
-
混入 (
mixin
) 提供了一种非常灵活的方式,来分发Vue
组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。 -
不同组件中的
mixin
是相互独立的!
局部混入
index.js
export const mixins =
data ()
return
msg: 'vue mixin 测试'
,
computed () ,
created ()
console.log('mixin 中 created 生命周期函数')
,
mounted ()
console.log('mixin 中 mounted生命周期函数')
,
methods:
clickMe ()
console.log('mixin 中 点击事件')
mixin
测试页面
<template>
<div>
<el-button @click="clickMe">点击按钮</el-button>
</div>
</template>
<script>
import mixins from './index.js'
export default
name: 'mixin-vueone',
mixins: [mixins],
components: ,
data ()
return
,
created ()
console.log('组件调用 mixin 数据', this.msg)
,
mounted ()
console.log('我是组件的 mounted 生命周期函数')
,
methods:
</script>
全局混入
main.js
import mixins from "./mixin/index";
Vue.mixin(mixins);
- 谨慎使用全局混入,因为它会影响每个单独创建的
Vue
实例 (包括第三方组件)。大多数情况下,只应当应用于自定义选项,就像上面示例一样。推荐将其作为插件发布,以避免重复应用混入。
优点
- 提高代码复用性
- 无需传递状态
- 维护方便,只需要修改一个地方即可
缺点
- 命名冲突
- 滥用的话后期很难维护
- 不好追溯源,排查问题稍显麻烦
- 不能轻易的重复代码
插槽
- 在一个组件标签中,加入一些内容,那就必须要在组件内声明
slot
元素,否则不会被渲染出来。
默认插槽
- 子组件
<template>
<div>
<h3> title </h3>
<slot name="center">center 部分</slot>
<slot name="fotter">fotter 部分</slot>
</div>
</template>
<script>
export default
name: 'childvueone',
data ()
return
,
props: ['title', 'listData']
</script>
- 父组件
<template>
<div>
<childvueone title="测试1">
<span slot="center">center 的内容1</span>
<a slot="fotter">更多</a>
</childvueone>
<childvueone title="测试2">
<span slot="center">center 的内容</span>
<div slot="fotter">
<span>插槽内容2</span>
</div>
</childvueone>
</div>
</template>
<script>
import childvueone from './childvue-one.vue'
export default
components:
childvueone
,
data ()
return 以上是关于# 技术栈知识点巩固——Vue的主要内容,如果未能解决你的问题,请参考以下文章