【直接收藏】前端 VUE 高阶面试题(一)

说说vue动态权限绑定渲染列表(权限列表渲染)

  1. 首先请求服务器,获取当前用户的权限数据,比如请求 this.$http.get("rights/list");

  2. 获取到权限数据之后,在列表中使用v-if v-if-else的组合来展示不同的内容





Vue用的哪种设计模式

属于发布订阅模式,在vue中使用observer和definereactive两个方法的结合对数据进行递归劫持,然后通过watch这个类来对属性进行订阅,Dep类用于解耦合,当数据变更的时候先触发数据的set方法,然后调用Dep.notiify通知视图更新

说说vue操作真实dom性能瓶颈

vue性能瓶颈的几种情况

  1. 一次渲染大量的数据的时候,存在大量数据并且都是复杂类型的时候,会导致vue对数据的劫持时间和渲染时间变长, js 连续执行时间过长,会导致页面长时间无法交互,而且渲染时间太慢,用户一次交互反馈的时间过长。

    优化方案:可以使用requestAnimation这个方法,将数据进行分割,分批次渲染,减少了 js 的连续运行时间,并且加快了渲染时间,利用加长总运行时间换取了渲染时间,用户既能快速得到反馈,而且不会因为过长时间的 js 运行而无法与页面交互。

  2. 当页面中存在大量数据,只是修改了一小部分导致页面也会导致页面卡顿,因为vue的更新以组件为粒度进行更新的,只要修改了当前组件中所使用的数据,组件就会整个去进行更新,造成大量的时间浪费

    优化方案:将不同的模块划分成不同的组件,这样有效降低虚拟dom的diff运算时间过长的问题,比如将大量数据的模块单独放一个组件,其它放一个组件,由于vue是以组件为粒度更新,修改其它组件的情况下不会导致table的重新diff,提升页面响应速度高达几百倍

  3. 动态插槽作用域或者静态插槽的更新

    使用插槽作用域来替换这两种操作方式,一样能提升性能,因为使用插槽作用域之后,插槽内容会被封装到一个函数中,被子组件渲染,而不是在父组件

Vue中如何获取dom、操作dom、更新dom

如何获取dom?在Vue中提供了一种特别的方式来获取dom,即给dom加上个ref属性,那么就可以通过this.$refs.名字来获取到该dom元素。

如何操作dom、更新dom?通过refs.名字就可以拿到对应的真实dom,然后就可以用原生JS进行操作和更新。当然vue框架本身就是不需要dom操作的,通过修改相应的数据并再配合指令、模板语法就可以轻松的操作和更新dom。

Vue 的双向数据绑定原理是什么

在Vue2.x中,双向数据绑定是通过 数据劫持 结合 发布订阅模式的方式来实现的,也就是说数据和视图同步,数据发生变化,视图跟着变化,视图变化,数据也随之发生改变。核心:关于VUE双向数据绑定,其核心是 Object.defineProperty()方法。

Vue3.x则是用ES6的语法Proxy对象来实现的。

Object.defineProperty()的缺点:

  1. 只能监听对象(Object),不能监听数组的变化,无法触发push, pop, shift, unshift,splice, sort, reverse。

  2. 必须遍历对象的每个属性

  3. 只能劫持当前对象属性,如果想深度劫持,必须深层遍历嵌套的对象。

 Proxy的优点:

  1. Proxy 可以直接监听对象而非属性。

  2. Proxy 可以直接监听数组的变化。

  3. Proxy 有多达 13 种拦截方法,不限于 apply、ownKeys、deleteProperty、has 等等是 Object.defineProperty 不具备的。

  4. Proxy 返回的是一个新对象,我们可以只操作新的对象达到目的,而 Object.defineProperty 只能遍历对象属性直接修改。

  5. Proxy 作为新标准将受到浏览器厂商重点持续的性能优化,也就是传说中的新标准的性能红利。

