Vue前端面试题

  1. Vue
  2. 一、Vue的响应式系统是什么?
  3. 二、什么是MVVM模式?
  4. 三、Vue原理是什么(双向数据绑定),有什么缺点?
    1. 缺点:
  5. 四、Vue的优点和缺点是什么?
    1. 优点:
    2. 缺点:
  6. 五、Vue生命周期函数有哪些?他们分别有什么不同?
    1. 1、beforeCreate函数(创建前):
    2. 2、created(创建后):
    3. 3、beforeMount(挂载前):
    4. 4、mounted(挂载后):
    5. 5、beforeUpdate(更新前):
    6. 6、updated(更新后):
    7. 7、beforeDestroy(销毁前):
    8. 8、destroyed(销毁前):
  7. 六、Vue生命周期有关问题:
    1. 1、vue生命周期的作用是什么?
    2. 2、第一次页面加载会触发哪几个生命钩子函数?
    3. 3、简述每个生命周期具体适合哪些场景?
  8. 七、什么是虚拟DOM(Virtual DOM)?有什么用?
    1. 1、什么是虚拟DOM?
    2. 2、虚拟DOM有什么用?
  9. 八、介绍Vue中的Diff算法是什么?
    1. 1、核心:
    2. 2、过程:
    3. 3、注意:
  10. 九、v-for渲染列表的时候key属性的作用是什么?没有写key会有什么影响?为什么不能用index作为 key?
    1. 1、作用:
    2. 2、影响:
    3. 3、index作为key值:
  11. 十、vuex是什么?有哪些属性?怎么使用vuex?哪种功能场景使用它?怎样是vuex持久化?
    1. 1、概念:
    2. 2、vuex功能:
    3. 3、vuex使用场景
    4. 4、vuex持久化:
    5. 4、属性:
      1. 1)State属性:
      2. 2)Getters属性:
      3. 3)Mutations属性:
      4. 4)Actions属性:
      5. 5)Modules属性:
    6. 5、怎样使用vuex:
  12. 十一、vue-router(路由)有哪几种导航钩子?
    1. 1、全局前置守卫 ==> router.beforeEach(to, from, next)
    2. 2、全局解析守卫 ==> router.beforeResolve(to, from, next)
    3. 3、全局后置钩子 ==> router.afterEach(to, from, next)
    4. 4、路由独享钩子 ==> router.beforeEnter(to, from, next)
    5. 5、组件内的导航钩子:
  13. 十二、Vue中常见性能优化?
    1. 1、编码优化:
    2. 2、Vue 加载性能优化:
    3. 2、打包优化:
  14. 十三、Vue中模板编译原理?
  15. 十四、请说下封装Vue组件的过程?为什么要封装组件?
    1. 1、为社么要封装组件:
    2. 2、封装组件的过程:
  16. 十五、Vue中常见的传值方法有哪些?(列表==>详情)
    1. 1、方法一(编程式导航跳转):
    2. 2、方法二(声明式导航跳转):
  17. 十六、v-if && v-show 的区别?如何使用?
    1. 1、相同点:
    2. 2、区别:
    3. 3、使用:
  18. 十七、v-if && v-for 哪个优先级更高?为什么不能连用?如果两个同时出现,应该怎么优化得到更好的性能?
    1. 1、优先级:
    2. 2、为什么不能连用:
    3. 3、同时出现的优化:
  19. 十八、Vue中$nextTick有什么作用?应用场景?
    1. 1、作用:
    2. 2、应用场景:
  20. 十九、vue中的$set有什么用?
    1. 1、作用:
    2. 2、使用情况:
    3. 2、使用方法:
  21. 二十、computed与watch的区别?应用场景有哪些?
    1. 1、区别:
    2. 2、应用场景:
  22. 二十一、Vue组件之间通信有哪几种方法?
    1. 1、方法一:props/$emit
      1. 1)props ==> 父组件向子组件传参:
      2. 2)$emit ==> 子组件向父组件传参:
    2. 2、方法二: 中央事件总线(eventBus)非父子组件间通信
    3. 3、方法三:Vuex
    4. 4、方法四:$attrs/$listeners
    5. 5、方法五:provide/inject
    6. 6、方法六:v-model
    7. 7、方法七:$parent/$children
  23. 二十二、Vue事件绑定原理
  24. 二十三、为什么组件的data必须是一个函数?
    1. 例子:
  25. 二十四、slot是什么?有什么作用?有哪几种插槽?区别是是什么?slot实现原理是什么?
    1. 1、slot是什么?
    2. 2、作用:
    3. 3、有哪几种插槽:
    4. 4、各种插槽的区别:
    5. 5、实现原理:
  26. 二十五、如何让CSS只在当前组件中起作用?原理是什么?为什么需要穿透scoped?如何穿透scoped?
    1. 1、只在当前组件中起作用:
    2. 2、原理:
    3. 3、为什么需要穿透scoped?
    4. 4、如何穿透scoped?
  27. 二十六、Vue中keep-alive的作用是什么?使用场景?
    1. 1、作用:
    2. 2、使用场景:
  28. 二十七、Vue中如何获取原生DOM?
  29. 二十八、Vue的两个核心是什么?
  30. 二十九、说说Vue2.0和Vue3.0有什么区别?
    1. 1、重构响应式系统,使用Proxy替换Object.defineProperty:
    2. 2、新增Composition API,更好的逻辑复用和代码组织:
    3. 3、重构 Virtual DOM:
    4. 4、精准的变更通知:
    5. 5、默认项目目录结构发生了变化:
  31. 三十、为什么Vue3.0要新增Composition API,能解决什么问题?
    1. 1、主要(一句话概括):
    2. 2、解释:
  32. 三十一、自定义组件(父子组件)的双向数据绑定
    1. 1、使用 v-model 语法糖:
    2. 2、过程:
  33. 三十二、Vue框架与jQuery类库的区别
  34. 三十三、SSR(服务端渲染)有了解吗?原理是什么?使用SSR好处是什么?
    1. 1、原理(服务端渲染):
    2. 2、好处:
  35. 三十四、如何让UI库的按需加载
    1. 一、安装 babel-plugin-component:
    2. 二、在 babel.config.js 文件下配置:
    3. 3、按需引入组件:
  36. 三十五、v-on可以监听多个方法吗?
    1. 1、使用方法:
  37. 三十六、mixins混入简化常见操作
    1. 1、概念:
    2. 2、minxins的特点:
  38. 三十七、vue中路由有哪几种模式?分别有什么区别?怎么切换路由模式?
    1. 1、hash模式
    2. 2、history模式
    3. 3、区别:
  39. 三十八、嵌套路由?动态路由?路由重定向?
    1. 1、嵌套路由:
    2. 2、动态路由:
    3. 3、路由重定向:
  40. 三十七、vue中路由的拆分管理
    1. 1、路由拆分
  41. 三十八、vue中路由懒加载(也叫延迟加载)
    1. 1、使用 import:
    2. 2、vue 异步组件:
    3. 3、webpack 的 require,ensure():
  42. 三十九、css的scoped私有作用域和深度选择器
    1. 1、私有作用域:
    2. 2、深度选择器:
  43. 四十、vue单页面应用及其优缺点?
    1. 1、优点:
    2. 2、缺点:
  44. 四十一、webpack是什么?常见配置有哪些?
    1. 1、概念:
    2. 2、常见配置:

