Vue
Vue 的问题比较杂乱
目录
说说你对 SPA 单页面的理解,它的优缺点分别是什么?
SPA( single-page application )仅在 Web 页面初始化时加载相应的 HTML、JavaScript 和 CSS。一旦页面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转;取而代之的是利用路由机制实现 HTML 内容的变换,UI 与用户的交互,避免页面的重新加载。
优点:
- 用户体验好、快,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染;
- 基于上面一点,SPA 相对对服务器压力小;
- 前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理;
缺点:
- 初次加载耗时多:为实现单页 Web 应用功能及显示效果,需要在加载页面的时候将 JavaScript、CSS 统一加载,部分页面按需加载;
- 前进后退路由管理:由于单页应用在一个页面中显示所有的内容,所以不能使用浏览器的前进后退功能,所有的页面切换需要自己建立堆栈管理;
- SEO 难度较大:由于所有的内容都在一个页面中动态替换显示,所以在 SEO 上其有着天然的弱势。
Vue 生命周期
什么是 Vue 生命周期?
Vue实例从创建到销毁的过程,就是生命周期。也就是从开始创建、初始化数据、编译模板、挂载 Dom -> 渲染、更新 -> 渲染、卸载等一系列过程。
Vue 生命周期的作用是什么?
它的生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻辑。
Vue 生命周期总共有几个阶段?
| 生命周期 | 描述 |
|---|---|
beforeCreate | 组件实例被创建之初,组件的属性生效之前 |
created | 组件实例已经完全创建,属性也绑定,但真实 dom 还没有生成,$el 还不可用 |
beforeMount | 在挂载开始之前被调用:相关的 render 函数首次被调用 |
mounted | el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子 |
beforeUpdate | 组件数据更新之前调用,发生在虚拟 DOM 打补丁之前 |
update | 组件数据更新之后 |
activited | keep-alive 专属,组件被激活时调用 |
deadctivated | keep-alive 专属,组件被销毁时调用 |
beforeDestory | 组件销毁前调用 |
destoryed | 组件销毁后调用 |
生命周期示意图

