以前咱們學過用 v-model
進行雙向數據綁定:css
<div id="root"> <textarea class="textarea" v-model="comment"></textarea> </div> <script> var vm = new Vue({ el:"#root", data:{ comment:"這是一條評論" } }); </script>
並且,提到過,v-model
只能用於表單控件,若是用於其餘元素,好比 p
:html
<p contenteditable="true" v-model="comment"></p>
那麼就會報錯:vue
v-model is not supported on this element type. If you are working with contenteditable, it's recommended to wrap a library dedicated for that purpose inside a custom component.ajax
它會提示用 custom component
,即自定義組件。在使用自定義組件以前,先來看看 v-model
的另一種等價寫法:ide
<textarea :value="comment" @input="comment = $event.target.value"></textarea>
該過程很好理解,首先,動態綁定輸入控件的 value
屬性到 comment
變量上,而後對 input
事件進行監控,實時同步 comment
的值。this
若是用這種寫法,就能夠對 p
等元素進行雙向綁定了。因爲 p
元素沒有 value
屬性,能夠使用 v-text
或者插值:spa
<p contenteditable="true" @input="comment = $event.target.innerText">{{ comment }}</p>
或者:雙向綁定
<p contenteditable="true" v-text="comment" @input="comment = $event.target.innerText"></p>
如今,咱們對評論的內容進行過濾,效果以下:code
能夠使用自定義組件,好比:component
<comment v-model="comment"></comment>
如何讓組件的 v-model
生效呢?須要按照 Vue 的約定:
接受一個 value
屬性
在有新的 value
時觸發 input
事件
跟咱們以前的寫法相似:
Vue.component('comment',{ props:['value'], template:` <textarea :value="value" @input="filterComment($event.target.value)"></textarea> `, methods: { filterComment(comment){ this.$emit('input',comment) } } });
這樣就能夠實現簡單的雙向綁定了,並且咱們能夠在 filterComment
方法中定義過濾規則:
filterComment(comment){ var filterRst = (comment.indexOf('敏感詞') >= 0 ? comment.replace(\敏感詞\g,"河蟹") : comment); this.$emit('input',filterRst) }
完整示例:
<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="https://cdn.bootcss.com/vue/2.2.6/vue.js"></script> <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.4.1/css/bulma.css"> </head> <body> <div id="root" class="container"> <comment v-model="comment"></comment> </div> <script> Vue.component('comment',{ props:['value'], template:` <textarea class="textarea" :value="value" @input="filterComment($event.target.value)"></textarea> `, data(){ return { sensitiveList:['包子','蛤蛤'], replaceWord:'河蟹' } }, methods: { filterComment(comment){ var that = this; this.sensitiveList.forEach(function(word){ var regex = new RegExp(word,'g');; comment = (comment.indexOf(word) >= 0 ? comment.replace(regex,that.replaceWord) : comment); }) this.$emit('input',comment) } } }); var vm = new Vue({ el:"#root", data:{ comment:'這是一條評論' } }); </script> </body>