1. 程式人生 > 其它 >可編輯非input,texrarea+vue實現雙向繫結(以div標籤為例)

可編輯非input,texrarea+vue實現雙向繫結(以div標籤為例)

想法來源

關於輸入,input標籤和textarea標籤可以滿足我們90%以上的需求,但有些時候有些一些特殊需求,或者在改別人的專案時,換標籤不方便,這個時候需求就沒辦法無法滿足。
此時,我們就可以使用div等一些標籤來實現

本文涉及知識點

屬性:contenteditable是一個列舉屬性,表示元素是否可被使用者編輯。 如果可以,瀏覽器會修改元素的部件以允許編輯。
當標籤加上這個屬性時,就可進行內容編輯,來實現輸入的效果。並且實現placeholder效果,如下

//html
<div>請在下方的框中輸入你喜歡的句子</div>
    <div contenteditable placeholder=
'請輸入文字' class="input"></div> //css .input { width: 500px; height: 24px; line-height: 24px; font-size: 14px; padding: 5px 8px; border: 1px solid #ddd; } .input:empty::before { content:
attr(placeholder); }

如下
在這裡插入圖片描述

這裡由於下面會用到,這裡先直接列出
大部分知道contenteditable屬性有 true 和 false。,但是不止這些

contenteditable屬性值

contenteditable="" //表示元素是可編輯的
contenteditable="events"
contenteditable="caret"
//讓div只能鍵入文字值
//相容性不好,除了谷歌,火狐ie都不支援
contenteditable="plaintext-only"
contenteditable="true"//表示元素是可編輯的 contenteditable="false" //表示元素是不可編輯的

至於contenteditable=“events”,contenteditable="caret"我也沒有查到是什麼意思,但是下面用不上我們這裡就不深挖了

雙向繫結

我們都知道,div是無法使用 v-model,那麼該如何實現雙向繫結呢?

//html
 <div id="id">
        <div>請在下方的框中輸入你喜歡的句子</div>
        <div contenteditable placeholder='請輸入文字' class="input" v-html="content" @input="content=$event.target.innerHTML"></div>
        <div>{{content}}</div>
    </div>
<div contenteditable placeholder='請輸入文字' v-html="item.content"></div>
//js
var id = new Vue({
            el: "#id",
            data: {
                content: "",
            },
        })

但是有時只想複製文字,卻發現複製過來的是標籤+標籤樣式,那麼改如何處理?
這個時候就要用到contenteditable="plaintext-only"
但是實際使用上有很多問題,比如游標的問題,我們可以依靠元件來對這些問題進行處理

<div id="app">
    <m-contenteditable :child="content"></m-contenteditable>
    <m-contenteditable :child="content"></m-contenteditable>
    <div><pre v-html="content.txt"></pre></div>
</div>
<script>
//定義一個全域性元件
Vue.component("mContenteditable",{
    props:{
        child:{
            type:Object,
            default:{
                txt:""
            }
        }
    },
    //資料
    data:function(){
        return {
            innerText:this.child.txt,
            lock:false
        }
    },
    //偵聽器
    watch:{
        child:{
            handler(newValue, oldValue) {
                if(!this.lock) {
                    this.innerText=this.child.txt;
                };
           },
           deep:true
        }
    },
    //改變的方法
    methods:{
        changeTxt:function(e){
            this.child.txt=this.$el.innerHTML;
        }
    },
    //模板
    template:`<div class="box" contenteditable="true" v-html="innerText" @input="changeTxt" @focus="lock=true" @blur="lock=false"></div>`
});
new Vue({
    el:"#app",
    data:{
        content:{
            txt:"內容<img src=\"http://pub.idqqimg.com/lib/qqface/0.gif\" width=\"38\" height=\"38\">"
        }
    }
});