Как обновить слот в Vue.JS - PullRequest
0 голосов
/ 08 мая 2018

У меня есть компонент Vue, упрощенный ниже.

Вот шаблон

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

Слот может содержать HTML, поэтому я решил использовать слот, а не опору, к которой я бы просто привязал. Я бы хотел, чтобы так было.

У меня есть метод, который получает новый HTML с сервера. Я хотел бы использовать этот новый HTML для обновления слота. Я не уверен, реагируют ли слоты и как я могу это сделать.

Я могу просмотреть слот по умолчанию, используя this.$slots.default[0], но я не знаю, как обновить его с помощью строки содержимого HTML. Простое присвоение строки элементу, очевидно, неверно, для .innerHtml не работает, потому что это недоступная функция, а для .text не работает. Я предполагаю, что, хотя текстовый элемент существует в объекте слота, свойства элемента имеют приоритет.

По предложению в комментариях я пробовал это вместе со свойством компьютера.

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

Но теперь проблема в том, что он перезаписывает переданный мне слот.

Как реактивно обновить слот с новым HTML в Vue.JS?

Ответы [ 2 ]

0 голосов
/ 09 мая 2018

Ниже мое решение, хотя мне не нравится это мнение (загрузка html в слот непосредственно на текущем уровне компонента), потому что это нарушает правила для слота. И я думаю, что вы должны поступить таким образом (<component><template v-html="yourHtml"></template></component>), это будет лучше, потому что Слот сосредоточится на своей работе в соответствии с дизайном 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>
0 голосов
/ 09 мая 2018

Я думаю, что ваша проблема связана с неправильным пониманием того, как <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>

В этом случае приложение имеет основное состояние по умолчанию, когда оно передает статический 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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...