当前位置: 首页 > article >正文

vue基础面试题

1.Vue指令

v-bind:动态绑定数据
v-on:绑定事件监听器
v-for:循环指令,可以循环数组或对象
v-if:根据表达式的真假值,判断是否渲染元素,会销毁并重建
v-show:显示隐藏元素,修改元素的display属性
v-model:实现双向绑定

插槽:vue2 使用slot是直接使用slot的,vue3 使用插槽必须为 v-slot

vue2和3的是双向绑定实现方式也不一样

1.数据双向绑定( new proxy() 替代 object.defineProperty() )
Vue3对响应式模块进行了重写,主要修改就是proxy替换了defineProperty实现响应式。
Vue2使用defineProperty存在一些原因:
对数组拦截有问题,需要做特殊处理
不能拦截新增、删除的属性
defineProperty方案在初始化时候,通过 数据劫持 结合 发布订阅模式的方式来实现的, 也就是说数据和视图同步,数据发生变化,视图跟着变化,视图变化,数据也随之发生改变;核心:关于VUE双向数据绑定,其核心是 Object.defineProperty()方法,加载时间有点慢。
Proxy代理
对数组进行拦截,还能对Map,Set实现拦截
proxy是懒处理行为,没有嵌套对象时,不会实施拦截,也使之初始化速度和内存得到改善
proxy存在兼容性问题,IE不支持。
proxy属性拦截原理

function reactive( obj ) {
	return new Proxy ( obj, {
		get(target,key){},
		set(target,key,val) {},
		deleteProperty(target,key){}
	}
}
  1. vue3双向绑定优点与vue2双向绑定的缺点
    001: 在vue2之中,假如设置了obj:{a:1} 若是给obj对象添加一个b属性值,直接在methods之中使用方法 obj.b = 2,导致的问题是:数据有更新,但是视图没有更新( 需要使用this.$set()方法去设置b属性为响应式属性值,才能支持试图更新 );vue3之中直接使用reactive定义对象,则当前对象为响应式对象,对于obj.b = 2 视图会更新!
    002: object.defineProperty对于后期添加的属性值是不参与劫持设置为响应式属性的,这就是为什么上面obj.b没有更新视图的缘故
    003: new Proxy对于后期添加的属性值是依旧走proxy内的set和get,这就是obj.b更新视图的缘故

3.vue2与vue3 设置响应式demo

// vue2 设置响应式属性demo
    let obj = {
      a: 1,
      b: 2
    }
    let vue = {}
    for (let k in obj) {
      Object.defineProperty(vue, k, {
        get() {
          console.log('获取了')
          return obj[k]
        },
        set(value) {
          obj[k] = value
        }
      })
    }
    console.log('obj', obj) // obj {a: 1, b: 2}
    vue.c = '000'
    console.log('vue-c', vue.c) // vue-c 000 没有走 Object.defineProperty这个逻辑
    console.log('vue-a', vue.a) // 获取了 vue-a 1 打印了,由于有a属性,则走了Object.defineProperty这个逻辑

// vue3 设置响应式属性demo
    let obj = {
      a: 1,
      b: 2
    }
    let vue = {}
    vue = new Proxy(obj, {
      get(target, key, receiver) {
        console.log('获取了')
        return Reflect.get(target, key, receiver)
      },
      set(target, key, val, receiver) {
        console.log('设置了')
        return Reflect.set(target, key, val, receiver)
      },
      deleteProperty(target, key) {}
    })

    vue.n = '000'
    console.log('vue-n', vue.n) // vue-c 000 设置了 获取了 vue3之中走了new Proxy的逻辑,设置为了响应式数据

2.v-if和v-show的区别是什么?

切换元素时,v-if会销毁并重建元素,v-show是修改display属性,来做到显示和隐藏。

v-show项目用处:回到顶部组件的显示隐藏,v-if项目用处:登陆方式切换。

3.v-if和v-for的优先级

当 v-if与 v-for 一起使用时,v-for具有比v-if更高的优先级,这意味着v-if 将分别重复运行于每个v-for 循环中。所以,不推荐 v-if 和 v-for 同时使用。如果 v-if 和 v-for一起用的话,vue中的的会自动提示 v-if应该放到外层去。

注意的是:
vue2的时候 v-for指令优先级比v-if高,先执行v-for再执行v-if,而且不推荐一起使用,vue3则再v-for之中使用的时候,把v-if当成一个判断语句,不会互相冲突的

4.v-for中key作用

需要使用key来给每个节点做一个唯一标识,Diff算法就可以正确的识别此节点,找到正确的位置区插入新的节点

Vue3 相比于 Vue2,虚拟DOM上增加 patchFlag 字段。借助Vue3 Template Explorer来看

<div id="app">
  <h1>vue3虚拟DOM讲解</h1>
  <p>今天天气真不错</p>
  <div>{{name}}</div>
</div>
import { createElementVNode as _createElementVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from vue

const _withScopeId = n => (_pushScopeId(scope-id),n=n(),_popScopeId(),n)
const _hoisted_1 = { id: app }
const _hoisted_2 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(h1, null, vue3虚拟DOM讲解, -1 /* HOISTED */))
const _hoisted_3 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(p, null, 今天天气真不错, -1 /* HOISTED */))

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createElementBlock(div, _hoisted_1, [
    _hoisted_2,
    _hoisted_3,
    _createElementVNode(div, null, _toDisplayString(_ctx.name), 1 /* TEXT */)
  ]))
}

