如何在Vue.JS中更新插槽

Goo*_*ose 2 javascript vue.js vue-component vuejs2

我在下面简化了Vue组件。

这是模板

<template>
    <slot></slot>
</template>
Run Code Online (Sandbox Code Playgroud)

插槽可能包含HTML,这就是为什么我决定使用插槽而不是我会简单绑定到的道具的原因。我想保持这种方式。

我有一种从服务器获取新HTML的方法。我想使用这个新的HTML来更新广告位。我不确定插槽是否具有反应性以及如何实现此目的。

我可以使用来查看默认广告位this.$slots.default[0],但是我不知道如何使用一串HTML内容更新它。简单地将字符串分配给元素显然是不正确的,to .innerHtml无效,因为它不是可用的函数,并且to.text无效。我假定即使插槽对象上存在文本元素,但元素属性仍然优先。

根据评论中的建议,我已经尝试过将其与计算机属性一起使用。

<span v-html="messageContent"><slot></slot></span>
Run Code Online (Sandbox Code Playgroud)

但是现在的问题是,它覆盖了传递给我的广告位。

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

Sph*_*inx 6

下面是我的解决方案,尽管我不喜欢这种意见(将 html 直接加载到当前组件级别的插槽中),因为它违反了插槽的规则。我认为你应该这样做(<component><template v-html="yourHtml"></template></component>),这样会更好,因为 Slot 会像 V​​ue 设计的那样专注于它的工作。

关键是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: ''
    }
  }
})
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<child><h1>Test</h1></child>
</div>
Run Code Online (Sandbox Code Playgroud)


Ter*_*rry 5

我认为您的问题来自<slot>对VueJS固有工作方式的误解。插槽用于将内容从使用中的父组件交织到子组件中。将其视为的HTML等效项v-bind:prop。在v-bind:prop组件上使用时,实际上是在将数据传递到子组件中。这与插槽相同。

如果没有最终的具体示例或代码,此答案充其量只是猜测。我假设您的父组件本身就是VueJS应用程序,而子组件就是包含该<slot>元素的组件。

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

<!-- Custom component template -->
<template>
    <slot></slot>
</template>
Run Code Online (Sandbox Code Playgroud)

在这种情况下,应用程序具有默认的基本状态,在该状态下,它将静态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>
Run Code Online (Sandbox Code Playgroud)

然后,在触发事件时,您想用新的传入标记替换该基态标记。这可以通过将传入的HTML存储在data属性中,然后简单地使用v-html有条件地呈现它来完成。假设我们要将传入的标记存储在应用程序的中vm.$data.customHTML

data: {
    customHTML: null
}
Run Code Online (Sandbox Code Playgroud)

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

<!-- 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>
Run Code Online (Sandbox Code Playgroud)

请注意,与您尝试的代码相比,不同之处在于:

  • 父组件(即消费组件)负责决定将哪种标记传递给子组件
  • 子组件变得愚蠢:它只是接收标记并将其呈现在<slot>元素中

请参阅下面的概念验证:

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

<!-- Custom component template -->
<template>
    <slot></slot>
</template>
Run Code Online (Sandbox Code Playgroud)
<!-- 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>
Run Code Online (Sandbox Code Playgroud)
data: {
    customHTML: null
}
Run Code Online (Sandbox Code Playgroud)