vue2 完成 div contenteditable="true" 类似于 v-model 的结果

题目

vue2 中对表单控件有着优越的双向数据绑定机制,然则关于要特定完成某些功用的输入时,我们就不得不运用到 contenteditable="true"div ,而在这个 div 上是运用 v-model 是没有结果的。那末题目就来了,输入是异常须要双向绑定的,这里的双向数据绑定该怎样完成?

处置惩罚思绪一:自定义指令

固然,说在这一段的前面,这类处置惩罚体式格局在 vue2 中是不可的,为何这么说,由于如今去搜刮这个题目绝大多数的搜刮结果是这个,所以放在前面。

完成的道理以及为何不能用了

道理:自定义一个双向数据绑定的指令,代码以下:

Vue.directive('demo', {
    twoWay: true,
    bind: function () {
        this.handler = function () {
            this.set(this.el.innerHTML)
        }.bind(this)
        this.el.addEventListener('input', this.handler)
    },
    update: function (newValue, oldValue) {
        this.el.innerHTML = newValue || ''
    },
    unbind: function () {
        this.el.removeEventListener('input', this.handler)
    }
})

至于 this 下的这些要领,在 vue 官网上能够不太轻易找到,由于这些是 vue1 中的内容,而在 vue2 中已被移除了。所以在 vue2 中我们是不能这么干的,固然假如你运用的是 vue1 那末完整没题目,直接拿去用即可。

处置惩罚思绪二:运用组件

零丁声明一个组件,在组件内部处置惩罚数据(也就是innerHTML),并将数据返回给父组件。
代码以下:

<template>
    <div contenteditable="true"
         v-html="innerText"
         @input="changeText"></div>
</template>
<script>
    export default {
        props: ['value'],
        data(){
            return {innerText:this.value}
        },
        methods:{
            changeText(){
                this.innerText = this.$el.innerHTML;
                this.$emit('input',this.innerText);
            }
        }
    }
</script>

然后在父组件中直接运用 v-model 就能够了(这里我把组件称号定义成了 v-edit-div)。

<template>
    <div>
        <v-edit-div v-model='text'></v-edit-div>
        <span>{{text}}</span>
    </div>
</template>
<script>
    export default {
        data(){
            return {
                text:'改一下试一试',
            }
        }
    }
</script>

至于为何能够直接用 v-model ,看官网的 API 吧。
v-model 传送门 运用自定义事宜的表单输入组件,那一章节。

题目处置惩罚。

=============== 分割线:更新于17-08-25 =====================

忙的不可,之前在批评区也有发明这个例子实在会有不少的题目,包含怎样完成异步数据的革新,更新值以后光标定位的题目等等,在斟酌了异步数据和光标题目后,有了以下的这个版本

<template>
    <div class="edit-div"
         v-html="innerText"
         :contenteditable="canEdit"
         @focus="isLocked = true"
         @blur="isLocked = false"
         @input="changeText">
    </div>
</template>
<script type="text/ecmascript-6">
    export default{
        name: 'editDiv',
        props: {
            value: {
                type: String,
                default: ''
            },
            canEdit: {
                type: Boolean,
                default: true
            }
        },
        data(){
            return {
                innerText: this.value,
                isLocked: false
            }
        },
        watch: {
            'value'(){
                if (!this.isLocked || !this.innerText) {
                    this.innerText = this.value;
                }
            }
        },
        methods: {
            changeText(){
                this.$emit('input', this.$el.innerHTML);
            }
        }
    }
</script>
<style lang="scss" rel="stylesheet/scss">
    .edit-div {
        width: 100%;
        height: 100%;
        overflow: auto;
        word-break: break-all;
        outline: none;
        user-select: text;
        white-space: pre-wrap;
        text-align: left;
        &[contenteditable=true]{
            user-modify: read-write-plaintext-only;
            &:empty:before {
                content: attr(placeholder);
                display: block;
                color: #ccc;
            }
        }
    }
</style>

这个版本是在项目中最终运用的版本,须要用的直接拿走用即可。
注:

  1. canEdit 标志这个div是不是是可编辑的,在父组件直接运用 v-model 即可。
  2. 该组件应该是一个div元素(也不一定非如果div)的子元素,父元素的大小即为子元素的大小。
    原文作者:aco
    原文地址: https://segmentfault.com/a/1190000008261449
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