目录

  1. Vue
  2. 一、Vue的响应式系统是什么?
  3. 二、什么是MVVM模式?
  4. 三、Vue原理是什么(双向数据绑定),有什么缺点?
    1. 缺点:
  5. 四、Vue的优点和缺点是什么?
    1. 优点:
    2. 缺点:
  6. 五、Vue生命周期函数有哪些?他们分别有什么不同?
    1. 1、beforeCreate函数(创建前):
    2. 2、created(创建后):
    3. 3、beforeMount(挂载前):
    4. 4、mounted(挂载后):
    5. 5、beforeUpdate(更新前):
    6. 6、updated(更新后):
    7. 7、beforeDestroy(销毁前):
    8. 8、destroyed(销毁前):
  7. 六、Vue生命周期有关问题:
    1. 1、vue生命周期的作用是什么?
    2. 2、第一次页面加载会触发哪几个生命钩子函数?
    3. 3、简述每个生命周期具体适合哪些场景?
  8. 七、什么是虚拟DOM(Virtual DOM)?有什么用?
    1. 1、什么是虚拟DOM?
    2. 2、虚拟DOM有什么用?
  9. 八、介绍Vue中的Diff算法是什么?
    1. 1、核心:
    2. 2、过程:
    3. 3、注意:
  10. 九、v-for渲染列表的时候key属性的作用是什么?没有写key会有什么影响?为什么不能用index作为 key?
    1. 1、作用:
    2. 2、影响:
    3. 3、index作为key值:
  11. 十、vuex是什么?有哪些属性?怎么使用vuex?哪种功能场景使用它?怎样是vuex持久化?
    1. 1、概念:
    2. 2、vuex功能:
    3. 3、vuex使用场景
    4. 4、vuex持久化:
    5. 4、属性:
      1. 1)State属性:
      2. 2)Getters属性:
      3. 3)Mutations属性:
      4. 4)Actions属性:
      5. 5)Modules属性:
    6. 5、怎样使用vuex:
  12. 十一、vue-router(路由)有哪几种导航钩子?
    1. 1、全局前置守卫 ==> router.beforeEach(to, from, next)
    2. 2、全局解析守卫 ==> router.beforeResolve(to, from, next)
    3. 3、全局后置钩子 ==> router.afterEach(to, from, next)
    4. 4、路由独享钩子 ==> router.beforeEnter(to, from, next)
    5. 5、组件内的导航钩子:
  13. 十二、Vue中常见性能优化?
    1. 1、编码优化:
    2. 2、Vue 加载性能优化:
    3. 2、打包优化:
  14. 十三、Vue中模板编译原理?
  15. 十四、请说下封装Vue组件的过程?为什么要封装组件?
    1. 1、为社么要封装组件:
    2. 2、封装组件的过程:
  16. 十五、Vue中常见的传值方法有哪些?(列表==>详情)
    1. 1、方法一(编程式导航跳转):
    2. 2、方法二(声明式导航跳转):
  17. 十六、v-if && v-show 的区别?如何使用?
    1. 1、相同点:
    2. 2、区别:
    3. 3、使用:
  18. 十七、v-if && v-for 哪个优先级更高?为什么不能连用?如果两个同时出现,应该怎么优化得到更好的性能?
    1. 1、优先级:
    2. 2、为什么不能连用:
    3. 3、同时出现的优化:
  19. 十八、Vue中$nextTick有什么作用?应用场景?
    1. 1、作用:
    2. 2、应用场景:
  20. 十九、vue中的$set有什么用?
    1. 1、作用:
    2. 2、使用情况:
    3. 2、使用方法:
  21. 二十、computed与watch的区别?应用场景有哪些?
    1. 1、区别:
    2. 2、应用场景:
  22. 二十一、Vue组件之间通信有哪几种方法?
    1. 1、方法一:props/$emit
      1. 1)props ==> 父组件向子组件传参:
      2. 2)$emit ==> 子组件向父组件传参:
    2. 2、方法二: 中央事件总线(eventBus)非父子组件间通信
    3. 3、方法三:Vuex
    4. 4、方法四:$attrs/$listeners
    5. 5、方法五:provide/inject
    6. 6、方法六:v-model
    7. 7、方法七:$parent/$children
  23. 二十二、Vue事件绑定原理
  24. 二十三、为什么组件的data必须是一个函数?
    1. 例子:
  25. 二十四、slot是什么?有什么作用?有哪几种插槽?区别是是什么?slot实现原理是什么?
    1. 1、slot是什么?
    2. 2、作用:
    3. 3、有哪几种插槽:
    4. 4、各种插槽的区别:
    5. 5、实现原理:
  26. 二十五、如何让CSS只在当前组件中起作用?原理是什么?为什么需要穿透scoped?如何穿透scoped?
    1. 1、只在当前组件中起作用:
    2. 2、原理:
    3. 3、为什么需要穿透scoped?
    4. 4、如何穿透scoped?
  27. 二十六、Vue中keep-alive的作用是什么?使用场景?
    1. 1、作用:
    2. 2、使用场景:
  28. 二十七、Vue中如何获取原生DOM?
  29. 二十八、Vue的两个核心是什么?
  30. 二十九、说说Vue2.0和Vue3.0有什么区别?
    1. 1、重构响应式系统,使用Proxy替换Object.defineProperty:
    2. 2、新增Composition API,更好的逻辑复用和代码组织:
    3. 3、重构 Virtual DOM:
    4. 4、精准的变更通知:
    5. 5、默认项目目录结构发生了变化:
  31. 三十、为什么Vue3.0要新增Composition API,能解决什么问题?
    1. 1、主要(一句话概括):
    2. 2、解释:
  32. 三十一、自定义组件(父子组件)的双向数据绑定
    1. 1、使用 v-model 语法糖:
    2. 2、过程:
  33. 三十二、Vue框架与jQuery类库的区别
  34. 三十三、SSR(服务端渲染)有了解吗?原理是什么?使用SSR好处是什么?
    1. 1、原理(服务端渲染):
    2. 2、好处:
  35. 三十四、如何让UI库的按需加载
    1. 一、安装 babel-plugin-component:
    2. 二、在 babel.config.js 文件下配置:
    3. 3、按需引入组件:
  36. 三十五、v-on可以监听多个方法吗?
    1. 1、使用方法:
  37. 三十六、mixins混入简化常见操作
    1. 1、概念:
    2. 2、minxins的特点:
  38. 三十七、vue中路由有哪几种模式?分别有什么区别?怎么切换路由模式?
    1. 1、hash模式
    2. 2、history模式
    3. 3、区别:
  39. 三十八、嵌套路由?动态路由?路由重定向?
    1. 1、嵌套路由:
    2. 2、动态路由:
    3. 3、路由重定向:
  40. 三十七、vue中路由的拆分管理
    1. 1、路由拆分
  41. 三十八、vue中路由懒加载(也叫延迟加载)
    1. 1、使用 import:
    2. 2、vue 异步组件:
    3. 3、webpack 的 require,ensure():
  42. 三十九、css的scoped私有作用域和深度选择器
    1. 1、私有作用域:
    2. 2、深度选择器:
  43. 四十、vue单页面应用及其优缺点?
    1. 1、优点:
    2. 2、缺点:
  44. 四十一、webpack是什么?常见配置有哪些?
    1. 1、概念:
    2. 2、常见配置:

