前端面试八股文--Vue篇(持续更新)

news2025/1/19 17:21:57

一. Vue2 篇

1.MVC MVVM区别

首先呢这是两种模式

MVC指的是 modal,view, controller

MVVM 指的是 modal ,view, view modal

mvc和mvvm区别是:1、处理业务的模式不同,MVC里,View是可以直接访问Model,而MVVM是将页面与数据逻辑分离的模式,它把数据绑定工作放到一个JS里去实现;2、处理数据操作不同,MVVM通过数据来显示视图层而不是节点操作。

2. vue的优点

采用MVVM框架,我们只需要关注对数据的修改就好,提供大量api,减少我们对dom的直接操作。采用spa页面,用户体验更佳。减轻服务器压力(服务器不需要发送html页面,只需要发送数据即可)。提供虚拟dom,减轻页面渲染压力。

3. vue组件间传值

(1)父传子

<son :data="data"/>

props接

(2)子传父

<son @getData="getData">

this.$emit("getData",data)

(3) 兄弟传

发布订阅模式

事件总线

4. v-show和v-if

就是是否显示和是否销毁。

实现本质方法区别

v-show本质就是标签display设置为none,控制隐藏

v-if是动态的向DOM树内添加或者删除DOM元素

编译的区别

v-show其实就是在控制css

v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件

编译的条件

v-show都会编译,初始值为false,只是将display设为none,但它也编译了

v-if初始值为false,就不会编译了

性能

v-show只编译一次,后面其实就是控制css,而v-if不停的销毁和创建,故v-show性能更好一点。

5. 常见的vue指令

v-on / :绑定事件

v-for :循环渲染

v-modal:双向绑定

v-if:显示或者销毁(就是css里的display是不是none的问题)

v-show:是否展示(只是显示或者隐藏,而不是销毁)

v-bind:绑定数据

6. 数据响应式原理(vue2,vue3的与此有差异)

在vue2中,对数据的代理主要
什么是响应式,也即是说,数据发生改变的时候,视图会重新渲染,匹配更新为最新的值。
Object.defineProperty 为对象中的每一个属性,设置 get 和 set 方法,每个声明的属性,都会有一个 专属的依赖收集器 subs,当页面使用到 某个属性时,触发 ObjectdefineProperty - get函数,页面的 watcher 就会被 放到 属性的依赖收集器 subs 中,在 数据变化时,通知更新;
当数据改变的时候,会触发Object.defineProperty - set函数,数据会遍历自己的 依赖收集器 subs,逐个通知 watcher,视图开始更新;
原文链接:https://blog.csdn.net/qq_44182284/article/details/111191455

下面写一个实例

用obj2代理obj1

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        let obj1 = { a: 1, b: 2 }
        let obj2={c:3}
        Object.defineProperty(obj2, "a", {
            get() {
                return obj1.a
            },
            set(value) {
                obj1.a = value
            }
        })
        console.log(obj2);
    </script>
</body>

</html>

我们可以看到obj2为

除了本身的c:3属性外,还有我们代理的a属性,并且有get和set方法,我们可以在调试工具中修改obj2.a=5

 此时查看obj1

发现obj1的a也变成了5,这就是一波简单的代理。或者我们修改obj1.a=10

 

再查看obj2

 发现obj2的a也变成了10,这就是双向绑定。

但是该绑定模式在vue2中是有缺点的,他对于数组和对象的修改有时候会出现问题,最典型的就是根据索引修改数组信息或者对象信息。直接修改对于vue来说是不会及时响应的,我们需要的是使用vue.$set(源,索引,修改值)或者$nextTick强制更新才行。

7. vue2 解决修改数组对象时数据代理问题

除了上面说到的nextTick和$set, 其实vue帮我们重写了数组的那七大方法,例如push,pop,shift,unshift,splice等等。通过这些方法修改数组,vue就可以及时响应并更新页面。

8. data是函数的问题

我们自己在连续vue时,在一个html文件中引入vue.js 我们发现data可以是对象的形式,也可以是函数的形式。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./js/vue.js"></script>
</head>

