Vue.js面试题

Vue.js面试题

1、MVVM框架

MVVM是Model-View-ViewModel的简写。MVVM分为三层,M层,V层,VM层。

  • M层即模型层,一般代表服务端的业务逻辑处理,负责与数据库交互。
  • V层即视图层,一般代表前端展示的页面,用于数据的展示。
  • VM层即视图模型层,负责通过接口从服务端(M层)获取数据,并将数据绑定到页面(V层);

VM层是连通M层和V层的桥梁。在Vue中,V层相当于vue实例的视图模板;VM层相当于vue实例本身,拥有向后台请求数据和操作数据的能力。

MVVM最主要的优点在于实现前后端分离,提高开发效率

2、Vue的响应式原理

响应式原理:Vue 遍历data选项对象所有的 property,并使用 Object.defineProperty(obj, propName, value) 把这些 property 全部转为 getter/setter

每个组件实例都对应一个 watcher 实例,监听数据更改并更新页面。

在这里插入图片描述
对于对象

Vue 无法检测 property 的添加或移除。由于 Vue 会在初始化实例时对 property 执行 getter/setter 转化,所以 property 必须在 data 对象上存在才能让 Vue 将它转换为响应式的。例如:

var vm = new Vue({
  data:{
    a:1
  }
})

// vm.a 是响应式的

vm.b = 2
// vm.b 是非响应式的

如何添加响应式属性?

可以使用 Vue.set(object, propertyName, value) 方法向嵌套对象添加响应式 property。

还可以使用 vm.$set 实例方法,这也是全局 Vue.set 方法的别名

赋值多个新 property:

// 代替Object.assign(this.someObject, { a: 1, b: 2 })
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })
对于数组

Vue 不能检测以下数组的变动:

  1. 利用索引设置数组项,例如:vm.items[indexOfItem] = newValue

  2. 修改数组长度,例如:vm.items.length = newLength

    举个例子:

    var vm = new Vue({
      data: {
        items: ['a', 'b', 'c']
      }
    })
    vm.items[1] = 'x' // 不是响应性的
    vm.items.length = 2 // 不是响应性的
    

如何响应式变动数组?

对于第1种情况:

// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)// 删除再添加
// vm.$set
vm.$set(vm.items, indexOfItem, newValue)

对于第2种情况:

// Array.prototype.splice
vm.items.splice(newLength)// 从指定索引处开始删除数组后的所有元素,若该数大于数组长度则不进行任何操作

3、Vue生命周期

常用钩子函数:

beforeCreate:

此时组件的选项对象还未创建,el 和 data 并未初始化,因此无法访问methods, data, computed等上的方法和数据。

created:

实例已完成以下配置:数据观测、属性和方法的运算,watch/event事件回调,完成了data 数据的初始化,$el还没有准备好。

beforeMount:

编译模板,把data里面的数据和模板生成html,完成了el和data 初始化,但并未挂载。

mounted:

挂载完成,也就是模板中的HTML渲染到HTML页面中,此时一般可以做一些ajax操作,mounted只会执行一次。

beforeUpdate:

发生在虚拟DOM重新渲染和打补丁之前

updated:

在由于数据更改导致的虚拟DOM重新渲染和打补丁完成时调用,调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作,在大多是情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。

beforeDestroy:

这一步还可以用this来获取实例,一般在这一步做一些重置的操作,比如清除掉组件中的定时器和 监听的dom事件。

destroyed:

在实例销毁之后调用,调用后,所有的事件监听器会被移除,所有的子实例也会被销毁。

4、v-for与key

在v-for中使用key属性的目的:

  • 高效地更新虚拟DOM

    在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述
  • 完整地触发组件的生命周期钩子

  • 触发过渡

5、路由的hash模式和history模式

1、hash