Vue

一、Vue的响应式系统是什么?

  • VueMVVM 框架,当数据 data 变化时,页面就发响应更新,原理是对 datagetter/setter 方法进行拦截(Object.defineProperty || Proxy),利用发布订阅者模式,在 getter 中进行订阅,在 setter 中发送通知,让所有订阅者完成响应。
<div id="app"></div>
<script>
    const obj = {}
    let v = 10
    Object.defineProperty(obj, 'x', {
        // get是再每次访问obj的x属性的时候就会执行,并且这个属性得到的值来自于get的返回值
        get () {
            return v
        },
        // 每次要修改obj的x属性,就会调用set
        set (newValue) {
            console.log('newValue:' + newValue)
            v = newValue
            // 每次set的时候都调用渲染DOM的方法,这样就实现了响应式
            setAppContent()
        }
    })
    // 这个方法专门负责渲染DOM
    const setAppContent = () => {
        document.querySelector('#app').innerHTML = obj.x
    }
    setAppContent()
</script>

二、什么是MVVM模式?

  • 首先由 View (视图层)接收到用户的交互请求,然后将请求转发给 ViewModel (Vue封装的),ViewModel 操作 Model(模型层) 进行数据更新,Model(模型层) 更新完成数据之后,通知 ViewModel 数据发生变化,最后由 ViewModel 更新视图层显示。
  • ViewModel 负责连接 ViewModel,保证视图和数据的一致性

三、Vue原理是什么(双向数据绑定),有什么缺点?

Vue 是采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty() 来劫持各个属性的 setter/getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

缺点:

  • vue 实例创建后,再向其上添加属性,不能监听,需使用Vue.set设置一个新的对象属性
  • 不能监听数组下标的变化,需要使用Vue.set更新视图

四、Vue的优点和缺点是什么?

优点:

  • 双向数据绑定

  • 轻量级框架性能好

  • 虚拟 DOM、运行速度快

  • 组件化开发

  • 简单易用

  • 单页面应用用户体验好

  • 前后端分离

缺点:

  • 不利于 SEO
  • 适合中小型项目
  • 不兼容 IE8

五、Vue生命周期函数有哪些?他们分别有什么不同?

1、beforeCreate函数(创建前):

  • 在实例初始化后被调用 ,这个时候的 this 不能用,在 data 中的数据 methods 的方法还有 watcher中的事件都获取不到。

2、created(创建后):

  • 实例已经创建完成了,实例对象已经完成了,这时候可以访问 data 中的 数据 ,一级 methods 中的方法和 watcher 中的事件了,但是 不能操作 DOM 节点。

3、beforeMount(挂载前):

  • 在这一阶段,我们虽然依然得不到具体的 DOM 元素,但 vue 挂载的根节点已经创建。

4、mounted(挂载后):

  • 挂载完毕 ,这时候可以使用 dom 节点 ,一些需要 DOM 的操作这时候才可以进行,发送请求等。

5、beforeUpdate(更新前):

  • 组件更新前 也就是说 数据 更新了 但是 vue 中的组件(事件)对应 DOM 内部中的数据没有变所以说叫做组件更新前。

6、updated(更新后):

  • 组件更新完成之后的操作,vue 中的组件(事件)已经对应 DOM 内部中的数据了。

7、beforeDestroy(销毁前):

  • 实例销毁之前调用 ,在 这个时候实例还是可以用的。

8、destroyed(销毁前):

  • 摧毁阶段 vue 的 生命周期结束 ,实例不能用了。

六、Vue生命周期有关问题:

1、vue生命周期的作用是什么?

  • 生命周期中有多个事件钩子,让我们在控制整个 Vue 实例的过程时更容易形成好的逻辑。

2、第一次页面加载会触发哪几个生命钩子函数?

  • 第一次页面加载时会触发 beforeCreatecreatedbeforeMountmounted

3、简述每个生命周期具体适合哪些场景?

  • beforecreate: 可以在这加个 loading 事件,在加载实例时触发。
  • created: 初始化完成时的事件写在这里,如在这结束 loading 事件,异步请求也适宜在这里调用。
  • mounted: 挂载元素,获取到 DOM 节点,发送异步请求。
  • updated: 如果对数据统一处理,在这里写上相应函数。
  • beforeDestroy: 可以做一个确认停止事件的确认框。

七、什么是虚拟DOM(Virtual DOM)?有什么用?

1、什么是虚拟DOM?

  • Virtual DOMDOM 节点在 JavaScript 中的一种抽象数据结构,VueDOM 抽象成一个以JavaScript 对象为节点的虚拟 DOM 树,以 VNode 节点模拟真实的 DOM,可以对这颗抽象树进行创建节点,删除节点以及修改节点的操作,经过 diff算法 得出一些需要修改的最小单位,再更新视图,大大提高了性能。

2、虚拟DOM有什么用?

  • 之所以需要虚拟DOM,是因为浏览器中操作 DOM 的代价比较昂贵,频繁操作 DOM 会产生性能问题。虚拟 DOM 的作用是在每一次响应式数据发生变化引起页面重渲染时,Vue 对比更新前后的虚拟DOM(Diff算法),匹配找出尽可能少的需要更新的真实 DOM,从而达到提升性能的目的。

八、介绍Vue中的Diff算法是什么?

1、核心:

  • Diff 算法的核心是对比新旧节点的 children,更新 DOM

2、过程:

  • 首先,对比节点本身,判断是否为同一节点,如果不为相同节点,则删除该节点重新创建节点进行替换。
  • 如果为相同节点,执行 patchVnode 函数,判断如何对该节点的子节点进行处理,先判断一方有子节点一方没有子节点的情况(如果新的 children 没有子节点,将旧的子节点移除)。
  • 比较如果都有子节点,则递归调用 updateChildren 函数,判断如何对这些新老节点的子节点进行操作(diff核心)

3、注意:

  • diff 中,只对同层的子节点进行比较,放弃跨级的节点比较,也就是说只有当新旧 children 都为多个子节点时才需要用核心的 Diff 算法进行同层级比较。

九、v-for渲染列表的时候key属性的作用是什么?没有写key会有什么影响?为什么不能用index作为 key?

1、作用:

  • key 属性可以避免数据混乱的情况出现,在列表中单条数据改变的情况下,可以进行单独渲染,减少页面资源消耗。

2、影响:

  • 如果没有写key值,在删除一个列表[1,2,3]中间元素的时候。会把把 2 变成了 3,然后把 3 删除了。
  • 因为计算机对比数组采用的是遍历的方法,首先对比 11,发现「1 没变」;然后对比 23,发现「2 变成了 3」;最后对比 undefined3,发现「3 被删除了」。所以使用 v-for 的时候必须加上 key 值,不然会对性能有很大的消耗。

