VUE 各种遇到的问题以及面试题

原文链接

原理

1.你知道vue的模板语法用的是哪个web模板引擎的吗?说说你对这模板引擎的理解.

mustache,主要是使用{
    {}}进行数据渲染。

2.你知道v-model的原理吗?那双向绑定的原理呢?

v-model是一个语法糖,真正实现双向绑定还是依靠v-bind:绑定响应式数据。以及触发input事件并传递数据(核心和重点)
双向绑定的原理:通过Observer把数据劫持(Object.defineProperty()),加入到订阅器(Dep),订阅器收集订阅者(watch),视图通过编译(Compile)
解析指令(Directive)等一系列操作收集给订阅者,最后通过触发数据变化update通知所有的订阅者完成数据驱动。
直白的理解为:Object.defineProperty()重新定义了set和get方法,修改触发set方法赋值。获取触发get方法取值,并通过数据劫持发布信息。

3.你知道vue中key的原理吗?说说你对它的理解

便于diff算法的更新,key的唯一性,能让diff算法更快的找到需要更新的dom节点。

4.Vue.Observable你有了解过吗?

vue2.6发布的一个新的api,可以处理简单的跨组件共享数据状态的问题。
精简版的vuex。

5.你知道style加scoped属性的用途和原理吗?

1.用途:防止全局同名css污染。
2.原理:在标签上添加v-data-something属性,再在选择器加上对应[v-data-something],即css带属性选择器,以此完成类似作用域的选择方式。

6.$nextTick的作用

// 官方文档:下次DOM更新循环结束执行延迟回调,在修改数据之后立刻调用这个方法,就会获取更新后的DOM。

//什么时候用到Vue.$nextTick();

//1.created初始化状态的时候没有挂载dom元素,所以此时需要操作dom元素就必须使用$nextTick();
//2.mounted不会承诺所有的子组件也都一起被挂载,如果你希望等到整个视图都渲染完毕,可以用$nextTick()替换mounted。

mounted:function(){
   this.$nextTick(()=>{
       
   })
}

文件路径

1.怎么解决vue打包后静态资源图片失效的问题?,那又怎么解决动态设置img的src不生效呢?

1.找到config/index.js配置文件,找到build打包对象里的assetsPublicPath属性,将默认值:'/',修改为:'./'。
2.因为动态添加的src被当做静态资源处理了,没有进行编译,所以要加上require。

2.分析下vue项目本地开发完后部署到服务器后报404是什么原因?

1.检查nginx(服务器)配置,是否正确配置资源映射条件。
2.检查vue.config.js中是否配置了pubilcPath属性,检查是否和项目资源文件在服务器摆放的位置一样。

3.在vue项目中如何配置favicon?

1.在html中添加mate标签
2.在vue-cil中开发环境webpack.dev.config.js中配置,和生产环境webpack.prod.config.js中配置。

4.使用vue后怎么针对搜索引擎做SEO优化?

使用服务端渲染,vue官方推荐nuxt.js

生命周期

1.Vue生命周期可以分为几个阶段?

8个阶段
1.beforeCreate:创建前,(data和methods都没初始化)
2.created:创建后,(data和methods已经初始化)
3.beforeMount:载入前,(在内存中已经编译好了模板,但是还没有挂载到页面上,dom还没有生成)
4.mounted:载入后,(Vue实例已经初始化完成了,此刻dom已经生成)
5.beforeUpdate:更新前,(此刻页面的数据是旧的,data的数据是更新的了,也就是页面还没有和最新的数据同步)
6.updated:更新后(页面的数据已经和更新的数据同步了),
7.beforeDestroy:销毁前(此刻data,mothods,指令,过滤器都处于可用状态),
8.destroyed:销毁后(此刻所有的data,mothods,指令等等,都处于不可用状态)

2.Vue在created和mounted这两个生命周期中请求的数据有什么区别?

1.在created请求时,是在页面渲染出来之前做的事情,如果数据过大,可能造成页面白屏过久,因为created还没有dom元素生成。并且也不能操作dom元素
2.在mounted请求时,是在页面渲染出来之后做的事情,此时可以操作dom元素。

3.跟keep-alive有关的生命周期是哪些?描述下这些生命周期

1.activated: 页面第一次进入的时候,钩子触发的顺序是created->mounted->activated
2.deactivated: 页面退出的时候会触发deactivated,当再次前进或者后退的时候只触发activated

