vue基础面试题

vue

什么是mvvm

MVVM是Model-View-ViewModel的缩写.MVVM是一种设计思想.Model层代表数据模型,也可以在Model中定义数据修改数据的操作,View代表UI组件,它负责讲数据模型转换成UI展现出来,ViewModel是一个同步View和Model的对象.

在MVVM架构下,View和Model并没有直接联系,而是通过ViewModel进行交互,Model和ViewModel之间的交互是双向的,因此View数据的变黄会同步到Model中,而Model数据的变化也会立即反应到View上.

ViewModel通过双向数据绑定把View和Model层连接起来,而View和Model之间的同步操作完全是自动的,无需人为干涉因此开发者只需关注业务逻辑,不需要手动操作DOM,不需要关注数据状态的同步问题复杂的数据状态维护全由MVVM来统一管理

MVVM与MVC的区别?它和其他框架Jquery的区别是什么?哪些场景适用

MVC和MVVM其实区别并不大,都是一种设计思想,主要就是MVC中Controller演变成MVVM中订单viewModel.mvvm主要剞劂了mvc中大量的DOM操作使页面渲染性能降低,加载速度变慢

与jquery的区别:vue数据驱动通过数据来显式视图层而不是节点操作.

场景:数据比较多,频繁的场景,更加便捷

veu优点

  • 低耦合:W视图(View)可以独立于model变化和修改,一个ViewModel可以绑定到不同的View上,当ViewView变化的时候 Model可以不变,当Model变化的时候View也可以不变
  • 可重用性:可以把一些视图逻辑放在一个ViewModel里,让很多view重用这段逻辑视图
  • 独立开发:开发人员你可以专注于业务逻辑和数据的开发(viewModel),设计人员可专注于页面设计
  • 可测试:界面速来是比较难于测试的,而现在测试可以针对ViewModel来写

父子组件传值

-父组件通过标签上:data=data方法定义传值

子组件通过proprs方法接受数据

子组件通过$emit方法传递参数

vuecli怎么样使用自定义组件

  1. 在compents目录新建组件indexPage.vue,script一定要export default{}
  2. 在需要用的页面(组件)中导入:import xxxx from xxx
  3. 注入到子组件的components属性上面
  4. 在template师徒值中用标签使用

vue如何实现按需加载配合webpack设置

webpack提供了require.ensure()来实现按需加载,以前引入路由是通过 import 这样的方式引入,改为const定义的方式进行引入.

页面不需加载引入方式 import xxx from xxx

页面按需加载

const home= r =>require.ensure([],()=>r(require('xxxx')))

v-show与v-if的区别

v-show是通过修改元素的display的css属性让其显式或隐藏;

v-if是直接销毁和重建dom达到让元素显式和隐藏的效果

v-show会更加节省性能上的开销;

vue生命周期函数

  1. beforeCreate:在实例初始化后,数据观测和事件配置前被调用,此时组件的选项还未被创建,el和data并未初始化,因此无法访问methods,data,computed等上的方法和数据
  2. created(创建后)实例研究创建完成之后被调用,实例已完成,数据观测,属性和方法的运算,watch/event事件回调,完成了data数据的初始化,el没有.
  3. beforeMount:挂载开始之前被使用,相关的render函数首次被调用(虚拟DOM)实例完成以下的配置:编译模板,吧data里面的数据和模板生成html,完成了el和data初始化,注意此时还没有挂载到html上
  4. mounted:挂载完成也就是模板中的HTML渲染到页面中,此时一般可以做一些ajax操作,mounted只会执行一次
  5. beforUpdate:在数据更新之前被调用,发生在虚拟DOM重新渲染和打补丁之前1可以在该钩子进一步地更改状态,不会触发附加的重复渲染过程
  6. updated(更新后):由于数据更改导致虚拟DOM冲洗你渲染和打补丁时会调用,调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作,然后在大多数情况下,应该避免在此期间更改状态,因为这会导致更新无限循环
  7. beforeDestory在实例销毁之前调用,实例仍然完全可用,this来获取实例,一般在这一步做一些重置的操作,比如清除掉组件中定时器和监听DOM的事件
  8. destoryed在实例销毁之后调用,调用后,所有的事件监听器会被移出,所有的实例也会被销毁,该钩子在服务器渲染期间不被调用

为什么页面渲染使用key

当vee.js用v-for正在更新已渲染过的元素列表时,它默认用就地复用策略.如果数据项的顺序被改变,Vue将不会移动DOM元素来匹配数据项的顺序,而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的元素

场景

假设Vue实例的data属性中有一个叫numbers的变量,它的值是[1, 2, 3, 7, 8, 9]

<div v-for="num in numbers">
  {{num}}
</div>

这种情况下应当是渲染了6个<div>元素,其中的内容分别对应numbers中6个数字,此时如果numbers变成了[0, 1, 2, 3, 7, 8, 9],即在数组头部插入了一个数字0,在没有key属性的情况下,渲染输出的更新步骤是这样的:

原先内容为1的div元素变成0,原先内容为2的元素变成1,以此类推,最后新增一个div元素,内容为9

在这种情况下,vue会通过改变元素内容和增加减少元素来完成这个改变,因为没有key属性,Vue无法跟踪每个节点,只能通过这样的方式来完成变更

让我们对以上代码进行一个小修改:

<div v-for="(num, index) in numbers" :key="index">
  {{num}}
</div>

这里用index变量,根据列表渲染规则,它实际上对应了1数组中每个元素的索引,这样的好处是它可以让每个元素的key值都不同,这是很重要的,如果我们要利用key属性的优点,必须保证同一斧子元素所有的子元素有不同的key属性

此时如果从[1, 2, 3, 7, 8, 9]变成了[0, 1, 2, 3, 7, 8, 9],渲染输出的更新步骤就变化了:

新增一个div元素,它的内容为0,并将它插入原先内容为1的元素之前

再有了key属性之后,vue会记住元素们的顺序,并根据这个顺序在适当的位置插入/删除元素来完成更新,这种方法比没有key属性时的就地复用策略效率更高

key使用id和index的区别

不推荐使用index作为key,这种做法会导致某些节点被错误地原地复用

  • 性能损耗:列表渲染时会导致变动项往后的所有节点(内容)更新(相当于key没有发挥作用)
  • 出现错误:某些节点在错误的位置被复用(录入当项目中用到复选框的时候)

计算属性和watch的区别

计算属性是自动监听依赖值的变化,从而返回动态内容,监听是一个过程,在监听的值变化时,可以出发一个回调并做些事情

所以区别来源于用法,只是需要动态的值,那就用计算属性,需要知道值变化后的业务执行逻辑,采用watch

组件中的data为什么是函数

为什么组件中的 data 必须是一个函数,然后 return 一个对象,而 new Vue 实例里,data 可以直接是一个对象?

因为组件是用来复用的,js里对象是引用关系,这样作用域没有隔离,而new Vue的实例,是不会被复用的,因此不存在对象的问题

v-model是怎么实现的

v-model的本质就是语法糖,即利用了v-model绑定数据后,其实就是即绑定了数据有添加了一个input事件监听

如下

<input v-model="xxx">

等价于

<input v-bind:value="xxx" v-on:input="xxx = $event"

理解Vue中的Render渲染函数

vue一般使用template来创建HTML,然后在有的时候,我们需要 使用js来创建html,这时候问我们需要用render函数.

render函数return一个createElement组件中子元素存储在组件实例$slots.default中

怎么理解单项数据流

这个概念出现在组件通信父组件通过prop把数据传递到子组件的,但是这个prop只能由父组件修改,子组件不能修改,否则会报错。子组件想修改时,只能通过 $emit派发一个自定义事件,父组件接收到后,由父组件修改.

一般来说对于子组件想要更改父组件状态的场景,可以有俩种方案.

在自己组建的data中拷贝一份prop,data是可以修改的,但prop不能

export default {
  props: {
    value: String
  },
  data () {
    return {
      currentValue: this.value
    }
  }
}

如果是对 prop 值的转换,可以使用计算属性:

export default {
  props: ['size'],
  computed: {
    normalizedSize: function () {
      return this.size.trim().toLowerCase();
    }
  }
}

vue.js2.x双向绑定原理

这个问题几乎是面试必问的.基本上要知道核心的API是通过Object.defineProperty()来劫持各个属性的setter/getter,在数据变动时发布消息给订阅者,出发响应的监听回调,在野生为什么vue.js2.x不支持IE8的原因

vuex

vuex是什么,怎么使用

vuex是一个专为vue.js开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态,并以响应的规则保证状态以一种可预测的方式发生变化.

在main.js引入store注入.新建一个store目录.场景有:单页应用中,组件之间的状态,音乐播放,登录状态,加入购物车等