<body>
    <div id="root">
        <h1>{{name}}</h1>
    </div>
    <script>
        // 阻止vue产品提示
        Vue.config.productionTip = false
        // 创建vue实例  
        const x = new Vue({
            //控制接管容器
            // el: '#root',
            // data 第一种写法
            // data: {
            //     name: 'test1'
            // }
            // data 第二种写法
            data:function(){
                return{
                    name:"test1",
                    testObj:{
                        name1:"111",
                        name2:'2222'
                    }
                }
            }
        })

        // 另一个绑定方式
        x.$mount('#root')
        console.log(x);
    </script>
</body>

</html>

但是在脚手架中开发时为什么都要使用函数方式呢。

原因是对象是引用数据类型。如果以对象形式写,会造成声明空间的污染,不同组件之间data数据的干扰。所以要使用函数返回的方式。

9.  watch和computed的区别

计算属性computed :

(1)、支持缓存,只有依赖数据发生改变,才会重新进行计算

(2)、不支持异步,当computed内有异步操作时无效,无法监听数据的变化

(3)、computed 属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data中声明过或者父组件传递的props中的数据通过计算得到的值

(4)、如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个多对一或者一对一,一般用computed

(5)、如果computed属性属性值是函数,那么默认会走get方法;函数的返回值就是属性的属性值;在computed中的,属性都有一个get和一个set方法,当数据变化时,调用set方法。

侦听属性watch:

(1)、不支持缓存,数据变,直接会触发相应的操作;

(2)、watch支持异步;

(3)、监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值;

(4)、当一个属性发生变化时,需要执行对应的操作;一对多;

(5)、监听数据必须是data中声明过或者父组件传递过来的props中的数据,当数据变化时,触发其他操作,函数有两个参数,

  immediate:组件加载立即触发回调函数执行,  deep: 深度监听,为了发现对象内部值的变化,复杂类型的数据时使用,例如数组中的对象内容的改变,注意监听数组的变动不需要这么做。注意:deep无法监听到数组的变动和对象的新

增,参考vue数组变异,只有以响应式的方式触发才会被监听到。

10. 生命周期(超级重要)

生命周期其实就是在vue组件生成挂载以及销毁过程中一系列的关键时间节点,vue给我们提供各种对应时间节点的回调函数(也叫钩子函数)来执行我们需要的逻辑。

直接上图

 

 通俗来讲,先创建created(主要就是数据初始化),再挂载,也就是mounted(dom操作)。数据更新走updata,销毁组件走destroyed。然后再加上他们的before就是所有的钩子。

这里最常考的就是:对于数据初始化,最好再created钩子里进行,对dom操作,最好再mounted里操作。

还有一些特殊的钩子,比如路由的钩子

  //   路由的钩子
  activated() {
    this.timer = setInterval(() => {
      console.log("@");
    }, 1000);
    console.log("被激活了");
  },
  deactivated() {
    console.log("不看了",this);
    clearInterval(this.timer);
  },

第一个是通过路由进入显示该组件时调用

第二个是通过路由离开该组件时调用

 11. 路由

基本情况

vue的路由通过监视我们浏览器地址栏的变化决定展示什么组件内容。

分为两种模式:hash模式和history模式

hash模式(默认):每次点击跳转后我们的地址栏会有一个#

注意#后的任何数据都不会被发送到服务器。

history模式:每次跳转就和我们普通的页面跳转类似,地址栏后面不会有#,这种情况下的地址会被发送到服务器,在部署时需要特殊解决一下。

路由的基本格式如下

import VueRouter from "vue-router";
import page1 from '../components/Page1'
import page2 from '../components/Page2'
import page1son from '../pages/Page1son'
import page2son from '../pages/Page2son'
//默认是hash模式 可以设置history
const router = new VueRouter({
    mode: 'history',
    routes: [
        {
            name: 'Page1',
            path: '/Page1',
            component: page1,
            children: [
                {
                    name: 'page1son',
                    path: 'page1son',
                    component: page1son,
                    // props:{a:11111,b:'ccc'},
                    // 这样所有param的参数就会以props传过去
                    // props:true,
                    props() {
                        return { id: ' query.id', title: 'query.title' }
                    },
                    // //独享路由
                    // beforeEnter:(to,from,next)=>{

                    // }
                }
            ]
        },
        {
            name: 'page2',
            path: '/Page2',
            component: page2,
            meta: { isAuth: true },
            children: [
                {
                    path: 'page2son',
                    component: page2son,
                }
            ]
        },
        {
            name: 'selectList',
            path: '/selectList',
            component: () => import(/* webpackChunkName: "about" */ '../components/selectList.vue'),
        }
    ]
})
// 全局前置路由守卫
// router.beforeEach((to, from, next) => {
//     if (to.meta.isAuth == true) {
//         alert("需要权限");
//         next()
//     } else {
//         console.log("路由调用", to, from, next);
//         next()
//     }
// })
// // 全局后置路由守卫
// router.afterEach((to, from) => {
//     console.log(to.name, from.name);
//     document.title=to.name
// })
export default router

实现跳转的方式

第一种

  <router-link
      replace
      :to="{ path: '/page1/page1son', query: [(id = 1111), (title = data)] }"
      >page1-child</router-link
    >
    <router-view></router-view>

to就是跳转的地方,下面是跳转后组件展示的区域。

第二种

 this.$router.push({ path: "/page1/page1son" });

一个效果,这个就是把地址push到了history的栈里

路由守卫

// 全局前置路由守卫
router.beforeEach((to, from, next) => {
    if (to.meta.isAuth == true) {
        alert("需要权限");
        next()
    } else {
        console.log("路由调用", to, from, next);
        next()
    }
})
// 全局后置路由守卫
router.afterEach((to, from) => {
    console.log(to.name, from.name);
    document.title=to.name
})

分为前置守卫,后置守卫

前置守卫负责确定权限或者做一些跳转前的初始化处理,主要三个参数,到哪来,从哪去,能不能继续,能就调用next()

后置守卫主要就是改个文档标题啥的,不算特别重要。

当然还有组件内置守卫

  //组件内路由
  beforeRouteEnter(to, from, next) {
    console.log("刚进", to, from);
    next();
  },
  beforeRouteLeave(to, from, next) {
    console.log("走", to, from);
    next();
  },

很好理解,来之前干嘛,离开前干嘛,只不过是写在组件内的。

12. vuex

主要是状态管理,通俗说就是如果多个组件会处理同一个数据,那么可以用vuex集中管理

 首先三个状态 Actions Mutations State

Actions主要用来记录组件需要进行的动作,我们可以在里面进行判断等等操作

Mutations负责修改数据,而数据就统一存在State中。

组件调用Actions里的方法时,使用的是dispatch("函数名",参数)

Actions通知Mutations修改State时,调用的是commit("函数名",参数)

然后Mutations修改数据

 data.sum += value

下面是代码实例

vuex的

import Vuex from 'vuex'
import Vue from 'vue'
// 用于响应动作
const actions = {
    increment: function (context, value) {
        console.log('收到的参数', context, value);
        context.commit('increment', value)
    }
}
// 用于操作数据
const mutations = {
    increment: function (data, value) {
        console.log("state中的数据", data, value);
        data.sum += value
    },
    decrement(data,value){
        data.sum-=value
    }
}
//用于存储
const state = {
    sum: 0
}
// 加工state中的数据
const getters ={
    bigSum(state){
        return state.sum*10
    }
}
Vue.use(Vuex)
const store = new Vuex.Store({ actions, mutations, state, getters })
// 暴露store
export default store

组件中操作

<template>
  <div>
    <h1>当前求和值为:{{ sum }}</h1>
    <h1>×10后的值为{{ bigSum }}</h1>
    <select v-model.number="num">
      <option :value="1">1</option>
      <option :value="2">2</option>
      <option :value="3">3</option>
    </select>
    <button @click="increment">+</button>
    <button @click="decrement">-</button>
    <button @click="oddincrement">当前求和奇数再加</button
    ><button @click="waitincrement">等一等再加</button>
  </div>
</template>

<script>
import {mapState,mapGetters} from 'vuex'
export default {
  name: "countvuex",
  data() {
    return {
      num: 1,
    };
  },
  computed:{
    // 直接映射state中的数据
      // ...mapState({he:'sum'})
    // 不换名字映射
    ...mapState(['sum']),
    ...mapGetters(['bigSum'])
  },
  mounted(){
  },
  methods: {
    increment() {
      this.$store.dispatch("increment", this.num);
    },
    decrement() {
      this.$store.commit("decrement", this.num);
    },
    oddincrement() {
      if (this.sum % 2 == 1) {
        this.sum = this.sum + this.num;
      }
    },
    waitincrement() {
      setTimeout(() => {
        this.sum = this.num + this.sum;
      }, 1000);
    },
  },
};
</script>

<style>
</style>

12.vue2双向绑定模拟

解释一下为什么会给input标签添加input事件,是因为v-modal本身就只是一个语法糖,它相当于

v-modal="valueA"   <=> @input = "valueA=event.target.value"

当然如果是chexkbox它就对应@change事件

它只是帮我们完成修改标签数据的同时修改我们组件的data。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <!-- 为什么要在标签里直接定义输入事件呢,其实v-modal本身就是个语法糖 -->
    <input type="text" id="dom1" />
    <input type="text" id="dom2" />
    <script>
        class Watcher {
            constructor(dom, msg) {
                this.dom = dom
                this.msg = msg
            }
            update(data) {
                this.dom.value = data
            }
        }
        //其实就是个发布订阅
        class Def {
            constructor() {
                this.subs = {}
            }
            //发布消息
            publish(msg, data) {
                if (this.subs[msg]) {
                    this.notice(msg, data)
                }
            }
            subscribe(item) {
                if (!this.subs[item.msg]) {
                    this.subs[item.msg] = []
                }
                this.subs[item.msg].push(item)
            }
            notice(msg, data) {
                for (let item of this.subs[msg]) {
                    item.update(data)
                }
            }
        }
        class VM {
            constructor(data, Watchers) {
                this.data = data
                this.def = new Def()
                this.Watchers = Watchers
            }
            Observe() {
                for (let key in this.data) {
                    Object.defineProperty(this, key, {
                        get() {
                            this.def.subscribe(this.WillUpdate)
                            return this.data[key]
                        },
                        set(newValue) {
                            //修改数据相同也会触发set,过滤一下。
                            if (newValue !== this.data[key]) {
                                this.data[key] = newValue
                                this.def.publish(key, this.data[key])
                            }
                        }
                    })
                }
            }
            default() {
                for (let item of this.Watchers) {
                    this.WillUpdate = item
                    item.dom.value = this[item.msg]
                    //就是v-modal语法糖的原理
                    item.dom.addEventListener("input", (e) => {
                        this[item.msg] = e.target.value
                    })
                }
            }
        }
        function data() {
            return {
                a: 111,
                b: 222,
                c: 'test',
            }
        }
        const Watcher1 = new Watcher(document.getElementById("dom1"), "a")
        const Watcher2 = new Watcher(document.getElementById("dom2"), "b")
        let Watchers = [Watcher1, Watcher2]
        const vm = new VM(data(), Watchers)
        vm.Observe()
        vm.default()
    </script>
</body>

</html>

13. 自定义指令

直接看例子就懂了(实现指令控制字体颜色)

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../js/vue.js"></script>
</head>

<body>
    <div id="root">
        <div v-color="color">{{name}}</div>
    </div>
    <script>
        const vm = new Vue({
            el: "#root",
            data() {
                return {
                    name: '小明',
                    host: 'xxx',
                    color: "red"
                }
            },
            directives: {
                color(dom, obj) {
                    // 标签和v-test等于的值
                    console.log("@@@", dom, obj);
                    dom.style.color=obj.value
                },
                //     // 完整写法
                //     fbind: {
                //         // 指令与标签结合
                //         bind(el, data) {

                //         },
                //         // 标签挂到页面上
                //         inserted(el, data) {

                //         },
                //         // 标签更新
                //         update(el, data) {

                //         },
                //     }
            }
        })
        console.log(vm);
    </script>
</body>

</html>

效果图

 

二. Vue3

1. Vue3与Vue2的对比

(1)双向数据绑定的原理发生改变

vue2是Object.definpropetry,但是有个缺点就是vue2中的数据代理无法检测通过索引修改的数组,对象变化,不能及时的更新页面。vue3的原理是proxy,一个window自带的api,并且读取数据以及修改数据使用了反射接口,可以更好的检测数组对象的变化。(后面有详细说明)。

(2)标签变化

vue3的模板标签下可以有多个根标签,而vue2只能有一个根标签。

(3)Composition API

Vue2与Vue3 最大的区别 — Vue2使用选项类型API(Options API)对比Vue3合成型API(Composition API)

直接给例子

vue2

<template>
  <div>
    <div class="father">我是父组件 {{ sondata }} {{ sondata1 }}</div>
    <son :testf1="testf1" @senddata1="senddata1">
      <!-- <template scope="data1">
        <div class="slotdemo">我是插槽插进去的:{{ data1.data1 }}</div>
      </template> -->
    </son>
    <son2 />
  </div>
</template>

<script>
import son from "./son.vue";
import son2 from "./son2.vue";
export default {
  name: "father",
  components: {
    son,
    son2,
  },
  data() {
    return {
      tip: "father",
      sondata: "",
      sondata1: "",
    };
  },
  methods: {
    senddata1(e) {
      this.sondata1 = e;
      console.log(e);
    },
    testf1(val) {
      console.log("son 的数据: ", val);
      this.sondata = val;
    },
  },
};
</script>

<style scoped>
.father {
  width: 200px;
  height: 200px;
  background-color: bisque;
}
.slotdemo {
  width: 200px;
  height: 200px;
  background-color: red;
}
</style>

选项类型api就是需要什么写什么。需要data,就把数据都放在data里,需要定义方法时间,就都写在methods里。

vue3

<template>
  <!-- 现在把所有的标签都保管在一个fragment虚拟根标签中 -->
  <button @click="tpshow = !tpshow">tpshow</button>
  <teleport to="body">
    <div v-if="tpshow">11111111111</div>
  </teleport>
  <h1 @click="say">{{ name }}--{{ fullname }}</h1>
  <input v-model="fullname" />
  <p>{{ age }}</p>
  <p>我是a---{{ a }}</p>
  <button @click="age++">sum+1</button>
  <button @click="obj.a++">a+1</button>
  <button @click="obj.c.test = '111'">
    {{ obj.c }}数据使用markraw非响应式属性
  </button>
  <input v-model="myRefData" />
  <p>{{ myRefData }}</p>
</template>
<script>
// import { h } from "vue";
import {
  ref,
  toRefs,
  reactive,
  computed,
  watch,
  watchEffect,
  toRef,
  toRaw,
  markRaw,
  customRef,
  provide,
  inject,
  isReactive,
  onMounted,
  getCurrentInstance,
} from "vue";
export default {
  name: "SetUp",
  props: ["TmdData"],
  // setup在beforecreat之前调用 this是undefined
  setup(props, context) {
    const { proxy } = getCurrentInstance();
    console.log("props", props);
    console.log("context", context);
    onMounted(() => {
      console.log(proxy, "@@@@@@@@@@@@@@");
      console.log("生成setup组件");
    });
    let name = "1111";
    let tpshow = ref(false);
    //ref底层还是vue2那一套 响应数据
    let age = ref(18);
    //底层是proxy----------------------------------------
    let obj = reactive({
      a: 111,
      b: 2222,
    });

    //----------------------------------------------------
    // 这些is的就是用来判断的
    console.log(isReactive(obj), "判断是不是reactive的");

    //----------------------------------------------------
    // 给自己的后代传数据
    provide("age", age);
    // 收provide的数据
    let injectdata = inject("age");
    //----------------------------------------------------
    // 自定义ref
    let myRefData = myRef("hello");
    function myRef(value) {
      //来一手防抖
      let timer;
      return customRef((track, trigger) => {
        return {
          get: function () {
            //模板重新解析后追踪该数据变化
            track();
            return value;
          },
          set: function (newval) {
            clearTimeout(timer);
            timer = setTimeout(() => {
              console.log("newval", newval);
              value = newval;
              //重新解析模板
              trigger();
            }, 1000);
          },
        };
      });
    }
    // ---------------------------------------------------
    //toRef在读取已有数据时创造响应式对象,包括toref 就是为了页面使用的时候舒服点直接
    //越过前缀 比如state.a
    let direA = toRef(obj, "a");
    let A = obj.a;
    console.log("toRef", direA, A);
    //让添加对象的属性为非响应式
    obj.c = markRaw({ test: "test" });
    // ------------------------------------------------------
    // 输出原生变量非代理
    console.log("old", obj, "new", toRaw(obj));

    //----------------------------------------------------------
    // 计算属性
    //1. 简写情况是只读的 无法修改
    let fullname = computed(() => {
      return obj.a + obj.b;
    });
    //2. 完整写法
    let fullage = computed({
      get() {
        return obj.a;
      },
      set(val) {
        obj.a = val;
      },
    });
    // 监视多个用数组
    //坑 监视reactive代理对象时读不到老的值 并且此时自动为deep
    watch(
      [age, obj],
      (newval, oldval) => {
        console.log("变化", newval, oldval);
      },
      { immediate: true }
    );
    //只监视reactive中的一个值的变化
    watch(
      () => obj.a,
      (newval, oldval) => {
        console.log("a变化", newval, oldval);
      }
    );

    function say() {
      age.value = 19;
      console.log(age, name);
    }
    // 全监视 看回调用了谁就监视谁
    watchEffect(() => {
      console.log("执行了watchEffect", obj.a);
    });
    return {
      myRefData,
      obj,
      name,
      age,
      say,
      ...toRefs(obj),
      fullname,
      fullage,
      direA,
      A,
      tpshow,
    };
    //渲染函数
    // return () => {
    //  return h("h1",'33333');
    // };
  },
};
</script>

