搜索
首页web前端Vue.js深入聊聊vue3中的reactive()

深入聊聊vue3中的reactive()

Jan 06, 2023 pm 09:21 PM
javascript前端vue.js

深入聊聊vue3中的reactive()

在vue3的开发中,reactive是提供实现响应式数据的方法。日常开发这个是使用频率很高的api。这篇文章笔者就来探索其内部运行机制。小白一枚,写得不好请多多见谅。

调试版本为3.2.45

  • 什么是reactive?

    reactive是Vue3中提供实现响应式数据的方法.

    在Vue2中响应式数据是通过defineProperty来实现的.

    而在Vue3响应式数据是通过ES6的Proxy来实现的

  • reactive注意点

    reactive参数必须是对象(json/arr)

    如果给reactive传递了其他对象,默认情况下修改对象,界面不会自动更新,如果想更新,可以通过重新赋值的方式。【相关推荐:vuejs视频教程web前端开发

<script setup>
import {reactive} from &#39;vue&#39;
const data = reactive({ //定义对象
  name:&#39;测试&#39;,
  age:10
})
const num = reactive(1)//定义基本数据类型
console.log(data)//便于定位到调试位置
</script>
<template>
<div>
<h1>{{ data.name }}</h1>
</div>
</template>

<style scoped></style>

设置断点

image.png

image.png

开始调试

接下来我们可以开始调试了,设置好断点后,只要重新刷新页面就可以进入调试界面。

复杂数据类型

我们先调试简单的基本数据类型

image.png1.

/*1.初始进来函数,判断目标对象target是否为只读对象,如果是直接返回*/
function reactive(target) {
    // if trying to observe a readonly proxy, return the readonly version.
    if (isReadonly(target)) {
        return target;
    }
    //创建一个reactive对象,五个参数后续会讲解
    return createReactiveObject(target, false, mutableHandlers, mutableCollectionHandlers, reactiveMap);
}


/*2.判断是来判断target是否为只读。*/
function isReadonly(value) {
    return !!(value && value["__v_isReadonly" /* ReactiveFlags.IS_READONLY */]);
}

