博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
VUE 面试总结
阅读量:7197 次
发布时间:2019-06-29

本文共 9129 字,大约阅读时间需要 30 分钟。

总结一些vue中必知必会的知识点,让我们在面试之前能够胸有成竹一点~

一、Vue组件通信

1、父组件向子组件通信

方法一:props

复制代码
复制代码

方法二:使用$children

使用$children可以在父组件中访问子组件。比如调用子组件的方法,并传入值等。

2、子组件向父组件通信

方法一:使用vue事件

父组件向子组件传递事件方法,子组件通过$emit触发事件,回调给父组件。

复制代码
复制代码

方法二:使用$parent

使用$parent可以访问父组件的实例,当然也就可以访问父组件的属性和方法了。

3、非父子组件、兄弟组件之间的数据传递

非父子组件通信,Vue官方推荐使用一个Vue实例作为中央事件总线

意思就是将一个公共状态保存在一个这些组件共用的一个父组件上,这样就可以使用子组件通信父组件的方式来间接的完成通信了。

二、new Vue()之后都发生了什么?

vue入口源码如下:

import { initMixin } from './init'import { stateMixin } from './state'import { renderMixin } from './render'import { eventsMixin } from './events'import { lifecycleMixin } from './lifecycle'import { warn } from '../util/index'function Vue (options) {  if (process.env.NODE_ENV !== 'production' &&    !(this instanceof Vue)  ) {    warn('Vue is a constructor and should be called with the `new` keyword')  }  this._init(options)}initMixin(Vue)// initMixin给Vue.prototype添加:// _init函数,stateMixin(Vue)/*stateMixin给Vue.prototype添加:$data属性,$props属性,$set函数,$delete函数,$watch函数,...*/eventsMixin(Vue)/*eventsMixin给Vue.prototype添加:$on函数,$once函数,$off函数,$emit函数,$watch方法,...*/lifecycleMixin(Vue)/*lifecycleMixin给Vue.prototype添加:_update方法:私有方法,用于更新dom,其中调用_patch产生跟新后的dom,$forceUpdate函数,$destroy函数,...*/renderMixin(Vue)/*renderMixin给Vue.prototype添加:$nextTick函数,_render函数,...*/export default Vue复制代码

vue源码加载的时候,也就是在new Vue()之前做了一些初始化工作。

new Vue的时候会执行一个_init方法。代码如下:

