MVVM的理解
- MVVM 是 Model-View-ViewModel 的缩写,它是一种软件架构风格,
- 核心是数据驱动 ,即ViewModel,ViewModel是View和Model的关系映射。
- MVVM本质就是基于操作数据来操作视图进而操作DOM,借助于MVVM无需直接操作DOM,开发者只需编写ViewModel中有业务,使得View完全实现自动化。
spa应用以及优缺点
spa就是单页应用,即web项目只有一个html文件,内容的的切换通过路由实现
优点
- 页面切换用户体验较好,不需要重新加载整个页面
- 服务端项相对压力较小
- 前后端职责分离,架构清晰
缺点
- 首页加载耗时较长,js,css等静态资源需要统一加载
- 浏览器前进后退导航失效,由于只有一个页面,需要自己建立堆栈管理
- seo优化难度较大,由于所有内容在一个页面上展示
生命周期
Vue实例从创建到晓辉的过程就是生命周期
!注意:浏览器有8个钩子,但是node中做服务端渲染的时候只有beforeCreate和created
beforeCreate是new Vue()之后触发的第一个钩子,在当前阶段data、methods、computed以及watch上的数据和方法都不能被访问。created在实例创建完成后发生,当前阶段已经完成了数据观测,也就是可以使用数据,更改数据,在这里更改数据不会触发updated函数。可以做一些初始数据的获取,在当前阶段无法与Dom进行交互,如果非要想,可以通过vm.$nextTick来访问Dom。beforeMount发生在挂载之前,在这之前template模板已导入渲染函数编译。而当前阶段虚拟Dom已经创建完成,即将开始渲染。在此时也可以对数据进行更改,不会触发updated。mounted在挂载完成后发生,在当前阶段,真实的Dom挂载完毕,数据完成双向绑定,可以访问到Dom节点,使用$refs属性对Dom进行操作。beforeUpdate发生在更新之前,也就是响应式数据发生更新,虚拟dom重新渲染之前被触发,你可以在当前阶段进行更改数据,不会造成重渲染。updated发生在更新完成之后,当前阶段组件Dom已完成更新。要注意的是避免在此期间更改数据,因为这可能会导致无限循环的更新。beforeDestroy发生在实例销毁之前,在当前阶段实例完全可以被使用,我们可以在这时进行善后收尾工作,比如清除计时器,销毁父组件对子组件的重复监听。beforeDestroy(){Bus.$off("saveTheme")}destroyed发生在实例销毁之后,这个时候只剩下了dom空壳。组件已被拆解,数据绑定被卸除,监听被移出,子实例也统统被销毁 生命周期调用顺序- 组件的调用顺序都是先父后子
- 渲染完成的顺序是先子后父
- 组件的销毁操作是先父后子
- 销毁完成的顺序是先子后父
加载渲染过程父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount- >子mounted->父mounted
子组件更新过程父beforeUpdate->子beforeUpdate->子updated->父updated
父组件更新过程父 beforeUpdate -> 父 updated
销毁过程父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
vue生命周期的作用是什么
它的生命周期中有多个事件钩子,让我们控制Vue实例过程更加清晰。
第一次页面加载会触发哪几个钩子
第一次页面加载时会触发 beforeCreate, created, beforeMount, mounted 这几个钩子
每个周期具体适合哪些场景
- beforecreate : 可以在这加个loading事件,在加载实例时触发
- created : 初始化完成时的事件写在这里,如在这结束loading事件,异步请求也适宜在这里调用
- mounted : 挂载元素,获取到DOM节点
- beforeDestroy : 可以清除定时器nextTick : 更新数据后立即操作dom
v-if和v-show的区别
v-if
- 是真正的条件渲染,v-if切换会销毁重建组件及dom
- 是惰性的,如果初始条件为假,会等到第一次条件为真的时候才会渲染
v-show
- 不管初始条件是真是假,都会渲染,显示隐藏是通过控制display属性
总结: v-show适用于频繁切换条件的场景,v-if适用于切换条件较少的场景
vue单向数据流
props只能从父组件流向子组件,反过来不行,这样能防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向变的混乱,想要改变父组件数据必须通过$emit手动触发一个父组件的事件,由父组件自己更改自己的数据
两种情况下子组件使用props
- 直接使用
props的初始值,在data里面定义一个变量接收props
props:['index'],
data(){
return {
subIndex: this.index
}
}
- 需要对
props进行转换时,定义一个计算属性
props:['index'],
computed:{
subIndex(){
return this.index +1
}
}
异步请求放在哪一个生命周期
官方异步请求放在mounted里面,也可以放在created里面,有以下几点好处:
created比mounted提前执行,能更快的获取到异步数据渲染,减少加载时间- ssr 不支持 beforeMount 、mounted 钩子函数,所以放在 created 中有助于一致性
Vue2.x组件通信方式有哪些
父子组件
- 父-->子:props 子-->父:$emit
- 获取父子组件实例:
$parent / $children 如:直接在子组件的methods方法里面写:this.$parent.show()//show为父组件中定义的方法 - 通过
ref获取子组件实例 (如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例),如在引入的子组件的标签上挂载一个: ref="comA",然后在方法中或者子组件的数据,this.$refs.comA.titles Provide、inject官方不推荐使用,但是写组件库时很常用
兄弟组件
- Event Bus 实现跨组件通信: Vue.prototype.$bus = new Vue
- Vuex
跨级组件
- Vuex
- attrs,listeners
$attrs: 包含了父作用域中不被 prop 所识别 (且获取) 的特性绑定 ( class 和 style 除外 )。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 ( class 和 style 除外 ),并且可以通过 v-bind="$attrs" 传入内部组件。通常配合 inheritAttrs 选项一起使用。
$listeners: :包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件
- Provide、inject
//父组件
<template>
<div id="app">
</div>
</template>
<script>
export default {
data () {
return {
datas: [
{
id: 1,
label: '产品一'
}
]
}
},
provide {
return {
datas: this.datas
}
}
}
</script>
//子组件
<template>
<div>
<ul>
<li v-for="(item, index) in datas" :key="index">
{{ item.label }}
</li>
</ul>
</div>
</template>
<script>
export default {
inject: ['datas']
}
</script>
什么是SSR
SSR也就是服务端渲染,也就是将Vue在客户端把标签渲染成HTML的工作放在服务端完成,然后再把html直接返回给客户端。
服务端渲染 SSR 的优缺点如下:
(1)服务端渲染的优点:
- 更好的 SEO: 因为 SPA 页面的内容是通过 Ajax 获取,而搜索引擎爬取工具并不会等待 Ajax 异步完成后再抓取页面内容,所以在 SPA 中是抓取不到页面通过 Ajax 获取到的内容;而 SSR 是直接由服务端返回已经渲染好的页面(数据已经包含在页面中),所以搜索引擎爬取工具可以抓取渲染好的页面;
- 更快的内容到达时间(首屏加载更快): SPA 会等待所有 Vue 编译后的 js 文件都下载完成后,才开始进行页面的渲染,文件下载等需要一定的时间等,所以首屏渲染需要一定的时间;SSR 直接由服务端渲染好页面直接返回显示,无需等待下载 js 文件及再去渲染等,所以 SSR 有更快的内容到达时间;
(2) 服务端渲染的缺点:
- 更多的开发条件限制: 例如服务端渲染只支持 beforCreate 和 created 两个钩子函数,这会导致一些外部扩展库需要特殊处理,才能在服务端渲染应用程序中运行;并且与可以部署在任何静态文件服务器上的完全静态单页面应用程序 SPA 不同,服务端渲染应用程序,需要处于 Node.js server 运行环境;
- 更多的服务器负载: 在 Node.js 中渲染完整的应用程序,显然会比仅仅提供静态文件的 server 更加大量占用CPU 资源 (CPU-intensive - CPU 密集),因此如果你预料在高流量环境 ( high traffic ) 下使用,请准备相应的服务器负载,并明智地采用缓存策略。
Vue路由
两种路由模式的说明如下:
- hash: 使用 URL hash 值来作路由。支持所有浏览器,包括不支持 HTML5 History Api 的浏览器;
- history : 依赖 HTML5 History API 和服务器配置;
hash模式原理
hash的前端路由的实现就是基于 location.hash 来实现的,location.hash 的值就是 URL 中 # 后面的内容。
- 在向服务器发出请求时,hash值(#号后面的内容)不会被发送
- 可以使用a标签的
href属性,或者location.hash改变hash值,跳转页面,而不会刷新页面 - 可以用
hashchange事件监听hash值的改变,改变内容显示 - hash值的改变会在浏览器的历史记录中新增一条,所以可以使用前进后退导航
history模式原理
history模式是利用H5的history API实现,只要的时两个API,history.pushState()和history.replaceState(),一个时新增历史记录,一个是替换历史记录
- 这两个API可以在不刷新页面的情况下,操作浏览器历史记录
- 可以通过
popState事件,监听url的变化,渲染新页面 history.pushState和history.replaceState不会触发popState事件
Vue项目的性能优化
代码层面
- v-if和v-for区分场景使用
- computed和watch区分场景使用
- v-for遍历,给每个item加key
- 路由懒加载
- 图片资源懒加载
- 事件销毁
- 第三方插件按需引入
webpack层面
- 使用loader压缩代码和静态资源
- treeshaking减少用于代码
- 优化sourceMap
- 提取css文件
- 项目编译优化
web基础技术优化
- CDN缓存静态资源
- 合理使用浏览器缓存
- 使用 Chrome Performance 查找性能瓶颈
Vue中key的作用
key 是为 Vue 中 vnode 的唯一标记,通过这个 key,我们的 diff 操作可以更准确、更快速
v-model的原理
v-model主要使用在 input、textarea、select等表单元素上,实现双向绑定,其实他只是一种语法糖,在内部为不同表单元素绑定不同属性,并抛出不同事件
<input v-model='something'>
相当于
<input v-bind:value="something" v-on:input="something = $event.target.value">
Vue组件中的data为什么是一个函数
一个组件被复用多次的话,也就会创建多个实例。本质上,这些实例用的都是同一个构造函数。如果data是对象的话,对象属于引用类型,会影响到所有的实例。所以为了保证组件不同的实例之间data不冲突,data必须是一个函数。而 new Vue 的实例,是不会被复用的,因此不存在引用对象的问题。
对keep-alive的理解
keep-alive时vue内置的一个组件,被包裹的组件会保留状态,避免重复渲染
- 提供
include和exclude属性,两者都支持字符串或正则表达式, include 表示只有名称匹配的组件会被缓存,exclude 表示任何名称匹配的组件都不会被缓存 ,其中 exclude 的优先级比 include 高; - 对应两个钩子函数
activated和deactivated,当组件被激活时,触发钩子函数activated,当组件被移除时,触发钩子函数deactivated。
父组件监听子组件生命周期的方法
利用$emit
// Parent.vue
<Child @mounted="doSomething"/>
// Child.vue
mounted() {
this.$emit("mounted");
}
用@hock监听
// Parent.vue
<Child @hook:mounted="doSomething" ></Child>
doSomething() {
console.log('父组件监听到 mounted 钩子函数 ...');
},
// Child.vue
mounted(){
console.log('子组件触发 mounted 钩子函数 ...');
},
// 以上输出顺序为:
// 子组件触发 mounted 钩子函数 ...
// 父组件监听到 mounted 钩子函数 ...
computed和watch
computed:
computed是计算属性,也就是计算值,它更多用于计算值的场景computed具有缓存性,computed的值在getter执行后是会缓存的,只有在它依赖的属性值改变之后,下一次获取computed的值时才会重新调用对应的getter来计算computed适用于计算比较消耗性能的计算场景
watch:
更多的是「观察」的作用,类似于某些数据的监听回调,用于观察props $emit或者本组件的值,当数据变化时来执行回调进行后续操作无缓存性,页面重新渲染时值不变化也会执行
小结:
当我们要进行数值计算,而且依赖于其他数据,那么把这个数据设计为computed 如果你需要在某个数据变化时做一些事情,使用watch来观察这个数据变化