3、index作为key值:

  • 如果你用 index 作为 key,那么在删除第二项的时候,index 就会从 1 2 3 变成 1 2(因为 index 永远都是连续的,所以不可能是 1 3),那么 Vue 依然会认为你删除的是第三项。也就是会遇到上面一样的 bug

十、vuex是什么?有哪些属性?怎么使用vuex?哪种功能场景使用它?怎样是vuex持久化?

1、概念:

  • VuexVue.js 中的状态管理模式

2、vuex功能:

  • 复杂非父子通信的问题。

  • 缓存后端数据,提高用户体验。

import http from '@/util/http'
const module = {
    namespaced: true, // 开启命名空间
    state: {
        cinemaList: []
    },
    actions: {
        getCinemaAction(store, id) {
            http.request({
                url: `/gateway?cityId=${id}&ticketFlag=1&k=8407651`,
                method: 'get',
                headers: {'X-Host': 'mall.film-ticket.cinema.list'}
            }).then(res => {
                store.commit('setCinemaList', res.data.data.cinemas)
            })
        }
    },
    mutations: {
        setCinemaList(state, data) {
            state.cinemaList = data
        }
    },
    getters: {
        topDataList(state) {
            return state.cinemaList.slice(0, 5)
        }
    }
}

export default module

3、vuex使用场景

  • 购物车的数据共享。
  • 登录注册。

4、vuex持久化:

  • 使用 vuex-persistedstate,是数据默认存储到 localStorage 里面。

4、属性:

1)State属性:

  • State 属性 就是数据源存放地,对应于一般 Vue 对象里面的 data

2)Getters属性:

  • getter 可以对 State 进行计算操作,它就是 Store 的计算属性。

3)Mutations属性:

  • Mutation 定义的方法动态修改状态或数据。

4)Actions属性:

  • Action 提交(store.commit)的是 mutation,而不是直接变更状态。
  • Action 可以理解为通过将 Mutation 里面处里数据的方法变成可异步的处理数据的方法,简单的说就是异步操作数据。view 层通过 store.dispath 来分发 Action

5)Modules属性:

  • 项目特别复杂的时候,可以让每一个模块拥有自己的 statemutationactiongetters 使得结构非常清晰,方便管理。

5、怎样使用vuex:

  • 安装 vuex

  • 建立 store 文件夹,并且在下面建立一个 store.js 文件。

  • 先引入 VueVuex 并且别忘了 Vue.use(Vuex)。

  • 并且在 Vue 实例上挂载 store

  • state 访问:

// 方法一:
this.$store.state.cityId


// 方法二:
import { mapState } from "vuex"; // mapState 是vuex提供的切割函数(映射函数)
computed: {
    ...mapState("city", ["cityId"]) // 把city 命名空间的cityId直接截出来(状态写在计算属性当中)
},
this.cityId // 可以通过this.cityId直接访问到vuex中的状态了
  • getter 访问:
// 方法一:
this.$store.geeters.topDataList


// 方法二:
import { mapGetters } from "vuex"; // mapGetters 是vuex提供的切割函数(映射函数)
computed: {
    // 状态值写在计算属性里面就行了
    ...mapGetters("cinema", ["topDataList"]),
},
this.topDataList // 可以通过this.topDataList直接调用vuex中的topDataList数据了
  • mutations 访问:
// 方法一:
this.$store.commit("hide");


// 方法二:
import { mapMutations } from "vuex"; // mapMutations 是vuex提供的切割函数(映射函数)
methods: {
    ...mapMutations("tabbar", ["hide", "show"]), // 把tabbar 命名空间的hide和show方法直接截出来(方法写在methods中)
},
this.hide() // 可以通过this.hide()直接调用vuex中的hide方法了
  • actions 访问:
// 方法一:
this.$store.dispatch("cinema/getCinemaAction");


// 方法二:
import { mapActions } from "vuex"; // mapActions 是vuex提供的切割函数(映射函数)
methods: {
    ...mapActions("cinema", ["getCinemaAction"]), // cinema 命名空间的getCinemaAction方法直接截出来(方法写在methods中)
},
this.getCinemaAction() // 可以通过this.getCinemaAction()getCinemaAction

十一、vue-router(路由)有哪几种导航钩子?

1、全局前置守卫 ==> router.beforeEach(to, from, next)

//to: 即将要进入的目标路由对象
//from: 当前正要离开的路由
//next: 一定要调用该方法来resolve这个钩子
router.beforeEach((to, from, next) => {
    if (to.path === '/mySelf') {
        if (localStorage.getItem('token')) {
            // 如果有token代表登录成功放行
            next()
        } else {
            // 没有token跳转到登录页面
            next('/login')
        }
    } else {
        next()
    }
})

2、全局解析守卫 ==> router.beforeResolve(to, from, next)

3、全局后置钩子 ==> router.afterEach(to, from, next)

4、路由独享钩子 ==> router.beforeEnter(to, from, next)

5、组件内的导航钩子:

  • beforeRouteEnter(to, from, next)
  • beforeRouteUpdate(to, from, next)
  • beforeRouteLeave(to, from, next)

十二、Vue中常见性能优化?

1、编码优化:

  • 不要将所有的数据都放到 data 中,data 中的数据都会增加 gettersetter,又会收集 watcher,这样还占内存,不需要响应式的数据我们可以定义在实例上。

  • 使用 v-show 代替 v-if 指令。

  • 使用 v-for 循环的时候加上 key

  • 使用 keep-alive 缓存组件,防止组件来回的创建和销毁这样浪费性能。

  • 使用路由懒加载,异步组件。

  • 预渲染插件 prerender-spa-plugin

  • 函数节流、防抖。

2、Vue 加载性能优化:

  • 第三方模块按需导入。
  • 图片懒加载(vue-lazyload)。
  • 滚动到可视区域动态加载(vue-virtual-scroll-list)。

2、打包优化:

  • 使用 cdn 的方式加载第三方模块。
  • 多线程打包 happypack
  • sourceMap 生成。

十三、Vue中模板编译原理?

  • .将模板字符串转换成 element AST(解析器parser)。

  • ast 进行静态节点标记,主要用来做虚拟 dom 的渲染优化(优化器optimizer)。

  • 使用 element AST 生成 render 函数代码字符串(代码生成器code generator )。


十四、请说下封装Vue组件的过程?为什么要封装组件?

1、为社么要封装组件:

  • 能够把页面抽象成多个相对独立的模块
  • 实现代码重用,提高开发效率和代码质量,使得代码易于维护

2、封装组件的过程:

  • 首先,使用 Vue.extend() 创建一个组件
  • 然后,使用 Vue.component() 方法注册组件
  • 接着,如果子组件需要数据,可以在 props 中接受定义
  • 最后,子组件修改好数据之后,想把数据传递给父组件,可以使用 emit() 方法

十五、Vue中常见的传值方法有哪些?(列表==>详情)

1、方法一(编程式导航跳转):

// 列表页
this.$router.push(`/detail/${id}`);

// 详情页接收
this.$route.params.id

2、方法二(声明式导航跳转):

// 列表页
<router-link
        v-for="data in navlist"
        :to="'/detail/' + data.id"
        :key="data.id"
        tag="li"
        activeClass="active"
>{{data.title}}</router-link>

// 详情页接收
this.$route.params.id;

十六、v-if && v-show 的区别?如何使用?

1、相同点:

  • 都能使元素显示或隐藏

2、区别:

  • v-if 是通过是否渲染元素来决定显示或隐藏
  • v-show 通过 display 属性来决定显示或隐藏

3、使用:

  • v-if 适合于元素不大可能改变
  • v-show 适合于元素频繁切换

十七、v-if && v-for 哪个优先级更高?为什么不能连用?如果两个同时出现,应该怎么优化得到更好的性能?

1、优先级:

  • v-ifv-for 一起使用时,v-for 具有比 v-if 更高的优先级。

2、为什么不能连用:

  • v-forv-if 一起使用的时候,每次渲染都会先循环再进行条件判断,带来性能方面的浪费。

3、同时出现的优化:

  • 为了过滤一个列表中的元素,可以使用计算属性先过滤在循环。

  • 为了避免渲染本应该被隐藏的列表,请将 v-if 移动至容器元素上 (比如 ul、ol)。


十八、Vue中$nextTick有什么作用?应用场景?

1、作用:

  • 在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM,才能对 DOM 进行操作。

2、应用场景:

  • Vue 生命周期的 created() 钩子函数进行的DOM操作一定要放 Vue.nextTick() 的回调函数中。
  • 在数据变化后要执行的某个操作,而这个操作需要使用随数据改变而改变的 DOM 结构的时候,这个操作都应该放进 Vue.nextTick() 的回调函数中。

十九、vue中的$set有什么用?

1、作用:

  • 如果在 Vue 实例创建之后添加新的属性到实例上,它不会触发视图更新,需要使用 $set 来完成视图的更新。

2、使用情况:

  • 数组:
// 当你利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue
// 解决:用$set方法
// 当你修改数组的长度时,例如:vm.items.length = newLength
// 解决:vm.items.splice(newLength)
  • 对象:
// 有时你想向已有对象上添加一些属性,但是,添加到对象上的新属性不会触发更新。

2、使用方法:

  • 更新数组:
let arr = ["玫瑰花","康乃馨","薰衣草"]
// 第一个参数是数组,第二个参数是下标,第三个参数是新的内容
this.$set(arr,2,"向日葵")   
// Vue.set(arr,2,"向日葵")   
  • 更新对象:
let obj = {name:"张三",age:18,sex:"女"}
// 第一个参数是对象,第二个参数是更新的属性名称,第三个参数是新的内容
this.$set(obj,"sex","男")
// Vue.set(obj,"sex","男")

二十、computed与watch的区别?应用场景有哪些?

1、区别:

  • computed:是计算属性,依赖其它属性值,并且 computed 的值有依赖缓存,只有它依赖的值发生改变,才会重新计算 computed 的值。
  • watch:是监听器,更多的是「观察」的作用,类似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行后续操作。

2、应用场景:

  • computed:购物车里面的商品列表和总金额之间的关系,只要商品列表里面的商品数量发生变化,总金额都应该发生变化。这里的这个总金额使用 computed 属性来进行计算是最好的选择。
  • watch:当一条数据的更改影响到多条数据的时候 ====> 搜索框

二十一、Vue组件之间通信有哪几种方法?

1、方法一:props/$emit

1)props ==> 父组件向子组件传参:

  • 父组件向子组件传参的过程:
    • 父组件里使用子组件的时候可以通过绑定属性传参(传递)
    • 在子组件里通过 props 来接收参数 (接收)
    • 子组件接收到的 props 就可以直接作为 data 去使用(渲染)
  • 父组件向子组件传参需要注意:
    • 参数如果是驼峰,那么传递的时候要转成小写加横杠(-)
    • html 里用(-)加小写,在 js 里面用驼峰
    • props 不仅可以用数组来接收参数,还可以使用对象来接收参数
    • props 是单向的传递数据

2)$emit ==> 子组件向父组件传参:

  • 子组件向父组件传参的过程:

    • 在子组件里使用 emit 向父组件触发一个自定义事件
toggleIsCart() {
    this.$emit("toggle-is-cart-form-item", {id: this.id})
}
  • 在父组件上监听子组件的自定义事件
<shop-item v-for="shopItem in list" @toggle-is-cart-form-item="toggleIsCartByParent">
</shop-item>
  • 在父组件上写一个方法去修改
toggleIsCartByParent({ id }) {
    this.list = this.list.map(shop => {
        if (shop.id === id) shop.isCart = !shop.isCart
        return shop
    })
}

2、方法二: 中央事件总线(eventBus)非父子组件间通信

  • 先定义一个事件总线:event bus (作用是帮助非父子组件之间的通信)
const bus = new Vue()
  • 然后在一个组件里使用 bus.$emitbus 触发一个自定义事件
playErdi() {
    // 先把这个行为通知bus,bus再去通知其他关联组件
    // 向bue触发一个自定义事件
    bus.$emit('play', { ku: true })
}
  • 最后在另一个组件创建的过程当中通过 bus.$on 去监听事件
created() {
    // 通过bus去监听play事件
    bus.$on('play', ({ ku }) => {
        this.ku = ku
    })
}

3、方法三:Vuex

4、方法四:$attrs/$listeners

5、方法五:provide/inject

6、方法六:v-model

7、方法七:$parent/$children


二十二、Vue事件绑定原理

  • 原生 DOM 事件的绑定,采用的是 addEventListener 实现
  • 组件绑定事件采用的 $on 方法

二十三、为什么组件的data必须是一个函数?

  • 如果组件中的 data 不是函数的话,那么多个组件将会共享同一个数据,其中一个组件上对数据做出的改变,也会影响另一个组件上的数据。

  • 组件上的 data 是函数的情况下,组件每次调用 data 里面的数据,都是由 data 这个独有的函数返回过来的数据,所以不会造成这个组件更改 data 的数据,另一个在使用这个数据的组件也会更改这个数据。

例子:

  • data 不为函数:
// data
const obj = {
    name: '超人',
    age: 20
}
// 通过这个函数分发
function giveData() {
    return obj
}
// 通过函数创建出来三个
const obj1 = giveData()
const obj2 = giveData()
// 打印出来看看
console.log(obj1) // 超人
console.log(obj2) // 超人
// 更改之后
obj1.name = '戴安娜'
// 在打印出来看看
console.log(obj1) // 戴安娜
console.log(obj2) // 戴安娜
  • data为函数:
// data为函数
function giveData() {
    return {
        name: '超人',
        age: 20
    }
}
const obj1 = giveData()
const obj2 = giveData()

console.log(obj1) // 超人
console.log(obj2) // 超人

// 更改之后
obj1.name = '戴安娜'
// 在打印出来看看
console.log(obj1) // 戴安娜
console.log(obj2) // 超人

二十四、slot是什么?有什么作用?有哪几种插槽?区别是是什么?slot实现原理是什么?

1、slot是什么?

  • slot 是插槽(内容分发)。
  • 内容分发:混合父组件的内容与子组件自己的模板。

2、作用:

  • 在定义子组件的时候预留一个插槽,使用子组件的时候就可以传递 html 结构进来。

3、有哪几种插槽:

  • 匿名插槽:没有name属性
