实现自己写的小程序富文本编辑以及展示,不跟PC端的兼容,但是可以在pc端显示以及修改,一旦修改,小程序不再做解析
富文本结构:
1 <div class="detail_box"> 2 <ul> 3 <li v-for="(item4,index4) in detailAry" :key="index4"> 4 <!-- 文字 --> 5 <div class="detail_list"> 6 <div class="list_t"> 7 <div class="list_l"> 8 <span>{{item4.title}}</span> 9 </div> 10 <div class="list_r"> 11 <div class="r_left"> 12 <img v-if="index4 == 0" src="https://img.xingxio.com/Group 7@2x (1).png" alt=""> 13 <img v-else @click="changeIndexL(index4)" src="https://img.xingxio.com/Group 7@2x.png" alt=""> 14 <img v-if="index4 == detailAry.length-1 && index4 != 0" src="https://img.xingxio.com/Group 11@2x.png" alt=""> 15 <img v-else @click="changeIndexR(index4)" src="https://img.xingxio.com/Group 8@2x.png" alt=""> 16 </div> 17 <div class="r_right"> 18 <img @click="delDetailAry(index4)" v-show="index4 >0" class="del_img" src="https://img.xingxio.com/close_icon.png" alt=""> 19 </div> 20 </div> 21 </div> 22 <div class="inp_box" v-if="item4.type == 1"> 23 <!-- <input type="text" v-model="item4.text" placeholder="请输入文字"> --> 24 <textarea v-show="isChange" class="textarea" maxlength="1000" v-model="item4.text" placeholder="填写多行,可以换行,最多填写1000字"></textarea> 25 </div> 26 <!-- <div class="inp_box" v-if="item4.type == 2"> --> 27 <div class="img_box" v-if="item4.type == 2"> 28 <img class="img" :src="item4.src" alt="" mode="aspectFit"> 29 </div> 30 <div class="img_box" v-if="item4.type == 3"> 31 <video :controls="controls" :autoplay="false" :src="item4.src"></video> 32 <div class="v_tips">苹果手机暂不支持播放视频</div> 33 <!-- <img class="img" :src="item4.src" alt="" mode="aspectFit"> --> 34 </div> 35 <!-- </div> --> 36 </div> 37 <!-- 图片 --> 38 <!-- <div class="detail_list img_list" v-if="item4.type == 2"> 39 <div class="list_t"> 40 <div class="list_l"> 41 <span>{{item4.title}}</span> 42 </div> 43 <div class="list_r"> 44 <img src="https://img.xingxio.com/Group 7@2x (1).png" alt=""> 45 <img src="https://img.xingxio.com/Group 7@2x.png" alt=""> 46 <img src="https://img.xingxio.com/Group 8@2x.png" alt=""> 47 <img src="https://img.xingxio.com/Group 11@2x.png" alt=""> 48 <img class="del_img" src="https://img.xingxio.com/close_icon.png" alt=""> 49 </div> 50 </div> 51 <div class="inp_box"> 52 <div class="img_box"> 53 <img class="img" :src="item4.src" alt="" mode="aspectFill"> 54 </div> 55 </div> 56 </div> --> 57 <!-- 视频 --> 58 <!-- <div class="detail_list img_list"> 59 <div class="list_t"> 60 <div class="list_l"> 61 <span>视频</span> 62 </div> 63 <div class="list_r"> 64 <img class="del_img" src="https://img.xingxio.com/close_icon.png" alt=""> 65 </div> 66 </div> 67 <div class="inp_box"> 68 <div class="img_box"> 69 <video></video> 70 </div> 71 </div> 72 </div> --> 73 </li> 74 </ul> 75 <div class="detail_f"> 76 <div class="f_list" @click="addDetailAry(1,'文字')"> 77 <img src="https://img.xingxio.com/text_icon.png" alt=""> 78 <span>文字</span> 79 </div> 80 <div class="f_list" @click="updateImg(6)"> 81 <img class="p_img" src="https://img.xingxio.com/image_icon.png" alt=""> 82 <span>图片</span> 83 </div> 84 <div class="f_list" v-if="false" > 85 <img class="yuyin_img" src="https://img.xingxio.com/yuyin_icon.png" alt=""> 86 <span>语音</span> 87 </div> 88 <div class="f_list" @click="uploadVideo"> 89 <img src="https://img.xingxio.com/video_icon.png" alt=""> 90 <span>视频</span> 91 </div> 92 </div> 93 </div>
富文本样式:
1 .detail_box { 2 width: 100%; 3 padding: 20rpx; 4 box-sizing: border-box; 5 ul { 6 width: 100%; 7 margin-bottom: 100rpx; 8 height: auto; 9 li{ 10 width: 100%; 11 height: auto; 12 .detail_list { 13 width: 100%; 14 .list_t { 15 width: 100%; 16 height: 80rpx; 17 display: flex; 18 align-items: center; 19 justify-content: space-between; 20 .list_l { 21 color: #4A4A4A; 22 font-size: 32rpx; 23 } 24 .list_r { 25 width: 200rpx; 26 height: 100%; 27 display: flex; 28 align-items: center; 29 justify-content: space-between; 30 .r_left { 31 width: 122rpx; 32 display: flex; 33 align-items: center; 34 justify-content: space-between; 35 img { 36 width: 36rpx; 37 height: 36rpx; 38 } 39 } 40 .r_right { 41 display: flex; 42 align-items: center; 43 img { 44 width: 36rpx; 45 height: 36rpx; 46 } 47 } 48 } 49 } 50 .inp_box { 51 margin-top: 20rpx; 52 width: 100%; 53 height: 300rpx; 54 input { 55 width: 100%; 56 line-height: 80rpx; 57 border: 0px; 58 padding-left: 20rpx; 59 box-sizing: border-box; 60 font-size: 28rpx; 61 } 62 .textarea { 63 width: 100%; 64 height: 280rpx; 65 border: 0px; 66 padding-left: 20rpx; 67 box-sizing: border-box; 68 font-size: 28rpx; 69 } 70 71 } 72 .img_box { 73 width: 100%; 74 height: 300rpx; 75 padding: 20rpx; 76 box-sizing: border-box; 77 img { 78 width: 100%; 79 height: 100%; 80 } 81 video { 82 width: 280rpx; 83 height: 180rpx; 84 } 85 .v_tips { 86 margin-top: 20rpx; 87 font-size: 28rpx; 88 color: #9B9B9B; 89 text-align: center; 90 // line-height: 100%; 91 } 92 } 93 } 94 95 } 96 } 97 98 .detail_f { 99 width: 100%; 100 height: 100rpx; 101 border-radius: 6rpx; 102 color: rgba(16, 16, 16, 1); 103 font-size: 28rpx; 104 105 // box-shadow: 0px 0px 8rpx 2rpx rgba(0, 0, 0, 0.07); 106 font-family: Arial; 107 // border: 1px solid rgba(231, 236, 242, 1); 108 display: flex; 109 align-items: center; 110 padding: 0px 30rpx; 111 box-sizing: border-box; 112 justify-content: space-between; 113 .f_list { 114 height: 100%; 115 display: flex; 116 align-items:center; 117 justify-content: center; 118 flex-direction: column; 119 img { 120 width: 32rpx; 121 height: 32rpx; 122 123 } 124 .p_img { 125 width: 34rpx; 126 } 127 .yuyin_img { 128 width: 34rpx; 129 height: 34rpx; 130 } 131 span { 132 margin-top: 12rpx; 133 color: #9B9B9B; 134 font-size: 28rpx; 135 // margin-left: 10rpx; 136 } 137 } 138 139 } 140 141 }
效果图:
既然要兼容到pc端上的编辑器(本pc项目使用的是百度编辑器),所以存数据的时候带上标签传给后台
/** * 处理详情的图文 */ handleDetail(){ console.log(this.detailAry) let ary = [] for (let i = 0; i < this.detailAry.length; i++) { if(this.detailAry[i].type == 1){ let arr2 = [] arr2.push(this.detailAry[i].text) // this.detailAry[i].text =arr2.join(`<br/>`) this.detailAry[i].text = this.detailAry[i].text.replace(/\n/g,"<br/>") console.log(this.detailAry[i].text) let text = `<div data-type="${1}">${this.detailAry[i].text}</div>` ary.push(text) }else if(this.detailAry[i].type == 2){ let imgs = `<div data-type="${2}"><img src="${this.detailAry[i].src}" alt=""></div>` ary.push(imgs) }else if(this.detailAry[i].type == 3){ console.log(this.detailAry[i].src) let video = `<div data-type="${3}"><video controls='true' src="${this.detailAry[i].src}"></video></div>` ary.push(video) } } console.log(ary) this.txt = ary.join('\n') console.log(this.txt) },
然而数据返回也是一个json的格式,所以解析方法,这是一个封装的方法,中间引用到一个插件的
xmldom是一个解析标签的,因为小程序么有dom元素,也没有js中获取某某某的id啊 百度搜索xmldom就可以找到了 支持npm下载
/** * 解析富文本 */ export const txtResolve = function(txt){ if (txt) { console.log(txt) let doc = new DOMParser().parseFromString(txt) console.log(doc) let ary1 = doc.documentElement.getElementsByTagName('div') let detailAry = [] console.log(ary1) if(ary1.length > 0){ for (let i = 0; i < ary1.length; i++) { if(ary1[i].attributes[0].nodeValue == 1){ let arr2 = ary1[i].childNodes let arr3 = [] let str = '' for (let j = 0; j < arr2.length; j++) { if(arr2[j].nodeValue){ arr3.push(`${arr2[j].nodeValue}`) }else { arr3.push(`\n`) } } str = arr3.join('') let obj = { type: 1, title: '文字', text: str } detailAry.push(obj) } if(ary1[i].attributes[0].nodeValue == 2){ let obj = { type: 2, title: '图片', src: ary1[i].firstChild.getAttribute('src') } detailAry.push(obj) } if(ary1[i].attributes[0].nodeValue == 3){ let obj = { type: 3, title: '视频', src: ary1[i].firstChild.getAttribute('src') } detailAry.push(obj) } if(ary1[i].attributes[0].nodeValue == 4){ let srcs = [] // console.log(ary1[i].childNodes) for (let k = 0; k < ary1[i].childNodes.length; k++) { // console.log(ary1[i].childNodes[k].getAttribute('src')) srcs.push(ary1[i].childNodes[k].getAttribute('src')) } // console.log(srcs) let obj = { type: 4, title: '多图', srcs: srcs } detailAry.push(obj) } } } console.log(detailAry) return detailAry } else { return [] } }
注释: 每一个编辑的文本或者图片都是一个对象,数组循环,还有点击上下可以改变顺序,上下顺序的执行方法
/** * 控制详情排序 */ changeIndexL(index){ // 上升 // console.log(index) // console.log(this.detailAry) if(index != 0){ this.swapArray(this.detailAry,index,index-1) }else { return false; } }, changeIndexR(index){ // 下降 // console.log(index) if(index != this.detailAry.length){ this.swapArray(this.detailAry,index,index+1) }else { return false; } }, swapArray(arr,index1,index2){ arr[index1] = arr.splice(index2,1,arr[index1])[0]; // console.log(arr) return arr },