如何在安装 vue 后更新模板引用

How to update template ref after mounted vue

我正在尝试 运行 一个函数,它可以在模板安装后计算或观察或观察效果。 watcheffect 只执行一次,当然是在安装前计算 运行s。 我试过 flush: 'post' 的 watcheffect 和 flush in watch,我有点卡住了。 查看文档它应该按预期工作: https://v3.vuejs.org/guide/composition-api-template-refs.html#watching-template-refs

Therefore, watchers that use template refs should be defined with the flush: 'post' option. This will run the effect after the DOM has been updated and ensure that the template ref stays in sync with the DOM and references the correct element.

app.vue

<template>
  <div ref="target">
    <h1>my title</h1>
    <p>Tenetur libero aliquam at distinctio.</p>
    <h1>hello</h1>
    <p class="fuckyeah yolo">quia nam voluptatem illum ratione ipsum.</p>
    <img src="img.jpg" />
    " title="hello" alt />
    <h2>hello</h2>
    <ol>
      <li>hello inital</li>
      <li v-for="i in inc">hello</li>
    </ol>
  </div>
  <div>
    <button @click="inc++">inc</button>
  </div>
  <pre>
  <code>
    {{ toJson }}
  </code>
</pre>
</template>

<script>
import { ref } from '@vue/reactivity'
import { templateRef } from '@vueuse/core'
import { useParser } from './markcomposable.js'
import { onMounted, computed, watchEffect } from '@vue/runtime-core';

export default {
  setup() {

    const inc = ref(0);

    const target = ref(null);


    const { toJson } = useParser(target);


    return {
      inc, target, toJson
    }
  }
}
</script>

//composable.js

import { parse, validate } from "fast-xml-parser"
import { ref, reactive, watchEffect, toRef, nextTick } from 'vue'

const useParser = (target) => {


    const toJson = ref(null);


    const jsonOptions = reactive({
        //defaults
        attributeNamePrefix: "",
        ignoreAttributes: false,
        textNodeName: "text",
        arrayMode: true
    })

    const dumpJson = (target, options) =>
        validate(target.outerHTML) ? parse(target.outerHTML, options) : isValid.value;


    watchEffect(() => {
        if (target.value) {
            toJson.value = dumpJson(target.value, jsonOptions)
            console.log(toJson.value)
        }
    }, {
        flush: 'post',
    })

    return {
        target,
        toJson,
    }

}

export { useParser }

澄清一下: 您正在尝试将模板引用传递给您的函数,但在您执行逻辑时它总是变成 null,对吗?

您可以简单地在 composable.js 文件中使用 onMounted(() => {}) 挂钩 或者 您可以实施 templateRef (您已经尝试包含从它的外观来看) 和 until(https://vueuse.org/shared/until/#usage).

因此,您将 const target = templateRef('target', null) 而不是 const target = ref(null) 并将其传递给您的 composable.js。

在那里你会看到直到裁判是真实的。 所以在你的实际逻辑之前你会这样做:

await until(unrefElement(target)).toBeTruthy() 之后 ref 应提供一个实际元素(使用 unrefElement 获取 templateRef 的元素),您可以开始对其应用实际逻辑。

如果我没理解错的话,您正在尝试观察模板引用的 outerHTML,并且您希望在插入节点时调用模板引用观察器(通过按钮回调) , 但它只被调用过一次。

发生这种情况是因为观察者实际上只观察模板引用而不是它的属性。只有在使用 component/element 引用初始化模板引用时才会调用观察者。无法重新分配模板引用,因此不会再次调用观察者。此外,模板 ref 的属性不是反应性的,因此如果目标节点的 HTML 更改,则不会调用观察者。

解决方案

代替watcher,使用MutationObserver来观察对目标节点所做的更改,包括outerHTML.

  1. 创建一个使用 MutationObserver 调用回调的函数:

    const observeMutations = (targetNode, callback) => {
      const config = { attributes: true, childList: true, subtree: true }
      const observer = new MutationObserver(callback)
      observer.observe(targetNode, config)
      return observer
    }
    
  2. onMounted hook 中,使用该函数观察 target.value 中的模板引用,传递设置 toJson.value:

    的回调
    let observer = null
    
    onMounted(() => {
      toJson.value = dumpJson(target.value.outerHTML, jsonOptions)
    
      observer = observeMutations(target.value, () => {
        toJson.value = dumpJson(target.value.outerHTML, jsonOptions)
      })
    })
    
  3. onUnmounted 挂钩中,断开观察者作为清理:

    onUnmounted(() => observer?.disconnect())
    

demo