IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Vue 2.0 入门系列(11)双向绑定其他元素以及自定义表单控件

    Zen10000发表于 2017-04-27 21:02:01
    love 0

    之前我们学过用 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>

    现在,我们对评论的内容进行过滤,效果如下:

    clipboard.png

    可以使用自定义组件,比如:

    <comment v-model="comment"></comment>

    如何让组件的 v-model 生效呢?需要按照 Vue 的约定:

    1. 接受一个 value 属性

    2. 在有新的 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>
    


沪ICP备19023445号-2号
友情链接