customText.vue 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. <!-- 搜索表单 -->
  2. <template>
  3. <div>
  4. <el-popover
  5. style="position: fixed; z-index: 2000"
  6. width="130"
  7. ref="popoverRef"
  8. v-model="rightClickShow"
  9. @click.native="rightClickShow = false"
  10. >
  11. <div>
  12. <el-button type="primary" @click="addHtml">插入输入框</el-button>
  13. </div>
  14. </el-popover>
  15. <div
  16. v-html="form"
  17. :contenteditable="edit"
  18. class="contenteditable"
  19. :ref="id"
  20. :id="id"
  21. @contextmenu.prevent="onRightClick($event)"
  22. >
  23. </div>
  24. </div>
  25. </template>
  26. <script>
  27. import dictMixins from '@/mixins/dictMixins';
  28. import { generateRandomString } from '@/utils/util';
  29. export default {
  30. props: {},
  31. mixins: [dictMixins],
  32. props: {
  33. id: '',
  34. edit: {
  35. default: true,
  36. type: Boolean
  37. },
  38. readonly: {
  39. default: false,
  40. type: Boolean
  41. }
  42. },
  43. data() {
  44. return {
  45. form: null,
  46. valueObj: {},
  47. equation: {},
  48. units: {},
  49. domId: '',
  50. rightClickShow: false
  51. };
  52. },
  53. methods: {
  54. addHtml() {
  55. this.insertInput();
  56. },
  57. objInit() {
  58. if (Object.keys(this.valueObj).length) {
  59. for (let key in this.valueObj) {
  60. this.$nextTick(() => {
  61. let dom = document.getElementById(key);
  62. dom.value = this.valueObj[key];
  63. });
  64. }
  65. }
  66. },
  67. insertInput() {
  68. const selection = window.getSelection();
  69. if (selection.rangeCount > 0) {
  70. const range = selection.getRangeAt(0);
  71. this.getParentID(range.commonAncestorContainer);
  72. if (this.getParentID(range.commonAncestorContainer)) {
  73. range.setStart(selection.anchorNode, selection.anchorOffset);
  74. range.setEnd(selection.focusNode, selection.focusOffset);
  75. range.deleteContents(); // 删除选中的内容(如果需要)
  76. range.insertNode(this.getInput()); // 插入input元素
  77. // 可以设置光标位置在input之后
  78. range.selectNodeContents(this.getInput());
  79. range.collapse(false); // 光标放在input之后
  80. selection.removeAllRanges();
  81. selection.addRange(range);
  82. }
  83. // return
  84. }
  85. },
  86. getParentID(data) {
  87. if (data.id == this.id) {
  88. return true;
  89. }
  90. if (data.parentElement) {
  91. return this.getParentID(data.parentElement);
  92. }
  93. },
  94. getInput() {
  95. let id = generateRandomString();
  96. const inputElement = document.createElement('input');
  97. inputElement.setAttribute('type', 'text');
  98. inputElement.setAttribute('class', 'templateInput');
  99. inputElement.setAttribute('autocomplete', 'off');
  100. inputElement.setAttribute('id', id);
  101. return inputElement;
  102. },
  103. getValue() {
  104. let inputs = document.querySelectorAll(
  105. '#' + this.id + ' .templateInput'
  106. );
  107. let data = {};
  108. if (inputs.length) {
  109. inputs.forEach((item) => {
  110. data[item.id] = item.value;
  111. });
  112. }
  113. return {
  114. form: this.$refs[this.id].innerHTML,
  115. valueObj: data,
  116. equation: this.equation,
  117. units: this.units
  118. };
  119. },
  120. equationValue({ domId, value }) {
  121. if (domId) {
  122. let dom = document.getElementById(domId);
  123. if (dom) {
  124. this.valueObj[domId] = value;
  125. dom.value = value;
  126. }
  127. }
  128. },
  129. init({ form, valueObj, equation, units }) {
  130. this.form = form;
  131. this.valueObj = valueObj;
  132. this.equation = equation || {};
  133. this.units = units || {};
  134. this.$nextTick(() => {
  135. if (this.readonly) {
  136. let inputs = document.querySelectorAll('.templateInput');
  137. inputs.forEach((item) => {
  138. item.setAttribute('readonly', 'readonly');
  139. });
  140. }
  141. });
  142. this.objInit();
  143. },
  144. editInputChange(domObj) {
  145. let dom = document.getElementById(this.domId);
  146. dom.style.width = domObj.width + 'px';
  147. if (domObj.readonly == 2) {
  148. dom.setAttribute('readonly', 'readonly');
  149. } else {
  150. dom.removeAttribute('readonly');
  151. }
  152. delete this.valueObj[dom.id];
  153. this.valueObj[domObj.id] = dom.value;
  154. if (domObj.equation) {
  155. this.equation[domObj.id] = domObj.equation;
  156. }
  157. if (domObj.units) {
  158. this.units[domObj.id] = domObj.units;
  159. }
  160. dom.id = domObj.id;
  161. },
  162. onRightClick(PointerEvent) {
  163. this.rightClickShow = true;
  164. this.$nextTick(() => {
  165. let y = PointerEvent.pageY;
  166. let x = PointerEvent.pageX + 10;
  167. if (PointerEvent.screenY >= PointerEvent.view.innerHeight) {
  168. y -= 80;
  169. }
  170. this.$refs.popoverRef.$el.style.top = y + 'px';
  171. this.$refs.popoverRef.$el.style.left = x + 'px';
  172. });
  173. },
  174. inputChange(event) {
  175. if (event.target && event.target.className == 'templateInput') {
  176. this.valueObj[event.target.id] = event.target.value;
  177. this.$emit('calculation');
  178. }
  179. },
  180. inputClick(event) {
  181. if (!this.edit) {
  182. return;
  183. }
  184. if (event.target && event.target.className == 'templateInput') {
  185. this.domId = event.target.id;
  186. this.$emit('editShow', {
  187. templateDivRef: 'customTextRef' + this.id,
  188. domObj: {
  189. width: event.target.offsetWidth,
  190. id: event.target.id,
  191. readonly: event.target.readOnly ? 2 : 1,
  192. equation: this.equation[this.domId],
  193. units: this.units[this.domId] || {}
  194. }
  195. });
  196. }
  197. }
  198. },
  199. mounted() {
  200. this.$nextTick(() => {
  201. document
  202. .getElementById(this.id)
  203. .addEventListener('input', this.inputChange);
  204. document
  205. .getElementById(this.id)
  206. .addEventListener('click', this.inputClick);
  207. });
  208. }
  209. };
  210. </script>
  211. <style lang="scss" scoped>
  212. :deep(.templateInput) {
  213. width: 80px;
  214. border: solid 1px #bfbfbf;
  215. padding: 1px;
  216. margin: 1px;
  217. margin-left: 3px;
  218. text-align: center;
  219. }
  220. .contenteditable {
  221. // padding: 5px;
  222. width: 100%;
  223. min-height: 20px;
  224. padding-left: 10px;
  225. // border: solid 1px #b3b0b0;
  226. }
  227. </style>