|
@@ -0,0 +1,311 @@
|
|
|
|
+<template>
|
|
|
|
+ <div>
|
|
|
|
+ <div
|
|
|
|
+ :id="id"
|
|
|
|
+ class="edit-div"
|
|
|
|
+ v-html="content"
|
|
|
|
+ :contenteditable="canEdit"
|
|
|
|
+ @compositionstart="compositStart"
|
|
|
|
+ @compositionend="compositEnd"
|
|
|
|
+ @paste="copyText"
|
|
|
|
+ @focus="isLocked = true"
|
|
|
|
+ @blur="handleBlur"
|
|
|
|
+ @input="input"
|
|
|
|
+ @keyup.enter="handleReplaceTone"
|
|
|
|
+ :style="{ textAlign: textAlign }"
|
|
|
|
+ placeholder=" "
|
|
|
|
+ ></div>
|
|
|
|
+ <!-- :placeholder="placeholder_value" -->
|
|
|
|
+ <div class="limit" v-if="isShow">{{ textSize }}/{{ maxLength }}</div>
|
|
|
|
+ </div>
|
|
|
|
+</template>
|
|
|
|
+<script>
|
|
|
|
+export default {
|
|
|
|
+ name: 'editDiv',
|
|
|
|
+ props: {
|
|
|
|
+ value: {
|
|
|
|
+ type: String,
|
|
|
|
+ default: '',
|
|
|
|
+ },
|
|
|
|
+ canEdit: {
|
|
|
|
+ type: Boolean,
|
|
|
|
+ default: true,
|
|
|
|
+ },
|
|
|
|
+ placeholder: {
|
|
|
|
+ type: String,
|
|
|
|
+ default: '',
|
|
|
|
+ },
|
|
|
|
+ id: {
|
|
|
|
+ type: String,
|
|
|
|
+ default: 'sendMsg',
|
|
|
|
+ },
|
|
|
|
+ textAlign: {
|
|
|
|
+ type: String,
|
|
|
|
+ default: 'left',
|
|
|
|
+ },
|
|
|
|
+ isShow: {
|
|
|
|
+ type: Boolean,
|
|
|
|
+ default: false,
|
|
|
|
+ },
|
|
|
|
+ maxLength: {
|
|
|
|
+ type: Number,
|
|
|
|
+ default: 200,
|
|
|
|
+ },
|
|
|
|
+ hengIndex: {
|
|
|
|
+ type: Number,
|
|
|
|
+ default: null,
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ data() {
|
|
|
|
+ return {
|
|
|
|
+ isLocked: false,
|
|
|
|
+ textSize: 0,
|
|
|
|
+ lock: true,
|
|
|
|
+ fullContent: '',
|
|
|
|
+ content: this.value, // 文本数据
|
|
|
|
+ tableData: [
|
|
|
|
+ ['ā', 'á', 'ǎ', 'à', 'a'],
|
|
|
|
+ ['ō', 'ó', 'ǒ', 'ò', 'o'],
|
|
|
|
+ ['ē', 'é', 'ě', 'è', 'e'],
|
|
|
|
+ ['ī', 'í', 'ǐ', 'ì', 'i'],
|
|
|
|
+ ['ū', 'ú', 'ǔ', 'ù', 'u'],
|
|
|
|
+ ['ǖ', 'ǘ', 'ǚ', 'ǜ', 'ü'],
|
|
|
|
+ ['Ā', 'Á', 'Â', 'À', 'A'],
|
|
|
|
+ ['Ō', 'Ó', 'Ô', 'Ò', 'O'],
|
|
|
|
+ ['Ē', 'É', 'Ê', 'È', 'E'],
|
|
|
|
+ ['Ī', 'Í', 'Î', 'Ì', 'I'],
|
|
|
|
+ ['Ū', 'Ú', 'Û', 'Ù', 'U'],
|
|
|
|
+ ],
|
|
|
|
+ };
|
|
|
|
+ },
|
|
|
|
+ watch: {
|
|
|
|
+ value() {
|
|
|
|
+ if (!this.isLocked && !this.content) {
|
|
|
|
+ this.content = this.value;
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ computed: {
|
|
|
|
+ placeholder_value() {
|
|
|
|
+ let value = '';
|
|
|
|
+ let _this = this;
|
|
|
|
+ if (_this.placeholder == 'place_en') {
|
|
|
|
+ value = '';
|
|
|
|
+ } else {
|
|
|
|
+ value = '';
|
|
|
|
+ }
|
|
|
|
+ if (_this.textAlign == 'left' || !_this.textAlign) {
|
|
|
|
+ value = ' ' + value;
|
|
|
|
+ } else if (_this.textAlign == 'center') {
|
|
|
|
+ value = value;
|
|
|
|
+ } else if (_this.textAlign == 'right') {
|
|
|
|
+ value = value + ' ';
|
|
|
|
+ }
|
|
|
|
+ return value;
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ methods: {
|
|
|
|
+ // 输入中文开始时
|
|
|
|
+ compositStart(e) {
|
|
|
|
+ this.lock = false;
|
|
|
|
+ let id = '#' + this.id;
|
|
|
|
+ document.querySelector(id).focus();
|
|
|
|
+ document.execCommand('selectAll', false, null);
|
|
|
|
+ document.getSelection().collapseToEnd();
|
|
|
|
+ },
|
|
|
|
+ // 输入中文结束时
|
|
|
|
+ compositEnd(e) {
|
|
|
|
+ this.lock = true;
|
|
|
|
+ this.input(e);
|
|
|
|
+ },
|
|
|
|
+ input(e) {
|
|
|
|
+ if (this.lock) {
|
|
|
|
+ this.textSize = e.target.innerHTML.length;
|
|
|
|
+ if (this.textSize >= this.maxLength) {
|
|
|
|
+ this.textSize = this.maxLength;
|
|
|
|
+ this.fullContent = e.target.innerHTML.substring(0, this.maxLength);
|
|
|
|
+ e.target.innerHTML = e.target.innerHTML.substring(0, this.maxLength);
|
|
|
|
+ } else {
|
|
|
|
+ this.fullContent = '';
|
|
|
|
+ }
|
|
|
|
+ this.$emit('input', e.target.innerHTML);
|
|
|
|
+ //this.content = e.target.innerHTML;
|
|
|
|
+ this.textFocus();
|
|
|
|
+ } else if (this.fullContent) {
|
|
|
|
+ // 目标对象:超过200字时候的中文输入法
|
|
|
|
+ // 原由:虽然不会输入成功,但是输入过程中字母依然会显现在输入框内
|
|
|
|
+ // 弊端:谷歌浏览器输入法的界面偶尔会闪现
|
|
|
|
+ e.target.innerHTML = this.fullContent;
|
|
|
|
+ this.lock = true;
|
|
|
|
+ this.textFocus();
|
|
|
|
+ }
|
|
|
|
+ this.$emit('saveBlankTF', e.target.innerHTML, this.hengIndex);
|
|
|
|
+ },
|
|
|
|
+ // 粘贴富文本转为纯文本
|
|
|
|
+ copyText(e) {
|
|
|
|
+ e.stopPropagation();
|
|
|
|
+ e.preventDefault();
|
|
|
|
+ let text = '',
|
|
|
|
+ event = e.originalEvent || e;
|
|
|
|
+ if (event.clipboardData && event.clipboardData.getData) {
|
|
|
|
+ text = event.clipboardData.getData('text/plain');
|
|
|
|
+ } else if (window.clipboardData && window.clipboardData.getData) {
|
|
|
|
+ text = window.clipboardData.getData('Text');
|
|
|
|
+ }
|
|
|
|
+ if (document.queryCommandSupported('insertText')) {
|
|
|
|
+ document.execCommand('insertText', false, text);
|
|
|
|
+ } else {
|
|
|
|
+ document.execCommand('paste', false, text);
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ // 文本输入框聚焦,焦点在最后位置
|
|
|
|
+ textFocus() {
|
|
|
|
+ let _this = this;
|
|
|
|
+ setTimeout(() => {
|
|
|
|
+ let id = '#' + _this.id;
|
|
|
|
+ document.querySelector(id).focus();
|
|
|
|
+ document.execCommand('selectAll', false, null);
|
|
|
|
+ document.getSelection().collapseToEnd();
|
|
|
|
+ }, 0);
|
|
|
|
+ },
|
|
|
|
+ handleReplaceTone(e) {
|
|
|
|
+ let _this = this;
|
|
|
|
+ _this.$nextTick(() => {
|
|
|
|
+ let value = e.target.innerHTML;
|
|
|
|
+ _this.resArr = [];
|
|
|
|
+ if (value) {
|
|
|
|
+ let reg = /\s+/g;
|
|
|
|
+ let valueArr = value.split(reg);
|
|
|
|
+ valueArr.forEach((item, index) => {
|
|
|
|
+ this.handleValue(item);
|
|
|
|
+ });
|
|
|
|
+ let str = '';
|
|
|
|
+ setTimeout(() => {
|
|
|
|
+ _this.resArr.forEach((item) => {
|
|
|
|
+ str += ' ';
|
|
|
|
+ item.forEach((sItem) => {
|
|
|
|
+ if (sItem.number && sItem.con) {
|
|
|
|
+ let number = Number(sItem.number);
|
|
|
|
+ let con = sItem.con;
|
|
|
|
+ let word = _this.addTone(number, con);
|
|
|
|
+ str += word;
|
|
|
|
+ } else {
|
|
|
|
+ if (sItem.number) {
|
|
|
|
+ str += sItem.number;
|
|
|
|
+ } else if (sItem.con) {
|
|
|
|
+ str += ' ' + sItem.con + ' ';
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ });
|
|
|
|
+ e.target.innerHTML = str.trim();
|
|
|
|
+ _this.fullContent = str.trim();
|
|
|
|
+ _this.$emit('input', str.trim());
|
|
|
|
+ _this.textFocus();
|
|
|
|
+ }, 10);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ },
|
|
|
|
+ handleValue(valItem) {
|
|
|
|
+ let reg = /\d/;
|
|
|
|
+ let reg2 = /[A-Za-z]+\d/g;
|
|
|
|
+ let numList = [];
|
|
|
|
+ let valArr = valItem.split('');
|
|
|
|
+ if (reg2.test(valItem)) {
|
|
|
|
+ for (let i = 0; i < valArr.length; i++) {
|
|
|
|
+ let item = valItem[i];
|
|
|
|
+ if (reg.test(item)) {
|
|
|
|
+ let numIndex = numList.length == 0 ? 0 : numList[numList.length - 1].index;
|
|
|
|
+ let con = valItem.substring(numIndex, i);
|
|
|
|
+ con = con.replace(/\d/g, '');
|
|
|
|
+ let obj = {
|
|
|
|
+ index: i,
|
|
|
|
+ number: item,
|
|
|
|
+ con: con,
|
|
|
|
+ isTran: true,
|
|
|
|
+ };
|
|
|
|
+ numList.push(obj);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ numList = [];
|
|
|
|
+ }
|
|
|
|
+ if (numList.length == 0) {
|
|
|
|
+ this.resArr.push([{ con: valItem }]);
|
|
|
|
+ } else {
|
|
|
|
+ this.resArr.push(numList);
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ addTone(number, con) {
|
|
|
|
+ let _this = this;
|
|
|
|
+ let zmList = ['a', 'o', 'e', 'i', 'u', 'v', 'A', 'O', 'E', 'I', 'U'];
|
|
|
|
+ if (number) {
|
|
|
|
+ for (let i = 0; i < zmList.length; i++) {
|
|
|
|
+ let zm = zmList[i];
|
|
|
|
+ if (con.indexOf(zm) > -1) {
|
|
|
|
+ let zm2 = _this.tableData[i][number - 1];
|
|
|
|
+ if (con.indexOf('iu') > -1) {
|
|
|
|
+ zm2 = _this.tableData[4][number - 1];
|
|
|
|
+ con = con.replace('u', zm2);
|
|
|
|
+ } else if (con.indexOf('ui') > -1) {
|
|
|
|
+ zm2 = _this.tableData[3][number - 1];
|
|
|
|
+ con = con.replace('i', zm2);
|
|
|
|
+ } else if (
|
|
|
|
+ con.indexOf('yv') > -1 ||
|
|
|
|
+ con.indexOf('jv') > -1 ||
|
|
|
|
+ con.indexOf('qv') > -1 ||
|
|
|
|
+ con.indexOf('xv') > -1
|
|
|
|
+ ) {
|
|
|
|
+ zm2 = _this.tableData[4][number - 1];
|
|
|
|
+ con = con.replace('v', zm2);
|
|
|
|
+ } else {
|
|
|
|
+ con = con.replace(zm, zm2);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return con;
|
|
|
|
+ },
|
|
|
|
+ handleBlur(e) {
|
|
|
|
+ this.isLocked = false;
|
|
|
|
+ e.target.innerHTML = e.target.innerHTML.replace(/ /gi, '').trim();
|
|
|
|
+ this.$emit('input', e.target.innerHTML);
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ mounted() {
|
|
|
|
+ if (this.content) {
|
|
|
|
+ this.textSize = this.content.length;
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+};
|
|
|
|
+</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;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+.limit {
|
|
|
|
+ position: absolute;
|
|
|
|
+ right: 0px;
|
|
|
|
+ bottom: 0px;
|
|
|
|
+ font-size: 16px;
|
|
|
|
+ line-height: 24px;
|
|
|
|
+ color: rgba(0, 0, 0, 0.45);
|
|
|
|
+}
|
|
|
|
+</style>
|