之前我们学过用 v-model
进行双向数据绑定:
<div id="root">
<textarea class="textarea" v-model="comment"></textarea>
</div>
<script>
var vm = new Vue({
el:"#root",
data:{
comment:"这是一条评论"
}
});
</script>
而且,提到过,v-model
只能用于表单控件,如果用于其他元素,比如 p
:
<p contenteditable="true" v-model="comment"></p>
那么就会报错:
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.
它会提示用 custom component
,即自定义组件。在使用自定义组件之前,先来看看 v-model
的另外一种等价写法:
<textarea :value="comment" @input="comment = $event.target.value"></textarea>
该过程很好理解,首先,动态绑定输入控件的 value
属性到 comment
变量上,然后对 input
事件进行监控,实时同步 comment
的值。
如果用这种写法,就可以对 p
等元素进行双向绑定了。由于 p
元素没有 value
属性,可以使用 v-text
或者插值:
<p contenteditable="true" @input="comment = $event.target.innerText">{{ comment }}</p>
或者:
<p contenteditable="true" v-text="comment" @input="comment = $event.target.innerText"></p>
现在,我们对评论的内容进行过滤,效果如下:
可以使用自定义组件,比如:
<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>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。