Vue.js 在 DOM 树突变后挂载组件以添加 vue 组件
Vue.js mount component after DOM tree mutation to add a vue component
我有一个用例(如下),我需要 mount
(如果那是正确的术语)通过 [= 插入到 DOM 中的 Vue.js 组件模板93=], 我可以设置一个 Mutation Observer 或对突变发生时触发的某些事件做出反应。
I am using 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
})
如代码中所述,销毁 re-instantiating 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
编写我的组件,这给了我 SEO 的优势以及 server-side 使用另一种称为 HTL 的模板语言进行渲染。
AEM 创作的工作方式是,当一个组件被编辑(通过对话框)时,该特定组件在 server-side 上 re-rendered 然后注入回 DOM替换旧组件,全部通过 Ajax 和 jQuery(无浏览器刷新)完成。
这是一个例子
AEM 组件模板:
<button>${properties.buttonTitle}</button>
以下是作者可能会做的事情:
- 作者访问创作页面
- 打开按钮组件对话框进行编辑
- 将按钮标题更改为 "new button title"
- 保存
保存后,发送 ajax,组件 HTML 在服务器上是 re-rendered,返回的是新的 HTML。 HTML 现在通过 jQuery 替换了旧的 HTML (变异了 DOM)
这对于静态组件来说很好,但是如果这是一个 Vue.js 组件,我该如何在保持其他组件已安装的同时动态安装它。
An easy solution to this is to refresh the page... but that is just bad experience... There has to be a better way.
在 runtime-generated 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/
多亏了@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 组件
看看这个 fiddle 基于问题的工作示例:
我有一个用例(如下),我需要 mount
(如果那是正确的术语)通过 [= 插入到 DOM 中的 Vue.js 组件模板93=], 我可以设置一个 Mutation Observer 或对突变发生时触发的某些事件做出反应。
I am using 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
})
如代码中所述,销毁 re-instantiating 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
编写我的组件,这给了我 SEO 的优势以及 server-side 使用另一种称为 HTL 的模板语言进行渲染。
AEM 创作的工作方式是,当一个组件被编辑(通过对话框)时,该特定组件在 server-side 上 re-rendered 然后注入回 DOM替换旧组件,全部通过 Ajax 和 jQuery(无浏览器刷新)完成。
这是一个例子
AEM 组件模板:
<button>${properties.buttonTitle}</button>
以下是作者可能会做的事情:
- 作者访问创作页面
- 打开按钮组件对话框进行编辑
- 将按钮标题更改为 "new button title"
- 保存
保存后,发送 ajax,组件 HTML 在服务器上是 re-rendered,返回的是新的 HTML。 HTML 现在通过 jQuery 替换了旧的 HTML (变异了 DOM)
这对于静态组件来说很好,但是如果这是一个 Vue.js 组件,我该如何在保持其他组件已安装的同时动态安装它。
An easy solution to this is to refresh the page... but that is just bad experience... There has to be a better way.
在 runtime-generated 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/
多亏了@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 组件
看看这个 fiddle 基于问题的工作示例: