[英]How to update a slot in Vue.JS
I have a Vue component simplified below. 我在下面简化了Vue组件。
Here is the template 这是模板
<template>
<slot></slot>
</template>
The slot may contain HTML, which is why I decided to use a slot rather than a prop which I would simply bind to. 插槽可能包含HTML,这就是为什么我决定使用插槽而不是我会简单绑定到的道具的原因。 I'd like to keep it that way.
我想保持这种方式。
I have a method that gets new HTML from the server. 我有一种从服务器获取新HTML的方法。 I'd like to use this new HTML to update the slot.
我想使用这个新的HTML来更新广告位。 I'm not sure if slots are reactive and how I can accomplish this.
我不确定插槽是否具有反应性以及如何实现此目的。
I can view the default slot using this.$slots.default[0]
, but I don't know how to update it with a string of HTML content. 我可以使用
this.$slots.default[0]
查看默认插槽,但是我不知道如何使用字符串HTML内容更新默认插槽。 Simply assigning the string to the element is obviously incorrect, to .innerHtml
does not work because it isn't an available function, and to .text
doesn't work. 简单地将字符串分配给元素显然是不正确的,因为
.innerHtml
不是可用的函数,因此对.innerHtml
不起作用,而对.text
不起作用。 I assume that even though the text element exists on the slot object, the element properties take precedence. 我假定即使插槽对象上存在文本元素,但元素属性仍然优先。
Per suggestion in comments, I've tried this along with a computer property. 根据评论中的建议,我已经尝试过将其与计算机属性一起使用。
<span v-html="messageContent"><slot></slot></span>
But now the problem is that it overwrites the slot passed to me. 但是现在的问题是,它覆盖了传递给我的广告位。
How can I reactively update a slot with new HTML in Vue.JS? 如何在Vue.JS中使用新的HTML反应式更新广告位?
I think your issue comes from a misunderstanding of how <slot>
inherently works in VueJS. 我认为您的问题源于对
<slot>
在VueJS中固有工作方式的误解。 Slots are used to interweave content from a consuming parent component into a child component. 插槽用于将内容从使用中的父组件交织到子组件中。 See it as a HTML equivalent of
v-bind:prop
. 将其视为等同于
v-bind:prop
的HTML。 When you use v-bind:prop
on a component, you are effectively passing data into a child component. 在组件上使用
v-bind:prop
时,实际上是在将数据传递到子组件中。 This is the same as slots. 这与插槽相同。
Without any concrete example or code from your end, this answer is at best just guess-work. 如果没有最终的具体示例或代码,此答案充其量只是猜测。 I assume that your parent component is a VueJS app itself, and the child component is the one that holds the
<slot>
element. 我假设您的父组件本身就是VueJS应用程序,子组件就是保存
<slot>
元素的组件。
<!-- Parent template -->
<div id="app">
<custom-component>
<!-- content here -->
</custom-component>
</div>
<!-- Custom component template -->
<template>
<slot></slot>
</template>
In this case, the app has a default ground state where it passes static HTML to the child component: 在这种情况下,应用程序具有默认的基本状态,在该状态下,它将静态HTML传递给子组件:
<!-- Parent template -->
<div id="app">
<custom-component>
<!-- Markup to be interweaved into custom component -->
<p>Lorem ipsum dolor sit amet.</p>
</custom-component>
</div>
<!-- Custom component template -->
<template>
<slot></slot>
</template>
Then, when an event is fired, you want to replace that ground-state markup with new incoming markup. 然后,在触发事件时,您想用新的传入标记替换该基态标记。 This can be done by storing the incoming HTML in the
data
attribute, and simply using v-html
to conditionally render it. 这可以通过将传入的HTML存储在
data
属性中,并简单地使用v-html
有条件地呈现它来完成。 Let's say we want to store the incoming markup in app's vm.$data.customHTML
: 假设我们要将传入的标记存储在应用程序的
vm.$data.customHTML
:
data: {
customHTML: null
}
Then your template will look like this: 然后您的模板将如下所示:
<!-- Parent template -->
<div id="app">
<custom-component>
<div v-if="customHTML" v-html="customHTML"></div>
<div v-else>
<p>Lorem ipsum dolor sit amet.</p>
</div>
</custom-component>
</div>
<!-- Custom component template -->
<template>
<slot></slot>
</template>
Note that in contrast to the code you have tried, the differences are that: 请注意,与您尝试的代码相比,不同之处在于:
<slot>
element <slot>
元素中 See proof-of-concept below: 请参阅下面的概念验证:
var customComponent = Vue.component('custom-component', { template: '#custom-component-template' }); new Vue({ el: '#app', data: { customHTML: null }, components: { customComponent: customComponent }, methods: { updateSlot: function() { this.customHTML = '<p>Foo bar baz</p>'; } } });
.custom-component { background-color: yellow; border: 1px solid #000; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script> <div id="app"> <h1>I am the app</h1> <button type="button" @click="updateSlot">Click me to update slot content</button> <custom-component> <div v-if="customHTML" v-html="customHTML"> </div> <div v-else> <p>Lorem ipsum dolor sit amet.</p> </div> </custom-component> </div> <!-- custom-component template --> <script type="text/template" id="custom-component-template"> <div class="custom-component"> <h2>I am a custom component</h2> <!-- slot receives markup set in <custom-component> --> <slot></slot> </div> </script>
Below is my solution though I don't like this opinion (load html into slot directly in current component level) because it breaks the rules for the slot. 以下是我的解决方案,尽管我不喜欢这种观点(将html直接加载到当前组件级别的插槽中),因为它违反了插槽的规则。 And I think you should do like this way (
<component><template v-html="yourHtml"></template></component>
), it will be better because Slot will focus on its job as Vue designed. 而且我认为您应该喜欢这种方式(
<component><template v-html="yourHtml"></template></component>
),这样会更好,因为Slot将专注于Vue设计的工作。
The key is this.$slots.default
must be one VNode, so I used extend()
and $mount()
to get the _vnode. 关键是
this.$slots.default
必须是一个VNode,因此我使用extend()
和$mount()
来获取_vnode。
Vue.config.productionTip = false Vue.component('child', { template: '<div><slot></slot><a style="color:green">Child</a></div>', mounted: function(){ setTimeout(()=>{ let slotBuilder = Vue.extend({ // use your html instead template: '<div><a style="color:red">slot in child</a></div>', }) let slotInstance = new slotBuilder() this.$slots.default = slotInstance.$mount()._vnode this.$forceUpdate() }, 2000) } }) new Vue({ el: '#app', data() { return { test: '' } } })
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script> <div id="app"> <child><h1>Test</h1></child> </div>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.