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
		}
	]
})
1
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)
		}
	]
})
1
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')
		}
	]
})
1
2
3
4
5
6
7
8
9
10
11
12

组件懒加载同路由懒加载
结论:路由和组件的常用两种懒加载方式:

  1. vue异步组件实现路由懒加载

component:resolve=>(['需要加载的路由的地址',resolve])

  1. 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
  }
}
1
2
3
4
5
6

这个 prop 以一种原始的值传入且需要进行转换

在这种情况下,最好使用这个 prop 的值来定义一个计算属性

props: ['size'],
computed: {
  normalizedSize: function () {
    return this.size.trim().toLowerCase()
  }
}
1
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-showv-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 事件触发和监听来实现通信和参数传递

路由跳转方式

  1. <router-link to='home'> router-link 标签会渲染为<a>标签,咋填 template 中的跳转都是这种
  2. 另一种是编程是导航 也就是通过 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工作原理

  1. computed 是计算属性,也就是计算值,它更多用于计算值的场景
  2. computed 具有缓存性,computed 的值在 getter 执行后是会缓存的,只有在它依赖的属性值改变之后,下一次获取 computed 的值时才会重新调用对应的 getter 来计算
  3. computed 适用于计算比较消耗性能的计算场景

watch:

  1. 更多的是「观察」的作用,类似于某些数据的监听回调,用于观察 props $emit 或者本组件的值,当数据变化时来执行回调进行后续操作
  2. 无缓存性,页面重新渲染时值不变化也会执行

小结

  1. 当我们要进行数值计算,而且依赖于其他数据,那么把这个数据设计为 computed
  2. 如果你需要在某个数据变化时做一些事情,使用 watch 来观察这个数据变化

key

key是为 Vue 中的 vnode 标记的唯一 id,通过这个key,我们的diff操作可以更准确、更快速
准确
如果不加key,那么Vue会选择复用节点(Vue的就地更新策略),导致之前节点的状态被保留下来,会产生一系列的 bug
快速
key的唯一性可以被Map数据结构充分利用

组件中的 data 为什么是函数

因为组件是用来复用的,JS 里对象是引用关系,这样作用域没有隔离,而 new Vue 的实例,是不会被复用的,因此不存在引用对象问题。

keep-alive

keep-aliveVue内置的一个组件,可以使被包含的组件保留状态,避免重新渲染,其有以下特性:

  • 一般结合路由和动态组件一起使用,用于缓存组件。
  • 提供 includeexclude 属性,两者都支持字符串或正则表达式,include表示只有名称匹配的组件会被缓存,exclude表示任何名称匹配的组件都不会被缓存 ,其中exclude的优先级比include高。
  • 对应两个钩子函数activateddeactivated,当组件被激活时,触发钩子函数activated,当组件被移除时,触发钩子函数deactivated

v-model 的原理

vue项目中主要使用v-model指令在表单inputtextareaselect等元素上创建双向数据绑定,我们知道v-model本质上不过是语法糖,v-model在内部为不同的输入元素使用不同的属性并抛出不同的事件:

texttextarea元素使用value属性和input事件;
checkboxradio使用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 默认会利用名为valueprop和名为input的事件,如下所示:
父组件:

<ModelChild v-model="message"></ModelChild>
1

子组件:

<div>{{value}}</div>
props:{
    value: String
},
methods: {
  test1(){
     this.$emit('input', '小红')
  },
}
1
2
3
4
5
6
7
8
9

nextTick()

在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后,立即使用的这个回调函数,获取更新后的 DOM。

// 修改数据
vm.msg = 'Hello'
// DOM 还未更新
Vue.nextTick(function () {
  // DOM 更新
})
1
2
3
4
5
6

vue 组件

组件是一个 vue 实例

vue 插槽

vuex 工作原理及内容

先给出结论:vuex中的store本质就是没有template的隐藏着的vue组件 核心概念:

  • State
  • Getter
  • Mutation
  • Action
  • Module

vue 项目优化

1. 代码层面的优化

  • v-ifv-show区分使用场景
  • computedwatch区分使用场景
  • v-for遍历必须为item添加key,且避免同时使用v-if
  • 长列表性能优化
  • 事件的销毁
  • 图片资源懒加载
  • 路由懒加载
  • 第三方插件的按需引入
  • 优化无限列表性能
  • 服务端渲染 SSR or 预渲染

2. webpack层面的优化

  • Webpack对图片进行压缩
  • 减少ES6转为ES5的冗余代码
  • 提取公共代码
  • 模板预编译
  • 提取组件的CSS
  • 优化SourceMap
  • 构建结果输出分析
  • Vue项目的编译优化

3.基础的 Web 技术的优化

  • 开启gzip压缩
  • 浏览器缓存
  • CDN的使用
  • 使用Chrome Performance查找性能瓶颈
上次更新时间: 8/11/2020, 4:44:59 PM