vue2 實(shí)現(xiàn) div contenteditable="true" 類似于 v-model 的效果

問題

點(diǎn)擊跳轉(zhuǎn)到原文

在vue2中對(duì)表單控件有著良好的雙向數(shù)據(jù)綁定機(jī)制,但是對(duì)于要特定實(shí)現(xiàn)某些功能的輸入時(shí),我們就不得不使用到contenteditable="true"的div,而在這個(gè)div上是使用v-model是沒有效果的。那么問題就來了,輸入是非常需要雙向綁定的,這里的雙向數(shù)據(jù)綁定該如何實(shí)現(xiàn)?

解決思路一:自定義指令

當(dāng)然,說在這一段的前面,這種解決方式在vue2中是不行的,為什么這么說,因?yàn)楝F(xiàn)在去搜索這個(gè)問題絕大多數(shù)的搜索結(jié)果是這個(gè),所以放在前面。

實(shí)現(xiàn)的原理以及為什么不能用了

原理:自定義一個(gè)雙向數(shù)據(jù)綁定的指令,代碼如下:

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官網(wǎng)上可能不太容易找到,因?yàn)檫@些是vue1中的內(nèi)容,而在vue2中已經(jīng)被移除了。所以在vue2中我們是不能這么干的,當(dāng)然如果你使用的是vue1那么完全沒問題,直接拿去用即可。

解決思路二:使用組件

單獨(dú)聲明一個(gè)組件,在組件內(nèi)部處理數(shù)據(jù)(也就是innerHTML),并將數(shù)據(jù)返回給父組件。

代碼如下:

v-html="innerText"

@input="changeText">

exportdefault{

props: ['value'],

? ? ? ? data(){

return{innerText:this.value}

? ? ? ? },

methods:{

? ? ? ? ? ? changeText(){

this.innerText =this.$el.innerHTML;

this.$emit('input',this.innerText);

? ? ? ? ? ? }

? ? ? ? }

? ? }

然后在父組件中直接使用v-model就可以了(這里我把組件名稱定義成了 v-edit-div)。

{{text}}

exportdefault{

? ? ? ? data(){

return{

text:'改一下試一試',

? ? ? ? ? ? }

? ? ? ? }

? ? }

至于為什么可以直接用v-model,看官網(wǎng)的 API 吧。

v-model 傳送門使用自定義事件的表單輸入組件,那一章節(jié)。

問題解決。

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

忙的不行,之前在評(píng)論區(qū)也有發(fā)現(xiàn)這個(gè)例子其實(shí)會(huì)有不少的問題,包括如何實(shí)現(xiàn)異步數(shù)據(jù)的刷新,更新值之后光標(biāo)定位的問題等等,在考慮了異步數(shù)據(jù)和光標(biāo)問題后,有了以下的這個(gè)版本

<template>

v-html="innerText"

:contenteditable="canEdit"

@focus="isLocked = true"

@blur="isLocked = false"

@input="changeText">

? ? </div>

</template>

exportdefault{

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>

? ? .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>

這個(gè)版本是在項(xiàng)目中最終使用的版本,需要用的直接拿走用即可。

注:

canEdit標(biāo)志這個(gè)div是否是可編輯的,在父組件直接使用v-model即可。

該組件應(yīng)該是一個(gè)div元素(也不一定非要是div)的子元素,父元素的大小即為子元素的大

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • "use strict";function _classCallCheck(e,t){if(!(e instanc...
    久些閱讀 2,156評(píng)論 0 2
  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML標(biāo)準(zhǔn)。 注意:講述HT...
    kismetajun閱讀 28,886評(píng)論 1 45
  • 這篇筆記主要包含 Vue 2 不同于 Vue 1 或者特有的內(nèi)容,還有我對(duì)于 Vue 1.0 印象不深的內(nèi)容。關(guān)于...
    云之外閱讀 5,187評(píng)論 0 29
  • 組件(Component)是Vue.js最核心的功能,也是整個(gè)架構(gòu)設(shè)計(jì)最精彩的地方,當(dāng)然也是最難掌握的。...
    六個(gè)周閱讀 5,783評(píng)論 0 32
  • 可編輯div可能很簡單contenteditable="true" 就能實(shí)現(xiàn)了 但是,,,輸入一個(gè)字的時(shí)候,焦點(diǎn)會(huì)...
    晴空萬里_d3c2閱讀 5,529評(píng)論 1 6

友情鏈接更多精彩內(nèi)容