<style>
</style>

大家都写在setup大舞台中。

(4). 生命周期钩子

Vue2--------------vue3
beforeCreate  -> setup()
created       -> setup()
beforeMount   -> onBeforeMount
mounted       -> onMounted
beforeUpdate  -> onBeforeUpdate
updated       -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed     -> onUnmounted
activated     -> onActivated
deactivated   -> onDeactivated
————————————————
版权声明:本文为CSDN博主「star@星空」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43638968/article/details/108800361

这个就直接复制了,可以看出来比较好理解,除了create都归setup()管以外,其他的就是在2的基础上多了一个on。然后on后第一个字母大写。最后就是destroyed改名为unmount,其实就是卸载的意思,比毁灭销毁贴切点。

2. Vue3数据代理 

先上示例

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <button onclick="logProxy()">输出源对象与代理对象</button>
    <script>
        let person = {
            name: 'zs',
            age: 18,
        }
        //vue2 响应式
        // let p = {}
        // Object.defineProperty(p, 'name', {
        //     //可配置的
        //     configurable: true,
        //     get() {
        //         return person.name
        //     },
        //     set(val) {
        //         person.name = val
        //         console.log("修改数据为", val);
        //     }
        // })
        //vue3底层
        const p = new Proxy(person, {
            get(target, propName) {
                console.log(target, propName);
                return Reflect.get(target, propName)
            },
            set(target, propName, value) {
                console.log(target, propName, value, "111");
                // target[propName] = value
                Reflect.set(target, propName, value)
            },
            deleteProperty(target, propName) {
                delete target[propName]
                return Reflect.deleteProperty(target, propName)
            }
        })
        //通过reflect来操作源对象
        function logProxy() {
            console.log("源对象", person, "代理对象", p);
        }
    </script>
</body>

</html>

可以看出来明显的区别就是,proxy代替Object.defineProperty。获取,设置,删除数据用的都是Reflect反射api。

为什么使用反射呢

bject上的一些属性,reflect也有

比如给object定义相同属性名,会导致代码单线程卡住,阻塞下面代码运行

 例如让obj代理两个c属性 一个是obj1的c。一个是obj2的c。

那么就报错

但是使用反射后,就不会直接保错,而是通过返回的布尔值知道是否成功。

虚拟dom

用普通js对象来描述DOM结构,因为不是真实DOM,所以称之为虚拟DOM。

我们先根据真实DOM生成一颗virtual DOM,当virtual DOM某个节点的数据改变后会生成一个新的Vnode,然后Vnode和oldVnode作对比,发现有不一样的地方就直接修改在真实的DOM上,然后使oldVnode的值为Vnode。

diff的过程就是调用名为patch的函数,比较新旧节点,一边比较一边给真实的DOM打补丁。
————————————————
版权声明:本文为CSDN博主「田野啸风」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_44439675/article/details/116461376

vue用到的设计模式

1.订阅者发布者模式                 2.Mvvm                   3. 工厂模式

vue父组件子组件的生命周期执行顺序

Vue 的父组件和子组件生命周期执行顺序可以理解为以下 4 点:

加载渲染过程
父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted
子组件更新过程
父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated
父组件更新过程
父 beforeUpdate -> 父 updated
销毁过程
父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed
————————————————
版权声明:本文为CSDN博主「没有码力」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_45272820/article/details/120450822

