index.vue 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. <template>
  2. <div>
  3. <div class="edit-box div_MAX_Height" contenteditable="true" :placeholder="placeholder" v-html="content" :key="keys" :id="keys"
  4. @blur="saveValue($event)" @click="getFocus($event)" v-on:paste="handlePaste($event)">
  5. </div>
  6. </div>
  7. </template>
  8. <script>
  9. export default {
  10. components: {},
  11. props:{
  12. value:{
  13. type:String,
  14. default:(value)=>{
  15. return ""
  16. }
  17. },
  18. placeholder:{
  19. type:String,
  20. default:()=>{
  21. return "请输入"
  22. }
  23. },
  24. keys:{
  25. type:String,
  26. default:()=>{
  27. const len = 6
  28. const codeList = []
  29. const chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz0123456789'
  30. const charsLen = chars.length
  31. for (let i = 0; i < len; i++) {
  32. codeList.push(chars.charAt(Math.floor(Math.random() * charsLen)))
  33. }
  34. return codeList.join('')
  35. }
  36. }
  37. },
  38. data() {
  39. return {
  40. content: this.value||"", // 内容
  41. };
  42. },
  43. watch: {
  44. value(val){
  45. this.content = val
  46. },
  47. },
  48. computed: {},
  49. created() {},
  50. mounted() {},
  51. methods: {
  52. open(){
  53. console.log(1)
  54. },
  55. async handlePaste(event){
  56. const items = (event.clipboardData || window.clipboardData).items;
  57. let file = null;
  58. if (!items || items.length === 0) {
  59. this.$message.error("当前浏览器不支持本地");
  60. return;
  61. }
  62. for (let i = 0; i < items.length; i++) {
  63. // if (items[i].type.indexOf("text") !== -1) {
  64. // var text = (e.originalEvent || e).clipboardData.getData('text/plain') || prompt('在这里输入文本');
  65. // //清除回车
  66. // text = text.replace(/\[\d+\]|\n|\r/ig,"")
  67. // var content = event.target.innerHTML
  68. // var str2 = content.slice(0, index.endOffset) + text + content.slice(index.endOffset);
  69. // event.target.innerHTML = str2
  70. // this.saveValue(event)
  71. // // this.$forceUpdate()
  72. // // if(this.tableHeight){
  73. // // this.setHeight()
  74. // // }
  75. // break;
  76. // }
  77. if (items[i].type.indexOf("image") !== -1) {
  78. var e = event || window.event
  79. e.preventDefault();
  80. file = items[i].getAsFile();
  81. break;
  82. }
  83. }
  84. if (!file) {
  85. return;
  86. }
  87. var content = event.target.innerHTML
  88. var str = await this.fileToBase64(file)
  89. var randNum=Math.floor(Math.random()*(9999-1000))+1000;;
  90. var new_img = '<img key="'+ randNum +'" src="' + str + '" style="width:80px;height: 80px;border: 1px solid #f9f6f675;vertical-align:middle">';
  91. // 创建新的光标对象
  92. // var range = document.createRange();
  93. // // 将光标对象的范围界定为新建的表情节点
  94. // range.selectNodeContents(new_img);
  95. // // 定位光标位置在表情节点的最大长度位置
  96. // range.setStart(new_img, new_img.length);
  97. // // 将选区折叠为一个光标
  98. // range.collapse(true);
  99. // // 清除所有光标对象
  100. // selection.removeAllRanges();
  101. // // 添加新的光标对象
  102. // selection.addRange(range);
  103. // console.log(event.target.innerHTML)
  104. var index = window.getSelection().getRangeAt(0)
  105. var indexText = this.getColumn(event.target,window.getSelection())
  106. var index2 = 0
  107. var str2 = content.slice(0, indexText) + new_img + content.slice(indexText);
  108. event.target.innerHTML = str2
  109. this.$nextTick(()=>{
  110. var selectedText = window.getSelection();
  111. var selectedRange = document.createRange();
  112. try{
  113. for(var i=0;i<event.target.childNodes.length;i++){
  114. if(event.target.childNodes[i].outerHTML == new_img){
  115. index2 = i
  116. throw new Error()
  117. }
  118. }
  119. }catch{
  120. }
  121. selectedRange.setStart(event.target,index2+1);
  122. selectedRange.collapse(true);
  123. selectedText.removeAllRanges();
  124. selectedText.addRange(selectedRange);
  125. event.target.parentNode.focus();
  126. })
  127. // this.saveValue(event)
  128. // var selection = window.getSelection()
  129. // window.getSelection().addRange(this.index)
  130. // console.log(window.getSelection().getRangeAt(0))
  131. },
  132. getColumn(node, selectObj) {
  133. var baseNode = node;
  134. var anchorNodePosition = this.getPosition(baseNode, selectObj.anchorNode, selectObj.anchorOffset);
  135. var focusNodePosition = this.getPosition(baseNode, selectObj.focusNode, selectObj.focusOffset);
  136. var num = Math.min(anchorNodePosition, focusNodePosition)
  137. return num;
  138. },
  139. getNodes(baseNode, path) {
  140. // 拿到所有类型的节点
  141. var temPath = path;
  142. if (baseNode != null) {
  143. temPath.push(baseNode);
  144. if (baseNode.childNodes.length > 0) {
  145. for (let i = 0; i < baseNode.childNodes.length; i++) {
  146. this.getNodes(baseNode.childNodes[i], temPath);
  147. }
  148. }
  149. }
  150. },
  151. getPosition(baseNode, node, offset) {
  152. //根据节点获取给定node中offset位置在栏位中的实际位置
  153. let path = [];
  154. this.getNodes(baseNode, path);
  155. var retIdx = 0;
  156. for (let i = 0; i < path.length; i++) {
  157. if (path[i] == node) {
  158. retIdx += offset;
  159. return retIdx;
  160. } else {
  161. if (path[i].nodeType == 3) {
  162. retIdx += path[i].nodeValue.length;
  163. }else if(i!=0 && path[i].nodeType == 1){
  164. retIdx += path[i].outerHTML.length;
  165. }
  166. }
  167. }
  168. },
  169. // 将file文件上传转化为base64进行显示
  170. fileToBase64(file) {
  171. return new Promise((resolve, reject) => {
  172. const reader = new FileReader()
  173. //开始读文件
  174. reader.readAsDataURL(file)
  175. reader.onload = () => resolve(reader.result)
  176. // 失败返回失败的信息
  177. reader.onerror = error => reject(error)
  178. })
  179. },
  180. getFocus(event){
  181. event.target.parentNode.focus();
  182. },
  183. saveValue(event){
  184. var a = event.target.innerHTML
  185. this.$emit('input',a)
  186. }
  187. },
  188. };
  189. </script>
  190. <style lang="scss" scoped>
  191. .edit-box{
  192. overflow-x: hidden;
  193. text-overflow: ellipsis;
  194. padding: 0 15px;
  195. min-height:40px;
  196. line-height: 40px;
  197. outline: #dcdfe6;
  198. border:1px solid #DCDFE6;
  199. border-radius:5px;
  200. div{
  201. height:30px !important;
  202. line-height: 30px !important;
  203. }
  204. }
  205. .edit-box:empty::before {
  206. content: attr(placeholder);
  207. // margin-left:15px;
  208. font-style: normal;
  209. white-space: nowrap;
  210. color: #cacdd4;
  211. }
  212. // .edit-box:focus::before {
  213. // content:none;
  214. // }
  215. </style>