在 vue2
中對錶單控件有着良好的雙向數據綁定機制,可是對於要特定實現某些功能的輸入時,咱們就不得不使用到 contenteditable="true"
的 div
,而在這個 div
上是使用 v-model
是沒有效果的。那麼問題就來了,輸入是很是須要雙向綁定的,這裏的雙向數據綁定該如何實現?css
固然,說在這一段的前面,這種解決方式在 vue2
中是不行的,爲何這麼說,由於如今去搜索這個問題絕大多數的搜索結果是這個,因此放在前面。html
原理:自定義一個雙向數據綁定的指令,代碼以下:vue
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
那麼徹底沒問題,直接拿去用便可。ecmascript
單獨聲明一個組件,在組件內部處理數據(也就是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)。ide
<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 傳送門 使用自定義事件的表單輸入組件,那一章節。ui
問題解決。this
=============== 分割線:更新於17-08-25 =====================spa
忙的不行,以前在評論區也有發現這個例子其實會有很多的問題,包括如何實現異步數據的刷新,更新值以後光標定位的問題等等,在考慮了異步數據和光標問題後,有了如下的這個版本雙向綁定
<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>
這個版本是在項目中最終使用的版本,須要用的直接拿走用便可。
注:
canEdit
標誌這個div是不是可編輯的,在父組件直接使用 v-model
便可。