第一次页面加载会触发哪几个钩子?
第一次页面加载时会触发 beforeCreate, created, beforeMount, mounted 这几个钩子
DOM 渲染在哪个周期中就已经完成?
DOM 渲染在 mounted 中就已经完成了
每个生命周期适合哪些场景?
生命周期钩子的一些使用方法:
beforecreate : 可以在这加个 loading 事件,在加载实例时触发
created : 初始化完成时的事件写在这里,如在这结束 loading 事件,异步请求也适宜在这里调用
mounted : 挂载元素,获取到 DOM 节点
updated : 如果对数据统一处理,在这里写上相应函数
beforeDestroy : 可以做一个确认停止事件的确认框
nextTick : 更新数据后立即操作 dom
vue-router 如何实现路由懒加载
懒加载简单来说就是延迟加载或按需加载,即在需要的时候的时候进行加载。
常用懒加载有两种方式:即使用 vue 异步组件和 ES 中的 import。
未使用懒加载是 vue 的 component 需要在 router 中先 import 进来,如下:
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
}
]
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
vue 异步组件实现懒加载
import Vue from 'vue'
import Router from 'vue-router' /* 此处省去之前导入的HelloWorld模块 */
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: resolve => require(['@/components/HelloWorld'], resolve)
}
]
})
2
3
4
5
6
7
8
9
10
11
12
13
ES6 的 import 方法
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: () => import('@/components/HelloWorld')
}
]
})
2
3
4
5
6
7
8
9
10
11
12
组件懒加载同路由懒加载
结论:路由和组件的常用两种懒加载方式:
- vue异步组件实现路由懒加载
component:resolve=>(['需要加载的路由的地址',resolve])
- es提出的import(推荐使用这种方式)
const HelloWorld = ()=>import('需要加载的模块地址')
vue 的单向数据流
所有的prop都使得其父子prop之间形成了一个单向下行绑定:父级prop的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。
额外的,每次父级组件发生更新时,子组件中所有的prop都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变prop。如果你这样做了,Vue会在浏览器的控制台中发出警告。子组件想修改时,只能通过$emit派发一个自定义事件,父组件接收到后,由父组件修改。
这个 prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用
在这种情况下,最好定义一个本地的 data 属性并将这个 prop 用作其初始值:
props: ['initialCounter'],
data: function () {
return {
counter: this.initialCounter
}
}
2
3
4
5
6
这个 prop 以一种原始的值传入且需要进行转换
在这种情况下,最好使用这个 prop 的值来定义一个计算属性
props: ['size'],
computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}
2
3
4
5
6
v-show 与 v-if 区别
v-show是 css 切换,v-if是完整的销毁和重新创建
使用频繁切换时用v-show,运行时较少改变时用v-if
v-if=‘false’ v-if是条件渲染,当false的时候不会渲染
开发中常用的指令有哪些
v-model:一般用在表达输入,很轻松的实现表单控件和数据的双向绑定
v-html: 更新元素的 innerHTML
v-show与v-if: 条件渲染
v-on:click: 可以简写为@click,@绑定一个事件。如果事件触发了,就可以指定事件的处理函数
v-for:基于源数据多次渲染元素或模板块
v-bind: 当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM
语法:v-bind:title="msg" 简写::title="msg"
绑定 class 的数组用法
对象方法 v-bind:class="{'orange': isRipe, 'green': isNotRipe}"
数组方法 v-bind:class="[class1, class2]"
行内 v-bind:style="{color: color, fontSize: fontSize+'px' }"
组件之间的传值通信
父组件给子组件传值
使用 props,父组件可以使用 props 向子组件传递数据
子组件向父组件通信
父组件向子组件传递事件方法,子组件通过$emit 触发事件,回调给父组件
非父子,兄弟组件之间通信
可以通过实例一个 vue 实例 Bus 作为媒介,要相互通信的兄弟组件之中,都引入 Bus,然后通过分别调用 Bus 事件触发和监听来实现通信和参数传递
路由跳转方式
<router-link to='home'>router-link 标签会渲染为<a>标签,咋填 template 中的跳转都是这种- 另一种是编程是导航 也就是通过 js 跳转 比如
router.push('/home')
MVVM
M - Model,Model 代表数据模型,也可以在 Model 中定义数据修改和操作的业务逻辑
V - View,View 代表 UI 组件,它负责将数据模型转化为 UI 展现出来
VM - ViewModel,ViewModel 监听模型数据的改变和控制视图行为、处理用户交互,简单理解就是一个同步 View 和 Model 的对象,连接 Model 和 View
computed 和 watch 有什么区别?
watch 和 computed 都可以用来监控某个属性值的变化
computed:
- computed 是计算属性,也就是计算值,它更多用于计算值的场景
- computed 具有缓存性,computed 的值在 getter 执行后是会缓存的,只有在它依赖的属性值改变之后,下一次获取 computed 的值时才会重新调用对应的 getter 来计算
- computed 适用于计算比较消耗性能的计算场景
watch:
- 更多的是「观察」的作用,类似于某些数据的监听回调,用于观察 props $emit 或者本组件的值,当数据变化时来执行回调进行后续操作
- 无缓存性,页面重新渲染时值不变化也会执行
小结
- 当我们要进行数值计算,而且依赖于其他数据,那么把这个数据设计为 computed
- 如果你需要在某个数据变化时做一些事情,使用 watch 来观察这个数据变化
key
key是为 Vue 中的 vnode 标记的唯一 id,通过这个key,我们的diff操作可以更准确、更快速
准确
如果不加key,那么Vue会选择复用节点(Vue的就地更新策略),导致之前节点的状态被保留下来,会产生一系列的 bug
快速
key的唯一性可以被Map数据结构充分利用
组件中的 data 为什么是函数
因为组件是用来复用的,JS 里对象是引用关系,这样作用域没有隔离,而 new Vue 的实例,是不会被复用的,因此不存在引用对象问题。
keep-alive
keep-alive是Vue内置的一个组件,可以使被包含的组件保留状态,避免重新渲染,其有以下特性:
- 一般结合路由和动态组件一起使用,用于缓存组件。
- 提供
include和exclude属性,两者都支持字符串或正则表达式,include表示只有名称匹配的组件会被缓存,exclude表示任何名称匹配的组件都不会被缓存 ,其中exclude的优先级比include高。 - 对应两个钩子函数
activated和deactivated,当组件被激活时,触发钩子函数activated,当组件被移除时,触发钩子函数deactivated。
v-model 的原理
vue项目中主要使用v-model指令在表单input、textarea、select等元素上创建双向数据绑定,我们知道v-model本质上不过是语法糖,v-model在内部为不同的输入元素使用不同的属性并抛出不同的事件:
text和textarea元素使用value属性和input事件;
checkbox和radio使用checked属性和change事件;
select字段将value作为prop并将change作为事件;
以input表单元素为例:
<input v-model='something'>
复制代码相当于
<input v-bind:value="something" v-on:input="something = $event.target.value">
复制代码如果在自定义组件中,v-model 默认会利用名为value的prop和名为input的事件,如下所示:
父组件:
<ModelChild v-model="message"></ModelChild>
子组件:
<div>{{value}}</div>
props:{
value: String
},
methods: {
test1(){
this.$emit('input', '小红')
},
}
2
3
4
5
6
7
8
9
nextTick()
在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后,立即使用的这个回调函数,获取更新后的 DOM。
// 修改数据
vm.msg = 'Hello'
// DOM 还未更新
Vue.nextTick(function () {
// DOM 更新
})
2
3
4
5
6
vue 组件
组件是一个 vue 实例
vue 插槽
vuex 工作原理及内容
先给出结论:vuex中的store本质就是没有template的隐藏着的vue组件
核心概念:
- State
- Getter
- Mutation
- Action
- Module
vue 项目优化
1. 代码层面的优化
v-if和v-show区分使用场景computed和watch区分使用场景v-for遍历必须为item添加key,且避免同时使用v-if- 长列表性能优化
- 事件的销毁
- 图片资源懒加载
- 路由懒加载
- 第三方插件的按需引入
- 优化无限列表性能
- 服务端渲染 SSR or 预渲染
2. webpack层面的优化
Webpack对图片进行压缩- 减少
ES6转为ES5的冗余代码 - 提取公共代码
- 模板预编译
- 提取组件的
CSS - 优化
SourceMap - 构建结果输出分析
Vue项目的编译优化
3.基础的 Web 技术的优化
- 开启
gzip压缩 - 浏览器缓存
CDN的使用- 使用
Chrome Performance查找性能瓶颈