hash模式也就是锚点(#), 本质上是改变window.location的hash属性。我们可以通过直接赋值location.hash来改变href, 但是页面不刷新

2、history

history接口是HTML5新增的, 它有五种模式改变URL而不刷新页面.

history.pushState()
history.replaceState()
history.go(num)
history.back()
history.forward()

发起http请求时的不同
1:hash 模式下,仅hash符号之前的内容会被包含在请求中,即使没有做到对路由的全覆盖,也不会返回404错误
2:history模式下,前端的URL必须和实际向后端发起请求的URL一致。否则将返回404错误 ,必须在服务器进行配置避免错误。

6、插槽

默认插槽、具名插槽、作用域插槽。

<!-- 子组件 -->
template: '
    <slot></slot>// 默认插槽
    <slot name='name'></slot>// 具名
    <slot name="name" :prop="data"></slot>// 作用域
'
<!-- 父组件 -->
1、默认插槽
<childComponent>
	<!-- 任何HTML内容 -->
</childComponent>

2、具名插槽
<childComponent>
	<template v-slot:name></template>
</childComponent>

3、作用域插槽
<childComponent>
	<template v-slot:name="propsObj">
    	{{ propsObj.prop }}
    </template>
</childComponent>

7、vue的内置组件

1、<component :is="conponentName"></component>
2、<transition></transition>
3、<keep-alive></keep-alive>// 使组件实例能够在它们第一次被创建的时候被缓存下来
4、<slot name="name"></slot>

8、组件传值

1、父=>子

通过子组件的props:

// 子组件
<template>
    <div>
        {{ prop1 }}
    </div>
</template>

<script>
export defualt {
    props: ['prop1','prop2', ...]
}
</script>
            

// 父组件
<template>
	<div>
        <child-component :prop1="parentData" />
    </div>
</template>

<script>
export default {
    data() {
        return {
            parentData: 'value';
        }
    }
}
</script>

2、子=>父

通过$emit(eventType, data)

// 子组件
<template>
	<div>
    	<button @click="handler"></button>
    </div>
</template>

<script>
export default {
    data() {
        return {
            childData: 'value',
        }
    },
    methods: {
        handler() {
            this.$emit('event-name', childData)
        }
    }
}
</script>


//父组件
<template>
	<div>
        <child-component @event-name="getData" />
        {{ parentData }}
    </div>
</template>

<script>
export default {
    data() {
        return {
            parentData: ''
        }
    },
    methods: {
        getData(value) {
            this.parentData = value;
        }
    }
}
</script>

3、非父子组件间

通过vuex

// store/index.js
let store = Vuex.Store({
    state: {
        storeData: 'data',
    },
    mutations: {
        changeData(state, newValue) {
            state.storeData = newValue;
        }
    }
})

export default store;

// component-a
<template>
  <div>
  	<input v-model="dataA">
    <button @click="change(dataA)">改变component-a的数据</button>
  </div>
</template>

<script>
import { mapMutations} from 'vuex'
export default {
  name: 'Home',
  data() {
    return {
      dataA: 'value'
    }
  },
  methods: {
    ...mapMutations(['changeData']),
    change(newValue) {
      //this.changeData(newValue)
      this.$store.commit('changeData', newValue)
    }
  }
}
</script>


// component-b
<template>
  <div>
    component-b的数据将改变:{{ dataB }}
  </div>
</template>

<script>
export default {
  computed: {
    dataB() {
      return this.$store.state.storeData;
    }
  }
}
</script>

9、v-if和v-show的区别

1、v-if值为假时直接将元素从DOM中删除

2、v-show是切换元素的css属性display

/* v-show值为真时 */
display: block;
/* v-show值为假时 */
display: none;

10、为什么要避免v-if和v-for一起使用在同一个元素上

因为v-for比v-if有更高的优先级,所以每次渲染时都会遍历整个数据列表,无论数据列表是否发生了变化,这在数据列表庞大时会造成一定性能问题。可以通过将数据列表换成计算属性来解决,以此避免使用v-if。

11、异步更新队列

1、Vue在观察到数据变化时并不是直接更新DOM,而是开启一个队列,并缓冲同一事件循环中发生的所有数据改变。

2、在缓冲时会去除重复的(未改变的)数据,以此减少DOM操作,

3、vue是数据驱动的,所以我们应避免直接操作DOM,因为可能达不到我们想要的效果。我们可以把依赖于更新后的DOM的操作放到一个特殊的函数nextTick中,该函数的回调会在下次DOM更新完成后执行

this.$nextTick(function() {
  ...
})
// 或
Vue.nextTick(function() {
  ...
})

12、Vuex

Vuex用于Vue的状态管理。

通过new Vuex.Store()并传入一个选项对象来创建一个主仓库store实例。

一个store实例一般有几个属性:

1、state, 存放数据,这些数据是响应式的。
2、getters, 相当于数据的计算属性。
3、mutations, 存放更改state数据的一些方法,更改state的唯一方式就是调用store实例的commit方法。
4、actions, 存放提交mutation的一些方法,可以是异步的。
// 主仓库
5、modules, 用于声明子仓库
6、plugins, 声明插件
// 子仓库
7、namespaced, 开启命名空间

vuex的辅助函数:

mapState, mapGetters, mapMutations, mapActions。

13、 r o u t e r 和 router和 routerroute的区别

$router是通过VueRouter构造函数创建的router实例,常用方法有:push,replace, beforeEach, afterEach

$route表示当前路由对象,存储当前路由的一些信息,比如path、fullpath、hash、query等。

14、路由传参的方式和区别

1、方式:params 和 query
2、区别:
	1)params配合name,传递的参数在地址栏不会显示,类似于post
  2)query配合path,传递的参数会在地址栏显示出来,类似于get