vuex使用单一状态树,用一个对象就包含了全部的应用层级状态.至此它便作为一个唯一数据源SSOT而存在.这也意味着,每个应用将基金包含一个store实例

vuex的state特性

  • vuex就是一个仓库,仓库里面放了很多对象.其中state就是数据源存放地,对应于一般Vue对象里面的data
  • state里面存放的数据是响应式的,Vue组件从store中读取数据,弱是store中的数据发生改变,依赖这个数据的组件也会发生更新
  • 通过mapState把全局state和getters映射到当前组件的compputed计算数学当中

vuex的getter特性

  • getters可以对state进行计算操作,它就是store的计算属性
  • 虽然在组件内也可以走计算属性,但是getters可以在多组件之间复用
  • 如果一个状态实在一个组件内使用,可以不用getters

vuex的Mutation和action特性

Mutation

更改vuex的store中的状态的唯一方法是mutation.Vuex中的mutation非常类似于事件:每个mutation都有一个字符串的事件类型和一个回调函数.这回调函数就是我们实际进行状态更改的地方,并且它会接受state作为第一个参数

可以像store.commit传入额外参数,即mutation的载荷.mutation必须是同步函数

action

action类似于mutation不同在于

action提交的是mutation,而不是直接变更状态

action 可以包含任意异步操作

vuex Modules概念

由于使用单一状态树,应用的所有状态会被几种到一个比较大的对象.当应用变得非常复杂时,store对象就有可能变得相当臃肿.

为了解决这个问题vuex允许讲store分成模块(module).每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:

const moduleA = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}
​
const moduleB = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... }
}
​
const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})
​
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态

vue-router

路由模式

history和hash模式

vue-router默认hash模式,使用URL的hash来模拟一个完整的URL,于是当URL改变时,页面不会重新加载.

history模式时,URL就像正常的URL

hash

开发中的默认模式,在url中永远带着#号,在浏览器方面支持度极佳,甚至兼容低版本的ie浏览器.

原理:window是开源监听到哈希值的变化的(onhashchage事件),这就意味着:当url的哈希值发生了变化,无需发起http请求,window也可以监听到这种变化,并按需加载前端的代码块

哈希模式也就是当下单页应用的标配,所谓前端路由的强大之处就在这里:路由分发不需要服务器来做,其阿奴单自己就可以完成

history模式

在url中不带#号,用的是传统的路由分发模式,即当用户输入一个url时,石油服务器在接受用户的这个输入请求,病友服务器解析url的路径然后做响应的逻辑处理.如果要做到改变url但又不刷新页面的效果就需要前端用上pushState和replaceState俩个H5的api,来把url替换的同时又不刷新页面,但需要后端女人缘去配置url重定向的问题,不然 在访问耳机月面时,做刷新操作会报404错误.这和hash天生就不会刷新页面的特效不同,历史模式来做这件事情属于一种障眼法,或者说老技术甘新活

vue导航钩子

vue-router有哪几种导航钩子

  1. 全局守卫router.befreEach
  2. 全局解析守卫:Wrouter.feforResolve
  3. 全局后置钩子:router.afterEach
  4. 路由独享的守卫:beforeEnter
  5. 组件内的守卫:beforeRouteEnter、beforeRouteUpdate (2.2 新增)、beforeRouteLeave

全局守卫

使用router.beforEach注册一个全局前置守卫

const router=new VueRouter({....})
router.beforeAch((to,from,next)=>{
    
})

当一个导航触发时,全局前置守卫按照创建顺序调用.守卫是异步解析执行此时导航在所有守卫resolve完成之前一直处于等待中

每个守卫接受三个参数

to:route即将要进入的目标 路由对象

from:route:当前导航正要离开路由

next:function:一定要调用该方法来resolve这个钩子

全局解析守卫

2.5.0新增

在2.5.0+快要用router.beforeResolve注册一个全局守卫.这和router.beforeEach类似,区别是:在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。

全局后置钩子

和守卫不同的是,这些钩子不会接受next函数,也不会改变导航本身

router.afterEach((to, from) => {
  // ...
})

路由的共享的守卫

在路由配置上直接定义 beforeEnter 守卫:

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
})

这些守卫与全局前置守卫方法参数是一样的

组件内的守卫

组件内快要直接定义以下路由导航守卫

  1. beforerouterEnter
  2. beforeRouuteUpdate
  3. beforeRouteLeave
Last modification:April 19, 2022
如果觉得我的文章对你有用,请随意赞赏