// 父组件
<template>
    <div class="father">
        <h3>这里是父组件</h3>
        <child>
            <div class="tmpl">
                <span>菜单1</span>
                <span>菜单2</span>
            </div>
        </child>
    </div>
</template>

// 子组件
<template>
    <div class="child">
        <h3>这里是子组件</h3>
        <slot></slot>
    </div>
</template>
  • 具名插槽:有name属性
// 父组件
<template>
  <div class="father">
    <h3>这里是父组件</h3>
    <child>
      <div class="tmpl" slot="up">
        <span>菜单1</span>
        <span>菜单2</span>
      </div>
      <div class="tmpl" slot="down">
        <span>菜单-1</span>
        <span>菜单-2</span>
      </div>
      <div class="tmpl">
        <span>菜单->1</span>
        <span>菜单->2</span>
      </div>
    </child>
  </div>
</template>

// 子组件
<template>
  <div class="child">
    // 具名插槽
    <slot name="up"></slot>
    <h3>这里是子组件</h3>
    // 具名插槽
    <slot name="down"></slot>
    // 匿名插槽
    <slot></slot>
  </div>
</template>
  • 作用域插槽:在slot上面绑定数据
// 父组件
<template>
    <div class="father">
        <h3>这里是父组件</h3>
        <!--第一次使用:用flex展示数据-->
        <child>
            <template slot-scope="user">
                <div class="tmpl">
                    <span v-for="item in user.data">{{item}}</span>
                </div>
            </template>
        </child>

        <!--第二次使用:用列表展示数据-->
        <child>
            <template slot-scope="user">
                <ul>
                    <li v-for="item in user.data">{{item}}</li>
                </ul>
            </template>
        </child>

        <!--第三次使用:直接显示数据-->
        <child>
            <template slot-scope="user">
                {{user.data}}
            </template>
        </child>

        <!--第四次使用:不使用其提供的数据, 作用域插槽退变成匿名插槽-->
        <child>
            我就是模板
        </child>
    </div>
</template>


// 子组件
<template>
    <div class="child">
        <h3>这里是子组件</h3>
        // 作用域插槽
        <slot :data="data"></slot>
    </div>
</template>
<script>
    export default {
        data: function(){
            return {
                data: ['zhangsan','lisi','wanwu']
            }
        }
    }
</script>

4、各种插槽的区别:

  • 匿名插槽和具名插槽,需要父组件提供的模板,一般要既包括样式又包括内容。
  • 作用域插槽,父组件只需要提供一套样式。

5、实现原理:

  • 当子组件vm实例化时,获取到父组件传入的 slot 标签的内容,存放在vm.$slot中,默认插槽为vm.$slot.default,具名插槽为vm.$slot.xxxxxx 为插槽名,当组件执行渲染函数时候,遇到slot标签,使用$slot中的内容进行替换,此时可以为插槽传递数据,若存在数据,则可称该插槽为作用域插槽。

二十五、如何让CSS只在当前组件中起作用?原理是什么?为什么需要穿透scoped?如何穿透scoped?

1、只在当前组件中起作用:

  • 在组件中的 style 标后面面加上 scoped 就可以了。

2、原理:

  • vue 中的 scoped 属性的效果主要通过 PostCSS 转译实现,即:PostCSS *给一个组件中的所有 *DOM 添加了一个独一无二的动态属性,然后,给 CSS 选择器额外添加一个对应的属性选择器来选择该组件中 DOM ,这种做法使得样式只作用于含有该属性的 DOM——组件内部DOM
// 转义前
<style scoped>
    .example {
        color: red;
    }
</style>

// 转义后
<style>
    .example[data-v-558831a] {
        color: red;
    }
</style>

3、为什么需要穿透scoped?

  • 引用了第三方组件,需要在组件中局部修改第三方组件的样式,而又不想去除 scoped 属性造成组件之间的样式污染。此时只能通过穿透 scoped

4、如何穿透scoped?

  • 使用 >>> 可以穿透 scoped 属性,修改其他第三方组件的样式。
<style scoped>
    外层 >>> 第三方组件 {
        样式
    }
</style>
  • 使用曲线救国的一个方法,用两个 style 标签,一个带 scoped 属性,一个不带 scoped 属性,用来修改第三方组件的样式。
<style>
    /* 全局样式 */
</style>

<style scoped>
    /* 局部样式 */
</style>
  • 使用 sassless 的样式穿透 /deep/

  • 写一套公用样式放在assets文件夹下,需要的页面就引入样式文件。

二十六、Vue中keep-alive的作用是什么?使用场景?

1、作用:

  • keep-alive可以在组件切换时,保存其包裹的组件的状态,使其不被销毁,防止多次渲染。

2、使用场景:

  • 比如有一个列表和一个详情,那么用户就会经常执行打开详情=>返回列表=>打开详情…这样的话列表和详情都是一个频率很高的页面,那么就可以对列表组件使用keep-alive进行缓存,这样用户每次返回列表的时候,都能从缓存中快速渲染,而不是重新渲染。

二十七、Vue中如何获取原生DOM?

  • 给标签或组件添加 ref 属性,通过 this.$refs 获取。

二十八、Vue的两个核心是什么?

  • 数据驱动: ViewModel,保证数据和视图的一致性。
  • 组件系统:应用类 UI 可以看作全部是由组件树构成的。

二十九、说说Vue2.0和Vue3.0有什么区别?

1、重构响应式系统,使用Proxy替换Object.defineProperty:

  • 可直接监听数组类型的数据变化。
  • 监听的目标为对象本身,不需要像 Object.defineProperty 一样遍历每个属性,有一定的性能提升。
  • 可拦截 applyownKeyshas 等种方法,而 Object.defineProperty 不行。
  • 直接实现对象属性的新增/删除。

2、新增Composition API,更好的逻辑复用和代码组织:

3、重构 Virtual DOM:

  • Vue2.x 使用的 Virtual Dom 实现的渲染。
  • Vue3.0 不论是原生的 html 标签还是 vue 组件,他们都会通过 h 函数来判断,如果是原生 html 标签,在运行时直接通过 Virtual Dom 来直接渲染,同样如果是组件会直接生成组件代码。

4、精准的变更通知:

  • Vue2.x 版本中,使用 Vue.set 来给对象新增一个属性时,这个对象的所有 watcher 都会重新运行;Vue3.0 版本中,只有依赖那个属性的 watcher 才会重新运行。

5、默认项目目录结构发生了变化:

  • 移除了配置文件目录,configbuild 文件夹
  • 移除了 static 文件夹,新增 public 文件夹,并且 index.html 移动到 public
  • src 文件夹中新增了 views 文件夹,用于分类 视图组件 和 公共组件

三十、为什么Vue3.0要新增Composition API,能解决什么问题?

1、主要(一句话概括):

  • 使项目更加方便维护,代码变得简洁,让代码具备更好的可读性和可扩展性,实现代码的逻辑提取与复用。

