Vue.js 在 DOM 树突变后挂载组件以添加一个 vue 组件
Posted
技术标签:
【中文标题】Vue.js 在 DOM 树突变后挂载组件以添加一个 vue 组件【英文标题】:Vue.js mount component after DOM tree mutation to add a vue component 【发布时间】: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]);
);
似乎有效,但看起来也很丑陋,我不确定这可能会产生什么其他影响..
用例:
我正在研究一种为名为 Adobe Experience Manager (AEM) 的 CMS 编写 Vue.js 组件的方法。
我使用 inlined-template
编写我的组件,这让我利用了 SEO 以及使用另一种称为 HTL 的模板语言进行服务器端渲染的优势。
AEM 创作的工作方式是,当(通过对话框)编辑组件时,该特定组件会在服务器端重新渲染,然后注入回 DOM 以替换旧组件,所有这些都通过 Ajax 完成和 jQuery(无浏览器刷新)。
这是一个例子
AEM 组件模板:
<button>$properties.buttonTitle</button>
作者可能会这样做:
-
作者访问创作页面
打开按钮组件对话框进行编辑
将 buttonTitle 更改为“新按钮标题”
保存
保存后,发送一个 ajax,组件 HTML 在服务器上重新渲染,返回的是新的 HTML。该 HTML 现在通过 jQuery 替换旧的 HTML(改变 DOM)
这对于静态组件来说很好,但是如果这是一个 Vue.js 组件,我如何在保持其他组件挂载的同时动态挂载它。
一个简单的解决方案是刷新页面......但这只是糟糕的体验......必须有更好的方法。
【问题讨论】:
将新部分实例化为新的 Vue 似乎是正确的方法,但似乎绑定不起作用,因为它们在另一个 Vue 中。但是,他们可能会在作用域插槽中。 有没有办法手动挂载组件,然后将它们添加到 Vue 实例中? 我真的不知道。让其他东西修改 DOM 然后告诉 Vue 接管这些更改是非常不符合 Vue 的。如果您的服务器只提供不同的数据并且前端可以进行 DOM 更新,那就更好了。 我完全同意,这只会发生在创作界面上。对于最终用户来说,这永远不会发生。我认为现在只用更新的 DOM 创建一个新的 Vue 实例就足够了。 可能会有帮助:css-tricks.com/… 【参考方案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/
【讨论】:
以防万一有人觉得它有用,这里有一个不使用inline-template
的版本:jsfiddle.net/9hL8zvx7/2【参考方案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/
【讨论】:
虽然不是我正在寻找的完整答案,但它帮助我找到了我正在寻找的答案,我会尽快发布该答案以上是关于Vue.js 在 DOM 树突变后挂载组件以添加一个 vue 组件的主要内容,如果未能解决你的问题,请参考以下文章