$nextTick有什么用?

  1. Vue是异步渲染的框架。
  2. data改变之后,DOM不会立刻渲染。
  3. $nextTick会在DOM渲染之后被触发,以获取最新的DOM节点。
  4. 连续多次的异步渲染,$nextTick只会执行最后一次渲染后的结果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/408927.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

在 Vue3 中使用 Vuex

本篇文章主要记录 Vue3 中使用 Vuex 的步骤和注意事项&#xff1a; 1、安装依赖库 npm install vuex --save-dev2、配置 Vuex 实例 对比 Vue2 和 Vue3 各自创建 Store 实例的区别&#xff1b; Vue2 是用 Vue.use(Vuex)注入 Vuex 插件&#xff0c;然后通过 new Vuex.Store(o…

真正有效解决vue addRoute动态添加路由后刷新页面白屏的靠谱方法及思路,切实可行!

PS&#xff1a;想直接看解决方法的可以跳过前面的废话阶段从后往前看~ 前情回顾&#xff1a;萌新最近从Vue2转战Vue3&#xff0c;一边自学一遍自己做点娱乐项目练练手&#xff0c;这次Vue3项目权限管理用到动态路由&#xff0c;由于以前一直用的addRoutes()方法已经被废弃&…

如何在Windows server 2012配置Web服务器

现在&#xff0c;我们浏览网页已经成为了一种常态&#xff0c;但是你知道网页是怎么运行的吗&#xff1f; 我们浏览网页&#xff0c;首先会打开浏览器&#xff0c;然后输入网页的地址&#xff08;当然这里现在已经可以不用我们自己输入地址了&#xff0c;一般现在就是直接搜索…

在vite里获取env环境变量

在vite里获取env环境变量.env环境配置文件在cli项目中我们可以是配置.env.[mode]文件来配置环境变量在cli项目中使用.env.[mode]在vite中使用.env文件.env环境配置文件 在项目中总会遇到一些默认的配置,需要我们配置到静态文件中方便我们去获取,这时候就可以用到这个.env环境变…

vue项目中使用vuedraggable

最近在学习一个可视化搭建的项目&#xff0c;里面用的拖拽就是draggable.js。看了几个中文的文档&#xff0c;有很多坑&#xff0c;可能是没有及时更新的原因。 VUe 建议去看vuedraggable的官方文档&#xff0c;只不过是英文的。官方文档&#xff1a;https://github.com/Sor…

【HTML】筑基篇

&#x1f348;作者简介&#xff1a;大家好&#xff0c;我是亦世凡华、渴望知识储备自己的一名在校大学生 &#x1f347;个人主页&#xff1a;亦世凡华、的csdn博客 &#x1f353;系列专栏&#xff1a;HTML专栏 &#x1f95d;推荐一款模拟面试刷题神器&#x1f525;&#xff1a;…

echarts 定制legend内容,显示和位置

echarts 定制legend内容&#xff0c;显示和位置1.type(当图例很多的时候可以用到)2.orient(图例的排版方向)3.top,bottom,left,right(图例在容器中的位置)4.width,height&#xff08;图例组件的大小&#xff09;;itemWidth,itemHeight(图例图标的大小)5. align&#xff08;图例…

六、Echart图表 之 tooltip提示框组件配置项大全

&#x1f353; 作者主页&#xff1a;&#x1f496;仙女不下凡&#x1f496; &#x1f353; 前言介绍&#xff1a;以下&#x1f447;内容是我个人对于该技术的总结&#xff0c;如有不足与错误敬请指正&#xff01; &#x1f353; 欢迎点赞&#x1f44d; 收藏⭐ 留言&#x1f4…

【JavaScript 进阶教程】函数的定义 调用 及 this指向问题

这篇文章开始我们函数的进阶篇&#xff0c;和我们JavaScript基础学的函数有了很多拓展&#xff0c;这篇文章首先我们从函数的定义&#xff0c;调用&#xff0c;及其 this指向 来一个总结。 文章目录&#xff1a; 一&#xff1a;函数的定义 1.1 命名函数 1.2 匿名函数 1…

若依(ruoyi)框架:如何实现灵活自定义路由配置

如何灵活自定义路由配置业务背景如何实现方式一&#xff1a;直接在前端路由表&#xff08;router/index.js&#xff09;里面某个路由的meta属性里面配置。方式二&#xff1a;在后台返回动态路由的接口中组装meta信息如何改造效果展示使用方法总结业务背景 随着项目的深入开发&a…