let arr = [];
let proxy = new Proxy(arr, {
  get: function(obj, prop){
    return obj[prop];
  },
  set: function(obj, prop, value){
    obj[prop] = value;   //可以被监听到变化
    return true;
  }
});
setTimeout(()=>{
  proxy.push(1);
}, 2000)

mvvm框架是什么

MVVM是Model-View-ViewModel的简写。它本质上就是MVC(Model-View-Controller)的改进版。在开发过程中,由于需求的变更或添加,项目的复杂度越来越高,代码量越来越大,此时我们会发现MVC维护起来有些吃力,尤其Controller控制层非常的厚重,非常的庞大,难以维护。

所以有人想到把Controller的数据和逻辑处理部分从中抽离出来,用一个专门的对象去管理,这个对象就是ViewModel。ViewModel 是由前端开发人员组织生成和维护的视图数据层。在这一层,前端开发者对从后端获取的 Model 数据进行转换处理,做二次封装,以生成符合 View 层使用预期的视图数据模型。

由于实现了双向绑定,ViewModel 的内容会实时展现在 View 层,这是激动人心的,因为前端开发者再也不必低效又麻烦地通过操纵 DOM 去更新视图,MVVM 框架已经把最脏最累的一块做好了,我们开发者只需要处理和维护 ViewModel,更新数据视图就会自动得到相应更新,真正实现数据驱动开发。

谈谈Vue的token存储

在前后端完全分离的情况下,Vue项目中实现token验证大致思路如下:

1、第一次登录的时候,前端调后端的登陆接口,发送用户名和密码

2、后端收到请求,验证用户名和密码,验证成功,就给前端返回一个token

3、前端拿到token,将token存储到localStorage和vuex中,并跳转路由页面

4、前端每次跳转路由,就判断 localStroage 中有无 token ,没有就跳转到登录页面,有则跳转到对应路由页面

5、每次调后端接口,都要在请求头中加token

6、后端判断请求头中有无token,有token,就拿到token并验证token,验证成功就返回数据,验证失败(例如:token过期)就返回401,请求头中没有token也返回401

7、如果前端拿到状态码为401,就清除token信息并跳转到登录页面

知道nextTick的作用吗,谈谈对它的理解,是什么,怎么用

当你设置 vm.message = 'new message',该组件不会立即重新渲染。当刷新队列时,组件会在下一个事件循环“tick”中更新。多数情况我们不需要关心这个过程,但是如果你想基于更新后的 DOM 状态来做点什么,这就可能会有些棘手。虽然 Vue.js 通常鼓励开发人员使用“数据驱动”的方式思考,避免直接接触 DOM,但是有时我们必须要这么做。为了在数据变化之后等待 Vue 完成更新 DOM,可以在数据变化之后立即使用 Vue.nextTick(callback)。这样回调函数将在 DOM 更新完成后被调用。例如:

{{message}}
var vm = new Vue({
  el: '#example',
  data: {
    message: 'old message'
  }
})
vm.message = 'new message' // 更改数据
vm.$el.textContent  // 'old message'
Vue.nextTick(function () {
  vm.$el.textContent  // 'new message'
})

nextTick和setTimeout区别

 首先Vue 在更新 DOM 时是异步执行的,也就是说数据变了,DOM不会立即改变,那么我们是如何知道DOM什么时候会改变呢?也就是说如何知道异步后的触发时机呢?

 可以通过nextTick方法,这个方法在源码内,先监听是否具备Promise.then,利用promise来监听,如果当前环境不支持promise,那么就降级采用MutationObserver,如果MutationObserver不支持的话,那么就降级采用setImmediate,如果setImmediate不支持的话,那么就使用setTimeout(fn, 0)。

 所以说nextTick和setTimeout区别总结就是:nextTick会先尝试使用promise、MutationObserver、setImmediate这些技术去监听,如果都不支持才会采用setTimeout