2、解释:

  • 随着功能的增加,组件变得越来越复杂,越来越难维护,而难以维护的根本原因是 VueAPI 设计迫使开发者使用watchcomputedmethods选项组织代码,而不是实际的业务逻辑。
  • Vue2.0 缺少一种较为简洁的低成本的机制来完成逻辑复用,虽然可以 minxis 完成逻辑复用,但是当mixin 变多的时候,会使得难以找到对应的 datacomputed 或者 method 来源于哪个 mixin,使得类型推断难以进行。
  • 所以 Composition API 的出现,主要是也是为了解决 Option API 带来的问题,第一个是代码组织问题,Compostion API 可以让开发者根据业务逻辑组织自己的代码,让代码具备更好的可读性和可扩展性,也就是说当下一个开发者接触这一段不是他自己写的代码时,他可以更好的利用代码的组织反推出实际的业务逻辑,或者根据业务逻辑更好的理解代码。
  • 第二个是实现代码的逻辑提取与复用,当然 mixin 也可以实现逻辑提取与复用,但是像前面所说的,多个 mixin 作用在同一个组件时,很难看出 property 是来源于哪个 mixin,另外,多个 mixinproperty 存在变量命名冲突的风险。而 Composition API 刚好解决了这两个问题。

三十一、自定义组件(父子组件)的双向数据绑定

1、使用 v-model 语法糖:

<div id="box">
    <input type="text" v-model="mytext"/>
    <childmodel v-model="mytext"></childmodel>        
</div>
<script>
    Vue.component("childmodel",{
        template:`
            <div>
                childmodel -{{value}}
                <button @click="handleClick">click</button>  
        </div>`,
        props:["value"],//value固定
        methods: {
            handleClick(){
                this.$emit("input","222222222222222222") // input事件固定的
            }
        },
    })


    new Vue({
        el:"#box",
        data:{
            mytext:""
        },
        methods: {
            handleEvent(data){
                this.mytext = data
            }
        },
    })
</script>

2、过程:

  • 在组件上用 v-model 绑定传过来的值:
<childmodel v-model="mytext"></childmodel>   
  • 在组件当中用 props 接收 value,value 是固定的写法:
props:["value"],//value固定
  • 使用 $emit 触发 input 事件,input 事件也是固定的写法:
this.$emit("input","222222222222222222") // input事件固定的

三十二、Vue框架与jQuery类库的区别

  • jQuery 操作的是真实DOM,Vue操作的是虚拟 DOM。
  • jQuery 属于库, Vue属于框架。

三十三、SSR(服务端渲染)有了解吗?原理是什么?使用SSR好处是什么?

1、原理(服务端渲染):

  • 在客户端请求服务器的时候,服务器到数据库中获取到相关的数据,并且在服务器内部将 Vue 组件渲染成 HTML,并且将数据、HTML 一并返回给客户端,这个在服务器将数据和组件转化为 HTML 的过程,叫做服务端渲染 SSR

2、好处:

  • 有利于 SEO

  • 更利于首屏渲染(加载快)。


三十四、如何让UI库的按需加载

一、安装 babel-plugin-component:

npm install babel-plugin-component -D

二、在 babel.config.js 文件下配置:

module.exports = {
    presets: [
        '@vue/cli-plugin-babel/preset',
    ],
    plugins: [
        [
            "component",
            {
                "libraryName": "element-ui",
                "styleLibraryName": "theme-chalk"
            }
        ]
    ]
}

3、按需引入组件:

import Vue from 'vue';
import {
  Pagination,
  Dialog,
  Autocomplete,
  Dropdown,
  DropdownMenu,
  DropdownItem,
  Menu,
  Submenu,
  MenuItem,
  MenuItemGroup,
  Input,
  MessageBox,
  Loading
} from 'element-ui';

Vue.use(Pagination);
Vue.use(Dialog);
Vue.use(Autocomplete);
Vue.use(Dropdown);
Vue.use(DropdownMenu);
Vue.use(DropdownItem);
Vue.use(Menu);
Vue.use(Submenu);
Vue.use(MenuItem);
Vue.use(MenuItemGroup);
Vue.use(Input);
Vue.use(Loading.directive);

Vue.prototype.$loading = Loading.service;
Vue.prototype.$msgbox = MessageBox;
Vue.prototype.$alert = MessageBox.alert;
Vue.prototype.$confirm = MessageBox.confirm;
Vue.prototype.$message = Message;

三十五、v-on可以监听多个方法吗?

  • 可以

1、使用方法:

  • v-on 绑定多个方法:
<p v-on="{click:dbClick,mousemove:MouseClick}"></p>
  • 一个事件绑定多个函数:
<p @click="one(),two()">点击</p>

三十六、mixins混入简化常见操作

1、概念:

  • 混入 (mixins): 是一种分发 Vue 组件中可复用功能的非常灵活的方式。混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项。

2、minxins的特点:

  • 方法和参数在各组件中不共享。
  • 同一个生命周期混入组件会在普通组件出发生命周期前调用。
  • 值为对象的选项,例如 methodscomponentsmounted,将被合并为同一个对象。两个对象键名冲突时,取组件对象的键值对。

三十七、vue中路由有哪几种模式?分别有什么区别?怎么切换路由模式?

1、hash模式

2、history模式

3、区别:

  • hash模式 的路径带 #history模式 末尾不带 #
  • hash模式 的原理是 onhashchange 事件。
  • history模式 的原理 history.pushState 切换,window.onpopstate 监听路径的切换。
  • history模式 虽然路径好看,但是很危险,用户直接刷新会返回 404,需要后端配置代码才能解决。

三十八、嵌套路由?动态路由?路由重定向?

1、嵌套路由:

const routes = [
    {
        path: '/film',
        component: Film,
        children: [
            {
                path: '/film/nowplaying',
                component: Nowplaying,
            },
            {
                path: '/film/comingsoon',
                component: Comingsoon,
            }
        ]
    },
]

2、动态路由:

const routes = [
    {
        path: '/detail/:filmId', // 配置动态路由用:加上需要传的参数(随便写)
        component: Detail
    }
]

3、路由重定向:

const routes = [
    {
        path: '/',
        redirect: '/film/nowplaying' // 访问根目录的时候重新定向到/film/nowplaying
    },
]

三十七、vue中路由的拆分管理

1、路由拆分

  • 首先我们在 router 文件夹中创建一个 index.js 作为路由的入口文件,然后新建一个 modules 文件夹,里面存放各个模块的路由文件。

img

  • index.js 文件:
import Vue from 'vue'
import Router from 'vue-router'

// 公共页面的路由文件
import PUBLIC from './modules/public' 
// 投票模块的路由文件
import VOTE from './modules/vote' 

Vue.use(Router)

// 定义路由
const router = new Router({  
    mode: 'history',  
    routes: [    
        ...PUBLIC,    
        ...VOTE,  
    ]
})
// 导出
export default router
  • vote.js 文件:
/** 
  * 投票模块的router列表  
  */

export default [    
    // 投票模块首页    
    {        
        path: '/vote/index',        
        name: 'VoteIndex',        
        component: resolve => require(['@/view/vote/index'], resolve),     
        meta: {            
            title: '投票'        
        }    
    },    
    // 详情页 
    {        
        path: '/vote/detail',        
        name: 'VoteDetail',        
        component: resolve => require(['@/view/vote/detail'], resolve),
        meta: {            
            title: '投票详情'        
        }    
    }
]

三十八、vue中路由懒加载(也叫延迟加载)

