Vue在created和mounted这两个生命周期中请求数据有什么区别呢?
参考答案
在created中,页面视图未出现,如果请求信息过多,页面会长时间处于白屏状态,DOM节点没出来,无法操作DOM节点。在mounted不会这样,比较好。v-model的原理是什么?
参考答案
<template>
<div>
<my-component v-model="value"></my-component>
<!-- 等同 -->
<my-component :value="value" @input="value=$event"></my-component>
<button @click="value=true">显示</button>
</div>
</template>
<script>
export default{
data(){
return{
value:false,
}
},
components:{
myComponent:resolve =>require(['./my_component'],resolve),
}
}
</script>
<template>
<div v-show="value">
<span>我的组件</span>
<button @click="$emit('input',false)">隐藏</button>
</div>
</template>
<script>
export default{
props:{
value:{
type:Boolean,
default:false,
}
},
data(){
return{}
},
}
</script>
说说你对keep-alive的理解
参考答案
keep-alive是一个抽象组件:它自身不会渲染一个DOM元素,也不会出现在父组件链中;使用keep-alive包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。其有三个参数
include
定义缓存白名单,会缓存的组件;exclude
定义缓存黑名单,不会缓存的组件;- 以上两个参数可以是逗号分隔字符串、正则表达式或一个数组,
include="a,b"
、:include="/a|b/"
、:include="['a', 'b']"
; - 匹配首先检查组件自身的 name 选项,如果 name 选项不可用,则匹配它的局部注册名称 (父组件 components 选项的键值)。匿名组件不能被匹配;
max
最多可以缓存多少组件实例。一旦这个数字达到了,在新实例被创建之前,已缓存组件中最久没有被访问的实例会被销毁掉;- 不会在函数式组件中正常工作,因为它们没有缓存实例;
- 当组件在内被切换,它的activated和deactivated这两个生命周期钩子函数将会被对应执行。
v-if和v-for的优先级是什么?如果这两个同时出现时,那应该怎么优化才能得到更好的性能?
参考答案
当它们处于同一节点,v-for
的优先级比v-if
更高,这意味着v-if
将分别重复运行于每个v-for
循环中。当你只想为部分项渲染节点时,这种优先级的机制会十分有用。
<ul>
<li v-for="item in items" v-if="item.show">{{item}}</li>
</ul>
如果你的目的是有条件地跳过循环的执行,那么可以将 v-if 置于外层元素 (或 <template>
)上。
<ul v-if="items.length">
<li v-for="item in items">{{item}}</li>
</ul>
使用v-for遍历对象时,是按什么顺序遍历的?如何保证顺序?
参考答案
按Object.keys()的顺序的遍历,转成数组保证顺序。在v-for中使用key,会提升性能吗,为什么?
参考答案
主要看v-for渲染的是什么。
- 如果渲染是一个简单的列表,如不依赖子组件状态或临时DOM状态(例如:表单输入值)的列表渲染输出,不用key性能会更好,因为不用key采用的是“就地更新”的策略。如果数据项的顺序被改变, Vue将不会移动DOM元素来匹配数据项的顺序,而是就地更新每个元素。
以上的例子,v-for的内容会生成以下的DOM节点数组,我们给每一个节点标记一个身份id,以辨别节点的位置:<template> <div> <span v-for="item in lists">{{item}}</span> </div> </template> <script> export default { data() { return { lists: [1, 2, 3, 4, 5] } }, } </script>
将lists中的数据进行位置调换,变成[ '<span>1</span>', // id: A '<span>2</span>', // id: B '<span>3</span>', // id: C '<span>4</span>', // id: D '<span>5</span>' // id: E ]
[2,4,3,1,5]
,在没有key的情景下,节点位置不变,但是节点的内容更新了,这就是“就地更新”
但是在有key的情景下,节点位置进行了交换,但是内容没有更新[ '<span>2</span>', // id: A '<span>4</span>', // id: B '<span>3</span>', // id: C '<span>1</span>', // id: D '<span>5</span>' // id: E ]
[ '<span>2</span>', // id: B '<span>4</span>', // id: D '<span>3</span>', // id: C '<span>1</span>', // id: A '<span>5</span>' // id: E ]
- 如果渲染不是一个简单的列表,用key性能会更好一点,因为vue是采用diff算法来对比新旧虚拟节点来更新节点,在diff算法中,当新节点跟旧节点头尾交叉对比没有结果时,先处理旧节点生成一个健为key,值为节点下标index的map映射,如果新节点有key,会通过map映射找到对应的旧节点,如果新节点没有key,会采用遍历查找的方式去找到对应的旧节点,一种一个map映射,另一种是遍历查找。相比而言。map映射的速度更快。
创建map函数// vue源码 src/core/vdom/patch.js 488行 // 以下是为了阅读性进行格式化后的代码 // oldCh 是一个旧虚拟节点数组 // oldKeyToIdx map映射对象 // idxInOld 对比后得到旧节点下标 if (isUndef(oldKeyToIdx)) { oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx) } if (isDef(newStartVnode.key)) { // map 方式获取 idxInOld = oldKeyToIdx[newStartVnode.key] } else { // 遍历方式获取 idxInOld = findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx) }
遍历寻找函数function createKeyToOldIdx(children, beginIdx, endIdx) { let i, key const map = {} for (i = beginIdx; i <= endIdx; ++i) { key = children[i].key if (isDef(key)) map[key] = i } return map }
// sameVnode 是对比新旧节点是否相同的函数 function findIdxInOld(node, oldCh, start, end) { for (let i = start; i < end; i++) { const c = oldCh[i]; if (isDef(c) && sameVnode(node, c)) return i } }
key除了在v-for中使用,还有什么作用?
参考答案
还可以强制替换元素/组件而不是重复使用它。在以下场景可以使用
- 完整地触发组件的生命周期钩子
- 触发过渡
<transition>
<span :key="text">{{ text }}</span>
</transition>
当 text 发生改变时,<span>
会随时被更新,因此会触发过渡。
使用key要什么要注意的吗?
参考答案
-
不要使用对象或数组之类的非基本类型值作为key,请用字符串或数值类型的值;
-
不要使用数组的index作为key值,因为在删除数组某一项,index也会随之变化,导致key变化,渲染会出错。
例:在渲染
[a,b,c]
用 index 作为 key,那么在删除第二项的时候,index 就会从 0 1 2 变成 0 1(而不是 0 2),随之第三项的key变成1了,就会误把第三项删除了。
说说组件的命名规范
参考答案
给组件命名有两种方式,一种是使用链式命名my-component,一种是使用大驼峰命名MyComponent,
-
在字符串模板中
<my-component></my-component>
和<MyComponent></MyComponent>
都可以使用, -
在非字符串模板中最好使用
<MyComponent></MyComponent>
,因为要遵循W3C规范中的自定义组件名 (字母全小写且必须包含一个连字符),避免和当前以及未来的 HTML 元素相冲突。
为什么组件中data必须用函数返回一个对象?
参考答案
对象为引用类型,当重用组件时,由于数据对象都指向同一个data对象,当在一个组件中修改data时,其他重用的组件中的data会同时被修改;而使用返回对象的函数,由于每次返回的都是一个新对象(Object的实例),引用地址不同,则不会出现这个问题。Vue父子组件双向绑定的方法有哪些?
参考答案
- 通过在父组件上自定义一个监听事件
<myComponent @diy="handleDiy"></myComponent>
,在子组件用this.$emit('diy',data)
来触发这个diy事件,其中data为子组件向父组件通信的数据,在父组件中监听diy个事件时,可以通过$event访问data这个值。 - 通过在父组件上用修饰符
.sync
绑定一个数据<myComponent :show.sync="show"></myComponent>
,在子组件用this.$emit('update:show',data)
来改变父组件中show
的值。 - 通过
v-model
。
组件的name选项有什么作用?
参考答案
- 递归组件时,组件调用自身使用;
- 用
is
特殊特性和component
内置组件标签时使用; keep-alive
内置组件标签中include
和exclude
属性中使用。
什么是递归组件?举个例子说明下?
参考答案
递归引用可以理解为组件调用自身,在开发多级菜单组件时就会用到,调用前要先设置组件的name选项, 注意一定要配合v-if使用,避免形成死循环,用element-vue组件库中NavMenu导航菜单组件开发多级菜单为例:
<template>
<el-submenu :index="menu.id" popper-class="layout-sider-submenu" :key="menu.id">
<template slot="title">
<Icon :type="menu.icon" v-if="menu.icon"/>
<span>{{menu.title}}</span>
</template>
<template v-for="(child,i) in menu.menus">
<side-menu-item v-if="Array.isArray(child.menus) && child.menus.length" :menu="child"></side-menu-item>
<el-menu-item :index="child.id" :key="child.id" v-else>
<Icon :type="child.icon" v-if="child.icon"/>
<span>{{child.title}}</span>
</el-menu-item>
</template>
</el-submenu>
</template>
<script>
export default{
name: 'sideMenuItem',
props: {
menu: {
type: Object,
default(){
return {};
}
}
}
}
</script>
说说你对slot的理解?slot使用场景有哪些?
参考答案
组件的插槽功能
说下$attrs
和$listeners
的使用场景?
参考答案
$attrs
: 包含了父作用域中(组件标签)不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外)。 在创建基础组件时候经常使用,可以和组件选项inheritAttrs:false
和配合使用在组件内部标签上用v-bind="$attrs"
将非prop特性绑定上去;$listeners
: 包含了父作用域中(组件标签)的 (不含.native
) v-on 事件监听器。 在组件上监听一些特定的事件,比如focus事件时,如果组件的根元素不是表单元素的,则监听不到,那么可以用v-on="$listeners"
绑定到表单元素标签上解决。
说说你对provide和inject的理解
参考答案
组件的依赖注入
EventBus注册在全局上时,路由切换时会重复触发事件,如何解决呢?
参考答案
在有使用$on
的组件中要在beforeDestroy
钩子函数中用$off
销毁。
Vue组件里写的原生addEventListeners监听事件,要手动去销毁吗?为什么?
参考答案
要,不然会造成多次绑定和内存泄露。关于移除事件监听的坑。
Vue组件里的定时器要怎么销毁?
参考答案
- 如果页面上有很多定时器,可以在
data
选项中创建一个对象timer
,给每个定时器取个名字一一映射在对象timer
中, 在beforeDestroy
构造函数中for(let k in this.timer){clearInterval(k)}
; - 如果页面只有单个定时器,可以这么做。
const timer = setInterval(() =>{}, 500); this.$once('hook:beforeDestroy', () => { clearInterval(timer); })
Vue中能监听到数组变化的方法有哪些?为什么这些方法能监听到呢?
参考答案
push()
、pop()
、shift()
、unshift()
、splice()
、sort()
、reverse()
,这些方法在Vue中被重新定义了,故可以监听到数组变化;filter()
、concat()
、slice()
,这些方法会返回一个新数组,也可以监听到数组的变化。
在Vue中那些数组变化无法监听,为什么,怎么解决?
参考答案
-
利用索引直接设置一个数组项时;
-
修改数组的长度时。
- 第一个情况,利用已有索引直接设置一个数组项时
Object.defineProperty()
是可以监听到,利用不存在的索引直接设置一个数组项时Object.defineProperty()
是不可以监听到,但是官方给出的解释是由于JavaScript的限制,Vue不能检测以上数组的变动,其实根本原因是性能问题,性能代价和获得的用户体验收益不成正比。 - 第二个情况,原因是
Object.defineProperty()
不能监听到数组的length
属性。
- 第一个情况,利用已有索引直接设置一个数组项时
-
用
this.$set(this.items, indexOfItem, newValue)
或this.items.splice(indexOfItem, 1, newValue)
来解决第一种情况; -
用
this.items.splice(newLength)
来解决第二种情况。
在Vue中那些对象变化无法监听,为什么,怎么解决?
参考答案
- 对象属性的添加
- 对象属性的删除
因为Vue是通过Object.defineProperty
来将对象的key转成getter/setter的形式来追踪变化,但getter/setter只能追踪一个数据是否被修改,无法追踪新增属性和删除属性,所以才会导致上面对象变化无法监听。
- 用
this.$set(this.obj,"key","newValue")
来解决第一种情况; - 用
Object.assign
来解决第二种情况。
删除对象用delete和Vue.delete有什么区别?
参考答案
- delete:只是被删除对象成员变为
' '
或undefined
,其他元素键值不变; - Vue.delete:直接删了对象成员,如果对象是响应式的,确保删除能触发更新视图,这个方法主要用于避开 Vue 不能检测到属性被删除的限制。
watch和计算属性有什么区别?
参考答案
watch
:一个数据影响多个数据,当需要在数据变化时执行异步或开销较大的操作时;- 计算属性:一个数据受多个数据影响。是基于它的响应式依赖进行缓存的,只在相关响应式依赖发生改变时它才会重新求值。
计算属性和方法有什么区别?
参考答案
- 计算属性:是基于它们的响应式依赖进行缓存的,只在相关响应式依赖发生改变时它们才会重新求值。
- 方法:每当触发重新渲染时,调用方法将总会再次执行函数。当我们不希望有缓存,可以使用方法,但是如果求值开销大时建议用计算属性。
过渡动画实现的方式有哪些?
参考答案
你有写过自定义指令吗?自定义指令的生命周期(钩子函数)有哪些?
参考答案
自定义指令的钩子函数
手写一个自定义指令及写出如何调用
参考答案
注册一个让字体颜色闪烁的指令v-color
Vue怎么定义全局方法
参考答案
有三种
-
挂载在Vue的prototype上
// base.js const install = function (Vue, opts) { Vue.prototype.demo = function () { console.log('我已经在Vue原型链上') } } export default { install }
//main.js //注册全局函数 import base from 'service/base'; Vue.use(base);
-
利用全局混入mixin
-
用
this.$root.$on
绑定方法,用this.$root.$off
解绑方法,用this.$root.$emit
全局调用。this.$root.$on('demo',function(){ console.log('test'); }) this.$root.$emit('demo'); this.$root.$off('demo');
说说你对DOM选项el、template、render的理解?
参考答案
el
:提供一个在页面上已存在的DOM元素作为Vue实例的挂载目标。可以是CSS选择器,也可以是一个HTMLElement实例。- 因为所有的挂载元素会被Vue生成的DOM替换。因此不推荐挂载Vue实例到
html
或者body
上。 - 如果在
const vm = new Vue({})
中存在这个选项,实例将立即进入编译过程,否则,需要显式调用vm.$mount()
手动开启编译。
- 因为所有的挂载元素会被Vue生成的DOM替换。因此不推荐挂载Vue实例到
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
</head>
<body>
<div id="app">我是el挂载的内容:小明今年{{age}}岁了</div>
</body>
<script>
const vm= new Vue({
el:'#app',
data:{
age:17
},
}
</script>
</html>
<script>
const vm= new Vue({
data:{
age:17
},
})
vm.$mount('#app')
</script>
template
:一个字符串模板作为Vue实例的标识使用。如果el
存在,模板将会替换挂载的元素。挂载元素的内容都将被忽略,除非模板的内容有分发插槽。- 如果值以 # 开始,则它将被用作选择符,并使用匹配元素的 innerHTML 作为模板。
<script>
const vm= new Vue({
el:'#app',
data:{
age:17
},
template:'<div>我是template的内容:小明今年{{age}}岁了</div>',
})
</script>
<script type="x-template" id="mb">
<div>我是template的内容:小明今年{{age}}岁了</div>
</script>
<script>
const vm= new Vue({
el:'#app',
data:{
age:17
},
template:'#mb',
})
</script>
<body>
<div id="app">
我是el挂载的内容:小明今年{{age}}岁了
</div>
<template id="mb">
<div>我是template的内容:小明今年{{age}}岁了</div>
</template>
</body>
<script>
const vm= new Vue({
el:'#app',
data:{
age:17
},
template:'#mb',
})
</script>
render
:Vue 选项中的 render 函数若存在,则 Vue 构造函数不会从 template 选项或通过 el 选项指定的挂载元素中提取出的 HTML 模板编译渲染函数。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
</head>
<body>
<div id="app">
我是el挂载的内容:小明今年{{age}}岁了
</div>
</body>
<script>
const vm= new Vue({
el:'#app',
data:{
age:17
},
template:'<div>我是template的内容:小明今年{{age}}岁了</div>',
render(h){
return h('div',`我是render的内容:小明今年${this.age}岁了`)
}
})
</script>
</html>
<template></template>
有什么用?
参考答案
当做一个不可见的包裹元素,减少不必要的DOM元素,整个结构会更加清晰。Vue怎么改变插入模板的分隔符?
参考答案
用delimiters
选项,其默认是["{{", "}}"]
// 将分隔符变成ES6模板字符串的风格
new Vue({
delimiters: ['${', '}']
})
Vue变量名如果以_、$开头的属性会发生什么问题?怎么访问到它们的值?
参考答案
以 _
或 $
开头的属性 不会 被 Vue 实例代理,因为它们可能和 Vue 内置的属性、API 方法冲突,你可以使用例如 vm.$data._property
的方式访问这些属性。
怎么捕获Vue组件的错误信息?
参考答案
errorCaptured
是组件内部钩子,当捕获一个来自子孙组件的错误时被调用,接收error
、vm
、info
三个参数,return false
后可以阻止错误继续向上抛出。errorHandler
为全局钩子,使用Vue.config.errorHandler
配置,接收参数与errorCaptured
一致,2.6后可捕捉v-on
与promise
链的错误,可用于统一错误处理与错误兜底。
Vue.observable你有了解过吗?说说看
参考答案
让一个对象可响应。可以作为最小化的跨组件状态存储器。Vue项目中如何配置favicon?
参考答案
- 静态配置
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
, 其中<%= BASE_URL %>
等同vue.config.js中publicPath
的配置; - 动态配置
<link rel="icon" type="image/png" href="">
import browserImg from 'images/kong.png';//为favicon的默认图片 const imgurl ='后端传回来的favicon.ico的线上地址' let link = document.querySelector('link[type="image/png"]'); if (imgurl) { link.setAttribute('href', imgurl); } else { link.setAttribute('href', browserImg); }
怎么修改Vue项目打包后生成文件路径?
参考答案
- 在Vue CLI2中修改config/index.js文件中的
build.assetsPublicPath
的值; - 在Vue CLI3中配置publicPath的值。
怎么解决Vue项目打包后静态资源图片失效的问题?
参考答案
在项目中一般通过配置alias路径别名的方式解决,下面是Vue CLI3的配置。
configureWebpack: {
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'@': resolve('src'),
'assets': resolve('src/assets'),
'css': resolve('src/assets/css'),
'images': resolve('src/assets/images'),
}
},
},
怎么解决Vue中动态设置img的src不生效的问题?
参考答案
因为动态添加src被当做静态资源处理了,没有进行编译,所以要加上require。
<template>
<img class="logo" :src="logo" alt="公司logo">
</template>
<script>
export default {
data() {
return {
logo:require("assets/images/logo.png"),
};
}
};
</script>
在Vue项目中如何引入第三方库(比如jQuery)?有哪些方法可以做到?
参考答案
- 先在主入口页面 index.html 中用 script 标签引入
<script src="./static/jquery-1.12.4.js"></script>
,如果你的项目中有用ESLint检测,会报'$' is not defined
,要在文件中加上/* eslint-disable */
- 先在主入口页面 index.html 中用 script 标签引入
<script src="./static/jquery-1.12.4.js"></script>
,然后在webpack 中配置一个 externals,即可在项目中使用。externals: { 'jquery': 'jQuery' }
- 先在webpack中配置alias,最后在main.js中用
import $ from 'jquery'
,即可在项目中使用。resolve: { extensions: ['.js', '.vue', '.json'], alias: { '@': resolve('src'), 'jquery': resolve('static/jquery-1.12.4.js') } }
- 在webpack中新增一个plugins,即可在项目中使用
plugins: [ new webpack.ProvidePlugin({ $:"jquery", jQuery:"jquery", "windows.jQuery":"jquery" }) ]
其他Vue系列面试题
- Vue-Router面试题汇总
- Vue初级前端工程师面试必备
- Vue初级面试题汇总
- Vue中级面试题汇总
- Vue高级面试题汇总
代办报建
本公司承接江浙沪报建代办施工许可证。
联系人:张经理,18321657689(微信同号)。
11条评论
鉴定完毕!https://sdceda.com/lao/614856335/
没人理我,好伤心啊!http://muq50.farhataas.com
我默默的回帖,从不声张!http://vvhu2w.cbbhome.com
很多天不上线,一上线就看到这么给力的帖子!http://1l2tq.banisy.com
对牛弹琴的人越来越多了!http://xbq7.roskoyzr.com
关注一下!http://vz7g1n.ailawo.cn
管它三七二十一!http://t3t01.5glh.com
楼上的真不讲道理!http://hqlf.zhongshenghaitian.com
看帖回帖一条路!http://ih54jx.pt350128.cn
被楼主的逻辑打败了!http://www.guangcexing.net/tv/yMfjwBx.html
看了这么多帖子,第一次看到这么经典的!https://www.skypeis.com/
发表评论