4.第一次加载页面时会触发哪几个钩子?

1.beforeCreate
2.created
3.beforeMount
4.mounted

组件

1.如何通过子组件访问父组件的实例

this.$parent :拿到父组件的实例
this.$children拿到子组件实例(数组)

2.如何访问子组件的实例或者子元素

//父组件

使用this.$refs.baseAlert获取到子组件,并且可以调用子组件this.$refs.baseAlert.add()方法。

3.vue怎么实现强制刷新组件?

//强制刷新某组件

//选项里绑定data
data(){
  return{
      theKey:0
  }
}
//刷新key达到刷新组件的目的
theKey++;

4.vue自定义事件中父组件如何接收子组件的多个参数?

//子组件提交多个参数
var data = {
    'name':'1',
    'name2':'2'
}
this.$emit('func',data)

5.vue给组件绑定自定义事件无效怎么解决?

1、组件外部加修饰符:.native
//父组件
2、组件内部添加$emit()方法提交事件

6.vue如果想扩展某个现有的组件时,该怎么做?

1.使用slot插槽。
2.使用mixin混入。
3.使用vue.extends直接扩展。(优先级比mixin高)
4.使用HOC高阶组件。

7.vue为什么要求组件模板只能有一个根元素?

就像一个HTML文档只能有一个根元素一样....
多个根元素必将导致无法构成一颗树
所以解释了 只有一个
根元素。

8.vue中什么是递归组件?

//当前注册一个vue组件定义 name 为 'node-tree' ,在组件 template 内部调用 实现递归。
//tree.vue


9.vue边界情况有哪些?

1.访问元素&组件
   访问根实例
   访问父组件实例
   访问子组件实例或子元素
   依赖注入
2.程序化的事件侦听器
   $on(event,,,) :侦听一个事件
   $once(event,,,):一次性侦听一个事件
   $off(event,,,):停止侦听一个事件
3.循环引用
   3.1:递归组件
   3.2:组件之间的循环引用

10.vue组件中定时器要怎么销毁?

const time = setInterval(()=>{
    //do.somthing
},500)
//通过$once监听定时器,在beforeDestroy钩子可以被清除。
this.$once('hook:beforeDestroy',()=>{
     clearInterval(time)
})

11.vue组件会在什么情况下被销毁?

在组件中使用v-if的时候。

12.vue组件里写的原生addEventListeners监听事件,可以用手动销毁吗?为什么?

可以用手动销毁,因为一方面是绑定多次,另一方面是函数没有释放会造成内存溢出。

13.你了解函数式组件吗?

需要提供一个render方法,接收一个参数(createElement函数),方法内根据业务逻辑写需求,createElement创建vnodes,最后return vnodes

createElement函数接收三个参数,1:html标签或自定义组件。2:一个object(包含props,on...等等),3:children(通过createElement构建,或者字符串)

问题知识点-HTML

1.Vue渲染模板时怎么保留模板中的HTML注释呢?

//模板标签添加 comments 属性

2.如何修改分隔符"{ {}}"?

//对于laravel+vue开发已经成为常态(php),laravel框架开发下我们的分隔符"{
    {}}"是和vue+webapck+node是一样的。所以我们要修改我们的分隔符。

var vm =new Vue({
     el:"app",
     delimiters:['${' , '}'], //修改定界符'{
    {}}';
    data(){}
})
//最后laravel框架下的分割符变成了${}

3.slot(插槽)的理解有多少?

//插销显示与否:应根据父组件在引入子组件时,子组件中是否存在模板。

