簡體   English   中英

如何在Vue.JS中更新插槽

[英]How to update a slot in Vue.JS

我在下面簡化了Vue組件。

這是模板

<template>
    <slot></slot>
</template>

插槽可能包含HTML,這就是為什么我決定使用插槽而不是我會簡單綁定到的道具的原因。 我想保持這種方式。

我有一種從服務器獲取新HTML的方法。 我想使用這個新的HTML來更新廣告位。 我不確定插槽是否具有反應性以及如何實現此目的。

我可以使用this.$slots.default[0]查看默認插槽,但是我不知道如何使用字符串HTML內容更新默認插槽。 簡單地將字符串分配給元素顯然是不正確的,因為.innerHtml不是可用的函數,因此對.innerHtml不起作用,而對.text不起作用。 我假定即使插槽對象上存在文本元素,但元素屬性仍然優先。

根據評論中的建議,我已經嘗試過將其與計算機屬性一起使用。

<span v-html="messageContent"><slot></slot></span>

但是現在的問題是,它覆蓋了傳遞給我的廣告位。

如何在Vue.JS中使用新的HTML反應式更新廣告位?

我認為您的問題源於對<slot>在VueJS中固有工作方式的誤解。 插槽用於將內容從使用中的父組件交織到子組件中。 將其視為等同於v-bind:prop的HTML。 在組件上使用v-bind:prop時,實際上是在將數據傳遞到子組件中。 這與插槽相同。

如果沒有最終的具體示例或代碼,此答案充其量只是猜測。 我假設您的父組件本身就是VueJS應用程序,子組件就是保存<slot>元素的組件。

<!-- Parent template -->
<div id="app">
    <custom-component>
        <!-- content here -->   
    </custom-component>
</div>

<!-- Custom component template -->
<template>
    <slot></slot>
</template>

在這種情況下,應用程序具有默認的基本狀態,在該狀態下,它將靜態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>

然后,在觸發事件時,您想用新的傳入標記替換該基態標記。 這可以通過將傳入的HTML存儲在data屬性中,並簡單地使用v-html有條件地呈現它來完成。 假設我們要將傳入的標記存儲在應用程序的vm.$data.customHTML

data: {
    customHTML: null
}

然后您的模板將如下所示:

<!-- 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>

請注意,與您嘗試的代碼相比,不同之處在於:

  • 父組件 (即消費組件 )負責決定將哪種標記傳遞給子組件
  • 子組件非常笨拙 :僅接收標記並將其呈現在<slot>元素中

請參閱下面的概念驗證:

 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> 

以下是我的解決方案,盡管我不喜歡這種觀點(將html直接加載到當前組件級別的插槽中),因為它違反了插槽的規則。 而且我認為您應該喜歡這種方式( <component><template v-html="yourHtml"></template></component> ),這樣會更好,因為Slot將專注於Vue設計的工作。

關鍵是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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM