网站建设静态代码/哈尔滨seo优化公司
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){}}
}
- 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 设置响应式属性demolet 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 设置响应式属性demolet 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 vueconst _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, // 不会改变子节点顺序的 fragmentKEYED_FRAGMENT = 1 << 7, // 带有 key 属性的 fragment 或部分子节点UNKEYED_FRAGMENT = 1 << 8, // 子节点没有 key 的fragmentNEED_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.childrenconst c2 = n2.childrenconst prevShapeFlag = n1 ? n1.shapeFlag : 0const { patchFlag, shapeFlag } = n2// 处理 patchFlag 大于 0 if(patchFlag > 0) {if(patchFlag && PatchFlags.KEYED_FRAGMENT) {// 存在 keypatchKeyedChildren()return} els if(patchFlag && PatchFlags.UNKEYED_FRAGMENT) {// 不存在 keypatchUnkeyedChildren()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_ARRc2 = c2 || EMPTY_ARRconst oldLength = c1.lengthconst newLength = c2.lengthconst commonLength = Math.min(oldLength, newLength)let ifor(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 vueconst _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.name和this.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拦截对象的get和set属性进行操作。而proxy有着13种拦截方法。- 5:由vue2的响应式原理可以看出,vue底层需要对vue实例的返回的每一个key进行get和set操作,无论这个值有没有被用到。所以在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 初始化的时候拦截对象,设置为get和set属性
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
相关文章:

vue基础面试题
1.Vue指令 v-bind:动态绑定数据 v-on:绑定事件监听器 v-for:循环指令,可以循环数组或对象 v-if:根据表达式的真假值,判断是否渲染元素,会销毁并重建 v-show:显示隐藏元素࿰…...

关系型数据库和非关系型数据库的区别
1.常见的主流数据库 关系型数据库: MySql 、达梦 、PostgreSQL 、Oracle 、Sql Server 、Sqlite非关系型数据库: Redis 、MongoDB 、HBase 、 Neo4J 、 CouchDB 2.介绍 关系型数据库最典型的数据结构是表,由二维表及其之间的联系…...

学习之什么是迭代器
什么是迭代器 迭代器的作用:访问容器中的元素 首先要了解什么是Iterablelterable(可迭代的) 字符串、列表、元组、字典都是lterable,都可以放到for循环语句中遍历 lterable类型的定义中一定有一个_iter_方法iter 方法必须返回一个lterator(迭代器) 可以…...

数据结构-3.6.队列的链式实现
队列可以理解为单链表的阉割版,相比单链表而言,队列只有在添加和删除元素上和单链表有区别 一.队列的链式实现: 1.图解: 2.代码: #include<stdio.h> typedef struct LinkNode //链式队列结点 {int data;st…...

Java中去除字符串中的空格
在平时的开发中,在后端经常要获取前端传过来的字符串,有的是用户从输入框中输入的,有的是通过excel表格中获取的。 在这些字符串中,有时候会遇到字符串中有空格、换行符或者制表符,对于这种字符串来说,直接…...

AI大模型算法工程师就业宝典—— 高薪入职攻略与转行秘籍!
从ChatGPT到新近的GPT-4,GPT模型的发展表明,AI正在向着“类⼈化”⽅向迅速发展。 GPT-4具备深度阅读和识图能⼒,能够出⾊地通过专业考试并完成复杂指令,向⼈类引以为傲的“创造⼒”发起挑战。 现有的就业结构即将发⽣重⼤变化&a…...

node-rtsp-stream、jsmpeg.min.js实现rtsp视频在web端播放
1. 服务地址(私有):https://gitee.com/nnlss/video-node-server 2.node-rtsp-stream 需要安装FFMPEG; 3.给推拉流做了开关,可借助http请求,有更好方式可联系; 4.存在问题: 1&…...

C++ 9.27
作业: 将之前实现的顺序表、栈、队列都更改成模板类 Stack #include <iostream> using namespace std; template <typename T> class Stack { private: T* arr; // 存储栈元素的数组 int top; // 栈顶索引 int capacity; // 栈的…...

让具身智能更快更强!华东师大上大提出TinyVLA:高效视觉-语言-动作模型,遥遥领先
论文链接:https://arxiv.org/pdf/2409.12514 项目链接:https://tiny-vla.github.io/ 具身智能近期发展迅速,拥有了大模型"大脑"的机械臂在动作上更加高效和精确,但现有的一个难点是:模型受到算力和数据的制…...

Excel 获取某列不为空的值【INDEX函数 | SMALL函数或 LARGE函数 | ROW函数 | ISBLANK 函数】
〇、需求 Excel 获取某列不为空的值(获取某列中第一个非空值 或 获取某列中最后一个非空值)。 一、知识点讲解 INDEX函数 和 SMALL函数 两个函数搭配使用都可以实现上述需求 获取某列中第一个非空值 。 INDEX函数 和 LARGE函数 两个函数搭配使用都可以实现上述需求 获取某…...

爆火!大模型算法岗 100 道面试题全解析,赶紧收藏!
大模型应该是目前当之无愧的最有影响力的AI技术,它正在革新各个行业,包括自然语言处理、机器翻译、内容创作和客户服务等等,正在成为未来商业环境的重要组成部分。 截至目前大模型已经超过200个,在大模型纵横的时代,不…...

Python画笔案例-068 绘制漂亮米
1、绘制漂亮米 通过 python 的turtle 库绘制 漂亮米,如下图: 2、实现代码 绘制 漂亮米,以下为实现代码: """漂亮米.py注意亮度为0.5的时候最鲜艳本程序需要coloradd模块支持,安装方法:pip install coloradd程序运行需要很长时间,请耐心等待。可以把窗口最小…...

得物App荣获国家级奖项,正品保障引领潮流电商新风尚
近日,在2024年中国国际服务贸易交易会上,得物App凭借其在科技创新保障品质消费领域的突出成果,再次荣获国家级殊荣——“科技创新服务示范案例”。这是继上海市质量金奖之后,得物App获得的又一个“高含金量”奖项。 作为深受年轻人…...

【BurpSuite】SQL注入 | SQL injection(1-2)
🏘️个人主页: 点燃银河尽头的篝火(●’◡’●) 如果文章有帮到你的话记得点赞👍收藏💗支持一下哦 【BurpSuite】SQL注入 | SQL injection(1-2) 实验一 Lab: SQL injection vulnerability in WHERE clause…...

ThreadPoolExecutor有哪些核心的配置参数?
ThreadPoolExecutor 是 Java 中强大的线程池实现,具有多种配置参数,可以灵活地根据具体应用需求进行调整。以下是 ThreadPoolExecutor 的核心配置参数及其简要说明: 1. corePoolSize 描述:核心线程池的大小,即最小保…...

关于工作虚拟组的一些思考
这是学习笔记的第 2493篇文章 因为各种工作协作,势必要打破组织边界,可能会存在各种形态的虚拟组。 近期沉淀了一些虚拟组的管理方式,在一定时间范围内也有了一些起色,所以在不断沉淀的过程中,也在不断思考。 这三个虚…...

【Redis入门到精通六】在Spring Boot中集成Redis(含配置和操作演示)
目录 Spring Boot中集成Redis 1.项目创建和环境配置 2.基本操作演示 Spring Boot中集成Redis Spring社区也自定义了一套Redis的客户端,与jedis的操作方式有所差异,Spring中把每个类型的操作都单独封装了起来。下面就让我来带大家了解如何在Spring Boot…...

【CSS】透明度 、过渡 、动画 、渐变
opacity 透明度transition 过渡animation 动画background 渐变 ( 线性渐变 \ 径向渐变 \ 锥形渐变 ) opacity 透明度 设置元素的透明度,会影响元素及其所有子元素的透明度,值范围:0(完全透明)到 1(完全不透…...

尚硅谷vue3+TypeScript笔记大全
1. Vue3简介 2020年9月18日,Vue.js发布版3.0版本,代号:One Piece(n 经历了:4800次提交、40个RFC、600次PR、300贡献者 官方发版地址:Release v3.0.0 One Piece vuejs/core 截止2023年10月,最…...

New major version of npm available! 8.3.1 -> 10.8.3 报错
问题 npm install 安装新项目时,出现如下升级错误。 npm notice npm notice New major version of npm available! 8.3.1 -> 10.8.3 npm notice Changelog: https://github.com/npm/cli/releases/tag/v10.8.3 npm notice Run npm install -g npm10.8.3 to upd…...

Python(七)- 文件操作
目录 文件操作 打开文件 读数据 写数据 关闭文件 文件读写实例 文件写 文件读 读数据类型 备份文件 os模块 目录的具体操作 文件操作 在Python中操作文件记录信息的步骤: (1)打开文件,或新建一个文件; o…...

Docker技术深度解析与实践案例
Docker技术深度解析与实践案例 在当今快速迭代的软件开发环境中,如何高效地打包、部署和管理应用成为了开发人员和运维团队面临的重大挑战。Docker,作为一种开源的应用容器引擎,凭借其轻量级、可移植性和高效性,迅速成为解决这些…...

llama_deploy
本文于 240924 翻译整理自: https://docs.llamaindex.ai/en/stable/module_guides/workflow/deployment/ 文章目录 一、关于 🦙`llama_deploy`🤖为什么使用 `llama_deploy`?等等,`llama-agents` 在哪里?二、入门1、安装2、高级部署3、部署核心系统4、部署工作流5、与部…...

平衡二叉搜索树插入的实现
前言 因为二叉搜索树在插入的时候最坏的情况可能会变成一条单一链表,从而使查找或者插入的时候消耗大量的时间。所以为了解决这一情况诞生了平衡二叉搜索树,其作用是为了减少二叉搜索树的整体高度,从而使查找插入删除的效率提高。 一、平衡二…...

ROS理论与实践学习笔记——2 ROS通信机制之通信机制实践
5.1 话题发布 需求描述:编码实现乌龟运动控制,让小乌龟做圆周运动。 实现分析: ①乌龟运动控制实现,关键节点有两个,一个是乌龟运动显示节点 turtlesim_node,另一个是控制节点,二者是订阅发布模…...

CDGA|数据治理:策略与价值的深度融合
在当今这个数据驱动的时代,企业数据治理的重要性日益凸显。数据不仅是企业的核心资产,更是驱动业务决策、优化运营流程、创新产品服务的关键力量。然而,要让数据治理真正发挥价值,企业需要采取一系列策略来确保数据的准确性、完整…...

49. 建模软件绘制3D场景(Blender)
这文章主要给大家科普一些三维模型创建、美术和程序员协作的相关问题。 三维建模软件作用 对于简单的立方体、球体等模型,你可以通过three.js的几何体相关API快速实现,不过复杂的模型,比如一辆轿车、一栋房子、一个仓库,一般需要…...

如何使用 DomCrawler 进行复杂的网页数据抓取?
在互联网时代,数据是宝贵的资源。无论是市场分析、客户洞察还是内容聚合,从网页中抓取数据都是一项关键技能。Symfony 的 DomCrawler 是一个强大的工具,可以帮助开发者从复杂的网页中提取所需的数据。本文将详细介绍如何使用 DomCrawler 进行…...

维修服务品牌小程序渠道客获
维修服务可覆盖家电电器、家具、手机电脑等多个细分类目,本地同城也有着不少目标用户且该行业客户有着一定粘性,比如服务完成递上一张名片/电话留存则有着较高复购率。 线上各行业便捷化程度提升,服务进店/上门都需要快捷完成,包…...

【全新课程】正点原子《基于GD32 ARM32单片机项目实战入门》培训课程上线!
正点原子《基于GD32 ARM32单片机项目实战入门》全新培训课程上线啦!正点原子工程师手把手教你学!彻底解决ARM32单片机项目入门难的问题! 一、课程介绍 本课程专为ARM32单片机的入门学习者设计,涵盖了环境搭建、编程软件使用、模…...