Vue實現(xiàn)contenteditable元素雙向綁定的方法詳解
前言
如何實現(xiàn)一個即時通訊的聊天頁面,網(wǎng)上有很多的開源或不開源的成品,可以直接使用,或者簡單修改后使用。但在實際項目中,直接使用開源的即時通訊往往不是我們想要的,如何自己開發(fā)一個聊天頁面呢。本文就著學(xué)習(xí)的目的,從0開始一步步實現(xiàn)一個聊天框的開發(fā),至于消息的發(fā)送和接收,這個就得依靠后端大佬了。
在開發(fā)前,首先得明確用什么來實現(xiàn)。用input
輸入框和textare
文本輸入肯定是不行的,這兩個只能輸入文本類數(shù)據(jù)(輸入法表情也算),想要在輸入框內(nèi)展示圖片、表情包或回復(fù)消息等復(fù)雜內(nèi)容時就不行了。靈光一閃,展示圖片這些用富文本不就好了,但仔細想想,使用富文本不就引入額外的組件了嘛。想要自己實現(xiàn)一個類似“富文本”輸入框,就需要借助contenteditable
來實現(xiàn)。
本項目需要解決的問題:
實現(xiàn)一個可輸入文本、圖片等復(fù)雜消息的輸入框
實現(xiàn)數(shù)據(jù)的“雙向綁定”
contenteditable
contenteditable
是所有HTML元素都有的枚舉屬性,表示元素是否可以被用戶編輯??捎糜谒性兀遣皇撬性貙υ搶傩远计鹱饔?。如果元素支持該屬性,并且設(shè)置了contenteditable
,則瀏覽器會修改元素以允許編輯。
關(guān)于contenteditable
需要注意:
- true或者空字符串,表示元素可編輯
- false,表示元素不可編輯
- 如果沒有設(shè)置該屬性的值,則其值被視為空字符串
- 如果沒有設(shè)置該屬性或者設(shè)置了無效值,則其值默認繼承自父元素。如果父元素是可編輯的,那么該子元素也是可編輯的;否則,該子元素不可編輯。
- 雖然該屬性可以設(shè)置true、false,但是
contenteditable
是一個枚舉屬性而不是布爾屬性。
本項目采用對div
增加contenteditable
屬性實現(xiàn)輸入框。
基礎(chǔ)使用
首先新建一個Vue項目(如果只是實現(xiàn)demo,也可以不創(chuàng)建Vue項目),vue create simple-chat-inputbox
,采用默認的即可(新版vue-cli默認新建的是Vue3項目,本項目采用Vue2)。
然后進入項目,npm run serve
運行起來,不運行怎么能看到效果呢。
在實際開發(fā)前,先做好準(zhǔn)備工作:
- 初始化本地倉庫,并關(guān)聯(lián)遠端倉庫(可選)
- 取消
App.vue
中的默認樣式,隱藏HelloWorld
新建InputBox.vue
,作為輸入框組件
... <div class="input-box" contenteditable="true"></div> ... <style scoped> .input-box { width: 400px; height: 250px; border: 1px solid #6e6e6e; outline: none; /* 隱藏聚焦時外邊框 */ padding: 10px; } </style>
注冊并引入InputBox.vue
,運行后如下圖:
此時就可以在輸入框中就可以輸入你想輸入的內(nèi)容,但是僅僅是輸入,怎么獲取值,以及怎么實現(xiàn)雙向綁定呢。
進階使用
在自定義事件 — Vue.js (vuejs.org)有一句話:
一個組件上的 v-model
默認會利用名為 value
的 prop 和名為 input
的事件,仍然需要在組件的 props
選項里聲明 value
這個 prop
根據(jù)此特性,我們再來改造一下項目:
雖然div
變成了可編輯,但是并不能像input
一樣直接使用v-model
來完成雙向綁定,但我們可以另辟蹊徑,模擬實現(xiàn)雙向綁定。首先我們需要創(chuàng)建兩個組件:InputBox.vue
和DivEditable.vue
,分別表示父組件和子組件,對外只提供父組件。
對于父組件來說,只需要使用v-model
傳入值就行。
// InputBox.vue <template> <div> <DivEditable v-model="inputContent" /> <input type="text" v-model="inputContent"> <div @click="changeValue">父組件修改子組件的值</div> </div> </template> <script> import DivEditable from '@/components/DivEditable' export default { name: 'inputBox', data() { return { inputContent: '', } }, watch: { inputContent(val) { console.log('父組件接收到的輸入框的值', val); } }, components: { DivEditable }, methods: { changeValue() { this.inputContent = this.model1; } } } </script>
子組件處理就相對復(fù)雜點,需要接收值并且監(jiān)聽事件:
<template> <div ref="editor" class="input-box" contenteditable="true" @input="inputText" @blur="inputBlur" @focus="inputFocus"></div> </template> <script> export default { name: 'inputBox', props: ['value'], // 父組件v-model綁定的prop data() { return { isBlur: true, // 解決賦值時光標(biāo)自動定位到起始位置 } }, watch: { value(val) { if (this.isBlur) { this.$refs.editor.innerHTML = val; } } }, methods: { // 監(jiān)聽輸入框內(nèi)容 inputText() { console.log('子組件輸入框的輸入內(nèi)容', this.$refs.editor.innerHTML); this.$emit('input', this.$refs.editor.innerHTML); }, inputFocus() { this.isBlur = false; }, inputBlur() { this.isBlur = true; } } } </script> <style scoped> .input-box { width: 400px; height: 250px; border: 1px solid #6e6e6e; outline: none; /* 隱藏聚焦時外邊框 */ padding: 10px; } </style>
雖然div
不可以使用v-model
,但是可以監(jiān)聽input
、focus
、blur
等事件。上述代碼其實并不復(fù)雜,主要就是利用了v-model
的特性。有一點需要說明,由于是“雙向綁定”,子組件里面輸入的值會通過父組件賦值到子組件,導(dǎo)致子組件的光標(biāo)始終處于起始位置,因此需要增加一個isBlur
變量,用來解決這個問題。感興趣的可以試一下去掉isBlur
會是什么效果。
運行結(jié)果如下圖:
通過修改父組件輸入框的值,子組件對應(yīng)的值也會發(fā)生改變;同理,修改子組件也是同樣的效果?;緦崿F(xiàn)了“雙向綁定”。
總結(jié)
本文基于contenteditable,實現(xiàn)可“雙向綁定”的輸入框
實現(xiàn)雙向綁定,可以動態(tài)賦值,或者根據(jù)用戶的輸入實時處理,例如輸入@的時候彈出渲染的彈窗,在選擇用戶后再插入到輸入框
項目完整代碼可參考 項目地址,接下來將陸續(xù)介紹怎么實現(xiàn)粘貼文本、圖片,以及對光標(biāo)的處理。
到此這篇關(guān)于Vue實現(xiàn)contenteditable元素雙向綁定的方法詳解的文章就介紹到這了,更多相關(guān)Vue元素雙向綁定內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue.js內(nèi)置組件之keep-alive組件使用
keep-alive是Vue.js的一個內(nèi)置組件。這篇文章主要介紹了vue.js內(nèi)置組件之keep-alive組件使用,需要的朋友可以參考下2018-07-07使用typescript構(gòu)建Vue應(yīng)用的實現(xiàn)
這篇文章主要介紹了使用typescript構(gòu)建Vue應(yīng)用的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08