v-if 和 v-show 区别
- 操作手段:
- v-if是动态的向DOM树内添加或者删除DOM元素;
- v-show是通过设置DOM元素的display样式属性控制显隐;
- 编译过程:
- v-if切换有一个局部编译/卸载的过程,切换过程中合适当地销毁和重建内部的事件监听和子组件;
- v-show只是简单的基于css切换;
- 编译条件:
- v-if是惰性的,如果初始条件为假则什么也不做,只有在条件第一次变为真时才开始局部编译;
- v-show是在任何条件下都被编译,然后被缓存,而且DOM元素保留;
- 性能消耗:
- v-if有更高的切换消耗;
- v-show有更高的初始渲染消耗;
- 适用场景:
- v-if 适合运营条件不大可能改变的场景;
- v-show适合频繁切换的场景。
- 总结:
- v-show只编译一次,后面其实就是控制css,而v-if不停的销毁和创建,如果要频繁切换某节点时,故v-show性能更好一点。
vue常用的修饰符
- .prevent: 阻止默认事件的发生,例如:提交事件不再重载页面;
- .stop: 阻止事件进行冒泡;
- .self: 元素绑定的事件只会在元素自身触发,而子元素无法调用;
- .capture: 事件侦听,事件发生的时候会调用。
js中的冒泡是什么?vue中如何阻止冒泡事件
- js中冒泡的概念:父元素内多级子元素绑定了同一个事件,js会依次从内往外或者从外往内执行每个元素的该事件,从而引发冒泡。
- js阻止冒泡方法:event.stopPropagation();或者在使用 addEventListener注册事件时,将第三个参数设置为 false;
- vue中阻止冒泡: 事件.stop,例如:@click.stop="" 、@mouseover.stop=""
vue中常用的一些指令
- v-model:用于表单输入,实现表单控件和数据的双向绑定;
- v-on:简写为@,基础事件绑定;
- v-bind:简写为:,动态绑定一些元素的属性,类型可以是:字符串、对象或数组;
- v-if:作用与js中的if语句相似,可以在实例中定义判断语句,也可以在dom处直接定义三元运算,取值为true/false,控制元素是否需要被渲染,可以与v-else 配合使用;
- v-else指令:和v-if指令搭配使用,没有对应的值。当v-if的值false,v-else才会被渲染出来;
- v-else-if:必须和 v-if 配合使用,作用与 else-if 相似;
- v-show指令:指令的取值为true/false,分别对应着显示/隐藏;
- v-for指令:遍历data中存放的数组数据,实现列表的渲染;
- v-once: 通过使用 v-once 指令,你也能执行一次性地插值,当数据改变时,插值处的内容不会更新;
- v-pre:正文中包含了不希望被vue编译的{{ }}时,采用v-pre保护;
- v-html:绑定一段HTML代码片段到页面上。
vue的自定义指令
Vue除了核心功能默认内置的指令 ,Vue 也允许注册自定义指令。
自定义指令是用来操作DOM的。尽管Vue推崇数据驱动视图的理念,但并非所有情况都适合数据驱动。自定义指令就是一种有效的补充和扩展,不仅可用于定义任何的DOM操作,并且是可复用的。
添加自定义指令的两种方式:
- 全局指令: 通过 Vue.directive() 函数注册一个全局的指令。
- 局部指令:通过组件的 directives 属性,对该组件添加一个局部的指令。
vue的指令周期
指令 | 调用周期 |
---|
bind | 一次初始化调用 | inserted | 被绑定元素插入父节点调用 | update | 模板更新时调用 | unbind | 指令与元素解绑时调用 | vue.nextTick | 在dom更新后执行,一般用于dom操作 | vue.$nextTick | 一直到真实的dom渲染结束后再执行 |
vue循环中 key值的作用
当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,默认用“就地复用”策略,如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。key的作用主要是为了高效的更新虚拟DOM。
v-for循环遍历时为什么要加上 “:key”?
- 为每个元素添加唯一标识;
- 避免重建整个列表;
- 提高修改效率。
为什么避免 v-if 和 v-for 一起使用?
当 Vue 处理指令时,v-for 比 v-if 具有更高的优先级,通过v-if 移动到容器元素,不会再重复遍历列表中的每个值。取而代之的是,我们只检查它一次,且不会在 v-if 为否的时候运算 v-for。
Vue的生命周期
- 什么是生命周期:
- Vue 实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模版、挂载 Dom 渲染 更新 渲染 卸载等一系列过程,我们称这是 Vue 的生命周期。
- 生命周期各阶段的作用:
- beforeCreate(创建前)数据观测和初始化事件还未开始;
- created(创建后)完成数据观测,属性和方法的运算,初始化事件,$el属性还未显示出来;
- beforeMount(挂载前)在挂载开始之前被调用,相关的render函数首次被调用,实例已完成以下的配置:编译模板,把data里面的数据和模板生成html;注意此时还没有挂载html到页面上;
- mounted(挂载后)el被新创建的 vm.$el 替换,并挂载到实例上去调用。实例已完成以下的配置:用上面编译好的html内容替换el属性指向的DOM对象。完成模板中的html渲染到html页面中。此过程中进行ajax交互;
- beforeUpdate(更新前) 在数据更新之前调用,发生在虚拟DOM重新渲染和打补丁之前。可以在该钩子中进一步地更改状态,不会触发附加的重渲染过程;
- updated(更新后) 在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用;
- beforeDestroy(销毁前) 在实例销毁之前调用,实例仍然完全可用;
- destroyed(销毁后) 在实例销毁之后调用。调用后,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。
点击查看详解
Vue组件间参数的传递
-
父子组件间传参
- 父给子传参(父:自定义属性传递变量;子:用Props[‘父元素自定义属性’]接受)
- 给父传参(子:this.$emit(父元素自定义事件,传递的值) ;父:自定义事件用参数去接收传递来 的值)
-
兄弟间传参(除了以下方式也可直接用Vuex)
- 通过给eventbus注册事件,别的组件触发事件,实现通信。
- 创建一个eventbus对象,即创造一个vue对象,用作传递信息。
- 接收信息的一方将事件通过vm.$on(“事件名”,事件处理函数)添加在eventbus对象上。
- 发送数据的一方,通过vm.$emit(“事件名”,传递的数据)触发事件,将数据传递。
-
路由传参
{
path: "/two",
name: "two",
component: two
}
this.$router.push({
path: `/two`
})
this.$route.params
this.$router.push({
path: `/two`,
query: { id: this.message, data: 456 }
});
this.$route.query
-
params 和 query 都是传递参数的,params不会在url上面出现,并且params参数是路由的一部分,是一定要存在的 , query是我们通常看到的url后面的跟在 “?”后面的拼接显示的携带参数。
Vue的父组件和子组件生命周期钩子函数执行顺序
Vue 的父组件和子组件生命周期钩子函数执行顺序可以归类为以下 4 部分:
-
加载渲染过程: 父 beforeCreate --> 父 created --> 父 beforeMount --> 子 beforeCreate --> 子 created --> 子 beforeMount --> 子 mounted --> 父 mounted -
子组件更新过程: 父 beforeUpdate --> 子 beforeUpdate --> 子 updated --> 父 updated -
父组件更新过程: 父 beforeUpdate --> 父 updated -
销毁过程: 父 beforeDestroy --> 子 beforeDestroy --> 子 destroyed --> 父 destroyed
methods、computed、watch的区别
- methods是个方法,执行的时候需要事件进行触发;
- computed是一个计算属性,是实时响应的,只要data中的属性发生了变化那么就会触发computed,计算属性是基于属性的依赖进行缓存的,methods调用的时候需要加(),而computed调用的时候不需要加();
- watch用来监听属性的变化,当值发生变化的时候来执行特定的函数,watch监听属性的时候会有2个参数newVal和oldVal一个新值一个旧值。
可以在哪个生命周期内调用异步请求?
可以在钩子函数 created(创建后)、beforeMount(挂载前)、mounted(挂载后) 中进行调用,因为在这三个钩子函数中,data 已经创建,可以将服务端端返回的数据进行赋值。但是更推荐在 created 钩子函数中调用异步请求,因为在 created 钩子函数中调用异步请求有以下优点:
- 能更快获取到服务端数据,减少页面 loading 时间;
- ssr 不支持 beforeMount 、mounted 钩子函数,所以放在 created 中有助于一致性。
在vue生命周期的什么阶段才能访问操作DOM
在钩子函数 mounted 被调用前,Vue 已经将编译好的模板挂载到页面上,所以在 mounted 中可以访问操作 DOM。
vue项目性能优化
- 编码层优化:
- 尽量减少data中的数据,data中的数据都会增加getter和setter,会收集对应的watcher
- v-if 和 v-show 区分使用场景
- v-for 遍历必须为 item 添加 key,且保证key值唯一
- 避免连用 v-for 和 v-if
- computed 和 watch 区分使用场景
- 使用路由懒加载、异步组件
- 第三方模块,插件按需导入
- 如果需要使用v-for给每项元素绑定事件时,使用事件代理(事件委派)
- 优化无限列表性能,长列表滚动到可视区域动态加载
- 图片资源懒加载
- SPA 页面采用keep-alive缓存组件
- 适当进行事件销毁
- 设置防抖,节流
- 服务端渲染 SSR or 预渲染
- 打包优化:
- Webpack 对图片进行压缩
- 减少 ES6 转为 ES5 的冗余代码
- 模板预编译
- 提取公共代码
- 提取组件的 CSS
- 使用cdn加载第三方模块
- 多线程打包happypack
- splitChunks抽离公共文件
- sourceMap优化
- Vue 项目的编译优化
- 构建结果输出分析
- 基础的 web 技术的优化
- 开启 gzip 压缩
- 使用浏览器缓存
- 使用CDN
- 使用 Chrome Performance 查找性能瓶颈
虚拟DOM的优缺点
- 优点:
- 保证性能下限: 框架的虚拟 DOM 需要适配任何上层 API 可能产生的操作,它的一些 DOM 操作的实现必须是普适的,所以它的性能并不是最优的;但是比起粗暴的 DOM 操作性能要好很多,因此框架的虚拟 DOM 至少可以保证在不需要手动优化的情况下,依然可以提供还不错的性能,即保证性能的下限;
- 无需手动操作 DOM: 我们不再需要手动去操作 DOM,只需要写好 View-Model 的代码逻辑,框架会根据虚拟 DOM 和 数据双向绑定,帮我们以可预期的方式更新视图,极大提高我们的开发效率;
- 跨平台: 虚拟 DOM 本质上是 JavaScript 对象,而 DOM 与平台强相关,相比之下虚拟 DOM 可以进行更方便地跨平台操作,例如服务器渲染、weex 开发等等。
- 缺点:
- 无法进行极致优化: 虽然虚拟 DOM + 合理的优化,足以应对绝大部分应用的性能需求,但在一些性能要求极高的应用中虚拟 DOM 无法进行针对性的极致优化。
虚拟DOM的实现原理
虚拟 DOM 的实现原理主要包括以下 3 部分:
- 用 JavaScript 对象模拟真实 DOM 树,对真实 DOM 进行抽象;
- diff 算法 — 比较两棵虚拟 DOM 树的差异;
- pach 算法 — 将两个虚拟 DOM 对象的差异应用到真正的 DOM 树。
直接给一个数组项赋值,Vue 能检测到变化吗?
由于 JavaScript 的限制,Vue 不能检测到以下数组的变动:
- 利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue
- 当你修改数组的长度时,例如:vm.items.length = newLength
为了解决第一个问题,Vue 提供了以下操作方法:
Vue.set(vm.items, indexOfItem, newValue)
vm.$set(vm.items, indexOfItem, newValue)
vm.items.splice(indexOfItem, 1, newValue)
为了解决第二个问题,Vue 提供了以下操作方法:
vm.items.splice(newLength)
vuex有哪几种属性?
有五种,分别是 State、Getter、Mutation 、Action、Module;
- state为单一状态树,在state中需要定义我们所需要管理的数组、对象、字符串等等,只有在这里定义了,在vue.js的组件中才能获取定义对象的状态;
- getter类似vue.js的计算属性,当我们需要从store的state中派生出一些状态时,就需要使用getter,getter会接收state作为第一个参数,而且getter的返回值会根据它的依赖被缓存起来,只有getter中的依赖值(state中的某个需要派生状态的值)发生改变的时候才会被重新计算;
- 更改store中state状态的唯一方法就是提交mutation,每个mutation都有一个字符串类型的事件类型和一个回调函数,我们需要改变state的值就要在回调函数中改变,要执行这个回调函数,就需要执行一个相应的调用方法:store.commit;
- action可以提交mutation,在action中可以执行store.commit,而且action中可以有任何的异步操作。在页面中如果我们要用这个action,就需要执行store.dispatch;
- 当state中很复杂臃肿的时候,module可以将store分割成模块,每个模块中拥有自己的state、mutation、action和getter。
不使用vuex会带来什么问题?
- 可维护性会下降,要想修改数据,得维护三个地方;
- 可读性会下降,因为一个组件里的数据,看不出来是从哪来;
- 增加耦合,大量的上传派发,会让耦合性大大的增加,本来Vue用Component就是为了减少耦合,现在这么用,和组件化的初衷相背。
简述vuex的数据传递流程
当组件进行数据修改的时候我们需要调用dispatch来触发actions里面的方法,actions里面的每个方法中都会 有一个commit方法,当方法执行的时候会通过commit来触发mutations里面的方法进行数据的修改,mutations里面的每个函数都会有一个state参数,这样就可以在mutations里面进行state的数据修改 ,当数据修改完毕后,会传导给页面,页面的数据也会发生改变。
解释一下vuex
vuex是用来做状态管理的,有五个常用属性state, getter, actions, mutations, modules;
- state是数据源,类似vue中的data,我们可以通过两种方式来获取它,mapStates, mapGerters。获取state必须放到computed中,这样才能保证state发生改变的时候该组件中用到state的地方都发生变化。
- getters:相当于计算属性;
- mutation:同步操作, 修改数据;
- action:异步操作;
- modules:模块化
如何获取vuex的state对象中的属性?
方法1:直接从store实例中取值 ****this.$store.state.属性****;
方法2:利用vuex的mapState方法来获取vuex的state对象中属性;
import { mapState } from 'vuex'
computed:{
...mapState({
count:state => state.count
})
}
computed:
...mapState(['count'])
}
使用vue脚手架搭建的项目中怎样使用自定义组件?组件使用时注意什么?
- 第一步:在components目录新建组件文件(smithButton.vue),在组件文件中的script代码中一定要用 export default 将组件导出;
- 第二步:在需要用的页面(组件)中导入:import smithButton from ‘…/components/smithButton.vue’;
- 第三步:注入到vue的子组件的components属性上面,components:{smithButton};
- 第四步:在template视图view中使用,
- 注意:可以使用 smithButton命名组件,但是使用的时候应该是:smith-button的形式(浏览器识别HTML标签是不区分大小写)。
这里是万物之恋,我们下次再见了!
|