2016-09-15 219 views
3

如何將元素動態添加到內容中?示例如下:Vue.js中的動態html元素

<template> 
    {{{ message | hashTags }}} 
</template> 

<script> 
    export default { 
     ... 

     filters: { 
      hashTags: function(value) { 
       // Replace hash tags with links 
       return value.replace(/#(\S*)/g, '<a v-on:click="someAction()">#$1</a>') 
      } 
     } 
    } 
</script> 

問題是,如果我按下鏈接,則不會觸發任何操作。 Vue沒有看到新的元素。

回答

3

Vue綁定不會發生在插入的HTML上。您需要Vue將其視爲模板,如a partial。但是,Vue只對一個部分應用綁定;您無法返回並更改模板文本並重新綁定。所以每次模板文本改變時,你都必須創建一個新的部分。

有一個<partial>標籤/元素,你可以把你的HTML,它接受一個變量名,所以程序是:

  • 模板HTML的新變化
  • 寄存器中的新部分名稱模板HTML
  • 更新名稱變量,這樣新的部分呈現

這是一個有點可怕每有一個變化的時間來註冊新的東西,所以它如果可能的話,最好使用具有更多結構化模板的組件,但如果您真的需要完全動態的HTML和綁定,它就可以工作。

下面的示例從一條消息開始,按照您的過濾器進行鏈接,並在兩秒後更改message

您可以使用message作爲註冊部分的名稱,但是您需要一個在註冊後返回該名稱的計算器,否則它會嘗試在名稱註冊之前呈現。

var v = new Vue({ 
 
    el: 'body', 
 
    data: { 
 
    message: 'hi #linky' 
 
    }, 
 
    computed: { 
 
    partialName: function() { 
 
     Vue.partial(this.message, this.hashTags(this.message)); 
 
     return this.message; 
 
    } 
 
    }, 
 
    methods: { 
 
    someAction: function() { 
 
     console.log('Action!'); 
 
    }, 
 
    hashTags: function(value) { 
 
     // Replace hash tags with links 
 
     return value.replace(/#(\S*)/g, '<a v-on:click="someAction()">#$1</a>') 
 
    } 
 
    } 
 
}); 
 

 
setTimeout(() => { 
 
    v.$set('message', 'another #thing'); 
 
}, 2000);
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/1.0.26/vue.min.js"></script> 
 
<partial :name="partialName"></partial>

+0

我想說,你們非常感謝,我已經搜查了這3天..,在gitter問,所有人都說這是不可能的,但你做到了。但是你說過這不是一個很好的解決方案,我的目標是用鏈接替換'#hashtags','@ mentions'或許還有更好的解決方案?當然,我可以在後端進行準備,但是當所有邏輯都在一邊提供時,它看起來會更好。 – user2058653

4

我剛剛得知$compile,它似乎以滿足您的需求非常漂亮。使用$compile的一個非常簡單的指令可以避免所有註冊。

Vue.directive('dynamic', function(newValue) { 
 
    this.el.innerHTML = newValue; 
 
    this.vm.$compile(this.el); 
 
}); 
 

 
var v = new Vue({ 
 
    el: 'body', 
 
    data: { 
 
    message: 'hi #linky' 
 
    }, 
 
    computed: { 
 
    messageAsHtml: function() { 
 
     return this.message.replace(/#(\S*)/g, '<a v-on:click="someAction()">#$1</a>'); 
 
    } 
 
    }, 
 
    methods: { 
 
    someAction: function() { 
 
     console.log('Action!'); 
 
    } 
 
    } 
 
}); 
 

 
setTimeout(() => { 
 
    v.$set('message', 'another #thing'); 
 
}, 2000);
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/1.0.26/vue.min.js"></script> 
 
<div v-dynamic="messageAsHtml"></div>

0

由於partial已從VueJS 2移除(https://vuejs.org/v2/guide/migration.html#Vue-partial-removed

一種更好的方式可能是創建用於處理其內容的組件並創建適當的DOM元素

以上組件將通過可點擊鏈接取代主題標籤

<process-text>Hi #hashtag !</process-text> 
Vue.component('process-text', { 
    render: function (createElement) { 
     var hashtagRegex = /(^|\W)(#[a-z\d][\w-]*)/ig 
     var text = this.$slots.default[0].text 
     var list = text.split(hashtagRegex) 
     var children = [] 
     for (var i = 0; i < list.length; i++) { 
      var element = list[i] 
      if (element.match(hashtagRegex)) { 
       children.push(createElement('a', { 
       attrs: { 
        href: 'https://www.google.fr/search?q=' + element, 
        target: "_blank" 
        }, 
       domProps: { 
        innerHTML: element 
        } 
       })) 
      } else { 
       children.push(element) 
      } 
     } 
    } 
    return createElement('p', {}, children) // VueJS expects root element 
}) 
0

我找到的最好的解決方案,它正常工作與自定義HTML是看起來像這樣,它就像你有種創建新組件各次html屬性的變化。實際上沒有人這樣做,我們只是使用計算屬性來創建新組件。

這是它的外觀:

new Vue({ 
 
    el: "#root", 
 
    data: { 
 
     value: '', 
 
     name: 'root', 
 
     htmlData: '<div><input @input="onInputProxy($event)" ' + 
 
          'v-model="value" ' + 
 
          'v-for="i in 3" ' + 
 
          ':ref="`customInput${i}`"></div>' 
 
    }, 
 
    computed: { 
 
    // our component is computed property which returns the dict 
 
    htmlDataComponent() { 
 
     return { 
 
     template: this.htmlData, // we use htmlData as template text 
 

 
     data() { 
 
      return { 
 
      name: 'component', 
 
      value: '' 
 
      } 
 
     }, 
 
     created() { 
 
      // value of "this" is formComponent 
 
      console.log(this.name + ' created'); 
 
     }, 
 
     methods: { 
 
      // proxy components method to parent method, 
 
      // actually you done have to 
 
      onInputProxy: this.onInput 
 
     } 
 
     } 
 
    } 
 
    }, 
 
    methods: { 
 
    onInput ($event) { 
 
     // while $event is proxied from dynamic formComponent 
 
     // value of "this" is parent component 
 
     console.log(this.name + ' onInput'); 
 

 
     // use refs to refer to real components value 
 
     console.log(this.$refs.htmlDataComponent.value); 
 
     console.log(this.$refs.htmlDataComponent.$refs.customInput1); 
 
     console.log(this.$refs.htmlDataComponent.$refs.customInput2); 
 
     console.log(this.$refs.htmlDataComponent.$refs.customInput3); 
 
    } 
 
    } 
 
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.min.js"> 
 
</script> 
 

 
<div id="root"> 
 
    <component ref="htmlDataComponent" 
 
      v-if="htmlData" 
 
      :is="htmlDataComponent"></component> 
 
</div>

我沒有檢查它的內存效率,但它看起來像作品就好了。