3、举例说明:
   1)params 传参
    传: this.$router.push({
          name: 'particulars',
          params: {
            id: id
          }
        })
     接:this.$route.params.id
     
   2)query传参
     传:this.$router.push({
          path: '/particulars',
          query: {
            id: id
          }
        })
      接:this.$route.query.id

15、导航守卫

导航守卫函数一般都需传入三个参数:to, from, next,后置守卫一般不用传入next方法。

守卫种类包括:

1、全局守卫

beforeEach
afterEach

2、路由独享守卫

beforeEnter, ...

3、组件内守卫

beforeRouteEnter// 不能直接访问组件实例,可通过传入next()的回调的第一个参数vm访问
beforeRouteUpdate// 在路由改变但组件被复用时调用
beforeRouteLeave

16、请求/响应拦截器

1、请求拦截器

axios.interceptors.request.use((config) => {
  	// 给请求头设置一个token或其他操作
    return config;
  }, (error) => {
    // 对请求错误做些什么
    return Promise.reject(error);
  });

2、响应拦截器

axios.interceptors.response.use((response) => {
    // 对响应数据做一些预处理
    return response.data;
  }, (error) => {
    // 对响应错误做点什么
    return Promise.reject(error);
  });

17、Vue有哪些优点?

1、简单易学
2、双向数据绑定
3、组件化
4、数据驱动
5、虚拟DOM

18、单页应用程序(SPA)的优缺点

SPA即整个应用只有一个HTML页面,HTML内容的变化是由路由跳转机制实现的,不会重新加载整个页面。

优点:局部更新,性能良好,用户体验好。

缺点:首屏加载耗时多,且不利于SEO(搜索引擎优化)。

19、SPA首屏加载缓慢怎么解决?

// 1、路由懒加载
routes = [
  {
    path: '',
    name: '',
    component: () => import('./A.vue')
  }
]

// 2、静态资源本地缓存(怎么实现?)
 

// 3、UI组件库按需加载
// 4、图片资源压缩
// 5、使用SSR(服务端渲染)
// 6、开启gzip
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@前端攻城狮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值