使用 iframe出现了缓存,导致页面不会刷新的解决方案

事情是这样的&#xff0c;我在打代码的时候&#xff0c;需要在A页面里引入B页面我使用了iframe 这个标签 来引入页面B但是我发现 当我更改完页面B的内容 将它上传到服务器后&#xff0c;我访问这个A页面&#xff0c;这个我使用iframe 引入的页面B 的内容并没有更新,经过一番研究…

VsCode工具开发vue项目必装插件

VsCode工具开发vue项目必装插件 目录VsCode工具开发vue项目必装插件1.概述2.VsCode插件清单2.1.Vetur插件让vue文件代码高亮2.2.Vue VSCode Snippets自动生成vue模板内容插件1.安装插件2.使用插件生成vue模板代码2.3.LiveServer实时刷新网页1.安装LiveServer2.使用LiveServer打…

若依框架搭建和使用

一.搭建系统 若依官网&#xff1a;RuoYi 若依官方网站 |后台管理系统|权限管理系统|快速开发框架|企业管理系统|开源框架|微服务框架|前后端分离框架|开源后台系统|RuoYi|RuoYi-Vue|RuoYi-Cloud|RuoYi框架|RuoYi开源|RuoYi视频|若依视频|RuoYi开发文档|若依开发文档|Java开源框…

Jasper Report详细使用教程(保姆级教程),整合Springboot使用

Jasper Report详细使用教程1、下载Jaspersoft Studio2、编写jrxml文件3、编译模板文件4、输出PDF报表&#xff08;SpringBoot整合&#xff09;5、解决中文乱码&#xff08;不显示的问题&#xff09;6、最后1、下载Jaspersoft Studio 官网下载地址&#xff1a;https://communit…

CSS网页布局

&#x1f4dc;个人简介 ⭐️个人主页&#xff1a;微风洋洋&#x1f64b;‍♂️ &#x1f351;博客领域&#xff1a;编程基础&#x1f4a1;,后端&#x1f4a1;,大数据,信息安全 &#x1f345;写作风格&#xff1a;干货,干货,还是tmd的干货 &#x1f338;精选专栏&#xff1a;【J…

叮咚,您有一封告白信件待查收(原生HTML+CSS+JS绘制表白信件,代码+链接+步骤详解)

马上就要5月20号啦&#xff0c;准备好如何向心仪的她/他表白了嘛&#xff01;特此出一篇告白小信件&#xff0c;效果图如下。纯htmlcss绘制&#xff0c;包含详细教程注释&#xff0c;干货满满哦。 链接置于文章结尾总结处。 文章目录一、叮咚&#xff01;查收您的信件&#x…

js二十五道面试题(含答案)

目录 1.线程和进程是什么&#xff1f;举例说明 2. js中的基础数据类型有哪几种? 了解包装对象吗&#xff1f; 3.对内存泄漏的了解 4.js中数组合并的方法 5.合并对象的方法 6.什么是作用域&#xff0c;什么是作用域链&#xff1f; 7.JS如何实现异步编程&#xff08;5种&…

1.vite初识、vite搭建项目

1.vite优势 1.1启动速度 解释一下冷启动&#xff1a;它是指输入启动指令后他编译到启动完成的过程&#xff1b; 当你使用vite和webpack后你就会得出这个结论&#xff0c;vite相对于webpack启动速度还是略胜一筹的&#xff0c;当你的项目是小型项目时&#xff0c;不是特别明显…

TypeScript 报错汇总

TypeScript 报错汇总 在这篇文章中将记录我遇到的ts错误&#xff0c;应该会持续更新。 有时候从错误点入手学习似乎是一个不错的选择&#xff0c;所以也欢迎你私信我一些ts的问题。 一、内置工具 1.1 Pick & Partial 先看看Pick和Partial工具的源码&#xff1a; type…

浅析什么是伪类和伪元素?伪类和伪元素的区别解析

一、理解什么是伪类&#xff1f;什么是伪元素&#xff1f; 1、伪类种类 伪类作用对象是整个元素 a:link{color:#111} a:hover{color:#222}div:first-child{color:#333} div:nth-child&#xff08;3&#xff09;{color:#444} 尽管这些条件不是基于DOM的&#xff0c;但结果每一…