1、使用 import:

// 下面2行代码,没有指定webpackChunkName,每个组件打包成一个js文件。
/* const Home = () => import('@/components/home')
const About = () => import('@/components/about') */
// 下面2行代码,指定了相同的webpackChunkName,会合并打包成一个js文件。 把组件按组分块
const Home =  () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/home')
const About = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/about')
const routes = [
    {
        path: '/about',
        component: About
    }, {
        path: '/home',
        component: Home
    }
]

2、vue 异步组件:

/* vue异步组件技术 */
const routes = [
    {
        path: '/home',
        name: 'home',
        component: resolve => require(['@/components/home'],resolve)
    },{
        path: '/index',
        name: 'Index',
        component: resolve => require(['@/components/index'],resolve)
    },{
        path: '/about',
        name: 'about',
        component: resolve => require(['@/components/about'],resolve)
    } 
]

3、webpack 的 require,ensure():

/* 组件懒加载方案三: webpack提供的require.ensure() */
const routes = [
    {
        path: '/home',
        name: 'home',
        component: r => require.ensure([], () => r(require('@/components/home')), 'demo')
    }, {
        path: '/index',
        name: 'Index',
        component: r => require.ensure([], () => r(require('@/components/index')), 'demo')
    }, {
        path: '/about',
        name: 'about',
        component: r => require.ensure([], () => r(require('@/components/about')), 'demo-01')
    }
]

三十九、css的scoped私有作用域和深度选择器

1、私有作用域:

// 编译前代码:
<style scoped>
    .example {
        color: red;
    }
</style>

// 编译后代码:
<style>
    .example[data-v-f3f3eg9] {
        color: red;
    }
</style>
  • 从编译前后的代码可以很容易地看出,scoped的底层机制其实是在写的组件的样式中添加了一个额外的属性而已,通过这种形式就能实现所谓的私有作用域。

2、深度选择器:

  • 因为 scoped 属性,限制了作用域,父组件的样式不能应用到子组件上,所以需要深度选择器 /deep/>>>,来向下扩大范围。
<style scoped>
    // 非css语言预处理器,可以使用>>>
    .parentElementClassName >>> .childrenElementClassName {
        background: red;
    }
    // less或scss,可以使用/deep/
    .parentElementClassName /deep/ .childrenElementClassName {
        background: red;
    }
</style>

四十、vue单页面应用及其优缺点?

1、优点:

  • 用户体验好,内容的改变不需要重新加载整个页面。
  • 对服务器压力较小。
  • 前后端分离。
  • 完全的前端组件化,更多地采用组件化的思想,代码结构和组织方式更加规范化。

2、缺点:

  • 首次加载耗时比较多。
  • 不利于 SEO 优化。
  • 页面导航不可用,如果一定要导航需要自行实现前进、后退。

四十一、webpack是什么?常见配置有哪些?

1、概念:

  • webpack 是一个用于现代 JavaScript 应用程序的静态模块打包工具。

2、常见配置:

  • devServer:本地开发服务相关配置。
module.exports = {
    // 关于webpack-dev-sever的一些配置
    devServer: {
        // 配置服务器的端口号
        port: 3000,
        // 显示每次打包编译的进度
        progress: true,
        // 指定访问资源目录
        contentBase: './dist',
        // 配置自动打开浏览器
        open: true
    },
}
  • entry:设置入口文件,从哪个文件开始打包。
module.exports = {
    // entry设置入口文件,从哪个文件开始打包
    entry: './src/index-my.js',
}
  • output:设置出口文件。
module.exports = {
    // output设置出口文件,
    output: {
        // 输出的文件名
        filename: 'bundle.min.js',
        // 输出目录必须是绝对路径
        path: path.resolve(__dirname, 'build')
    }
}
  • resolve:解析文件引用的模块的配置。
module.exports = {
    // 解析文件引用的模块的配置
    resolve: {
        // 模块的根目录,默认从node_modules开始找
        modules: [
            'node_modules',
            'browser_modules'
        ],
        // 模块的后缀名,我们引入模块有时候不写扩展名,自动补充扩展名的顺序如下
        extensions: ['.js', '.json', '.jsx', '.css'],
        // 模块解析时候的别名
        alias: {
            // 那么导入模块时则可以写import myComponent from '$component/myComponent';
            $component: './src/component',
            // 末尾加$精确匹配
            xyz$: path.resolve(__dirname, 'path/to/file.js')
        },
        // 此选项决定优先使用package.json配置哪份导出文件,详见补充5
        mainFields: ['jsnext:main', 'browser', 'main'],
        // 是否强制导入语句写明后缀
        enforceExtension: false,
        // 是否将符号链接(symlink)解析到它们的符号链接位置(symlink location)
        symlinks: true,
    },
}
  • module: 配置模块相关,使用加载器 loader 处理规则。
module.exports = {
    module: {
        rules: [ // 配置loaders
            {
                test: /\.jsx?$/, // 匹配规则,匹配文件使用,一般使用正则表达值
                include: [path.resolve(__dirname, 'app')], // 只会命中这个目录文件
                exclude: [path.resolve(__diranme, 'app/demo-files')], // 命中的时候排除的目录
                use: [ // 使用的loader,每一项为一个loader,从该数组的最后一个往前执行
                    'style-loader', // loader的名称,这样则是使用默认配置,可以在后面加!配置属性,也可以用下面方式
                    {
                        loader: 'css-loader', // loader的名称
                        options: {} // loader接受的参数
                    }
                ],
                noParse: [ // 不用解析和处理的模块 RegExp | [RegExp] | function(从 webpack 3.0.0 开始)
                    /jquery|lodash/
                ]
            }
        ]
    },
}
  • plugins:配置插件,使用插件压缩html(数组)。
module.exports = {
    plugins: [
        new HtmlWebpackPlugin({
            // 不指定模板会按照默认模板创建一个HTML页面,当然真实项目中一般都是把自己写好的HTML进行编译
            template: './src/index.html', // 输入的文件路径
            filename: 'index.html', // 输出的文件名
            // hash: true,  让我引入的js文件后面加上hash戳(清除缓存),但是真实项目当中我们一般都是每一次编译生成不同的JS文件引入,而不是在后面加一个hash戳

            minify: {//控制压缩 
                collapseWhitespace: true,// 清除空格
                removeComments: true,// 清除注释
                removeAttributeQuotes: true,// 删除属性的引号
                removeEmptyAttributes: true// 删除空属性 
            }
        }),
        new MiniCssExtractPlugin({
            filename: 'css/main.min.[hash].css', // 指定输出的css文件名
        }),
        // 向每一个模块注入全局变量就能在项目当中输出$
        new webpack.ProvidePlugin({
            $: 'jquery'
        })
    ],
}

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 848130454@qq.com

文章标题:Vue前端面试题

文章字数:11.5k

本文作者:Spicy boy

发布时间:2019-05-08, 18:51:18

最后更新:2021-03-24, 14:59:50

原始链接:http://www.spicyboy.cn/2019/05/08/Vue%E5%89%8D%E7%AB%AF%E9%9D%A2%E8%AF%95%E9%A2%98/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录
×

喜欢就点赞,疼爱就打赏