vue中为什么用虚拟dom而不操作真实dom

起初我们在使用JS/JQuery时,不可避免的会大量操作DOM,而DOM的变化又会引发回流或重绘,从而降低页面渲染性能。那么怎样来减少对DOM的操作呢?此时虚拟DOM应用而生,所以虚拟DOM出现的主要目的就是为了减少频繁操作DOM而引起回流重绘所引发的性能问题的!

虚拟DOM(Virtual Dom),起始本质上就是一个JS对象,当数据发生变化时,我们不直接操作真实DOM,因为很昂贵,我们去操作这个JS对象,就不会触发大量回流重绘操作,再加上diff算法,可以找到两次虚拟DOM之间改变的部分,从而最小量的去一次性更新真实DOM,而不是频繁操作DOM,性能得到了大大的提升。

虚拟DOM还有一个好处,可以渲染到 DOM 以外的平台,实现 SSR、同构渲染这些高级特性,Weex 等框架应用的就是这一特性。

Vue如何进行组件传值

父向子组件传值,可以利用prop方式。

子向父组件传值,可以利用自定义事件$emit方式。

多层级组件传值,可以使用provide/inject

无关系的组件传值,利用vuex状态管理

说说vue里面的父子通信

父 -> 子: 通过 Prop 向子组件传递数据,子组件通过props属性来接收。

Vue.component('blog-post', {
  props: ['title'],
  template: '

{{ title }}

' //获取父组件的值 })

子 -> 父: 父组件自定义事件,子组件利用$emit来完成。


Vue.component('blog-post', {
  props: ['title'],
  template: '

{{ title }}

' })

谈谈如何实现vue组件通信和传值方式 (两个问题为同一个答案问法不一样)

这类问题 首先分类 表明了解的比较多   具体就没说完 或者漏了  面试官也不会计较很多
组件通信的四大类   父与子    子与父    子与子     跨层级  
在细说各种方式 加入自己的理解
1、props和$emit
父组件向子组件传递数据是通过prop传递的,子组件传递数据给父组件是通过$emit触发事件

2、$attrs和$listeners

3、中央事件总线 bus

上面两种方式处理的都是父子组件之间的数据传递,而如果两个组件不是父子关系呢?这种情况下可以使用中央事件总线的方式。新建一个Vue事件bus对象,然后通过bus.$emit触发事件,bus.$on监听触发的事件。

4、provide和inject

父组件中通过provider来提供变量,然后在子组件中通过inject来注入变量。不论子组件有多深,只要调用了inject那么就可以注入provider中的数据。而不是局限于只能从当前父组件的prop属性来获取数据,只要在父组件的生命周期内,子组件都可以调用。

5、v-model

父组件通过v-model传递值给子组件时,会自动传递一个value的prop属性,在子组件中通过this.$emit(‘input’,val)自动修改v-model绑定的值

6、$parent和$children

7、boradcast和dispatch

8、vuex处理组件之间的数据交互 如果业务逻辑复杂,很多组件之间需要同时处理一些公共的数据,这个时候才有上面这一些方法可能不利于项目的维护,vuex的做法就是将这一些公共的数据抽离出来,然后其他组件就可以对这个公共数据进行读写操作,这样达到了解耦的目的。

说说vue中Key值的作用

关于这个可以的key的作用 首先表明 key 不是一定要有的  不写可以代码也可以跑  但是建议加上
    然后指出可以用的地方  key在v-for循环可以用用   在表单元素中也可以用key 减少缓存
    一般说key  只要说配合v-for的使用
   
key是为Vue中的vnode标记的唯一id,通过这个key,我们的diff操作可以更准确、更快速
diff算法的过程中,先会进行新旧节点的首尾交叉对比,当无法匹配的时候会用新节点的key与旧节点进行比对,然后超出差异能讲清楚diff算法就继续讲
diff程可以概括为:oldCh和newCh各有两个头尾的变量StartIdx和EndIdx,它们的2个变量相互比较,一共有4种比较方式。如果4种比较都没匹配,如果设置了key,就会用key进行比较,在比较的过程中,变量会往中间靠,一旦StartIdx>EndIdx表明oldCh和newCh至少有一个已经遍历完了,就会结束比较,这四种比较方式就是首、尾、旧尾新头、旧头新尾.

准确: 如果不加key,那么vue会选择复用节点(Vue的就地更新策略),导致之前节点的状态被保留下来,会产生一系列的bug. 快速: key的唯一性可以被Map数据结构充分利用,相比于遍历查找的时间复杂度O(n),Map的时间复杂度仅仅为O(1)
讲完以后 还要补充一点自己的看法
建议使用主键比如id  

说说vue中的虚拟dom和diff算法

Virtual DOM 其实就是一棵以 JavaScript 对象( VNode 节点)作为基础的树,用对象属性来描述节点,实际上它只是一层对真实 DOM 的抽象。最终可以通过一系列操作使这棵树映射到真实的DOM上

下面就是一个真实DOM映射到虚拟DOM的例子:


             
  • Item 1

  •          
  • Item 2

  •          
  • Item 3

  •        

       
var element = {
       tagName: 'ul', // 节点标签名
       props: { // DOM的属性,用一个对象存储键值对
           id: 'list'
       },
       children: [ // 该节点的子节点
         {tagName: 'li', props: {class: 'item'}, children: ["Item 1"]},
         {tagName: 'li', props: {class: 'item'}, children: ["Item 2"]},
         {tagName: 'li', props: {class: 'item'}, children: ["Item 3"]},
       ]
   }
   
 在补充点虚拟DOM的好处
具备跨平台的优势
由于 Virtual DOM 是以 JavaScript 对象为基础而不依赖真实平台环境,所以使它具有了跨平台的能力,比如说浏览器平台、Weex、Node 等。

操作原生DOM慢,js运行效率高。我们可以将DOM对比操作放在JS层,提高效率。
因为DOM操作的执行速度远不如Javascript的运算速度快,因此,把大量的DOM操作搬运到Javascript中,运用patching算法来计算出真正需要更新的节点,最大限度地减少DOM操作,从而显著提高性能。

Virtual DOM 本质上就是在 JS 和 DOM 之间做了一个缓存。可以类比 CPU 和硬盘,既然硬盘这么慢,我们就在它们之间加个缓存:既然 DOM 这么慢,我们就在它们 JS 和 DOM 之间加个缓存。CPU(JS)只操作内存(Virtual DOM),最后的时候再把变更写入硬盘(DOM)

提升渲染性能
Virtual DOM的优势不在于单次的操作,而是在大量、频繁的数据更新下,能够对视图进行合理、高效的更新。

diff算法
vdom因为是纯粹的JS对象,所以操作它会很高效,但是vdom的变更最终会转换成DOM操作,为了实现高效的DOM操作,一套高效的虚拟DOM diff算法显得很有必要

diff算法包括一下几个步骤:

用 JavaScript 对象结构表示 DOM 树的结构;然后用这个树构建一个真正的 DOM 树,插到文
档当中

当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较(diff),记录两棵树差异
把2所记录的差异应用到步骤1所构建的真正的DOM树上(patch),视图就更新了
diff算法是通过同层的树节点进行比较而非对树进行逐层搜索遍历的方式,所以时间复杂度只有O(n),是一种相当高效的算法

实现虚拟DOM的过程

vue3.0有了解过吗,你觉得vue3.0好吗,好在哪

这种问题 是开放的   多说就是都是对的    可以讲差异  也可以讲新增 的知识点  

比如说 常用的api特别好用

  1. ref、toRefs、toRef、isRef

  • ref 用于定义响应式变量、快捷DOM访问。

  • 基本语法:const a = ref(1) // {value:1}

  • 基础使用: 一般用于定义 String、Number、Boolean 这种基于数据类型,外在表现统一使用 .value 访问。

  • 补充:ref 还可以访问 DOM对象或者组件实例对象,可做DOM操作。

  • toRef、toRefs 用于把一个object的变量,变成响应式的变量。

  • 基本语法:const msg = toRef(obj, key)// 把obj[key]变成响应式的

  • 基本语法:const { msg } = toRefs(obj) // 把整个obj都变成响应式的

  • unref 返回一个变量的值

  • 基本语法:const x = unref(x) // 如果x是ref变量则返回x.value,如果x不是ref变量则直接返回x。

  • isRef 用于判断一个变量是不是ref响应式变量

  • 基本语法:const bol = isRef(x)

function useUpdBoxStyle() {
  const el = ref(null)
  const updateStyle = color => {
    el.value.style.color = color
  }
  return [el, updateStyle]
}
  1. shallowRef、triggerRef

  • shallowRef 用于性能优化,只对对象的第一层进行proxy

  • 基本语法:const obj = shallowRef({a:1,b:{c:{d:{e:2}}}})

  • triggerRef 用于手动触发那些shallowRef的变量进行更新视图

  • 基本语法:triggerRef(obj) // 当obj.value.b.c.d发生变化,triggerRef(obj) 强制更新视图。

  • customRef 自定义ref,把ref变量拆成get/set的写法

  • 基本语法:customRef((track, trigger) =>({get,set})

function useObj() {
  const obj = { a: 1, b: { c: { d: 2 }}}
  const obj1 = ref(obj)
  const obj2 = shallowRef(obj)
  // console.log('obj1', obj1)
  // console.log('obj2', obj2)
  const changeObj = (obj, newD) => {
    // obj1.value.b.c.d = 100
    obj.value.b.c.d = newD
    triggerRef(obj)
  }
  return [[obj1, obj2], changeObj]
  1. reactive、readonly

  • reactive 用于定义响应式变量(引用数据类型)

  • 基本语法:const arr = reactive([]) // {value: []}

  • ref和reactive是什么关系呢?ref背后是使用reactive来实现的。

  • shallowReactive 用于性能优化,只对对象的第一层进行proxy

  • 基本语法:const c = shallowReactive({a:{b:{c:100}}}) // 只对这个对象的第一层进行proxy

  • readonly 把响应式变量变成“只读的”,如果修改就报警告。

  • 基本语法:const user = readonly({name:1,age:2})

  • isReadonly 用于判断一个变量是否是readonly的,返回布尔值

  • 基本语法:const bol = isReadonly(x)

  • isProxy 用于判断一个变量是否是响应式的,返回布尔值

  • 基本语法:const bol = isProxy(x)

  • isReactive 用于判断一个变量是否是reactive响应式变量,返回布尔值

  • 基本语法:const bol = isReactive(x)

function useUser() {
  const user = readonly(reactive({name:'list',age:30}))
  console.log('user', user)
  // setTimeout(()=>user.age=40, 2000)
  const x = 1
  const y = readonly({a:1,b:{c:3}})
  console.log('是否被proxy拦截过', isProxy(user), isProxy(x), isProxy(y.b))
  return user
}
  1. toRaw、markRaw

  • toRaw 用于返回一个响应式变量的原始值

  • 基本语法:const a3 = toRow(reactive(a1))// a1===a3是true

  • markRaw 用于把一个普通变量标记成“不可proxy”的

  • 基本语法:const b2 = markRaw(b1)// b2是无法被reactive的

function useRaw() {
  const a1 = { title: 100 }
  const a2 = reactive(a1)
  const a3 = toRaw(a2)
  console.log('toRow(a2)===a1', a3===a1)
  console.log('a2===a1', a2===a1)
  return [a1,a2,a3]
}
  1. computed、watch、watchEffect

  • computed 用于对响应式变量进行二次计算,当它依赖的响应式变量发生变化时会重新计算

  • 基本语法:const c = computed(()=>c1.value*c2.value)// 只读

  • 基本语法:const c = computed({get:()=>c1.value*c2.value,set:(newVal)=>c1.value=newVal}) // 可写可读

  • watch 用于监听响应式变量的变化,组件初始化它不执行

  • 基本语法:const stop = watch(x, (new,old)=>{}) // 调用stop()可以停止监听

  • 基本语法:const stop = watch([x,y], ([newX,newY],[oldX,oldY])=>{})

  • watchEffect 用于监听响应式变量的变化,组件初始化会执行

  • 基本语法:const stop = watchEffect(()=>ajax({cate,page,size}))

export default function useWatchComputed() {
  const c1 = ref(10)
  const c2 = ref(20)
  const c3 = computed(()=>c1.value*c2.value)  // 只读
  // 可读也可写
  const c4 = computed({
    get: ()=>c1.value*c2.value,
    set: (newVal)=>{
      c1.value = parseInt(newVal) / c2.value
    }
  })
  const stop1 = watch(c4, (newC4, oldC4)=>console.log('c4变了', newC4, oldC4))
  const stop2 = watch([c1,c2], ([newC1,newC2],[oldC1,oldC2])=>{
    console.log('[c1,c2] 新值:', [newC1, newC2])
    console.log('[c1,c2] 旧值:', [oldC1, oldC2])
  })
  const stop3 = watchEffect(()=>{console.log('watch effect', c1.value, c2.value)})
  const update = (c,v) => c.value = v
  return [[c1,c2,c3,c4],[stop1,stop2,stop3,update]]
}

2:也可以说亮点

  1. 性能比vue2.x快1.2~2倍

  2. 支持tree-shaking,按需编译,体积比vue2.x更小

  3. 支持组合API

  4. 更好的支持TS

  5. 更先进的组

3.更可以说性能

1.diff算法更快

vue2.0是需要全局去比较每个节点的,若发现有节点发生变化后,就去更新该节点

vue3.0是在创建虚拟dom中,会根据DOM的的内容会不会发生内容变化,添加静态标记, 谁有flag!比较谁。

2、静态提升

vue2中无论元素是否参与更新,每次都会重新创建,然后再渲染 vue3中对于不参与更新的元素,会做静态提升,只被创建一次,在渲染时直接复用即可

3、事件侦听缓存

默认情况下,onclick为动态绑定,所以每次都会追踪它的变化,但是因为是同一函数,没有必要追踪变化,直接缓存复用即可

在之前会添加静态标记8 会把点击事件当做动态属性 会进行diff算法比较, 但是在事件监听缓存之后就没有静态标记了,就会进行缓存复用

v-model有了解过吗,原理是什么

这种原理性问题  不要直接说不清楚 不了解  

先讲下使用

v-model本质上是一个语法糖,可以看成是value + input 方法的语法糖。可以通过model的prop属性和event事件来进行自定义。

2、v-model是vue的双向绑定的指令,能将页面上控件输入的值同步更新到相关绑定的data属性, 也会在更新data绑定属性时候,更新页面上输入控件的值。

然后再来讲细节

vue的双向绑定是由数据劫持结合发布者-订阅者模式实现的,那么什么是数据劫持?vue是如何进行数据劫持的?说白了就是通过Object.defineProperty()来劫持对象属性的setter和getter操作,在数据变动时做你想要做的事情

我们已经知道实现数据的双向绑定,首先要对数据进行劫持监听,所以我们需要设置一个监听器Observer,用来监听所有属性。如果属性发生变化了,就需要告诉订阅者Watcher看是否需要更新。因为订阅者是有很多个,所以我们需要有一个消息订阅器Dep来专门收集这些订阅者,然后在监听器Observer和订阅者Watcher之间进行统一管理的。接着,我们还需要有一个指令解析器Compile,对每个节点元素进行扫描和解析,将相关指令(如v-model,v-on)对应初始化成一个订阅者Watcher,并替换模板数据或者绑定相应的函数,此时当订阅者Watcher接收到相应属性的变化,就会执行对应的更新函数,从而更新视图。因此接下去我们执行以下3个步骤,实现数据的双向绑定:

1.实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。

2.实现一个订阅者Watcher,每一个Watcher都绑定一个更新函数,watcher可以收到属性的变化通知并执行相应的函数,从而更新视图。

3.实现一个解析器Compile,可以扫描和解析每个节点的相关指令(v-model,v-on等指令),如果节点存在v-model,v-on等指令,则解析器Compile初始化这类节点的模板数据,使之可以显示在视图上,然后初始化相应的订阅者(Watcher)

3:最后补一下 vue2.0里面用Object.defineProperty  3.0里面用new  Proxy     一个监听每个属性 一个监听整个对象

VUE组件如何与iframe通信问题

像这种问题其实问的不是特别详情  面试者可能不懂题目的意思   但是我们要学会揣摩 面试官的问题

如果不知道 你就直说vue的组件通信 在讲iframe的页面获取v

vue组件内嵌一个iframe,现在想要在iframe内获取父组件内信息,采用的是H5新特性PostMessage来解决跨域问题

采用postMessage内涵两个API:

onMessage:消息监听

postMessage:消息发送

代码和例子

clearMap(){ let map = document.getElementsByName("map")[0].contentWindow map.postMessage("clearMap","*") } iframe内: window.addEventListener('message', function (evt) { if (evt.data == 'clearMap'){ clearMap() } //event.data获取传过来的数据 });

用过VUE 的自定义指令吗?自定义指令的方法有哪些

这种问题一样的  先回答经常用的一些指定 比如 v-for  v-if  v-model   v-show等等之类的  指令分为全局和局部的

然后在回答自定义指令

通过directive来自定义指令,自定义指令分为全局指令和局部指令,自定义指令也有几个的钩子函数,常用的有bind和update,当 bind 和 update 时触发相同行为,而不关心其它的钩子时可以简写。一个表达式可以使用多个过滤器。过滤器之间需要用管道符“|”隔开。其执行顺序从左往右。

当修改data时Vue的组件重渲染是异步还是同步

这个问题很有意思  因为平时我们一般问题异步和同步指的是 数据请求 同步和异步问题

这里加上了组件  还有修改data     这里给大家写个例子


    
{{num}}

以此可以说明  

数据更新是同步的  但是视图更新是异步的

解决这个问题需要使用 $nextTick 解决视图异步更新的问题

.sync修饰器的作用是

首先看到 .sync  我们需要知道这是个修饰器   类似修饰器还有  .stop  .prevent  之类

其实这个修饰符就是vue封装了 子组件要修改父组件传过来的动态值的语法糖,省去了父组件需要写的方法,但是子组件emit时要加上update

在有些情况下,我们可能需要对一个 prop 进行“双向绑定”。不幸的是,真正的双向绑定会带来维护上的问题,因为子组件可以修改父组件,且在父组件和子组件都没有明显的改动来源

代码解释

// 这里父组件,要给子组件传一个title的值

// 子组件

这里关键就是emit里的参数要写成'update'+ ':' +'要修改的props'

以前是用的this.$emit("自定义方法")

vue多组件嵌套通信方式

这个问题其实也是属于组件通信   常见的组件通信有 父传子  子传父  子传子  以及跨层级

这个多组件嵌套通信其实就是跨层级的另一种问法

多组件通信

方法一:props  一层 一层的传递

方法二:依赖注入  provide 声明  inject接收

方法三:利用公共的bus = new  Vue()   bus.$on  声明  bus.$emit()   调用

方法四:使用vuex 全局的状态管理

vue如何让css只在当前组件生效

当前组件