Как обновить шаблон 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.

  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крючок , используйте эту функцию для наблюдения за ссылкой на шаблон в 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())
    

демонстрация

Просто для пояснения: вы пытаетесь передать ссылку на шаблон в свою функцию, но при выполнении логики она всегда оказывается нулевой, верно?

Вы можете просто использовать 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), и вы можете начать применять к нему свою фактическую логику.

Другие вопросы по тегам