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 预渲染
webpack
层面的优化
2. Webpack
对图片进行压缩- 减少
ES6
转为ES5
的冗余代码 - 提取公共代码
- 模板预编译
- 提取组件的
CSS
- 优化
SourceMap
- 构建结果输出分析
Vue
项目的编译优化
3.基础的 Web 技术的优化
- 开启
gzip
压缩 - 浏览器缓存
CDN
的使用- 使用
Chrome Performance
查找性能瓶颈