v-if 和v-show的区别
共同点
- 都能控制元素的显示和隐藏
不同点
- v-show:通过css的display:none控制隐藏,只会编译一次
- v-if:动态的向DOM树添加或者删除DOM元素,若初始值为false,就不会编译了
v-if不停的销毁和创建比较消耗性能。所以如果要频繁切换某节点,使用v-show(切换开销比较小,初始开销较大);如果不需要频繁的切换某节点使用就使用v-if(初始渲染开心较小,切换开销较大)
v-if和v-for的优先级
- v-for优先于v-if被解析。
- 如果同时出现,每次渲染都会先执行循环再判断条件,无论如何循环都不可避免,浪费了性能。要避免这种情况,则在外层嵌套template,在这一层进行v-if判断,然后在内部进行v-for循环。
- 如果条件出现在循环内部,可通过计算属性提前过滤掉那些不需要显示的项。
vue组件中data为什么必须是一个函数
如果data是一个函数的话,这样每次复用一次组件,就会返回一个新data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。
而单纯的写成对象形式,就使得所有组件实例公用一份data,就会造成一个变了全部都变的结果。所以说vue组件的data必须是函数。
js本身的面向对象编程也是基于原型链和构造函数,应该会注意原型链上添加一般都是函数方法,而不会去添加一个对象。
vuex中actions与mutations的区别
actions
- 用于通过提交mutation改变数据
- 会默认将自身封装为一个promise
- 可以包含任意的异步操作
mutations
- 通过提交commit改变数据
- 只是一个单纯的函数
- 不要使用异步操作,会导致变量不能追踪
如何在vuex中使用异步修改
在调用vuex中的方法action的时候,使用promise实现异步修改
const actions = {
asyncLogin({commit},n){
return new Promise(resolve=>{
setTimeout(()=>{
commit(type.UserLogin,n);
resolve();
},3000)
})
}
}
vue有哪些组件间的通信方式
父子组件通信、隔代组件通信、兄弟组件通信
方法一: props/$emit
父组件A通过props的方式向子组件B传递,B to A通过B组件中的$emit,A组件中v-on的方式实现。
总结:父组件通过props向下传递数据给子组件。(子组件的数据共有三种形式:data、props、computed);子组件通过events给父组件发送消息,实际上就是子组件把自己的数据发送到父组件。
方法二:emit/on
这种方式通过一个空的vue实例作为中央事件总线(事件中心),用它来触发事件和监听事件,巧妙而轻量地实现了任何组件间的通信,包括父子、兄弟、跨级。当我们的项目比较大时,可以选择更好的状态管理解决方案vuex。
var App = new Vue();
App.$emit(事件名,数据);
App.$on(事件名,data=>{});
方法三:vuex与localStorage
vuex是vue的状态管理器,存储的数据是响应式的,但是并不会保存起来,刷新之后就会回到初始状态,具体做法应该在vuex里,数据改变的时候把数据拷贝一份保存到localStorage里面,刷新之后,如果localStorage里有保存的数据,取出来再替换store里的state。
vue中双向数据绑定是如何实现的
- vue.js 采用的是数据劫持结合发布订阅模式的方式。
- 通过
Object.defineProperty()
来劫持各个属性的setter和getter。 - 在数据变动时发布消息给订阅者,触发相应的监听回调。
var obj = {};
Object.defineProperty(obj,'name',{
get:function(){
console.log('我被获取了');
return val;
},
set:function(){
console.log
}
})
obj.name = 'fei'; //在给obj设置name属性的时候,出发了set方法
var val =obj.name; //在得到obj的name属性,会触发get方法
单页面应用和多页面应用区别及优缺点
单页面应用(SPA),通俗点说就是指只有一个主页面的应用,浏览器一开始要加载所有必须的html、css、js。所有的页面内容都包含在这个所谓的主页面中。但在写的时候,还是会分开写,然后在交互的时候由路有程序动态加载,单页面的页面跳转,仅刷新局部资源。多应用于pc端。
多页面(MPA),就是指一个应用中有多个页面,页面跳转时整页刷新。
单页面优点
- 用户体验好,快。内容的改变不需要重新加载整个页面,基于这一点spa对服务器压力较小
- 前后端分离
- 页面效果会比较炫酷(比如切换页面内容时专场动画)
单页面缺点
- 不利于seo
- 导航不可用,如果一定要导航需要自行实现前进、后退
- 初次加载时耗时多
- 页面复杂度提高很多
vue事件的修饰符
- .stop:等同于event.stopPropagation(),防止事件冒泡
- .prevent:等同于event.proventDefault(),防止执行预设的行为
- .capture:与事件冒泡的方向相反,事件捕获由外到内
- .self:只会触发自己范围内的事件,不包含子元素
- .once:只触发一次
- .passsive:passive表示listener函数不会调用preventDefault()
passive主要用于移动端的scroll事件,来提高浏览器相应速度,提升用户体验。因为passive=true等于提前告诉浏览器,touchstart和touchmove不会阻止默认事件,手刚开始触摸,浏览器就可以立刻给予响应。
vue的两个核心是什么
数据驱动
在vue中,数据的改变会驱动视图的自动更新。传统的做法是需要手动改变dom来使得视图更新,而vue只需要改变数据。
组件
组件化开发,优点很多,可以很好的降低数据之间的耦合度。将常用的代码封装组件之后,就能高度的复用,提高代码的可重用性。一个页面/模块可以由多个组件所组成。
v-model的原理
v-model本质是一个语法糖,可以看成是value + input 方法的语法糖。可以通过model属性的prop和event属性来进行自定义。
原生的v-model,会根据标签的不同生成不同的事件和属性。
v-model在内部为不同的输入元素使用不同的属性并抛出不同的事件,如下:
- text和textarea元素使用value属性和input事件
- checkbox和radio使用checked属性和change事件
- select字段将value作为prop并将change作为事件
nextTick的实现原理是什么
在下次DOM更新循环结束之后执行延迟回调。nextTick主要是使用了宏任务和微任务。根据执行环境分别尝试采用
- promise
- mutationObserver
- setImmediate
- 如果以上方法都不行则采用setTimeout
定义了一个异步方法,多次调用nextTick会将方法存入队列中,通过这个异步方法清空当前队列。
谈谈Computed和watch
computed本质是一个具备缓存的watcher,依赖的属性发生变化就会更新视图。
适用于计算比较消耗性能的计算场景。当表达式过于复杂时,在模版中放入过多逻辑会让模版难以维护,可以将复杂的逻辑放入计算属性中处理。
watch没有缓存性,更多的是观察的的作用,可以监听某些数据执行回调。
当我们需要深度监听对象中的属性时,可以打开deep:true选项,这样便会对对象中的每一项进行监听。
这样会带来性能问题,优化的话可以使用字符串形式监听,如果没有写到组件中,不要忘记使用unWatch手动注销。
v-text与{{}}与v-html的区别
- {{}}将数据解析为纯文本,不能显示输出html
- v-html可以渲染输出html
- v-text将数据解析为纯文本,不能输出真正的html,与花括号的区别是在页面加载时不显示双花括号
v-text:操作网页元素中的纯文本内容。{{}}是它的另一种写法。
v-text与{{}}的区别:v-text与{{}}等价,{{}}叫模版插值,v-text叫指令。有一点区别就是,在渲染的数据比较多的时候,可能会把大括号显示出来,俗称屏幕闪动。
v-on可以绑定多个方法吗
可以,如果绑定多个事件,可以用键值对的形式(事件类型:事件名);如果绑定的是多个相同事件,直接用逗号分隔就行。
vue中路有跳转方式
- 声明式:用router-link进行跳转,router-view路由出口,路由模版显示的位置。
- 编程式:this.$router.push()
路由的name属性有什么作用:
- 在router-link中使用name导航到对应路由
- 使用name导航的同时,给子路由传递参数
vue跨域的解决方式
- 后台更改header
- 使用jq提供jsonp
- 用http-proxy-middleware(配置代理服务器的中间件)
vue的生命周期请简述
vue的生命周期就是vue实例创建到实例销毁的过程。期间会8个钩子函数的调用
- beforeCreate:创建实例
- created:创建完成
- beforeMount:开始创建模版
- mounted:创建完成
- beforeUpdate:开始更新
- updated:更新完成
- beforeDestroy:开始销毁
- destroyed:销毁完成
DOM渲染在哪个生命周期阶段内完成
DOM渲染在mounted周期中就已经完成。
vue路由模式hash和histroy,简单讲一下
Hash模式地址栏有#,history没有,history模式下刷新,会出现404情况,需要后台配置。
使用JavaScript来对loaction.hash
进行赋值,改变URL的hash值。可以使用hashchange
事件来监听hash值的变化。
HTML5提供了History API来实现URL的变化。其中最重要的API有以下两个:history.pushState()
、history.replaceState()
。这两个API可以在不进行刷新的情况下,操作浏览器的历史记录。唯一不同的是,前者新增一个历史记录,后者直接替换当前的历史记录。
vue路由传参的两种方式params和query区别
动态路由也可以叫做路由传参,就是根据不同的选择在同一组件渲染不同的内容。
用法上:query用path引入,params用name引入,接收参数都是类似的,分别是this.$route.query.name
和this.$route.params.name
展示上:params类似于post,query类似与get,也就是安全问题。params传值相对于更安全一点,query通过url传参,刷新页面还在,params刷新页面不在了。
vue的路由钩子函数/路由守卫有哪些
全局守卫
beforeEach(to, from, next)
和after(to,from)
路由独享守卫
beforeEnter
组件内的守卫
路由进入/更新/离开之前 beforeRouterEnter/update/leave
对vue中keep-alive的理解
概念:keep-alive是vue的内置组件,当它动态包裹组件时,会缓存不活动的组件实例,它自身不会渲染成一个DOM元素也不会出现在父组件链中。
作用:在组件切换过程中将状态保留在内存中,防止重复渲染DOM,减少加载时间以及性能消耗,提高用户体验。
生命周期函数:Activated在keep-alive组件激活时调用,deactivated在keep-alive组件停用时调用。
如何让组件中的css在当前组件生效
在styled中加上scoped
vue组件中的data为什么是函数
Data是一个函数时,每个组件实例都有自己的作用域,每个实例相互独立,不会相互影响。如果时引用类型(对象),当多个组件公用一个数据源时,一处数据改变,所有的组件数据都会改变,所以要利用函数通过return返回对象的拷贝,让每个实例都有自己的作用域,相互不影响。
vuex流程
在vue组件里面,通过dispatch来触发actions提交修改数据的操作,然后通过actions的commit触发mutations来修改数据,mutations接收到commit的请求,就会自动通过mutate来修改state,最后由store出发每一个调用它的组件的更新。
vuex怎么请求异步数据
- 首先在state中创建变量
- 然后在action中调用封装好的axios请求,异步接收数据,commit提交给mutations
- mutations中改变state中的状态,将从action中获取到的值赋值给state
vue在created和mounted这两个生命周期中请求数据有什么区别
看实际情况,一般在created(或beforeRouter)里面就可以,如果涉及到需要页面加载完成之后的话就用mounted。
在created的时候,视图中的html并没有渲染出来,所以此时如果直接去操作html的dom节点,一定找不到相关的元素,而在mounted中,由于此时html已经渲染出来的了,所以可以直接操作dom节点。
说说你对proxy的理解
vue的数据劫持有两个缺点
- 无法监听通过索引修改数组的值的变化
- 无法监听object对象的值的变化,所以vue2.x中才会有$set属性的存在
proxy是es6中推出的新api,可以弥补以上两个缺点,所以vue3.x版本用proxy替换object.defineProperty
。