Comment utiliser l'effet du noyau réactif Vue3
Normalement, nous n'utiliserons pas effect directement, car effect est une API de bas niveau. Lorsque nous utilisons Vue3, Vue appelle effect pour nous par défaut. L'effet est traduit par effet, ce qui signifie le faire fonctionner. La fonction qui le fait fonctionner est la fonction que nous transmettons, donc la fonction de l'effet est de faire prendre effet à la fonction que nous transmettons, c'est-à-dire d'exécuter cette fonction. Un schéma simplifié du processus d'exécution est le suivant :
Ensuite, comprenez d'abord l'utilisation de base de l'effet à travers des exemples, puis comprenez le principe.
1. Utilisation de l'effet
1 Utilisation de base
const obj = reactive({count: 1}) const runner = effect(() => { console.log(obj.count) }) obj.count++
Le résultat imprimera 1 d'abord, puis dans obj.count++< /code > puis imprimez 2. <code>obj.count++
之后打印出2。
流程简图如下:
运行effect(fun)
// 先执行 fun() // 打印出1 const runner = new ReactiveEffect(fn) return runner runner: { run() { this.fun() //执行fun }, stop() { } }
console.log(obj.count)
track依赖收集 结构如下:
obj.count++
触发依赖,执行runner.run(), 实际运行的是
() => { console.log(obj.count) }
所以又打印出2
2、lazy属性为true
此值为 true 时,只有在第一次手动调用 runner 后,依赖数据变更时,才会自动执行 effect 的回调,可以理解为 effect 的是在手动调用 runner 后才首次执行
const obj = reactive({count: 1}) const runner = effect(() => { console.log(obj.count) }, { lazy: true }) runner() obj.count++
只会打印出2
原因是effect源码中有如下逻辑:
3、options中包含onTrack
let events = [] const onTrack = (e) => { events.push(e) } const obj = reactive({ foo: 1, bar: 2 }) const runner = effect( () => { console.log(obj.foo) }, { onTrack } ) console.log('runner', runner) obj.foo++ console.log("events", events)
看下events的打印结果:
[ { effect: runner, // effect 函数的返回值 target: toRaw(obj), // 表示的是哪个响应式数据发生了变化 type: TrackOpTypes.GET, // 表示此次记录操作的类型。 get 表示获取值 key: 'foo' } ]
二、源码分析
1、effect方法的实现
// packages/reactivity/src/effect.ts export interface ReactiveEffectOptions extends DebuggerOptions { lazy?: boolean scheduler?: EffectScheduler scope?: EffectScope allowRecurse?: boolean onStop?: () => void } export function effect<T = any>( fn: () => T, // 副作用函数 options?: ReactiveEffectOptions // 结构如上 ): ReactiveEffectRunner { // 如果 fn 对象上有 effect 属性 if ((fn as ReactiveEffectRunner).effect) { // 那么就将 fn 替换为 fn.effect.fn fn = (fn as ReactiveEffectRunner).effect.fn } // 创建一个响应式副作用函数 const _effect = new ReactiveEffect(fn) if (options) { // 将配置项合并到响应式副作用函数上 extend(_effect, options) // 如果配置项中有 scope 属性(该属性的作用是指定副作用函数的作用域) if (options.scope) recordEffectScope(_effect, options.scope) } if (!options || !options.lazy) { // options.lazy 不为true _effect.run() // 执行响应式副作用函数 首次执行fn() } // _effect.run作用域绑定到_effect const runner = _effect.run.bind(_effect) as ReactiveEffectRunner // 将响应式副作用函数赋值给 runner.effect runner.effect = _effect return runner }
核心代码:
创建一个响应式副作用函数const _effect = new ReactiveEffect(fn)
,其运行结果如下:
非lazy状态执行响应式副作用函数_effect.run()
if (!options || !options.lazy) { // options.lazy 不为true _effect.run() // 执行响应式副作用函数 首次执行fn() }
_effect.run
作用域绑定到_effect
// _effect.run作用域绑定到_effect const runner = _effect.run.bind(_effect) as ReactiveEffectRunner
返回副作用函数runner
2、ReactiveEffect函数源码
export class ReactiveEffect<T = any> { active = true deps: Dep[] = [] // 响应式依赖项的集合 parent: ReactiveEffect | undefined = undefined /** * Can be attached after creation * @internal */ computed?: ComputedRefImpl<T> /** * @internal */ allowRecurse?: boolean /** * @internal */ private deferStop?: boolean onStop?: () => void // dev only onTrack?: (event: DebuggerEvent) => void // dev only onTrigger?: (event: DebuggerEvent) => void constructor( public fn: () => T, public scheduler: EffectScheduler | null = null, scope?: EffectScope ) { // 记录当前 ReactiveEffect 对象的作用域 recordEffectScope(this, scope) } run() { // 如果当前 ReactiveEffect 对象不处于活动状态,直接返回 fn 的执行结果 if (!this.active) { return this.fn() } // 寻找当前 ReactiveEffect 对象的最顶层的父级作用域 let parent: ReactiveEffect | undefined = activeEffect let lastShouldTrack = shouldTrack // 是否要跟踪 while (parent) { if (parent === this) { return } parent = parent.parent } try { // 记录父级作用域为当前活动的 ReactiveEffect 对象 this.parent = activeEffect activeEffect = this // 将当前活动的 ReactiveEffect 对象设置为 “自己” shouldTrack = true // 将 shouldTrack 设置为 true (表示是否需要收集依赖) // effectTrackDepth 用于标识当前的 effect 调用栈的深度,执行一次 effect 就会将 effectTrackDepth 加 1 trackOpBit = 1 << ++effectTrackDepth if (effectTrackDepth <= maxMarkerBits) { // 初始依赖追踪标记 initDepMarkers(this) } else { // 清除依赖追踪标记 cleanupEffect(this) } // 返回副作用函数执行结果 return this.fn() } finally { // 如果 effect调用栈的深度 没有超过阈值 if (effectTrackDepth <= maxMarkerBits) { // 确定最终的依赖追踪标记 finalizeDepMarkers(this) } // 执行完毕会将 effectTrackDepth 减 1 trackOpBit = 1 << --effectTrackDepth // 执行完毕,将当前活动的 ReactiveEffect 对象设置为 “父级作用域” activeEffect = this.parent // 将 shouldTrack 设置为上一个值 shouldTrack = lastShouldTrack // 将父级作用域设置为 undefined this.parent = undefined // 延时停止,这个标志是在 stop 方法中设置的 if (this.deferStop) { this.stop() } } } stop() { // stopped while running itself - defer the cleanup // 如果当前 活动的 ReactiveEffect 对象是 “自己” // 延迟停止,需要执行完当前的副作用函数之后再停止 if (activeEffect === this) { // 在 run 方法中会判断 deferStop 的值,如果为 true,就会执行 stop 方法 this.deferStop = true } else if (this.active) {// 如果当前 ReactiveEffect 对象处于活动状态 cleanupEffect(this) // 清除所有的依赖追踪标记 if (this.onStop) { this.onStop() } this.active = false // 将 active 设置为 false } } }
run方法的作用就是执行副作用函数,并且在执行副作用函数的过程中,会收集依赖;
stop方法的作用就是停止当前的ReactiveEffect对象,停止之后,就不会再收集依赖了;
activeEffect和this并不是每次都相等的,因为activeEffect会跟着调用栈的深度而变化,而this则是固定的;
三、依赖收集相关
1、如何触发依赖收集
在副作用函数中, obj.count
就会触发依赖收集
const runner = effect(() => { console.log(obj.count) })
触发的入口在get拦截器里面
function createGetter(isReadonly = false, shallow = false) { // 闭包返回 get 拦截器方法 return function get(target: Target, key: string | symbol, receiver: object) { // ... if (!isReadonly) { track(target, TrackOpTypes.GET, key) } // ... }
2、track源码
const targetMap = new WeakMap(); /** * 收集依赖 * @param target target 触发依赖的对象,例子中的obj * @param type 操作类型 比如obj.count就是get * @param key 指向对象的key, 比如obj.count就是count */ export function track(target: object, type: TrackOpTypes, key: unknown) { if (shouldTrack && activeEffect) { // 是否应该依赖收集 & 当前的new ReactiveEffect()即指向的就是当前正在执行的副作用函数 // 如果 targetMap 中没有 target,就会创建一个 Map let depsMap = targetMap.get(target) if (!depsMap) { targetMap.set(target, (depsMap = new Map())) } let dep = depsMap.get(key) if (!dep) { depsMap.set(key, (dep = createDep())) // createDep 生成dep = { w:0, n: 0} } const eventInfo = __DEV__ ? { effect: activeEffect, target, type, key } : undefined trackEffects(dep, eventInfo) } }
shouldTrack在上面也讲过,它的作用就是控制是否收集依赖;
activeEffect就是我们刚刚讲的ReactiveEffect对象,它指向的就是当前正在执行的副作用函数;
track方法的作用就是收集依赖,它的实现非常简单,就是在targetMap中记录下target和key;
targetMap是一个WeakMap,它的键是target,值是一个Map,这个Map的键是key,值是一个Set;
targetMap的结构伪代码如下:
targetMap = { target: { key: dep }, // 比如: obj: { count: { w: 0, n: 0 } } }
以上是最原始的depMap
dev环境为增加响应式调试会增加eventInfo
const eventInfo = __DEV__ ? { effect: activeEffect, target, type, key } : undefined
eventInfo结构如下:
trackEffects(dep, eventInfo)
如果 dep 中没有当前的 ReactiveEffect 对象,就会添加进去, 作用就把对象的属性操作与副作用函数建立关联,接下来看trackEffects
3、trackEffects(dep, eventInfo)源码解读
export function trackEffects( dep: Dep, debuggerEventExtraInfo?: DebuggerEventExtraInfo ) { let shouldTrack = false if (effectTrackDepth <= maxMarkerBits) { if (!newTracked(dep)) { // 执行之前 dep = Set(0) {w: 0, n: 0} // 执行之后 dep = Set(0) {w: 0, n: 2} dep.n |= trackOpBit // set newly tracked shouldTrack = !wasTracked(dep) } } else { // Full cleanup mode. shouldTrack = !dep.has(activeEffect!) } if (shouldTrack) { // 将activeEffect添加到dep dep.add(activeEffect!) activeEffect!.deps.push(dep) if (__DEV__ && activeEffect!.onTrack) { // onTrack逻辑 activeEffect!.onTrack( extend( { effect: activeEffect! }, debuggerEventExtraInfo! ) ) } } }
dep.add(activeEffect!)
如果 dep 中没有当前的 ReactiveEffect 对象,就会添加进去
最终生成的depTarget结构如下:
四、触发依赖
比如例子中代码obj.count++

effect(fun)
#🎜🎜#function createSetter(shallow = false) { return function set( target: object, key: string | symbol, value: unknown, receiver: object ): boolean { //... const result = Reflect.set(target, key, value, receiver) // don't trigger if target is something up in the prototype chain of original if (target === toRaw(receiver)) { if (!hadKey) { trigger(target, TriggerOpTypes.ADD, key, value) // 触发ADD依赖更新 } else if (hasChanged(value, oldValue)) { trigger(target, TriggerOpTypes.SET, key, value, oldValue) //触发SET依赖更新 } } //... }
console .log( obj.count)
La structure de la collection de dépendances de suivi est la suivante : #🎜🎜##🎜🎜#
obj.count++
déclenche la dépendance et exécute runner.run() . Ce qui fonctionne réellement est #🎜🎜 #// 路径:packages/reactivity/src/effect.ts export function trigger( target: object, type: TriggerOpTypes, key?: unknown, newValue?: unknown, oldValue?: unknown, oldTarget?: Map<unknown, unknown> | Set<unknown> ) { const depsMap = targetMap.get(target) // 获取depsMap, targetMap是在track中创建的依赖 if (!depsMap) { // never been tracked return } let deps: (Dep | undefined)[] = [] if (type === TriggerOpTypes.CLEAR) { // collection being cleared // trigger all effects for target deps = [...depsMap.values()] } else if (key === 'length' && isArray(target)) { const newLength = Number(newValue) depsMap.forEach((dep, key) => { if (key === 'length' || key >= newLength) { deps.push(dep) } }) } else { // schedule runs for SET | ADD | DELETE if (key !== void 0) { deps.push(depsMap.get(key)) } // also run for iteration key on ADD | DELETE | Map.SET switch (type) { case TriggerOpTypes.ADD: if (!isArray(target)) { deps.push(depsMap.get(ITERATE_KEY)) if (isMap(target)) { deps.push(depsMap.get(MAP_KEY_ITERATE_KEY)) } } else if (isIntegerKey(key)) { // new index added to array -> length changes deps.push(depsMap.get('length')) } break case TriggerOpTypes.DELETE: if (!isArray(target)) { deps.push(depsMap.get(ITERATE_KEY)) if (isMap(target)) { deps.push(depsMap.get(MAP_KEY_ITERATE_KEY)) } } break case TriggerOpTypes.SET: if (isMap(target)) { deps.push(depsMap.get(ITERATE_KEY)) } break } } const eventInfo = __DEV__ ? { target, type, key, newValue, oldValue, oldTarget } : undefined if (deps.length === 1) { if (deps[0]) { if (__DEV__) { triggerEffects(deps[0], eventInfo) } else { triggerEffects(deps[0]) } } } else { const effects: ReactiveEffect[] = [] for (const dep of deps) { if (dep) { effects.push(...dep) } } if (__DEV__) { triggerEffects(createDep(effects), eventInfo) } else { triggerEffects(createDep(effects)) } } }

const eventInfo = __DEV__ ? { target, type, key, newValue, oldValue, oldTarget } : undefined if (deps.length === 1) { if (deps[0]) { if (__DEV__) { triggerEffects(deps[0], eventInfo) } else { triggerEffects(deps[0]) } } }

export function triggerEffects( dep: Dep | ReactiveEffect[], debuggerEventExtraInfo?: DebuggerEventExtraInfo ) { // spread into array for stabilization const effects = isArray(dep) ? dep : [...dep] for (const effect of effects) { if (effect.computed) { triggerEffect(effect, debuggerEventExtraInfo) } } for (const effect of effects) { if (!effect.computed) { triggerEffect(effect, debuggerEventExtraInfo) } } }
function triggerEffect( effect: ReactiveEffect, debuggerEventExtraInfo?: DebuggerEventExtraInfo ) { if (effect !== activeEffect || effect.allowRecurse) { // 如果 effect.onTrigger 存在,就会执行,只有开发模式下才会执行 if (__DEV__ && effect.onTrigger) { effect.onTrigger(extend({ effect }, debuggerEventExtraInfo)) } // 如果 effect 是一个调度器,就会执行 scheduler if (effect.scheduler) { effect.scheduler() } else { // 其它情况执行 effect.run() effect.run() } } }
const _effect = new ReactiveEffect (fn )
, les résultats en cours d'exécution sont les suivants : #🎜🎜##🎜🎜#
_effect.run()
#🎜🎜# rrreee#🎜🎜 #_effect.run
la portée est liée à _effect
#🎜🎜#rrreee#🎜🎜#Return side effect function runner#🎜🎜##🎜🎜#2 , Code source de la fonction ReactiveEffect #🎜🎜#rrreee- #🎜🎜#La fonction de la méthode run est d'exécuter la fonction d'effet secondaire, et en cours d'exécution de la fonction d'effet secondaire, les dépendances seront collectées ; #🎜🎜#
- #🎜🎜#La fonction de la méthode stop est d'arrêter l'objet ReactiveEffect actuel. Après l'arrêt, les dépendances ne seront plus collectées ; 🎜🎜#
- #🎜🎜#activeEffect et ce n'est pas égal à chaque fois, car activeEffect changera avec la profondeur de la pile d'appels, alors que cela est corrigé ; ul>#🎜🎜# 3. Lié à la collecte de dépendances#🎜 🎜##🎜🎜#1. Comment déclencher la collecte de dépendances#🎜🎜##🎜🎜#Dans la fonction d'effet secondaire,
obj.count
déclenchera la collecte de dépendances#🎜🎜#rrreee#🎜🎜#trigger L'entrée est dans l'intercepteur get #🎜🎜#rrreee#🎜🎜#2 Le code source du suivi #🎜🎜#rrreee#🎜🎜#shouldTrack est également mentionné ci-dessus. Sa fonction est de contrôler s'il faut collecter les dépendances ; #🎜🎜## 🎜🎜#activeEffect est l'objet ReactiveEffect dont nous venons de parler. Il pointe vers la fonction d'effet secondaire en cours d'exécution ; la méthode de suivi consiste à collecter les dépendances. Sa mise en œuvre est très simple, il suffit de l'enregistrer dans targetMap La cible et la clé suivantes #🎜🎜##🎜🎜#targetMap est une WeakMap, sa clé est une cible, sa valeur est une Map, la la clé de cette Map est la clé, et sa valeur est un Set ; php.cn/upload/article/000/887/227/168368876255114.png" alt="Vue3 responsive Comment utiliser l'effet principal" />#🎜🎜##🎜🎜#Ce qui précède est le depMap original#🎜🎜# #🎜🎜#Afin d'augmenter le débogage réactif, l'environnement de développement ajouteraeventInfo
#🎜🎜 #rrreee#🎜🎜#eventInfo a la structure suivante : #🎜🎜##🎜🎜##🎜🎜##🎜🎜#< code>trackEffects(dep, eventInfo)#🎜🎜##🎜🎜#S'il n'y a pas d'objet ReactiveEffect actuel dans le dépôt, alors sera ajouté et sa fonction est d'associer l'opération d'attribut de l'objet à la fonction d'effet secondaire . Ensuite, regardez
trackEffects
#🎜🎜##🎜🎜#3, trackEffects(dep, eventInfo) interprétation du code source#🎜🎜# rrreee#🎜🎜#dep.add(activeEffect! )
S'il n'y a pas d'objet ReactiveEffect actuel dans le dépôt, il sera ajouté #🎜🎜##🎜🎜##🎜🎜##🎜🎜#La structure depTarget finale générée est la suivante : #🎜 🎜##🎜🎜#
# 🎜🎜##🎜🎜#4. Déclencher des dépendances#🎜🎜##🎜🎜#Par exemple, le code dans l'exemple
obj.count++
déclenchera l'interception d'ensemble et déclenchera des mises à jour de dépendances#🎜🎜#function createSetter(shallow = false) { return function set( target: object, key: string | symbol, value: unknown, receiver: object ): boolean { //... const result = Reflect.set(target, key, value, receiver) // don't trigger if target is something up in the prototype chain of original if (target === toRaw(receiver)) { if (!hadKey) { trigger(target, TriggerOpTypes.ADD, key, value) // 触发ADD依赖更新 } else if (hasChanged(value, oldValue)) { trigger(target, TriggerOpTypes.SET, key, value, oldValue) //触发SET依赖更新 } } //... }
Copier après la connexionCopier après la connexion1、trigger依赖更新
// 路径:packages/reactivity/src/effect.ts export function trigger( target: object, type: TriggerOpTypes, key?: unknown, newValue?: unknown, oldValue?: unknown, oldTarget?: Map<unknown, unknown> | Set<unknown> ) { const depsMap = targetMap.get(target) // 获取depsMap, targetMap是在track中创建的依赖 if (!depsMap) { // never been tracked return } let deps: (Dep | undefined)[] = [] if (type === TriggerOpTypes.CLEAR) { // collection being cleared // trigger all effects for target deps = [...depsMap.values()] } else if (key === 'length' && isArray(target)) { const newLength = Number(newValue) depsMap.forEach((dep, key) => { if (key === 'length' || key >= newLength) { deps.push(dep) } }) } else { // schedule runs for SET | ADD | DELETE if (key !== void 0) { deps.push(depsMap.get(key)) } // also run for iteration key on ADD | DELETE | Map.SET switch (type) { case TriggerOpTypes.ADD: if (!isArray(target)) { deps.push(depsMap.get(ITERATE_KEY)) if (isMap(target)) { deps.push(depsMap.get(MAP_KEY_ITERATE_KEY)) } } else if (isIntegerKey(key)) { // new index added to array -> length changes deps.push(depsMap.get('length')) } break case TriggerOpTypes.DELETE: if (!isArray(target)) { deps.push(depsMap.get(ITERATE_KEY)) if (isMap(target)) { deps.push(depsMap.get(MAP_KEY_ITERATE_KEY)) } } break case TriggerOpTypes.SET: if (isMap(target)) { deps.push(depsMap.get(ITERATE_KEY)) } break } } const eventInfo = __DEV__ ? { target, type, key, newValue, oldValue, oldTarget } : undefined if (deps.length === 1) { if (deps[0]) { if (__DEV__) { triggerEffects(deps[0], eventInfo) } else { triggerEffects(deps[0]) } } } else { const effects: ReactiveEffect[] = [] for (const dep of deps) { if (dep) { effects.push(...dep) } } if (__DEV__) { triggerEffects(createDep(effects), eventInfo) } else { triggerEffects(createDep(effects)) } } }
Copier après la connexionCopier après la connexionconst depsMap = targetMap.get(target)
获取 targetMap 中的 depsMap targetMap结构如下:执行以上语句之后的depsMap结构如下:
将 depsMap 中 key 对应的 ReactiveEffect 对象添加到 deps 中
deps.push(depsMap.get(key))
之后的deps结构如下:triggerEffects(deps[0], eventInfo)
const eventInfo = __DEV__ ? { target, type, key, newValue, oldValue, oldTarget } : undefined if (deps.length === 1) { if (deps[0]) { if (__DEV__) { triggerEffects(deps[0], eventInfo) } else { triggerEffects(deps[0]) } } }
Copier après la connexionCopier après la connexiontrigger函数的作用就是触发依赖,当我们修改数据的时候,就会触发依赖,然后执行依赖中的副作用函数。
在这里的实现其实并没有执行,主要是收集一些需要执行的副作用函数,然后在丢给triggerEffects函数去执行,接下来看看triggerEffects函数。
2、triggerEffects(deps[0], eventInfo)
export function triggerEffects( dep: Dep | ReactiveEffect[], debuggerEventExtraInfo?: DebuggerEventExtraInfo ) { // spread into array for stabilization const effects = isArray(dep) ? dep : [...dep] for (const effect of effects) { if (effect.computed) { triggerEffect(effect, debuggerEventExtraInfo) } } for (const effect of effects) { if (!effect.computed) { triggerEffect(effect, debuggerEventExtraInfo) } } }
Copier après la connexionCopier après la connexion主要步骤
const effects = isArray(dep) ? dep : [...dep]
获取effectstriggerEffect(effect, debuggerEventExtraInfo)
执行effect,接下来看看源码3、triggerEffect(effect, debuggerEventExtraInfo)
function triggerEffect( effect: ReactiveEffect, debuggerEventExtraInfo?: DebuggerEventExtraInfo ) { if (effect !== activeEffect || effect.allowRecurse) { // 如果 effect.onTrigger 存在,就会执行,只有开发模式下才会执行 if (__DEV__ && effect.onTrigger) { effect.onTrigger(extend({ effect }, debuggerEventExtraInfo)) } // 如果 effect 是一个调度器,就会执行 scheduler if (effect.scheduler) { effect.scheduler() } else { // 其它情况执行 effect.run() effect.run() } } }
Copier après la connexionCopier après la connexioneffect.run()就是执行副作用函数
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Sujets chauds

vue3+vite:src utilise require pour importer dynamiquement des images et des rapports d'erreurs et des solutions. vue3+vite importe dynamiquement plusieurs images. Si vue3 est développé à l'aide de TypeScript, il y aura un message d'erreur indiquant que requireisnotdefined ne peut pas être utilisé comme imgUrl. :require(' .../assets/test.png') est importé car TypeScript ne prend pas en charge require, donc l'importation est utilisée. Voici comment le résoudre : utilisez waitimport.

tinymce est un plug-in d'éditeur de texte riche entièrement fonctionnel, mais l'introduction de tinymce dans vue n'est pas aussi fluide que les autres plug-ins de texte riche de Vue. tinymce lui-même ne convient pas à Vue, et @tinymce/tinymce-vue doit être introduit, et Il s'agit d'un plug-in de texte riche étranger et n'a pas passé la version chinoise. Vous devez télécharger le package de traduction depuis son site officiel (vous devrez peut-être contourner le pare-feu). 1. Installez les dépendances associées npminstalltinymce-Snpminstall@tinymce/tinymce-vue-S2. Téléchargez le package chinois 3. Introduisez le skin et le package chinois Créez un nouveau dossier tinymce dans le dossier public du projet et téléchargez le.

Pour implémenter le front-end du blog avec Vue, vous devez implémenter l'analyse markdown. S'il y a du code, vous devez implémenter la mise en évidence du code. Il existe de nombreuses bibliothèques d'analyse de démarques pour Vue, telles que markdown-it, vue-markdown-loader, Markdown, vue-markdown, etc. Ces bibliothèques sont toutes très similaires. Marked est utilisé ici et highlight.js est utilisé comme bibliothèque de mise en évidence du code. Les étapes d'implémentation spécifiques sont les suivantes : 1. Installez les bibliothèques dépendantes. Ouvrez la fenêtre de commande sous le projet vue et entrez la commande suivante npminstallmarked-save//marked pour convertir le markdown en htmlnpmins.

Pour réaliser un rafraîchissement partiel de la page, il suffit d'implémenter le re-rendu du composant local (dom). Dans Vue, le moyen le plus simple d'obtenir cet effet est d'utiliser la directive v-if. Dans Vue2, en plus d'utiliser l'instruction v-if pour restituer le dom local, nous pouvons également créer un nouveau composant vierge. Lorsque nous devons actualiser la page locale, accéder à cette page de composant vierge, puis y revenir. la garde beforeRouteEnter dans la page d’origine vierge. Comme le montre la figure ci-dessous, comment cliquer sur le bouton d'actualisation dans Vue3.X pour recharger le DOM dans la zone rouge et afficher l'état de chargement correspondant. Puisque la garde dans le composant dans la syntaxe scriptsetup dans Vue3.X n'a que o

Une fois le projet vue3 empaqueté et publié sur le serveur, la page d'accès affiche un 1 vide. Le publicPath dans le fichier vue.config.js est traité comme suit : const{defineConfig}=require('@vue/cli-service') module.exports=defineConfig({publicPath :process.env.NODE_ENV==='production'?'./':'/&

Préface Que ce soit vue ou réagir, lorsque nous rencontrons plusieurs codes répétés, nous réfléchirons à comment réutiliser ces codes, au lieu de remplir un fichier avec un tas de codes redondants. En fait, Vue et React peuvent être réutilisés en extrayant des composants, mais si vous rencontrez quelques petits fragments de code et que vous ne souhaitez pas extraire un autre fichier, en comparaison, React peut être utilisé dans le même Déclarez le widget correspondant dans le fichier. , ou implémentez-le via la fonction de rendu, telle que : constDemo:FC=({msg})=>{returndemomsgis{msg}}constApp:FC=()=>{return(

Utilisation de Vue pour créer des éléments personnalisés WebComponents est un nom collectif pour un ensemble d'API Web natives qui permettent aux développeurs de créer des éléments personnalisés réutilisables (customelements). Le principal avantage des éléments personnalisés est qu’ils peuvent être utilisés avec n’importe quel framework, même sans. Ils sont idéaux lorsque vous ciblez des utilisateurs finaux susceptibles d'utiliser une pile technologique frontale différente, ou lorsque vous souhaitez dissocier l'application finale des détails d'implémentation des composants qu'elle utilise. Vue et WebComponents sont des technologies complémentaires et Vue offre un excellent support pour l'utilisation et la création d'éléments personnalisés. Vous pouvez intégrer des éléments personnalisés dans des applications Vue existantes ou utiliser Vue pour créer

1 Introduction 1.1 Objectif ElementPlus utilise l'introduction à la demande pour réduire considérablement la taille du fichier empaqueté. 1.2 L'effet final est de générer automatiquement le fichier composants.d.ts et de l'introduire dans le fichier. d.ts et introduisez-le dans le fichier ElementPlusAPI2 Préparation Installer ElementPlus#Choisissez un gestionnaire de packages que vous aimez#NPM$npminstallelement-plus--save#Yarn$yarnaddelement-plus#pnpm$pnpminstallelement-plus3 Appuyez sur.