export function initMixin (Vue: Class
) { Vue.prototype._init = function (options?: Object) { const vm: Component = this // a uid vm._uid = uid++ let startTag, endTag /* istanbul ignore if */ if (process.env.NODE_ENV !== 'production' && config.performance && mark) { startTag = `vue-perf-start:${vm._uid}` endTag = `vue-perf-end:${vm._uid}` mark(startTag) } // a flag to avoid this being observed vm._isVue = true // merge options if (options && options._isComponent) { // optimize internal component instantiation // since dynamic options merging is pretty slow, and none of the // internal component options needs special treatment. initInternalComponent(vm, options) } else { vm.$options = mergeOptions( resolveConstructorOptions(vm.constructor), options || {}, vm ) } /* istanbul ignore else */ if (process.env.NODE_ENV !== 'production') { initProxy(vm) } else { vm._renderProxy = vm } // expose real self vm._self = vm initLifecycle(vm) initEvents(vm) initRender(vm) callHook(vm, 'beforeCreate') initInjections(vm) // resolve injections before data/props initState(vm) initProvide(vm) // resolve provide after data/props callHook(vm, 'created') /* istanbul ignore if */ if (process.env.NODE_ENV !== 'production' && config.performance && mark) { vm._name = formatComponentName(vm, false) mark(endTag) measure(`vue ${vm._name} init`, startTag, endTag) } if (vm.$options.el) { vm.$mount(vm.$options.el) } }}复制代码

从上面的代码我们看见_init很清淅的干了几件事, 合并相关配置, 初始化生命周期,初始化事件中心,初始化渲染,初始化 data、props、computed、watcher 等

三、组件data为什么必须是函数?

因为组件可能被多处使用,但它们的data是私有的,所以每个组件都要return一个新的data对象,如果共享data,修改其中一个会影响其他组件。

四、vue 为什么采用Virtual DOM?

  • 创建真实DOM的代价高:真实的 DOM 节点 node 实现的属性很多,而 vnode 仅仅实现一些必要的属性,相比起来,创建一个 vnode 的成本比较低。

  • 触发多次浏览器重绘及回流:使用 vnode ,相当于加了一个缓冲,让一次数据变动所带来的所有 node 变化,先在 vnode 中进行修改,然后 diff 之后对所有产生差异的节点集中一次对 DOM tree 进行修改,以减少浏览器的重绘及回流。

  • 虚拟dom由于本质是一个js对象,因此天生具备跨平台的能力,可以实现在不同平台的准确显示。

  • Virtual DOM 在性能上的收益并不是最主要的,更重要的是它使得 Vue 具备了现代框架应有的高级特性。

五、Vue创建的一个大致过程

首先实例化,然后数据绑定,组件挂在、内容替换。

结合上例子分析Vue的生命周期:

  
vue生命周期学习

{
{message}}

复制代码

[1] 在beforeCreate和created钩子函数之间的生命周期

在这个阶段开始初始化事件、并且对数据进行了检测(劫持),这时候还没有el。

[2] created钩子函数和beforeMount间的生命周期

  • 首先会判断对象是否有el选项。如果有的话就继续向下编译,如果没有el选项,则停止编译,也就意味着停止了生命周期,直到在该vue实例上调用vm.$mount(el)。此时注释掉代码中:el: '#app',

如果我们在后面继续调用vm.$mount(el),可以发现代码继续向下执行了

  • 然后,我们往下看,template参数选项的有无对生命周期的影响。

(1).如果vue实例对象中有template参数选项,则将其作为模板编译成render函数。 (2).如果没有template选项,则将外部HTML作为模板编译。 (3).可以看到template中的模板优先级要高于outer HTML的优先级。

  
vue生命周期学习

{
{message + '这是在outer HTML中的'}}

复制代码

那么将vue对象中template的选项注释掉后打印如下信息:

这下就可以想想什么el的判断要在template之前了~是因为vue需要通过el找到对应的outer template。

在vue对象中还有一个render函数,它是以createElement作为参数,然后做渲染操作,而且我们可以直接嵌入JSX.

new Vue({    el: '#app',    render: function(createElement) {        return createElement('h1', 'this is createElement')    }})复制代码

所以综合排名优先级: render函数选项 > template选项 > outer HTML.

总之在这个阶段就是判断是否有el,或者template。然后进行处理

[3] beforeMount和mounted 钩子函数间的生命周期

这段时间就是替换$el,将{

{message}}转为真正的内容。

[4] mounted

在mounted之前h1中还是通过{

{message}}进行占位的,因为此时挂在到页面上的还是JavaScript中的虚拟DOM形式。在mounted之后可以看到h1中的内容发生了变化。

[5] beforeUpdate钩子函数和updated钩子函数间的生命周期

当vue发现data中的数据发生了改变,会触发对应组件的重新渲染,先后调用beforeUpdate和updated钩子函数。

[6] beforeDestroy和destroyed钩子函数间的生命周期

beforeDestroy钩子函数在实例销毁之前调用。在这一步,实例仍然完全可用。 destroyed钩子函数在Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。

六、自定义指令

在代码的实例中

指令钩子函数会被传入以下参数:el:指令所绑定的元素,可以用来直接操作 DOM 。binding:一个对象,包含以下属性:    - name:指令名,不包括 v- 前缀。    - value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。    - oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。    - expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。    - arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。    - modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。    - vnode:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。    - oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。复制代码

七、Vue.js 插件开发详解

八、组件style的scoped

问题:在组件中用js动态创建的dom,添加样式不生效。复制代码
复制代码
  • 结果
// test生效   testAdd 不生效
.test[data-v-1b971ada]{ // 注意data-v-1b971ada background:blue; height:100px; width:100px;}复制代码

原因

<style> 标签有 scoped 属性时,它的 CSS 只作用于当前组件中的元素。 它会为组件中所有的标签和class样式添加一个scoped标识,就像上面结果中的data-v-1b971ada。 所以原因就很清楚了:因为动态添加的dom没有scoped添加的标识,没有跟testAdd的样式匹配起来,导致样式失效。

  • 解决办法:

去掉scoped即可。

九、Vue 数组/对象更新 视图不更新

data() { // data数据        return {          arr: [1,2,3],          obj:{              a: 1,              b: 2          }        };      },   // 数据更新 数组视图不更新    this.arr[0] = 'OBKoro1';    this.arr.length = 1;    console.log(arr);// ['OBKoro1'];    // 数据更新 对象视图不更新    this.obj.c = 'OBKoro1';    delete this.obj.a;    console.log(obj);  // {b:2,c:'OBKoro1'}复制代码

由于js的限制,Vue 不能检测以上数组的变动,以及对象的添加/删除,很多人会因为像上面这样操作,出现视图没有更新的问题。

解决方式:

  • 1、this.$set(你要改变的数组/对象,你要改变的位置/key,你要改成什么value)
this.$set(this.arr, 0, "OBKoro1"); // 改变数组this.$set(this.obj, "c", "OBKoro1"); // 改变对象复制代码
  • 2、数组原生方法触发视图更新:

Vue可以监测到数组变化的,数组原生方法:

splice()、 push()、pop()、shift()、unshift()、sort()、reverse()复制代码

意思是使用这些方法不用我们再进行额外的操作,视图自动进行更新。

十、Vue 过滤器的作用

过滤器,通常用于后台管理系统,或者一些约定类型,过滤。Vue过滤器用法是很简单,但是很多朋友可能都没有用过。

{
{ message | filterTest }}
复制代码
export default {         data() {        return {         message:1           }     },    filters: {          filterTest(value) {            // value在这里是message的值            if(value===1){                return '最后输出这个值';            }        }    }}复制代码

用法就是上面讲的这样,可以自己在组件中试一试就知道了,很简单很好用的。

十一、列表渲染相关

1、v-for循环绑定model:

input在v-for中可以像如下这么进行绑定,我敢打赌很多人不知道。

// 数据    data() {      return{        // 这里设置 key / value        obj: {          ob: "OB",          koro1: "Koro1"        },        // model 存储        model: {          ob: "默认ob",          koro1: "默认koro1"        }         }  },// html模板
// input就跟数据绑定在一起了,那两个默认数据也会在input中显示复制代码

2、v-if尽量不要与v-for在同一节点使用:

v-for 的优先级比 v-if 更高,如果它们处于同一节点的话,那么每一个循环都会运行一遍v-if。

如果你想根据循环中的每一项的数据来判断是否渲染,那么你这样做是对的:

  • {
    { todo }}
  • 复制代码

    如果你想要根据某些条件跳过循环,而又跟将要渲染的每一项数据没有关系的话,你可以将v-if放在v-for的父节点:

    // 数组是否有数据 跟每个元素没有关系
    • {
      { todo }}

    No todos left!

    复制代码

    如上,正确使用v-for与v-if优先级的关系,可以为你节省大量的性能。

    十二、深度watch和watch立即触发回调

    watch很多人都在用,但是这watch中的这两个选项deep、immediate,或许不是很多人都知道,我猜。

    • deep

    在选项参数中指定 deep: true,可以监听对象中属性的变化。

    • immediate

    在选项参数中指定 immediate: true, 将立即以表达式的当前值触发回调,也就是立即触发一次。

    watch: {    obj: {      handler(val, oldVal) {        console.log('属性发生变化触发这个回调',val, oldVal);      },      deep: true // 监听这个对象中的每一个属性变化    },    step: { // 属性      //watch      handler(val, oldVal) {        console.log("默认立即触发一次", val, oldVal);      },      immediate: true // 默认立即触发一次    },  },复制代码

    十三、这些情况下不要使用箭头函数:

    • 不应该使用箭头函数来定义一个生命周期方法
    • 不应该使用箭头函数来定义 method 函数
    • 不应该使用箭头函数来定义计算属性函数
    • 不应该对 data 属性使用箭头函数
    • 不应该使用箭头函数来定义 watcher 函数

    箭头函数绑定了父级作用域的上下文,this 将不会按照期望指向 Vue 实例。 也就是说,你不能使用this来访问你组件中的data数据以及method方法了。 this将会指向undefined。

    十四、路由懒加载写法

    // 我所采用的方法,个人感觉比较简洁一些,少了一步引入赋值。const router = new VueRouter({  routes: [    path: '/app',    component: () => import('./app'),  // 引入组件  ]})// Vue路由文档的写法:const app = () => import('./app.vue') // 引入组件const router = new VueRouter({  routes: [    { path: '/app', component: app }  ]})复制代码

    如果我们的路由比较多的话,是不是要在路由上方引入十几行组件?

    第一种跟第二种方法相比就是把引入赋值的一步,直接写在component上面,本质上是一样的。两种方式都可以的,只是第一种是懒加载的方式。

    十五、项目启动路由和404

    export default new Router({  routes: [    {      path: '/', // 项目启动页      redirect:'/login'  // 重定向到下方声明的路由     },    {      path: '*', // 404 页面       component: () => import('./notFind') // 或者使用component也可以的    },  ]})复制代码

    转载地址:http://iwakm.baihongyu.com/

    你可能感兴趣的文章
    Flex 当鼠标悬停在DataGrid某行上时用datatoolField显示当前行
    查看>>
    关于Integer包装类对象之间值的比较
    查看>>
    7.4 括号匹配
    查看>>
    nginx + fastDFS 设置开机自动启动
    查看>>
    Redis.py客户端的命令总结【一】
    查看>>
    AlertDialog错误
    查看>>
    Tiling 简单递推+大数
    查看>>
    iOS开发UI篇—Quartz2D使用(绘制基本图形)
    查看>>
    java web servlet
    查看>>
    几个博客
    查看>>
    v4l2
    查看>>
    JS倒计时
    查看>>
    (new Function("return " + json))();
    查看>>
    mscrm 4.0 报表服务器报错
    查看>>
    SVM原理简介
    查看>>
    TLV----Demo讲解
    查看>>
    Mermaid js与流程图、甘特图..
    查看>>
    什么是.Net的异步机制(线程间通信) - step 5
    查看>>
    Lambda应用设计模式
    查看>>
    解决svn异常报错“”cleanup failed to process the following paths …… previous operation has not finished”...
    查看>>