/*3.创建一个reactive对象*/
/*createReactiveObject接收五个参数:
target被代理的对象,
isReadonl是不是只读的,
baseHandlers proxy的捕获器,
collectionHandlers针对集合的proxy捕获器,
proxyMap一个用于缓存proxy的`WeakMap`对象*/
function createReactiveObject(target, isReadonly, baseHandlers, collectionHandlers, proxyMap) {
//如果target不是对象则提示并返回
/*这里会跳转到如下方法
判断是否原始值是否为object类型 
const isObject = (val) => val !== null && typeof val === &#39;object&#39;;
*/
    if (!isObject(target)) {
        if ((process.env.NODE_ENV !== &#39;production&#39;)) {
            console.warn(`value cannot be made reactive: ${String(target)}`);
        }
        return target;
    }
    // 如果target已经是proxy是代理对象则直接返回.
    if (target["__v_raw" /* ReactiveFlags.RAW */] &&
        !(isReadonly && target["__v_isReactive" /* ReactiveFlags.IS_REACTIVE */])) {
        return target;
    }
    // 从proxyMap中获取缓存的proxy对象,如果存在的话,直接返回proxyMap中对应的proxy。否则创建proxy。
    const existingProxy = proxyMap.get(target);
    if (existingProxy) {
        return existingProxy;
    }
    // 并不是任何对象都可以被proxy所代理。这里会通过getTargetType方法来进行判断。
    const targetType = getTargetType(target);
    //当类型值判断出是不能代理的类型则直接返回
    if (targetType === 0 /* TargetType.INVALID */) {
        return target;
    }
    //通过使用Proxy函数劫持target对象,返回的结果即为响应式对象了。这里的处理函数会根据target对象不同而不同(这两个函数都是参数传入的):
    //Object或者Array的处理函数是collectionHandlers;
    //Map,Set,WeakMap,WeakSet的处理函数是baseHandlers;
    const proxy = new Proxy(target, targetType === 2 /* TargetType.COLLECTION */ ? collectionHandlers : baseHandlers);
    proxyMap.set(target, proxy);
    return proxy;
}

getTargetType方法调用流程

//1.进入判断如果value有__v_skip属性且为true或对象是可拓展则返回0,否则走类型判断函数
function getTargetType(value) {
//Object.isExtensible() 方法判断一个对象是否是可扩展的(是否可以在它上面添加新的属性)。
    return value["__v_skip" /* ReactiveFlags.SKIP */] || !Object.isExtensible(value)
        ? 0 /* TargetType.INVALID */
        : targetTypeMap(toRawType(value));
}
//2.这里通过Object.prototype.toString.call(obj)来判断数据类型
const toRawType = (value) => {
    // extract "RawType" from strings like "[object RawType]"
    return toTypeString(value).slice(8, -1);
};
const toTypeString = (value) => objectToString.call(value);
//3.这里rawType是为&#39;Object&#39;所以会返回1
function targetTypeMap(rawType) {
    switch (rawType) {
        case &#39;Object&#39;:
        case &#39;Array&#39;:
            return 1 /* TargetType.COMMON */;
        case &#39;Map&#39;:
        case &#39;Set&#39;:
        case &#39;WeakMap&#39;:
        case &#39;WeakSet&#39;:
            return 2 /* TargetType.COLLECTION */;
        default:
            return 0 /* TargetType.INVALID */;//返回0说明除前面的类型外其他都不能被代理,如Date,RegExp,Promise等
    }
}

createReactiveObject方法中const proxy = new Proxy(target, targetType === 2 /* TargetType.COLLECTION */ ? collectionHandlers : baseHandlers);这一条语句中,第二个参数判断target是否为Map或者Set类型。从而使用不同的handler来进行依赖收集。

在调试的文件node_modules/@vue/reactivity/dist/reactivity.esm-bundler.js中,我们从reactive函数的createReactiveObject函数调用的其中两个参数mutableHandlersmutableCollectionHandlers开始往上查询

mutableHandlers的实现

const mutableHandlers = {
    get,// 获取值的拦截,访问对象时会触发
    set,// 更新值的拦截,设置对象属性会触发
    deleteProperty,// 删除拦截,删除对象属性会触发
    has,// 绑定访问对象时会拦截,in操作符会触发
    ownKeys// 获取属性key列表
};

function deleteProperty(target, key) {
    // key是否是target自身的属性
    const hadKey = hasOwn(target, key);
    // 旧值
    const oldValue = target[key];
    // 调用Reflect.deleteProperty从target上删除属性
    const result = Reflect.deleteProperty(target, key);
    // 如果删除成功并且target自身有key,则触发依赖
    if (result && hadKey) {
        trigger(target, "delete" /* TriggerOpTypes.DELETE */, key, undefined, oldValue);
    }
    return result;
}
//
function has(target, key) {
    //检查目标对象是否存在此属性。
    const result = Reflect.has(target, key);
    // key不是symbol类型或不是symbol的内置属性,进行依赖收集
    if (!isSymbol(key) || !builtInSymbols.has(key)) {
        track(target, "has" /* TrackOpTypes.HAS */, key);
    }
    return result;
}
/*ownKeys可以拦截以下操作:
1.Object.keys()
2.Object.getOwnPropertyNames()
3.Object.getOwnPropertySymbols()
4.Reflect.ownKeys()操作*/
function ownKeys(target) {
    track(target, "iterate" /* TrackOpTypes.ITERATE */, isArray(target) ? &#39;length&#39; : ITERATE_KEY);
    return Reflect.ownKeys(target);
}
get方法实现
const get = /*#__PURE__*/ createGetter();
/*传递两个参数默认都为false
isReadonly是否为只读
shallow是否转换为浅层响应,即Reactive---> shallowReactive,shallowReactive监听了第一层属性的值,一旦发生改变,则更新视图;其他层,虽然值发生了改变,但是视图不会进行更新
*/
function createGetter(isReadonly = false, shallow = false) {
    return function get(target, key, receiver) {
    //1.是否已被reactive相关api处理过;
        if (key === "__v_isReactive" /* ReactiveFlags.IS_REACTIVE */) {
            return !isReadonly;
        }
     //2.是否被readonly相关api处理过
        else if (key === "__v_isReadonly" /* ReactiveFlags.IS_READONLY */) {
            return isReadonly;
        }
        else if (key === "__v_isShallow" /* ReactiveFlags.IS_SHALLOW */) {
            return shallow;
        }
      //3.检测__v_raw属性
        else if (key === "__v_raw" /* ReactiveFlags.RAW */ &&
            receiver ===
                (isReadonly
                    ? shallow
                        ? shallowReadonlyMap
                        : readonlyMap
                    : shallow
                        ? shallowReactiveMap
                        : reactiveMap).get(target)) {
            return target;
        }
      //4.如果target是数组,且命中了一些属性,则执行函数方法
        const targetIsArray = isArray(target);
        if (!isReadonly && targetIsArray && hasOwn(arrayInstrumentations, key)) {
            return Reflect.get(arrayInstrumentations, key, receiver);
        }
      //5.Reflect获取值
        const res = Reflect.get(target, key, receiver);
      //6.判断是否为特殊的属性值
        if (isSymbol(key) ? builtInSymbols.has(key) : isNonTrackableKeys(key)) {
            return res;
        }
        if (!isReadonly) {
            track(target, "get" /* TrackOpTypes.GET */, key);
        }
        if (shallow) {
            return res;
        }
      //7.判断是否为ref对象
        if (isRef(res)) {
            // ref unwrapping - skip unwrap for Array + integer key.
            return targetIsArray && isIntegerKey(key) ? res : res.value;
        }
      //8.判断是否为对象
        if (isObject(res)) {
            // Convert returned value into a proxy as well. we do the isObject check
            // here to avoid invalid value warning. Also need to lazy access readonly
            // and reactive here to avoid circular dependency.
            return isReadonly ? readonly(res) : reactive(res);
        }
        return res;
    };
}
  • 检测__v_isReactive属性,如果为true,表示target已经是一个响应式对象了。

  • 依次检测__v_isReadonly__v_isShallow属性,判断是否为只读和浅层响应,如果是则返回对应包装过的target。

  • 检测__v_raw属性,这里是三元的嵌套,主要判断原始数据是否为只读或者浅层响应,然后在对应的Map里面寻找是否有该目标对象,如果都为true则说明target已经为响应式对象。

  • 如果target是数组,需要对一些方法(针对includesindexOflastIndexOfpushpopshiftunshiftsplice)进行特殊处理。并对数组的每个元素执行收集依赖,然后通过Reflect获取数组函数的值。

  • Reflect获取值。

  • 判断是否为特殊的属性值,symbol__proto____v_isRef__isVue, 如果是直接返回前面得到的res,不做后续处理;

  • 如果为ref对象,target不是数组的情况下,会自动解包。

  • 如果resObject,进行深层响应式处理。从这里就能看出,Proxy是懒惰式的创建响应式对象,只有访问对应的key,才会继续创建响应式对象,否则不用创建。

set方法实现

例子:data.name='2'

const set = /*#__PURE__*/ createSetter();
  //shallow是否转换为浅层响应,默认为false
function createSetter(shallow = false) {
    //1.传递四个参数
    return function set(target, key, value, receiver) {
        let oldValue = target[key];
        //首先获取旧值,如果旧值是ref类型,且新值不是ref类型,则不允许修改
        if (isReadonly(oldValue) && isRef(oldValue) && !isRef(value)) {
            return false;
        }
     //2.根据传递的shallow参数,来执行之后的操作
        if (!shallow) {
            if (!isShallow(value) && !isReadonly(value)) {
                oldValue = toRaw(oldValue);
                value = toRaw(value);
            }
            if (!isArray(target) && isRef(oldValue) && !isRef(value)) {
                oldValue.value = value;
                return true;
            }
        }
      //3.检测key是不是target本身的属性
        const hadKey = isArray(target) && isIntegerKey(key)
            ? Number(key) < target.length
            : hasOwn(target, key);
        //利用Reflect.set()来修改值,返回一个Boolean值表明是否成功设置属性
        //Reflect.set(设置属性的目标对象, 设置的属性的名称, 设置的值, 如果遇到 `setter`,`receiver`则为`setter`调用时的`this`值)
        const result = Reflect.set(target, key, value, receiver);
        // 如果目标是原始原型链中的某个元素,则不要触发
        if (target === toRaw(receiver)) {
        //如果不是target本身的属性那么说明执行的是&#39;add&#39;操作,增加属性
            if (!hadKey) {
                trigger(target, "add" /* TriggerOpTypes.ADD */, key, value);
            }
      //4.比较新旧值,是否触发依赖
            else if (hasChanged(value, oldValue)) {
      //5.触发依赖
                trigger(target, "set" /* TriggerOpTypes.SET */, key, value, oldValue);
            }
        }
        return result;
    };
}

1、以data.name='2'这段代码为例,四个参数分别为:

target:目标对象,即target={"name": "测试","age": 10}(此处为普通对象)

key:修改的对应key,即key: "name"

value:修改的值,即value: "2"

receiver:目标对象的代理。即receiver=Proxy {"name": "测试","age": 10}

2、shallow为false的时候。

第一个判断:如果新值不是浅层响应式并且不是readonly,新旧值取其对应的原始值。

第二个判断:如果target不是数组并且旧值是ref类型,新值不是ref类型,直接修改oldValue.value为value

3.检测key是不是target本身的属性。这里的hadKey有两个方法,isArray就不解释,就是判断是否为数组

isIntegerKey:判断是不是数字型的字符串key值

//判断参数是否为string类型,是则返回true
const isString = (val) => typeof val === &#39;string&#39;;
//如果参数是string类型并且不是&#39;NaN&#39;,且排除-值(排除负数),然后将 key 转换成数字再隐式转换为字符串,与原 key 对比
const isIntegerKey = (key) => isString(key) &&
    key !== &#39;NaN&#39; &&
    key[0] !== &#39;-&#39; &&
    &#39;&#39; + parseInt(key, 10) === key;

4.比较新旧值,如果新旧值不同,则触发依赖进行更新

hasChanged方法

//Object.is()方法判断两个值是否是相同的值。
const hasChanged = (value, oldValue) => !Object.is(value, oldValue);

5.触发依赖,这里太过复杂,笔者也没搞懂,如果有兴趣的读者可自行去调试

<script setup>
import { reactive } from "vue";
const data = reactive({
  name: "测试",
  age: 10,
});

data.name=&#39;1&#39;//这里并未收集依赖,在处理完 createSetupContext 的上下文后,组件会停止依赖收集,并且开始执行 setup 函数。具体原因有兴趣的读者可以自行去了解
const testClick = ()=>{
  data.name=&#39;test&#39;
}
</script>
<template>
  <div>
    <h1>{{ data.name }}</h1>
    <el-button @click="testClick">Click</el-button>
  </div>
</template>

<style scoped></style>

基本数据类型

const num = reactive(2)

这里比较简单,在createReactiveObject函数方法里面:

if (!isObject(target)) {
        if ((process.env.NODE_ENV !== &#39;production&#39;)) {
            console.warn(`value cannot be made reactive: ${String(target)}`);
        }
        return target;
    }

image.png

因为判断类型不是对象,所以会在控制台打印出警告,并且直接返回原数据

proxy对象

<script>
const data = reactive({
  name: "测试",
  age: 10,
});
const num = reactive(data)//定义一个已经是响应式对象
</script>

1.调试开始进来reactive函数,然后会经过isReadonly函数,这里跟前面不同的是,target是一个proxy对象,它已经被代理过有set,get等handler。所以在isReadonly函数读取target的时候,target会进行get函数的读取操作。

function reactive(target) {
    // if trying to observe a readonly proxy, return the readonly version.
    if (isReadonly(target)) {
        return target;
    }
    return createReactiveObject(target, false, mutableHandlers, mutableCollectionHandlers, reactiveMap);
}

2.可以看到get传入的参数有个key="__v_isReadonly",这里的isReadonly返回是false,接下来进入createReactiveObject函数

这里说明下,在本次调试中常见的vue里面定义的私有属性有:

  • __v_skip:是否无效标识,用于跳过监听
  • __v_isReactive:是否已被reactive相关api处理过
  • __v_isReadonly:是否被readonly相关api处理过
  • __v_isShallow:是否为浅层响应式对象
  • __v_raw:当前代理对象的源对象,即target

image.png

3.在createReactiveObject函数中,经过target["__v_isReactive"]的时候会触发target的get函数,这时候get函数传入的参数中key='__v_raw'

    if (target["__v_raw" /* ReactiveFlags.RAW */] &&
        !(isReadonly && target["__v_isReactive" /* ReactiveFlags.IS_REACTIVE */])) {
                return target;
    }

image.png

由上图可知我们检测target即已定义过的proxy对象,被reactiveapi处理过就会有__v_raw私有属性,然后再进行receiver的判断,判断target是否为只读或浅层响应。如果都不是则从缓存proxy的WeakMap对象中获取该元素。最后直接返回target的原始数据(未被proxy代理过)。

最后回到之前的判断,由下图可知,target__v_raw属性存在,isReadonly为false,__v_isReactive的值为true,可以说明reactive函数需要处理的对象是一个被reactiveAPI处理过的对象,然后直接返回该对象的原始数据。

image.png

ref类型

经过ref函数处理,其本质也是一个对象,所以使用reactive函数处理ref类型就跟处理复杂数据类型一样过程。对于ref函数,如果大家有兴趣可以阅读这篇文章vue3——深入了解ref()。有些内容跟这里差不多,也有对此补充,如果觉得不错请各位帮忙点个赞

(开发中应该不会有这种嵌套行为吧,这里只是为了测试多样化)。

<script setup>
import { reactive,ref } from "vue";
const data = reactive({
  name: "测试",
  age: 10,
});
const numRef = ref(1)
const dataRef = ref({
  name: "测试2",
  age: 20,
})
const num = reactive(numRef)
const dataReactive = reactive(dataRef)
console.log(&#39;data&#39;,data)
console.log(&#39;numRef&#39;,numRef)
console.log(&#39;num&#39;,num)
console.log(&#39;dataRef&#39;,dataRef)
console.log(&#39;dataReactive&#39;,dataReactive)
</script>

image.png

Map类型和Set类型

  • Map 类型是键值对的有序列表,而键和值都可以是任意类型。
  • SetMap类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在Set中,没有重复的key。
<script setup>
import { reactive } from "vue";
const mapData = new Map();
mapData.set(&#39;name&#39;,&#39;张三&#39;)
const setData = new Set([1,2,3,1,1])
console.log(mapData)
console.log(setData)
const mapReactive = reactive(mapData)
console.log(mapReactive)
</script>

image.png

由上图可知Map结构和Set结构使用typeof判断是object,所有流程前面会跟复杂数据类型一样,知道在createReactiveObject函数的getTargetType()函数开始不同。

getTargetType函数里面toRawType()判断数据类型所用方法为Object.prototype.toString.call()

const targetType = getTargetType(target);

function getTargetType(value) {
    return value["__v_skip" /* ReactiveFlags.SKIP */] || !Object.isExtensible(value)
        ? 0 /* TargetType.INVALID */
        : targetTypeMap(toRawType(value));
}

function targetTypeMap(rawType) {//rawType="Map",这里返回值为2
    switch (rawType) {
        case &#39;Object&#39;:
        case &#39;Array&#39;:
            return 1 /* TargetType.COMMON */;
        case &#39;Map&#39;:
        case &#39;Set&#39;:
        case &#39;WeakMap&#39;:
        case &#39;WeakSet&#39;:
            return 2 /* TargetType.COLLECTION */;
        default:
            return 0 /* TargetType.INVALID */;
    }
}

这时候targetType=2,在createReactiveObject的函数中const proxy = new Proxy(target, targetType === 2 /* TargetType.COLLECTION */ ? collectionHandlers : baseHandlers);的三元表达式中可得知,这里的handlercollectionHandlers

网上查找可在reactive函数中return createReactiveObject(target, false, mutableHandlers, mutableCollectionHandlers, reactiveMap);这条语句找到,当rawType=1handler是用mutableHandlers,rawType=1时是用mutableCollectionHandlers

mutableCollectionHandlers方法:

const mutableCollectionHandlers = {
    get: /*#__PURE__*/ createInstrumentationGetter(false, false)
};

//解构createInstrumentations
const [mutableInstrumentations, readonlyInstrumentations, shallowInstrumentations, shallowReadonlyInstrumentations] = /* #__PURE__*/ createInstrumentations();
//传入两个参数,是否为可读,是否为浅层响应
function createInstrumentationGetter(isReadonly, shallow) {
    const instrumentations = shallow
        ? isReadonly
            ? shallowReadonlyInstrumentations
            : shallowInstrumentations
        : isReadonly
            ? readonlyInstrumentations
            : mutableInstrumentations;
    return (target, key, receiver) => {
        if (key === "__v_isReactive" /* ReactiveFlags.IS_REACTIVE */) {
            return !isReadonly;
        }
        else if (key === "__v_isReadonly" /* ReactiveFlags.IS_READONLY */) {
            return isReadonly;
        }
        else if (key === "__v_raw" /* ReactiveFlags.RAW */) {
            return target;
        }
        return Reflect.get(hasOwn(instrumentations, key) && key in target
            ? instrumentations
            : target, key, receiver);
    };
}
//篇幅问题以及这方面笔者并未深入,所以就大概带过
function createInstrumentations() {
//创建了四个对象,对象内部有很多方法,其他去掉了,完整可自行去调试查看
    const mutableInstrumentations = {
        get(key) {
            return get$1(this, key);
        },
        get size() {
            return size(this);
        },
        has: has$1,
        add,
        set: set$1,
        delete: deleteEntry,
        clear,
        forEach: createForEach(false, false)
    };
    
    .................
    
    //通过createIterableMethod方法操作keys、values、entries、Symbol.iterator迭代器方法
    const iteratorMethods = [&#39;keys&#39;, &#39;values&#39;, &#39;entries&#39;, Symbol.iterator];
    iteratorMethods.forEach(method => {
        mutableInstrumentations[method] = createIterableMethod(method, false, false);
        readonlyInstrumentations[method] = createIterableMethod(method, true, false);
        shallowInstrumentations[method] = createIterableMethod(method, false, true);
        shallowReadonlyInstrumentations[method] = createIterableMethod(method, true, true);
    });
    return [
        mutableInstrumentations,
        readonlyInstrumentations,
        shallowInstrumentations,
        shallowReadonlyInstrumentations
    ];
}

后续比较复杂,加上笔者技术力还不够,如果想继续深入的读者,可以阅读这篇文章:Vue3响应式原理

总结:关于reactive的源码调试就到这了,这只是其中一小部分的源码,希望有兴趣的读者可以以此深入,输出文章,共同进步成长。最后,如果这篇文章对你有所收获,请点个赞,如果有写的不对的地方,请大佬们指出(* ̄︶ ̄)。

(学习视频分享:vuejs入门教程编程基础视频

以上是深入聊聊vue3中的reactive()的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
vue.js:定义其在网络开发中的作用vue.js:定义其在网络开发中的作用Apr 18, 2025 am 12:07 AM

Vue.js在Web开发中的角色是作为一个渐进式JavaScript框架,简化开发过程并提高效率。1)它通过响应式数据绑定和组件化开发,使开发者能专注于业务逻辑。2)Vue.js的工作原理依赖于响应式系统和虚拟DOM,优化性能。3)实际项目中,使用Vuex管理全局状态和优化数据响应性是常见实践。

了解vue.js:主要是前端框架了解vue.js:主要是前端框架Apr 17, 2025 am 12:20 AM

Vue.js是由尤雨溪在2014年发布的渐进式JavaScript框架,用于构建用户界面。它的核心优势包括:1.响应式数据绑定,数据变化自动更新视图;2.组件化开发,UI可拆分为独立、可复用的组件。

Netflix的前端:React(或VUE)的示例和应用Netflix的前端:React(或VUE)的示例和应用Apr 16, 2025 am 12:08 AM

Netflix使用React作为其前端框架。1)React的组件化开发模式和强大生态系统是Netflix选择它的主要原因。2)通过组件化,Netflix将复杂界面拆分成可管理的小块,如视频播放器、推荐列表和用户评论。3)React的虚拟DOM和组件生命周期优化了渲染效率和用户交互管理。

前端景观:Netflix如何处理其选择前端景观:Netflix如何处理其选择Apr 15, 2025 am 12:13 AM

Netflix在前端技术上的选择主要集中在性能优化、可扩展性和用户体验三个方面。1.性能优化:Netflix选择React作为主要框架,并开发了SpeedCurve和Boomerang等工具来监控和优化用户体验。2.可扩展性:他们采用微前端架构,将应用拆分为独立模块,提高开发效率和系统扩展性。3.用户体验:Netflix使用Material-UI组件库,通过A/B测试和用户反馈不断优化界面,确保一致性和美观性。

React与Vue:Netflix使用哪个框架?React与Vue:Netflix使用哪个框架?Apr 14, 2025 am 12:19 AM

NetflixusesAcustomFrameworkcalled“ Gibbon” BuiltonReact,notReactorVueDirectly.1)TeamExperience:selectBasedAsedonFamiliarity.2)ProjectComplexity:vueforsimplerprojects,vueforsimplerprojects,reactforforforecomplexones.3)cocatizationNeedsneeds:reactofficatizationneedneeds:reactofferizationneedneedneedneeds:reactoffersizatization needeffersefersmoreflexiblesimore.4)ecosyaka

框架的选择:是什么推动了Netflix的决定?框架的选择:是什么推动了Netflix的决定?Apr 13, 2025 am 12:05 AM

Netflix在框架选择上主要考虑性能、可扩展性、开发效率、生态系统、技术债务和维护成本。1.性能与可扩展性:选择Java和SpringBoot以高效处理海量数据和高并发请求。2.开发效率与生态系统:使用React提升前端开发效率,利用其丰富的生态系统。3.技术债务与维护成本:选择Node.js构建微服务,降低维护成本和技术债务。

反应,vue和Netflix前端的未来反应,vue和Netflix前端的未来Apr 12, 2025 am 12:12 AM

Netflix主要使用React作为前端框架,辅以Vue用于特定功能。1)React的组件化和虚拟DOM提升了Netflix应用的性能和开发效率。2)Vue在Netflix的内部工具和小型项目中应用,其灵活性和易用性是关键。

前端中的vue.js:现实世界的应用程序和示例前端中的vue.js:现实世界的应用程序和示例Apr 11, 2025 am 12:12 AM

Vue.js是一种渐进式JavaScript框架,适用于构建复杂的用户界面。1)其核心概念包括响应式数据、组件化和虚拟DOM。2)实际应用中,可以通过构建Todo应用和集成VueRouter来展示其功能。3)调试时,建议使用VueDevtools和console.log。4)性能优化可通过v-if/v-show、列表渲染优化和异步加载组件等实现。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
1 个月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
1 个月前By尊渡假赌尊渡假赌尊渡假赌
威尔R.E.P.O.有交叉游戏吗?
1 个月前By尊渡假赌尊渡假赌尊渡假赌

热工具

VSCode Windows 64位 下载

VSCode Windows 64位 下载

微软推出的免费、功能强大的一款IDE编辑器

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

MinGW - 适用于 Windows 的极简 GNU

MinGW - 适用于 Windows 的极简 GNU

这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

WebStorm Mac版

WebStorm Mac版

好用的JavaScript开发工具

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版