第3个_createElementVNode的第4个参数即 patchFlag 字段类型。
字段类型情况:1 代表节点为动态文本节点,那在 diff 过程中,只需比对文本对容,无需关注 class、style等。除此之外,发现所有的静态节点(HOISTED 为 -1),都保存为一个变量进行静态提升,可在重新渲染时直接引用,无需重新创建。

// patchFlags 字段类型列举
export const enum PatchFlags { 
  TEXT = 1,   // 动态文本内容
  CLASS = 1 << 1,   // 动态类名
  STYLE = 1 << 2,   // 动态样式
  PROPS = 1 << 3,   // 动态属性,不包含类名和样式
  FULL_PROPS = 1 << 4,   // 具有动态 key 属性,当 key 改变,需要进行完整的 diff 比较
  HYDRATE_EVENTS = 1 << 5,   // 带有监听事件的节点
  STABLE_FRAGMENT = 1 << 6,   // 不会改变子节点顺序的 fragment
  KEYED_FRAGMENT = 1 << 7,   // 带有 key 属性的 fragment 或部分子节点
  UNKEYED_FRAGMENT = 1 << 8,   // 子节点没有 key 的fragment
  NEED_PATCH = 1 << 9,   // 只会进行非 props 的比较
  DYNAMIC_SLOTS = 1 << 10,   // 动态的插槽
  HOISTED = -1,   // 静态节点,diff阶段忽略其子节点
  BAIL = -2   // 代表 diff 应该结束
}

5.Vue的生命周期

