在DOM树变异之后,Vue.js挂载组件以添加vue组件

时间:2018-02-17 01:18:15

标签: javascript vue.js vuejs2 aem

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

  

我正在使用Vue.js v2

这是一个简单的例子,我把它放在一起来说明这一点:

  

live 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

我希望能够在突变后找到新添加的组件并仅挂载那些,这可能吗?怎么样?

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

$('#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]});
});

似乎工作,但看起来也很难看,我不确定这可能带来什么其他影响......

使用案例

我正致力于为名为Adobe Experience Manager(AEM)的CMS编写Vue.js组件。

我使用inlined-template编写我的组件,这使我能够使用另一种名为HTL的模板语言进行搜索引擎优化以及服务器端渲染。

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

这是一个例子

AEM组件模板: <button>${properties.buttonTitle}</button>

以下是作者可能会做的事情:

  1. 作者访问创作页面
  2. 打开按钮组件对话框以进行编辑
  3. 将buttonTitle更改为&#34;新按钮标题&#34;
  4. 保存
  5. 保存后,发送ajax,组件HTML在服务器上重新呈现并返回新的HTML。该HTML现在通过jQuery替换旧的HTML(改变DOM)

    这适用于静态组件,但如果这是一个Vue.js组件,如何在保持其他组件安装的同时动态安装它。

      

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

2 个答案:

答案 0 :(得分:3)

感谢@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/

答案 1 :(得分:1)

在运行时生成的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/