【问题标题】:VueJs manipulate inline template and reinitialize itVueJs 操作内联模板并重新初始化它
【发布时间】:2017-05-05 12:35:46
【问题描述】:

这个问题类似于VueJS re-compile HTML in an inline-template componentHow to make Vue js directive working in an appended html element

不幸的是,该问题中的解决方案不能再用于当前的 VueJS 实现,因为 $compile 已被删除。

我的用例如下:

我必须使用第三方代码来操纵页面并在之后触发事件。现在,在该事件被触发后,我想让 VueJS 知道它应该重新初始化当前的 DOM。

(使用纯 javascript 编写的第三方允许用户向页面添加新的小部件)

https://jsfiddle.net/5y8c0u2k/

HTML

<div id="app">
    <my-input inline-template>
  <div class="wrapper">
  My inline template<br>
  <input v-model="value">
  <my-element inline-template :value="value">
    <button v-text="value" @click="click"></button>
  </my-element>
  </div>
    </my-input>
</div>

Javascript - VueJS 2.2

Vue.component('my-input', {
    data() {
        return {
            value: 1000
        };
    }
});

Vue.component('my-element', {
    props: {
        value: String
    },
    methods: {
        click() {
            console.log('Clicked the button');
        }
    }
});

new Vue({
    el: '#app',
});

// Pseudo code
setInterval(() => {
  // Third party library adds html:
  var newContent = document.createElement('div');
  newContent.innerHTML = `<my-element inline-template :value="value">
     <button v-text="value" @click="click"></button>
  </my-element>`;   document.querySelector('.wrapper').appendChild(newContent)

   //      
   // How would I now reinialize the app or
   // the wrapping component to use the click handler and value?
   //

}, 5000)

【问题讨论】:

  • 新代码可以绝对显示在页面的任何位置吗?
  • 是的,有多个动态生成的位置。我找到了解决方案,但感觉更像是 hack:jsfiddle.net/9ukmy0k0
  • 黑客行为是不可避免的:你违反了与 Vue 控制 DOM 的合同。
  • 这是大型项目和现有解决方案的痛点——你无法控制一切:(
  • 您想要my-elements 共享的my-input 的当前状态吗?这可能不那么骇人听闻。 jsfiddle.net/9ukmy0k0/2

标签: javascript html vue.js


【解决方案1】:

经过进一步调查,我联系了 VueJs 团队并得到了feedback,认为以下方法可能是一个有效的解决方案:

/**
 * Content change handler
 */
function handleContentChange() {
  const inlineTemplates = document.querySelector('[inline-template]');
  for (var inlineTemplate of inlineTemplates) {
    processNewElement(inlineTemplate);
  }
}


/**
 * Tell vue to initialize a new element
 */
function processNewElement(element) {
  const vue = getClosestVueInstance(element);
  new Vue({
    el: element,
    data: vue.$data
  });
}

/**
 * Returns the __vue__ instance of the next element up the dom tree
 */
function getClosestVueInstance(element) {
  if (element) {
    return element.__vue__ || getClosestVueInstance(element.parentElement);
  }
}

你可以在下面fiddle试试

【讨论】:

    【解决方案2】:

    一般当我听到这样的问题时,他们似乎总是通过使用 Vue 的一些更亲密和模糊的内在美来解决:)

    我已经使用了很多“坚持拥有数据”的第三方库,它们用于修改 DOM - 但如果您可以使用这些事件,您可以将更改代理到 Vue 拥有的对象 - 或者,如果你不能有一个 vue 拥有的对象,你可以通过计算属性观察一个独立的数据结构。

    window.someObjectINeedtoObserve = {...}
    
    yourLib.on('someEvent', (data) => {
      // affect someObjectINeedtoObserve...
    })
    
    new Vue ({
      // ...
      computed: {
        myObject () {
          // object now observed and bound and the dom will react to changes
          return window.someObjectINeedtoObserve 
        }
      }
    })
    

    如果您能阐明用例和库,我们或许可以提供更多帮助。

    【讨论】:

    • 只是为了澄清一下,如果你能清楚地表达整体功能需求,你可能会得到比上面的“解决方法”更简单、更简洁的答案——在我使用 Vue 的 3 年中,我从未有过这样做。我真的认为答案可能是采用不同的方法来链接数据、dom、vue 实例和您的 3rd 方库。
    • 关键问题是我们不只是构建一个简单的应用程序,而是尝试将 Vue 与 CMS 一起使用
    猜你喜欢
    • 2016-03-09
    • 1970-01-01
    • 1970-01-01
    • 2017-04-01
    • 1970-01-01
    • 2021-06-09
    • 2011-06-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多