1.vue2生命周期函数
beforeCreate:在实例创建之间执行,数据是未加载状态。
created:在实例创建、数据加载后,能初始化数据,DOM渲染之前执行。
beforeMount:虚拟DOM已创建完成,在数据渲染前最后一次更改数据。el未挂载。
mounted:页面、数据渲染完成。el挂载完毕。可以访问DOM节点。
beforeUpdate:重新渲染之前触发。不会造成重渲染。
Updated:数据已经更新完成,DOM也重新render完成,更改数据会陷入死循环。
`beforeDestroy:实例销毁前执行,实例仍然完全可用。
destroyed:实例销毁后执行,这时候只剩下DOM空壳。
第一次页面加载会触发:beforeCreate, created, beforeMount, mounted。
一般获取数据在 created/beforeMount/mounted中调用, 操作 DOM 在mounted操作
2.vue3生命周期函数
setup 、onBeforeMount 、 onMounted 、onBeforeUpdate 、onUpdated 、onBeforeUnmount、onUnmounted

6.vue3的新Composition API 组合api区别

1.ref和reactive的区别:ref一般用于定义普通数据类型和dom节点,使用 .value去取值 ( toRefs 结构数据,变成响应式数据),reactive一般用于定义复杂数据类型,使用的时候,直接取值即可。源码上的区别,ref若是定义的是简单数据类型,那么响应式原理走的是vue2的Object.defineProperty()的get与set方式,若是ref定义的是引用类型数据,那么响应式原理使用的proxy中Reflect.set与get,reactive响应式原理直接使用的是proxy处理负责数据类型,内部使用了Reflect.get与set实现响应式的。
2.watch和watchEffect的区别:watch侦测一个或者多个响应式数据,并在数据源变化时再调用一个回调函数,watchEffect立即运行一个函数,被动地追踪它的依赖,当这些依赖改变时重新执行该函数

7.vue2每个周期适用场景

beforeCreate: 在new一个vue实例后,只有一些默认的生命周期钩子和默认事件,其他的东西都还没创建。在beforeCreate生命周期执行的时候,data和methods中的数据都还没有初始化。不能在这个阶段使用data中的数据和methods中的方法

create: data 和 methods都已经被初始化好了,如果要调用 methods 中的方法,或者操作 data 中的数据,最早可以在这个阶段中操作

beforeMount: 执行到这个钩子的时候,在内存中已经编译好了模板了,但是还没有挂载到页面中,此时,页面还是旧的

mounted: 执行到这个钩子的时候,就表示Vue实例已经初始化完成了。此时组件脱离了创建阶段,进入到了运行阶段。如果我们想要通过插件操作页面上的DOM节点,最早可以在和这个阶段中进行

beforeUpdate: 当执行这个钩子时,页面中的显示的数据还是旧的,data中的数据是更新后的, 页面还没有和最新的数据保持同步

updated: 页面显示的数据和data中的数据已经保持同步了,都是最新的

beforeDestory: Vue实例从运行阶段进入到了销毁阶段,这个时候上所有的 data 和 methods , 指令, 过滤器 ……都是处于可用状态。还没有真正被销毁

destroyed: 这个时候上所有的 data 和 methods , 指令, 过滤器 ……都是处于不可用状态。组件已经被销毁了。

8.Diff算法

Vue3 patchChildren 源码。结合上文与源码,patchFlag 帮助 diff 时区分静态节点,以及不同类型的动态节点。一定程度地减少节点本身及其属性的比对

function patchChildren(n1, n2, container, parentAnchor, parentComponent, parentSuspense, isSVG, optimized) {
  // 获取新老孩子节点
  const c1 = n1 && n1.children
  const c2 = n2.children
  const prevShapeFlag = n1 ? n1.shapeFlag : 0
  const { patchFlag, shapeFlag } = n2

  // 处理 patchFlag 大于 0 
  if(patchFlag > 0) {
    if(patchFlag && PatchFlags.KEYED_FRAGMENT) {
      // 存在 key
      patchKeyedChildren()
      return
    } els if(patchFlag && PatchFlags.UNKEYED_FRAGMENT) {
      // 不存在 key
      patchUnkeyedChildren()
      return
    }
  }

  // 匹配是文本节点(静态):移除老节点,设置文本节点
  if(shapeFlag && ShapeFlags.TEXT_CHILDREN) {
    if (prevShapeFlag & ShapeFlags.ARRAY_CHILDREN) {
      unmountChildren(c1 as VNode[], parentComponent, parentSuspense)
    }
    if (c2 !== c1) {
      hostSetElementText(container, c2 as string)
    }
  } else {
    // 匹配新老 Vnode 是数组,则全量比较;否则移除当前所有的节点
    if (prevShapeFlag & ShapeFlags.ARRAY_CHILDREN) {
      if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
        patchKeyedChildren(c1, c2, container, anchor, parentComponent, parentSuspense,...)
      } else {
        unmountChildren(c1 as VNode[], parentComponent, parentSuspense, true)
      }
    } else {

      if(prevShapeFlag & ShapeFlags.TEXT_CHILDREN) {
        hostSetElementText(container, '')
      } 
      if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
        mountChildren(c2 as VNodeArrayChildren, container,anchor,parentComponent,...)
      }
    }
  }
}

patchUnkeyedChildren 源码如下所示

function patchUnkeyedChildren(c1, c2, container, parentAnchor, parentComponent, parentSuspense, isSVG, optimized) {
  c1 = c1 || EMPTY_ARR
  c2 = c2 || EMPTY_ARR
  const oldLength = c1.length
  const newLength = c2.length
  const commonLength = Math.min(oldLength, newLength)
  let i
  for(i = 0; i < commonLength; i++) {
    // 如果新 Vnode 已经挂载,则直接 clone 一份,否则新建一个节点
    const nextChild = (c2[i] = optimized ? cloneIfMounted(c2[i] as Vnode)) : normalizeVnode(c2[i])
    patch()
  }
  if(oldLength > newLength) {
    // 移除多余的节点
    unmountedChildren()
  } else {
    // 创建新的节点
    mountChildren()
  }

}

9.去除URL中的#

将路由的hash模式改为history模式

10.Vue3事件缓存

Vue3 的cacheHandler可在第一次渲染后缓存我们的事件。相比于 Vue2 无需每次渲染都传递一个新函数。加一个 click 事件。

<div id="app">
  <h1>vue3事件缓存讲解</h1>
  <p>今天天气真不错</p>
  <div>{{name}}</div>
  <span onCLick=() => {}><span>
</div>
import { createElementVNode as _createElementVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from vue

const _withScopeId = n => (_pushScopeId(scope-id),n=n(),_popScopeId(),n)
const _hoisted_1 = { id: app }
const _hoisted_2 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(h1, null, vue3事件缓存讲解, -1 /* HOISTED */))
const _hoisted_3 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(p, null, 今天天气真不错, -1 /* HOISTED */))
const _hoisted_4 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(span, { onCLick: () => {} }, [
  /*#__PURE__*/_createElementVNode(span)
], -1 /* HOISTED */))

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createElementBlock(div, _hoisted_1, [
    _hoisted_2,
    _hoisted_3,
    _createElementVNode(div, null, _toDisplayString(_ctx.name), 1 /* TEXT */),
    _hoisted_4
  ]))
}

观察以上渲染函数,你会发现 click 事件节点为静态节点(HOISTED 为 -1),即不需要每次重新渲染。

11

12.vue-router的两种模式

hash模式: 即地址栏 URL 中的 # 符号
history模式: window.history对象打印出来可以看到里边提供的方法和记录长度。利用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法(需要特定浏览器支持)

13.$NextTick

$nextTick是在下次DOM更新循环结束之后执行延迟回调,在修改数据之后使用

14.Vue-router跳转和location.href有什么区别?

使用 location.href= /url来跳转,简单方便,但是刷新了页面;使用 history.pushState( /url ),无刷新页面,静态跳转;引进 router,然后使用 router.push( /url ) 来跳转,使用了 diff 算法,实现了按需加载,减少了 dom 的消耗。其实使用router跳转和使用 history.pushState()没什么差别的,因为vue-router就是用了 history.pushState() ,尤其是在history模式下

15.vue修饰符

.stop:等同于 JavaScript 中的 event.stopPropagation() ,防止事件冒泡
.prevent :等同于 JavaScript 中的 event.preventDefault(),防止执行预设的行为(如果事件可取消,则取消该事件,而不停止事件的进一步传播)
.capture :与事件冒泡的方向相反,事件捕获由外到内
.self :只会触发自己范围内的事件,不包含子元素
.once :只会触发一次

16.多根节点

// vue2只能存在一个根节点,需要用一个<div>来包裹着
<template>
  <div>
    <header></header>
    <main></main>
    <footer></footer>
  </div>
</template>
//Vue3 支持多个根节点,也就是 fragment。即以下多根节点的写法是被允许的
<template>
  <header></header>
  <main></main>
  <footer></footer>
</template>

17.vue2组件中data为什么必须是一个函数?

因为 JavaScript 的特性所导致,在component中,data必须以函数的形式存在,不可以是对象。组建中的 data 写成一个函数,数据以函数返回值的形式定义,这样每次复用组件的时候,都会返回一份新的 data ,相当于每个组件实例都有自己私有的数据空间,它们只负责各自维护的数据,不会造成混乱。而单纯的写成对象形式,就是所有的组件实例共用了一个 data ,这样改一个全都改了。

18.params和query的区别

用法:query要用path来引入,params要用name来引入,接收参数都是类似的,分别是 this. r o u t e . q u e r y . n a m e 和 t h i s . route.query.name 和 this. route.query.namethis.route.params.name 。url地址显示:query更加类似于我们ajax中get传参,params则类似于post,说的再简单一点,前者在浏览器地址栏中显示参数,后者则不显示

19.computed、watch、methods的区别

computed要有返回值,支持缓存。
watch不支持缓存。
methods:不支持缓存。
watch项目用处:搜索框输入框的监听,监听路由地址的改变

20.keep-alive

可以实现组件缓存,当组件切换时不会对当前组件进行卸载
有include、exclude两个属性,可以有条件的进行组件缓存
两个钩子函数activated/ deactivated,用来得知当前组件是否处于活跃状态
keep-alive项目用处:页面跳转保留当前位置。

21.父子组件通信

vue2 父传子,直接props,子传父,采用Emitting Events,this. e m i t ( ‘事件’ , 参数 ) ,父组件访问子组件 emit(‘事件’,参数),父组件访问子组件 emit(事件,参数),父组件访问子组件children(获取全部)、 r e f s (获取指定的),子组件访问父组件 refs(获取指定的), 子组件访问父组件 refs(获取指定的),子组件访问父组件parent、$root(根组件)

vue3 父传子,直接props,子传父,采用Emitting Events,但需要从vue之中解构出defineEmits,再defineEmits(['事件名称‘])
const emit = defineEmits([“change-handerAdd”, “change-handerStep”]);
emit(“change-handerAdd”, id);

22.兄弟组件通信

Vue.prototype.$bus = new Vue()
this.$bus.$emit('data-to-b', 'some data');
this.$bus.$on('data-to-b', this.receiveData);

23.监听组件原生事件

给对应的事件加上native修饰符,才能进行监听

24.单页面应用的优缺点

优点:
良好的交互体验。
良好的前后端工作分离模式。
减轻服务器压力。
缺点:
SEO难度较高。
前进、后退管理。
初次加载耗时多。

25.MVVM

MVVM是Model-View-ViewModel缩写,是把MVC中的Controller演变成ViewModel,Model层代表数据模型,View代表视图UI,ViewModel是View和Model层的桥梁,数据会绑定到viewModel层并自动将数据渲染到页面中,视图变化的时候会通知viewModel层更新数据

26.路由守卫

//全局前置守卫
router.beforeEach((to, from,next) => {
  // 返回 false 以取消导航
  return false
})
/* 全局后置守卫 */
router.afterEach((to,from,nex)=>{
  document.title = to.meta.title;// 1,修改当前页面的标题
  window.scrollTo(0,0) // 2,每次切换页面的时候,让页面滚动到最顶部
 })
 //路由独享守卫
  	// 西瓜播放器页面 beforeEnter介绍
      {
        path: '/xgplayer',
        name: 'Xgplayer',
        meta: { title: '西瓜播放器' },
        component: () => import('../views/xgplayer/xgplayer.vue'),

        /* 路由独享守卫 只在进入路由时触发  不想让进可以直接 return false */
        beforeEnter: (to, from,next) => {
         if (to.path == '/login') {
              next()
         } else {
              alert('请登入');
              next('/login')
         	}
        },
      },
//组件内部守卫
beforeRouteEnter
beforeRouteUpdate
beforeRouteLeave

27.vue2生命周期的理解

总共分为8个阶段创建前/后,载入前/后,更新前/后,销毁前/后。

创建前/后: 在beforeCreate阶段,vue实例的挂载元素el和数据对象data都为undefined,还未初始化。在created阶段,vue实例的数据对象data有了,el为undefined,还未初始化。

载入前/后:在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。在mounted阶段,vue实例挂载完成,data.message成功渲染。

更新前/后:当data变化时,会触发beforeUpdate和updated方法

销毁前/后:在执行destroy方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在

28.vue如何获取dom?

先给标签设置一个ref值,再通过this.$refs.domName获取,例如:

<div ref="test"></div>

const dom = this.$refs.test

29.v-on可以监听多个方法

<input type="text" v-on="{ input:onInput,focus:onFocus,blur:onBlur, }">

30.assets和static的区别?

这两个都是用来存放项目中所使用的静态资源文件。

两者的区别:
assets中的文件在运行npm run build的时候会打包,简单来说就是会被压缩体积,代码格式化之类的。打包之后也会放到static中。
static中的文件则不会被打包。
建议:将图片等未处理的文件放在assets中,打包减少体积。而对于第三方引入的一些资源文件如iconfont.css等可以放在static中,因为这些文件已经经过处理了。

31.vue初始化页面闪动问题?

使用vue开发时,在vue初始化之前,由于div是不归vue管的,所以我们写的代码在还没有解析的情况下会容易出现花屏现象,看到类似于{{message}}的字样,虽然一般情况下这个时间很短暂,但是我们还是有必要让解决这个问题的。

首先:在css里加上以下代码

[v-cloak] {
    display: none;
}

如果没有彻底解决问题,则在根元素加上style=“display: none;” :style=“{display: ‘block’}”

32.vuex中有几个核心属性,分别是什么?

State:数据唯一来源(数据源),vuex所有的数据都会存在state中,就像一个很大的仓库,存储所有数据,可以实例化用来存储所有的数据,如何存储呢?实际上status就是一个庞大的对象,本身是一个json对象,用来存储所有的数据
Getter:获取数据。本来可以通过state实例化拿到所有数据,但是getter有其存在的道理,好比是vue的computed计算属性,相似性:从现有的state来派生出一个新的state,大大方便我们获取数据,或者state派生出新的状态的时候有很大的作用
Mutation:修改数据,不是通过直接修改,需要通过一个commit
mutation来修改数据,mutation本质上就是一个function,为什么不能直接通过实例化state直接去给state里面的数据做修改,而是通过commit一个mutation,在通过mutation传入一个state,再对state进行修改呢?这里主要是因为,每次提交mutation,都会有一个记录,vue这样做是为了更方便的记录下每一个数据改变的历史和轨迹,方便于监听和回滚之类的操作。还需要注意一点,mutation的操作一定是同步的,写成异步会有很大的麻烦,具体看文档
Action:提交mutation,为什么会多出这个呢?实际上mutation是同步修改数据,而往往业务需求有很多的异步操作,来修改vuex的数据状态,action里面可以进行异步操作,因为我们提交的时候mutation,mutation是通过同步修改数据。Action相当于包装了一层,可以进行任意的异步编程。来提交mutation,在通过mutation同步修改数据

面对复杂的应用程序,当管理的状态比较多时;我们需要将vuex的store对象分割成模块(modules)。
const store = new Vuex.Store({
modules:{}
})

33.ajax请求代码应该写在组件的methods中还是vuex的actions中?

如果请求来的数据是不是要被其他组件公用,仅仅在请求的组件内使用,就不需要放入vuex 的state里。

如果被其他地方复用,这个很大几率上是需要的,如果需要,请将请求放入action里,方便复用

34.vuex中的数据在页面刷新后数据消失问题?

用sessionstorage 或者 localstorage 存储数据
存储: sessionStorage.setItem(‘名’,JSON.stringify(值) )
使用: sessionStorage.getItem(‘名’) —得到的值为字符串类型,用JSON.parse()去引号;

35.怎么在组件中批量使用Vuex的getter属性?

使用mapGetters辅助函数, 利用对象展开运算符将getter混入computed 对象中

import {mapGetters} from 'vuex'
export default{
    computed:{
        ...mapGetters(['total','discountTotal'])
    }
}

36.组件中重复使用mutation?

使用mapMutations辅助函数,在组件中这么使用

import { mapMutations } from 'vuex'
methods:{
    ...mapMutations({
        setNumber:'SET_NUMBER',
    })
}

然后调用this.setNumber(10)相当调用this.$store.commit(‘SET_NUMBER’,10)

37.mutation和action有什么区别?

38.在v-model上怎么用Vuex中state的值?

需要通过computed计算属性来转换

<input v-model="message">
// ...
computed: {
    message: {
        get () {
            return this.$store.state.message
        },
        set (value) {
            this.$store.commit('updateMessage', value)
        }
    }
}

39.vue2和vue3响应式原理区别

vue3对于vue2来说,最大的变化就是composition Api 替换了vue2的options Api
vue3的响应式原理替换为了proxy,vue2的则是Object.defineproperty。其中proxy有着以下这些优点:
 - 1:对象新增的属性不需要使用$set添加响应式,因为proxy默认会监听动态添加属性和删除属性等操作
 - 2:消除数组上无法监听数组索引、length属性,不再进行数组原型对象上重写数组方法
 - 3:Object.defineproperty是劫持所有对象的属性设置为getter、setter,然后遍历递归去实现。而proxy则是代理了整个对象。
 - 4:vue2使用Object.defineproperty拦截对象的getset属性进行操作。而proxy有着13种拦截方法。
 - 5:由vue2的响应式原理可以看出,vue底层需要对vue实例的返回的每一个key进行getset操作,无论这个值有没有被用到。所以在vue中定义的data属性越多,那么初始化开销就会越大。而proxy是一个惰性的操作,它只会在用到这个key的时候才会执行get,改值的时候才会执行set。所以在vue3中实现响应式的性能实际上要比vue2实现响应式性能要好

+ proxy原理
 - 作用:能够为另外一个对象创建代理,该代理可以拦截和重新定义该对象的基本操作(获取,设置,定义属性等)
 - proxy的两个参数: 参数1=> 要代理的原始对象; 参数2=>一个对象,这个对象定义了操作将被拦截以及如何重新定义被拦截的操作
``js
const target = {name: "ts",age: 18};
const handler = {};
const proxy = new Proxy(target, handler); // 使用proxy代理了一个空对象 proxy对象具有响应式


const target2 = {name: "ts",age: "18"};
const handler2 = {
  get(target, key, receiver) {
    console.log(`访问属性${key}`)
    return Reflect.get(target, key, receiver)
  },
  set(target, key, value, receiver) {
    console.log(`设置属性${key}`)
    return Reflect.set(target, key, value, receiver)
  }
};
const proxy2 = new Proxy(target2, handler2); // 使用proxy代理了一个handler2对象 handler2对象中设置了get和set属性
console.log('proxy2.name', proxy2.name)
proxy2.name = 'jkl';
proxy2.sex = 'male';
console.log('proxy2',proxy2);

Object.defineproperty 与 proxy 的区别:由 vue2 的响应式原理可以看出,vue 底层需要对 vue 实例的返回的每一个 key 进行 get 和 set 操作,无论这个值有没有被用到。所以在 vue 中定义的 data 属性越多,那么初始化开销就会越大。而 proxy 是一个惰性的操作,它只会在用到这个 key 的时候才会执行 get,改值的时候才会执行 set。所以在 vue3 中实现响应式的性能实际上要比 vue2 实现响应式性能要好

1:Object.defineproperty 初始化的时候拦截对象,设置为getset属性
const obj = {
  name: "wxs",
  age: 25,
};
Object.entries(obj).forEach(([key, value]) => {
  Object.defineProperty(obj, key, {
    get() {
      return value;
    },
    set(newValue) {
      console.log(`监听到属性${key}改变`);
      value = newValue;
    },
  });
});
obj.name = 11;
obj.age = 22;
obj.ak47 = "ak47";

1:输出结果 => 监听到属性name改变、监听到属性age改变

2: proxy 初始化的时候,有使用这个key值则get一下,有设置这个key值则set一下
const obj = {
    name:'wxs',
    age:25
}

const prxoyTarget = new Proxy(obj,{
    get(target,key){
        return target.key
    },
    set(target,key,value){
        console.log(`监听到属性${key}需要改成${value}`)
        target[key] = value
    }
})

prxoyTarget.name = 11
prxoyTarget.age = 22
prxoyTarget.ak47 = 'ak47'

2:输出结果 => 监听到属性name需要改成11、监听到属性age需要改成22、监听到属性ak47需要改成ak47

http://www.kler.cn/a/319032.html

相关文章:

  • 【缺陷检测】Anomaly Detection via Reverse Distillation from One-Class Embedding
  • vue请求数据报错,设置支持跨域请求,以及2种请求方法axios或者async与await
  • qt QKeySequence详解
  • Fastapi使用MongoDB作为数据库
  • 【stable diffusion部署】超强AI绘画Stable Diffusion,本地部署使用教程,完全免费使用
  • 【计算机网络】【网络层】【习题】
  • 简单水印通过python去除
  • 数造科技荣获“2024爱分析·数据智能优秀厂商”
  • 传输大咖45 | 跨国传输大文件的高效、安全传输系统
  • 大数据Flink(一百二十一):Flink CDC基本介绍
  • 数据在内存中的存储(上)
  • Spring Boot 学习和使用
  • 大数据新视界 --大数据大厂之探索ES:大数据时代的高效搜索引擎实战攻略
  • 基于SpringBoot的CSGO赛事管理系统
  • 自动化等保测评:提升效率,降低成本的新路径
  • 科研绘图系列:R语言箱线图和连线图(boxplot linechart)
  • Vue.js 与 Flask/Django 后端配合:构建现代 Web 应用的最佳实践
  • uniapp实现触底分页加载
  • 微服务面试-修改nacos配置,不重启服务怎生效
  • Zerotier 内网穿透教程
  • TomCat乱码问题
  • APP自动化中 ADB Monkey用法
  • Python办公自动化案例:将Excel数据批量保存到Word表格中
  • 【大数据入门 | Hive】DDL数据定义语言(数据库DataBase)
  • TON生态系统开发指南:从零开始构建你的Web3应用
  • 动手学深度学习(pytorch土堆)-05-1神经网络