【问题标题】:Vue.js mount component after DOM tree mutation to add a vue componentVue.js 在 DOM 树突变后挂载组件以添加一个 vue 组件
【发布时间】:2018-07-27 23:11:58
【问题描述】:

我有一个用例(如下),我需要 mount(如果这是正确的术语)一个通过 jQuery 插入 DOM 的 Vue.js 组件模板,我可以设置一个 Mutation Observer 或对某些响应突变发生时触发的事件。

我正在使用 Vue.js v2

下面是我整理的一个简单例子来说明这一点:

直播 jsFiddle https://jsfiddle.net/w7q7b1bh/2/

下面的 HTML 包含两个组件的 inlined-templates

<script src="https://cdn.jsdelivr.net/npm/vue@2.5.13/dist/vue.min.js"></script>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<div id="app">
  <!-- The use of inline-template is required for my solution to work -->
  <simple-counter inline-template>
    <button v-bind:style="style" v-on:click="add">clicks: {{ counter }}</button>
  </simple-counter>
  <simple-counter inline-template>
    <button v-on:click="counter += 1">{{ counter }}</button>
  </simple-counter>
</div>

<button id="mutate">Mutate</button>

js:

// simple counter component
Vue.component('simple-counter', {
  data: function() {
    return {
      counter: 0,
      style: {
        color: 'red',
        width: '200px'
      }
    }
  },
  methods: {
    add: function() {
      this.counter = this.counter + 1;
      this.style.color = this.style.color == 'red' ? 'green' : 'red';
    }
  }
})

// create the Vue instance
var initV = () => new Vue({
  el: '#app'
});

// expose the instance for later use
window.v = initV();

// click handler that will add a new `simple-counter` template to the Vue.el scope
$('#mutate').click(function(){
    $('#app').append(`  <div is="simple-counter" inline-template>
    <button v-bind:style="style" v-on:click="add">click to add: <span class="inactive" v-bind:class="{ active: true }">{{ counter }}</span></button></div>`)
    // do something after the template is incerted
    window.v.$destroy()
    window.v = initV(); // does not work

})

如代码中所述,销毁重新实例化 Vue 实例不起作用,我理解为什么,组件的模板在第一次 Vue 实例化时更改为最终的 HTML,当您尝试第二次实例化时,模板不存在,组件不存在mounted

我希望能够在突变后找到新添加的组件并仅安装那些,这可能吗?以及如何?

更新: 我能够通过将 el 设置为 DOM 的特定变异部分而不是整个 #app 树实例化一个新的 Vue 实例来找到一种方法:

$('#mutate').click(function(){
    var appended = 
            $(`
       <div is="simple-counter" inline-template>
         <button v-bind:style="style" v-on:click="add">
           click to add: {{ counter }}
         </button>
       </div>`
      ).appendTo($('#app'));

    var newV = new Vue({el: appended[0]});
});

似乎有效,但看起来也很丑陋,我不确定这可能会产生什么其他影响..

用例:

我正在研究一种为名为 Adob​​e Experience Manager (AEM) 的 CMS 编写 Vue.js 组件的方法。

我使用 inlined-template 编写我的组件,这让我利用了 SEO 以及使用另一种称为 HTL 的模板语言进行服务器端渲染的优势。

AEM 创作的工作方式是,当(通过对话框)编辑组件时,该特定组件会在服务器端重新渲染,然后注入回 DOM 以替换旧组件,所有这些都通过 Ajax 完成和 jQuery(无浏览器刷新)。

这是一个例子

AEM 组件模板: &lt;button&gt;${properties.buttonTitle}&lt;/button&gt;

作者可能会这样做:

  1. 作者访问创作页面
  2. 打开按钮组件对话框进行编辑
  3. 将 buttonTitle 更改为“新按钮标题”
  4. 保存

保存后,发送一个 ajax,组件 HTML 在服务器上重新渲染,返回的是新的 HTML。该 HTML 现在通过 jQuery 替换旧的 HTML(改变 DOM)

这对于静态组件来说很好,但是如果这是一个 Vue.js 组件,我如何在保持其他组件挂载的同时动态挂载它。

一个简单的解决方案是刷新页面......但这只是糟糕的体验......必须有更好的方法。

【问题讨论】:

  • 将新部分实例化为新的 Vue 似乎是正确的方法,但似乎绑定不起作用,因为它们在另一个 Vue 中。但是,他们可能会在作用域插槽中。
  • 有没有办法手动挂载组件,然后将它们添加到 Vue 实例中?
  • 我真的不知道。让其他东西修改 DOM 然后告诉 Vue 接管这些更改是非常不符合 Vue 的。如果您的服务器只提供不同的数据并且前端可以进行 DOM 更新,那就更好了。
  • 我完全同意,这只会发生在创作界面上。对于最终用户来说,这永远不会发生。我认为现在只用更新的 DOM 创建一个新的 Vue 实例就足够了。
  • 可能会有帮助:css-tricks.com/…

标签: javascript vue.js vuejs2 aem


【解决方案1】:

感谢@liam,我能够找到合适的解决方案来解决我的问题

在使用 HTML 模板改变 DOM 后,保留对该模板的父元素的引用

例如:

var $template = $('<div is="simple-counter" inline-template> ..rest of template here.. <div>').appendTo('#app') // app is the Vue instance el or a child of it

现在您可以创建组件的新实例并将$template 添加到它作为el 属性

如果我的组件是:

var simpleCounterComponent = Vue.component('simple-counter', {
  data: function() {
    return {
      counter: 0,
      style: {
        color: 'red',
        width: '200px'
      }
    }
  },
  methods: {
    add: function() {
      this.counter = this.counter + 1;
      this.style.color = this.style.color == 'red' ? 'green' : 'red';
    }
  }
})

我能做到:

var instance = new simpleCounterComponent({
  el: $template.get(0) // getting an HTML element not a jQuery object
});

这样,那个新添加的模板就变成了一个Vue组件

根据问题看一下这个小提琴的工作示例:

https://jsfiddle.net/947ojvnw/11/

【讨论】:

【解决方案2】:

在运行时生成的 HTML 中实例化 Vue 组件的一种方法是:

var ComponentClass = Vue.extend({
    template: '...',
});
var instance = new ComponentClass({
    propsData: { name: value },
});
instance.$mount('#uid'); // HTML contains <... id="uid">
...
instance.$destroy(); // if HTML containing id="uid" is dropped

更多在这里(我不隶属于这个网站)
https://css-tricks.com/creating-vue-js-component-instances-programmatically/

【讨论】:

  • 虽然不是我正在寻找的完整答案,但它帮助我找到了我正在寻找的答案,我会尽快发布该答案
猜你喜欢
  • 1970-01-01
  • 2019-05-31
  • 2021-05-08
  • 1970-01-01
  • 2018-04-13
  • 1970-01-01
  • 2023-03-05
  • 2021-02-14
  • 2017-08-19
相关资源
最近更新 更多