Как обновить шаблон ref после смонтированного vue
Я пытаюсь запустить функцию, будь то вычисление, наблюдение или наблюдение после установки шаблона. эффект watcheffect выполняется только один раз, вычисленный, конечно, запускается перед установкой. я пытался
flush: 'post'
в часовом эффекте и флеше в часах я довольно застрял. глядя на документы, он должен работать, как ожидалось: https://v3.vuejs.org/guide/composition-api-template-refs.html#watching-template-refs
Следовательно, наблюдатели, использующие ссылки на шаблоны, должны быть определены с параметром flush: 'post'. Это запустит эффект после обновления DOM и обеспечит синхронизацию ссылки шаблона с DOM и ссылки на правильный элемент.
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 }
2 ответа
Если я правильно понимаю, вы пытаетесь наблюдать за шаблоном ref и ожидаете, что наблюдатель шаблона ref будет вызываться всякий раз, когда вы вставляете узлы (через обратный вызов кнопки), но он вызывается только один раз.
Это происходит потому, что наблюдатель фактически наблюдает только за ссылкой на шаблон, а не за его свойствами. Наблюдатель будет вызываться только тогда, когда ссылка на шаблон инициализируется ссылкой на компонент / элемент. Ссылки на шаблоны нельзя переназначить, поэтому наблюдатель не будет вызываться снова. Более того, свойства шаблона ref не являются реактивными, поэтому наблюдатель не будет вызываться при изменении HTML-кода целевого узла.
Решение
Вместо наблюдателя используйте a для наблюдения за изменениями, внесенными в целевой узел, включая
outerHTML
.
Создайте функцию, которая использует
MutationObserver
для вызова обратного вызова:const observeMutations = (targetNode, callback) => { const config = { attributes: true, childList: true, subtree: true } const observer = new MutationObserver(callback) observer.observe(targetNode, config) return observer }
В
onMounted
крючок , используйте эту функцию для наблюдения за ссылкой на шаблон в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) }) })
В
onUnmounted
крючок, отключите наблюдателя как очистку:onUnmounted(() => observer?.disconnect())
Просто для пояснения: вы пытаетесь передать ссылку на шаблон в свою функцию, но при выполнении логики она всегда оказывается нулевой, верно?
Вы можете просто использовать
onMounted(() => {})
подключите свой файл composable.js или вы можете реализовать
templateRef
(который, судя по всему, вы уже пытались включить) и
until
(https://vueuse.org/shared/until/#usage).
Так что вместо
const target = ref(null)
вы будете делать
const target = templateRef('target', null)
и передайте это своему composable.js.
Там и будешь смотреть, пока рефери не станет правдивым. Итак, перед вашей реальной логикой вы сделаете это:
await until(unrefElement(target)).toBeTruthy()
После этого ссылка должна предоставить фактический элемент (используйте
unrefElement
чтобы получить элемент templateRef), и вы можете начать применять к нему свою фактическую логику.