1.匿名插槽:在父组件中只能出现一个。
2.具名插槽:在父组件中可以出现多个
3.作用于插槽:在插槽中要绑定数据,

 export default {
    data: function(){
      return {
        data: ['zhangsan','lisi','wanwu','zhaoliu','tianqi','xiaoba']
      }
    },

4.如何优化首页的加载速度?

1.http请求控制次数。
2.异步加载数据,异步路由。
3.分屏加载,按需加载,延迟加载图片,cdn静态资源缓存。 

问题知识点-CSS

1.Vue的:class和;style有几种表达方式?

:class 绑定变量,绑定对象,绑定一个数组,绑定三元运算符
:style 绑定变量,绑定对象,绑定函数返回值,绑定三元运算符

问题知识点-JS

1.Vue中怎么重置data

1.Object.assign()方法:用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。
2.this.$data:获取当前状态下的data。
3.this.$option.data:获取该组件初始化状态下的data。
4.Object.assign(this.$data,this.$option.data);

2.watch的属性用箭头函数定义结果会怎么样?

this为undefined,因为箭头函数绑定了父级作用域的山下文,所以this将不会按照期望指向vue实例。

3.在vue项目中如果methods的方法用箭头函数定义结果会怎么样?

因为箭头函数默认绑定了父级作用域的上下文,所以this将不会绑定vue实例,所以this是undefined。

4.你有使用过babel-polyfill模块吗?主要是用来做什么的?

babel默认只进行转换语法,而不转换新的api。所以想要转换新的api还需要对应的转换插件。或者使用polyfill模拟新api。

5.说说你对vue的错误处理的了解?

vue错误处理有两种,
1.errorCaptured:是组件内部钩子,可以捕获到本组件以及子孙组件抛出的错误,接收参数有error,vm,info三个参数,return false后可以阻止错误继续向上抛出、
2.errorHandler:为全局钩子,使用vue.config.errorHandler配置,接收参数和errorCaptured一致,2.6后可捕获v-on与promise链的错误,可用于统一错误处理与错误兜底。
  1. 在vue事件中传入$event,使用e.target和e.currentTarget有什么区别?
e.target:属于事件发生者(鼠标触发的元素)
e.currentTarget:属于事件绑定的元素。

7.vue变量名如果以_、$开头的属性会发生什么问题?怎么访问到它们的值?

以_或者$开头的属性 不会被vue实例代理,因为它们可能会和vue内置属性,api方法冲突,
我们可以使用vm.$data._property的方式访问这些属性

8.vue使用v-for遍历对象时,是按照什么顺序遍历的?如何保证顺序?

1.会先判断对象是否存在iterator接口,如果有循环执行next()方法。
2.没有iterator的情况下,会调用Object.Keys()方法,在不同的浏览器中,js引擎不能保证输出的顺序是一致的。
3.如果想要保证输出的顺序一致,可以将对象放进数组中,作为数组的元素。

9.说下 a t t r s 和 attrs和 attrslisteners的使用场景

$attrs:获取父级以上的所有(非props属性)的属性。
$listeners:调用在父级以上的所有定义的方法。

10.EventBus事件总线注册在全局上时,路由切换的时候重复触发事件,该如何解决呢?

1、EventBus的使用
//创建EventBus
import Vue from 'vue'
export default new Vue;

2、在main.js导入eventbus,然后挂载在vue原型上

import bus from './utils/eventBus';

Vue.prototyle.bus = bus;

3、发送事件
//在触发事件的地方发送事件
this.bus.$emit(this.$route.path);$emit()里面接收一个string字符串事件名,

4、接收事件
//事件已经发送,接下来只需要在需要接收事件的地方接收这个事件,然后对事件进行响应就可以了。
this.bus.$on(this.$route.path,()=>{
  this.getData();
})
//接收事件同样需要一个事件名。

5、事件重复触发的问题
 //我们只需要在组件的beforeDestroy或者destroy生命周期中执行销毁方法。
beforeDestroy(){
 this.bus.$off(this.$route.path)
}

6、如果使用this.$route.path作为事件名,那么虽然我们在生命周期注销了事件,但是还是发现事件会执行多次,原因在于我们在beforeDestroy中,this.$router.path根本不是我们发送和响应事件时候的路由了,而是将要跳转的页面路由。所以只要我们在当前页面用一个变量将当前路由存下来。用这个变量作为变量名注销事件即可。

11.Vue组件中写name选项有什么作用?

1.使用keep-alive时,可以搭配组件name进行缓存过滤
2.DOM做递归组件时需要调用自身name。
3.vue-devtools调式工具里显示的组件名称是有vue中name决定的

12.Vue中的provide和inject是什么?

provide:是一个对象,或者是返回对象的函数,里面包含要给子孙后代的东西,也就是属性和属性值。(不再需要逐级往上找值)
inject:是一个字符串数组,或者是一个对象,属性值可以是一个对象,包含from,和default默认值。

13.v-if和v-for同时出现的优先级问题?

//v-for的优先级比v-if高。所以同时出现的时候,先给v-for套一层template作为父级元素,再在父级元素进行v-if判断