用於微信小程序的圖文編輯器

因爲微信小程序不能使用常規的圖文編輯器(好比百度的UEditor )編輯新聞內容之類的,因此用vue寫了個針對小程序用的圖文編輯器。效果以下javascript

 

多圖上傳圖片用到了  ajaxfileupload.js (不知道哪位仁兄寫的,拿來用了,很好用)html

 

最終造成一串Json數據(轉成字符串,傳入後臺存入數據庫,小程序端用JSON.parse 轉成JSON ,按照後臺同樣的方式渲染便可【小程序端代碼還沒寫,後面再貼出來吧】)vue

json格式如java

[{"mytype":1,"content":"測試數據\n\n11111\n\n","font":{"size":0,"weight":1,"del":1,"line":0,"center":1,"color":"#ED1C24","bgcolor":"#fff","showcolor":0}},{"mytype":3,"content":""},{"mytype":2,"content":"/upload/dyProductImgs/20180725/9841925131090216.jpg_E500_100.jpg","loading":1,"groupid":"627459ec-d372-e372-218e-b93b83cb2d02"},{"mytype":2,"content":"/upload/dyProductImgs/20180725/1574162212592205.jpg_E500_100.jpg","loading":1,"groupid":"627459ec-d372-e372-218e-b93b83cb2d02"},{"mytype":2,"content":"/upload/dyProductImgs/20180725/8745023656415428.jpg_E500_100.jpg","loading":1,"groupid":"627459ec-d372-e372-218e-b93b83cb2d02"},{"mytype":2,"content":"/upload/dyProductImgs/20180725/7027501123579481.jpg_E500_100.jpg","loading":1,"groupid":"627459ec-d372-e372-218e-b93b83cb2d02"}]

  

 

html代碼jquery

 1 <div class="editor-box vue-container">
 2     <div class="vuefor" v-for="i in editorData.length+1" v-on:click="hidecolorbox(i-1)">
 3         <div class="tool-box">
 4             <div class="tool-box-sub">
 5                 <div class="tool-list">
 6                     <div v-if="reload">
 7                         <input type="file" v-on:change.stop="uploadfile(i-1)" v-bind:id="buildfileid(i-1)" v-bind:name="buildfileid(i-1)" multiple="multiple">
 8                     </div>
 9                     <label class="tool-item" v-on:click.stop="itemadd(i-1,1)">
 10                         <div class="icon"><img src="~/res/img/icon-font.png" alt="" /></div>
 11                         <div class="text">文字</div>
 12                     </label>
 13                     <!--v-on:click.stop="itemadd(i-1,2)"-->
 14                     <label class="tool-item" v-bind:for="buildfileid(i-1)">
 15                         <div class="icon"><img src="~/res/img/icon-img.png" alt="" /></div>
 16                         <div class="text">圖片</div>
 17                     </label>
 18                     <label class="tool-item" v-on:click.stop="itemadd(i-1,3)">
 19                         <div class="icon"><img src="~/res/img/icon-line.png" alt="" /></div>
 20                         <div class="text">分割</div>
 21                     </label>
 22                     <label class="tool-item enabled" v-on:click.stop="itemadd(i-1,4)">
 23                         <div class="icon"><img src="~/res/img/icon-video.png" alt="" /></div>
 24                         <div class="text">視頻</div>
 25                     </label>
 26                     <label class="tool-item enabled" v-on:click.stop="itemadd(i-1,5)">
 27                         <div class="icon"><img src="~/res/img/icon-link.png" alt="" /></div>
 28                         <div class="text">連接</div>
 29                     </label>
 30                 </div>
 31             </div>
 32         </div>
 33         <div class="editor-item" v-if="i <= editorData.length">
 34 
 35             <div class="head">
 36                 <div class="h-btn fleft" v-on:click.stop="itemup(i-1)">
 37                     <img src="~/res/img/icon-up.png" />
 38                 </div>
 39                 <div class="h-btn fleft" v-on:click.stop="itembottom(i-1)">
 40                     <img src="~/res/img/icon-bottom.png" />
 41                 </div>
 42                 <div class="h-btn fright" v-on:click.stop="itemdel(i-1)">
 43                     <img src="~/res/img/icon-del.png" />
 44                 </div>
 45             </div>
 46             <div class="content" v-if="editorData[i-1].mytype==1">
 47                 <!--文字類型的輸入框-->
 48                 <div class="text-box">
 49                     <div class="head">
 50                         <div title="加粗" v-on:click.stop="fontweight(i-1)" v-bind:class="{ 'head-btn': true,'sel':editorData[i-1].font.weight==1 }"><img src="~/res/img/icon-font-weight.png" alt="" /></div>
 51                         <div title="放大字體" v-on:click.stop="fontda(i-1)" v-bind:class="{ 'head-btn': true}"><img src="~/res/img/icon-font-da.png" alt="" /></div>
 52                         <div title="縮小字體" v-on:click.stop="fontxiao(i-1)" v-bind:class="{ 'head-btn': true}"><img src="~/res/img/icon-font-xiao.png" alt="" /></div>
 53                         <div title="刪除線" v-on:click.stop="fontdel(i-1)" v-bind:class="{ 'head-btn': true,'sel':editorData[i-1].font.del==1 }"><img src="~/res/img/icon-font-del.png" alt="" /></div>
 54                         <div title="下劃線" v-on:click.stop="fontline(i-1)" v-bind:class="{ 'head-btn': true,'sel':editorData[i-1].font.line==1 }"><img src="~/res/img/icon-font-line.png" alt="" /></div>
 55                         <div title="居中" v-on:click.stop="fontcenter(i-1)" v-bind:class="{ 'head-btn': true,'sel':editorData[i-1].font.center==1 }"><img src="~/res/img/icon-font-center.png" alt="" /></div>
 56                         <div title="字體顏色" v-on:click.stop="fontshowcolor(i-1)" v-bind:class="{ 'head-btn': true }" v-bind:style="initfontcolor(editorData[i-1].font)">
 57  A  58                             <div v-on:click.stop="stopclick" class="color-box" v-bind:class="{'hide':editorData[i-1].font.showcolor!=1}">
 59                                 <div class="color-title">
 60  字體顏色  61                                 </div>
 62                                 <div class="color-list">
 63                                     <div class="color-item" v-for="color in colors">
 64                                         <span v-on:click.stop="fontsetcolor(i-1,color)" v-bind:style="initbgcolor(color)"></span>
 65                                     </div>
 66                                 </div>
 67                                 <div class="color-title">
 68  字體顏色代碼  69                                 </div>
 70                                 <div class="color-input">
 71                                     <input type="text" v-model="editorData[i-1].font.color" />
 72                                 </div>
 73                                 <!--<div class="color-title">  74  字體背景顏色  75  </div>  76  <div class="color-list">  77  <div class="color-item" v-for="color in colors">  78  <span v-on:click.stop="fontsetcolor(i-1,color)" v-bind:style="initbgcolor(color)"></span>  79  </div>  80  </div>  81  <div class="color-title">  82  字體背景顏色代碼  83  </div>  84  <div class="color-input">  85  <input type="text" v-model="editorData[i-1].font.bgcolor" />  86  </div>-->
 87                             </div>
 88                         </div>
 89                     </div>
 90                     <div class="line"></div>
 91                     <div class="input">
 92                         <textarea name="" rows="" cols="" v-bind:style="initstyle(editorData[i-1].font)" v-model="editorData[i-1].content"></textarea>
 93                     </div>
 94                     <div class="line"></div>
 95                 </div>
 96             </div>
 97 
 98             <div class="content" v-if="editorData[i-1].mytype==2" style="">
 99                 <!--圖片-->
100                 <div class="img-box">
101                     <img v-if="editorData[i-1].loading==1" v-bind:src="editorData[i-1].content" alt="" />
102                     <img class="loading" v-if="editorData[i-1].loading==0" src="~/res/img/img_loading.gif" alt="" />
103                 </div>
104             </div>
105 
106             <div class="content" v-if="editorData[i-1].mytype==3">
107                 <!--分割線-->
108                 <div class="line-box">
109                 </div>
110             </div>
111 
112             <div class="clear" style=""></div>
113         </div>
114     </div>
115 </div>
HTML代碼

js 代碼web

須要引用 jquery、vue、ajaxfileuploadajax

var pageData = { editorData: [], colors: [ "#000", "#7F7F7F", "#880015", "#ED1C24", "#FF7F27", "#FFF200", "#22B14C", "#3F48CC", "#E36C09", "#31859B", "#5F497A", "#76923C", "#953734", "#366092", "#938953", "#fff" ], reload:true }; //初始化vue var vmMenu = new Vue({ el: '.vue-container', data: pageData, methods: { //生成一個fileid buildfileid: function (index) { return "file" + index; }, initstyle: function (font) { var stylestr = ""; var fontsize = 18; fontsize += font.size * 3; stylestr += "font-size: " + fontsize + "px;" if (font.weight == 1) stylestr += "font-weight: bold;" if (font.del == 1) stylestr += "text-decoration:line-through;" if (font.line == 1) stylestr += "text-decoration:underline;" if (font.center == 1) stylestr += "text-align: center;" if (font.color) stylestr += ("color:" + font.color + ";"); if (font.bgcolor) stylestr += ("display: inline;background-color:" + font.bgcolor + ";"); return stylestr; }, //字體的顏色 initfontcolor: function (font) { var result = ""; result += "color:"; result += font.color; result += ";"; result += "background-color:"; result += font.bgcolor; result += ";"; return result; }, //字體背景的顏色 initbgcolor: function (color) { return "background-color:" + color; }, //加粗或者取消嘉措 fontweight: function (index) { pageData.editorData[index].font.weight = (pageData.editorData[index].font.weight == 1 ? 0 : 1); }, //字體加大 fontda: function (index) { pageData.editorData[index].font.size++; }, //字體減少 fontxiao: function (index) { pageData.editorData[index].font.size--; }, //刪除線 fontdel: function (index) { pageData.editorData[index].font.del = (pageData.editorData[index].font.del == 1 ? 0 : 1); }, //下劃線 fontline: function (index) { pageData.editorData[index].font.line = (pageData.editorData[index].font.line == 1 ? 0 : 1); }, //居中顯示 fontcenter: function (index) { pageData.editorData[index].font.center = (pageData.editorData[index].font.center == 1 ? 0 : 1); }, fontshowcolor: function (index) { pageData.editorData[index].font.showcolor = (pageData.editorData[index].font.showcolor == 1 ? 0 : 1); }, //選擇字體顏色 fontsetcolor: function (index, color) { pageData.editorData[index].font.color = color; this.hidecolorbox(index); }, //隱藏顏色選擇框 hidecolorbox: function (index) { if (pageData.editorData && pageData.editorData.length > index && pageData.editorData[index].mytype == 1) pageData.editorData[index].font.showcolor = 0; }, //上傳圖片 uploadfile: function (index) { //用於強制從新渲染 input.file 用於清空以前的文件 ^_^ pageData.reload = false; //添加一個組ID,方便後面上傳完成後識別應該更新哪條數據 var groupid = guid(); var that = this; var fileid = "file" + index; var files = $("#" + fileid)[0].files; for (var i = 0; i < files.length; i++) { that.itemadd(index + i, 2, groupid); } jQuery.ajaxFileUpload({ url: '@Url.Content("~/img/uploadproductdpicArray?path=dyProductImgs")', //用於文件上傳的服務器端請求地址 secureuri: false, //是否須要安全協議,通常設置爲false fileElementId: fileid, //文件上傳域的ID dataType: 'json', //返回值類型 通常設置爲json success: function (data) //服務器成功響應處理函數 { //var result = JSON.parse(data); pageData.reload = true; var result = data; console.log(result); if (result.resultState == "1") { var j = 0; for (var i = 0; i < pageData.editorData.length; i++) { if (pageData.editorData[i].groupid && pageData.editorData[i].groupid == groupid) { pageData.editorData[i].content = "@Url.Content("~")" + result.Data[j].substring(1); pageData.editorData[i].loading = 1; j++; } } console.log(result); } else alert("上傳失敗!"); }, error: function (data)//服務器響應失敗處理函數 { alert("上傳失敗!"); } }); }, //上升模塊 itemup: function (index) { if (index > 0) { var itemData = pageData.editorData[index]; pageData.editorData.splice(index, 1); pageData.editorData.splice(index - 1, 0, itemData); } }, //降低模塊 itembottom: function (index) { if (index + 1 < pageData.editorData.length) { var itemData = pageData.editorData[index]; pageData.editorData.splice(index, 1); pageData.editorData.splice(index + 1, 0, itemData); } }, //刪除模塊 itemdel: function (index) { pageData.editorData.splice(index, 1); }, //添加一個新的模塊 itemadd: function (index, type, groupid) { var itemData = null; switch (type) { case 1: itemData = { mytype: 1, content: "", font: { size: 0, //字體大小 每+1 字體+2px -1同減 weight: 0, //是否加粗 del: 0, //是否刪除線 line: 0, //是否下劃線 center: 0, //是否居中 color: "#000", //字體顏色 bgcolor: "#fff", //字體顏色 showcolor: 0 //是否顯示顏色選擇框 } }; break; case 2: itemData = { mytype: 2, content: "res/img/1.jpg", loading: 0 //是否已經成功上傳 }; break; case 3: itemData = { mytype: 3, content: "" }; break; default: alert('暫不支持'); break; } if (itemData) { if (groupid) itemData.groupid = groupid; pageData.editorData.splice(index, 0, itemData); } }, //一個用於阻止冒泡的事件 stopclick: function () { }, }, //實例被調用後 created: function () { }, //el 被新建立的 vm.$el 替換,並掛載到實例上去以後調用該鉤子。 updated: function () { this.$nextTick(function () { ////console.log(pageData); //var files = this.$refs.feedbakcImg; //for (var i = 0; i < files.length; i++) { // files[i].clearFiles(); //} }) } });
JS代碼

 

後臺代碼 .net (有些方法沒有放出來,後面我有時間整理一個單獨的demo出來放到雲盤)數據庫

/// <summary>
        /// 批量上傳商品詳情圖片 /// </summary>
        /// <returns></returns>
 [HttpPost] public ContentResult uploadproductdpicArray(string path) { rData<List<string>> result = new rData<List<string>>(); result = UpLoadPicArray(path); if (result.resultState == 1) for (int i = 0; i < result.Data.Count; i++) { if (ST.Tool.ImageHelp.GetImageSuffix(result.Data[i]) != ".gif") { string imgPath = Server.MapPath($"~{result.Data[i]}"); string imgPathNoSuffix = imgPath.Substring(0, imgPath.LastIndexOf(".")); string imgSuffix = ST.Tool.ImageHelp.GetImageSuffix(imgPath); Image oldimg = Image.FromFile(imgPath); //讀取圖片 //壓縮寬度爲500的圖片,等比 清晰度 100
                     ST.Tool.ImageHelp.PicThumbnail(oldimg, imgPath + "_E500_100" + imgSuffix, 500, 0, 100); oldimg.Dispose(); result.Data[i] = result.Data[i] + "_E500_100" + imgSuffix; } } var jsonResult = JsonConvert.SerializeObject(result); return new ContentResult() { Content = jsonResult }; } /// <summary>
        /// 上傳圖片 /// </summary>
        /// <param name="_path">保存圖片的文件夾名稱</param>
        /// <returns>保存結果</returns>
        private rData<string> UpLoadPic(string _path="public") { rData<string> result = new rData<string>(); HttpFileCollectionBase _file = Request.Files; if (_file.Count > 0) { long size = _file[0].ContentLength; string type = _file[0].ContentType; string name = _file[0].FileName; //文件格式
                string _tp = Path.GetExtension(name); if (_tp.ToLower() == ".jpg" || _tp.ToLower() == ".jpeg" || _tp.ToLower() == ".gif" || _tp.ToLower() == ".png" || _tp.ToLower() == ".swf") { Stream stream = _file[0].InputStream; Image image = Image.FromStream(stream); string dateDir = DateTime.Now.ToString("yyyyMMdd"); string saveName = ST.Tool.ExpandString.GetNonceNumberT(16) + _tp; string filePath = $"{BaseConfig.headpath}{_path}/{dateDir}/"; string path = Server.MapPath(filePath); if (!Directory.Exists(path)) Directory.CreateDirectory(path); //_file[0].SaveAs(Server.MapPath($"{filePath}{saveName}")); //初始化圖片對象 //Image image = new Bitmap(Server.MapPath($"{filePath}{saveName}"));
                    foreach (var p in image.PropertyItems) { if (p.Id == 0x112) { var rft = p.Value[0] == 6 ? RotateFlipType.Rotate90FlipNone : p.Value[0] == 3 ? RotateFlipType.Rotate180FlipNone : p.Value[0] == 8 ? RotateFlipType.Rotate270FlipNone : p.Value[0] == 1 ? RotateFlipType.RotateNoneFlipNone : RotateFlipType.RotateNoneFlipNone; p.Value[0] = 0;  //旋轉屬性值設置爲不旋轉
                            image.SetPropertyItem(p); //回拷進圖片流
 image.RotateFlip(rft); } } //從新保存爲正常的圖片
                    image.Save(Server.MapPath($"{filePath}{saveName}")); result.Data = $"{filePath}{saveName}"; } else result.errorMsg = "只能上傳圖片。"; } else result.errorMsg = "未選擇文件"; return result; } /// <summary>
        /// 上傳多張圖片 /// </summary>
        /// <param name="_path"></param>
        /// <returns></returns>
        private rData<List<string>> UpLoadPicArray(string _path = "public") { rData<List<string>> result = new rData<List<string>>(); result.Data = new List<string>(); HttpFileCollectionBase _file = Request.Files; if (_file.Count > 0) for (int i = 0; i < _file.Count; i++) { //Thread.Sleep(500);
                    long size = _file[i].ContentLength; string type = _file[i].ContentType; string name = _file[i].FileName; //文件格式
                    string _tp = Path.GetExtension(name); if (_tp.ToLower() == ".jpg" || _tp.ToLower() == ".jpeg" || _tp.ToLower() == ".gif" || _tp.ToLower() == ".png" || _tp.ToLower() == ".swf") { Stream stream = _file[i].InputStream; Image image = Image.FromStream(stream); string dateDir = DateTime.Now.ToString("yyyyMMdd"); string saveName = ST.Tool.ExpandString.GetNonceNumberT(16) + _tp; string filePath = $"{BaseConfig.headpath}{_path}/{dateDir}/"; string path = Server.MapPath(filePath); if (!Directory.Exists(path)) Directory.CreateDirectory(path); //_file[0].SaveAs(Server.MapPath($"{filePath}{saveName}")); //初始化圖片對象 //Image image = new Bitmap(Server.MapPath($"{filePath}{saveName}"));
                        foreach (var p in image.PropertyItems) { if (p.Id == 0x112) { var rft = p.Value[0] == 6 ? RotateFlipType.Rotate90FlipNone : p.Value[0] == 3 ? RotateFlipType.Rotate180FlipNone : p.Value[0] == 8 ? RotateFlipType.Rotate270FlipNone : p.Value[0] == 1 ? RotateFlipType.RotateNoneFlipNone : RotateFlipType.RotateNoneFlipNone; p.Value[0] = 0;  //旋轉屬性值設置爲不旋轉
                                image.SetPropertyItem(p); //回拷進圖片流
 image.RotateFlip(rft); } } //從新保存爲正常的圖片
                        image.Save(Server.MapPath($"{filePath}{saveName}")); result.Data.Add($"{filePath}{saveName}"); //result.Data = $"{filePath}{saveName}";
 } else result.errorMsg = "只能上傳圖片。"; } else result.errorMsg = "未選擇文件"; return result; }

 如今增長上微信小程序端的代碼 json

js:(對從接口返回的數據進行處理)小程序

//將後臺返回的數據轉成JSON格式。
            ProductDesc = JSON.parse(ProductDesc);
            if (ProductDesc)
              for (var p = 0; p < ProductDesc.length; p++) {
                ProductDesc[p].style = "";
                //若是是文字類型,須要設置樣式
                if (ProductDesc[p].mytype == 1 && ProductDesc[p].font) {
                  if (ProductDesc[p].font.del == 1) ProductDesc[p].style += "text-decoration:line-through;"
                  if (ProductDesc[p].font.line == 1) ProductDesc[p].style += "text-decoration:underline;"
                  if (ProductDesc[p].font.center == 1) ProductDesc[p].style += "text-align:center;"
                  if (ProductDesc[p].font.weight == 1) ProductDesc[p].style += "font-weight:bold;"
                  if (ProductDesc[p].font.color) ProductDesc[p].style += "color:" + ProductDesc[p].font.color + ';'
                  if (ProductDesc[p].font.size) ProductDesc[p].style += "font-size:" + (30 + 6 * ProductDesc[p].font.size) + 'rpx'
                }
              }

  view:(按照預約格式展示視圖)

<block wx:for="{{ProductDesc}}" wx:for-item="item" wx:key="index">
          <block wx:if="{{item.mytype==1&&item.font}}">
            <view class='ProductDesctext' style='{{item.style}}'>
              {{item.content}}
            </view>
          </block>
          <block wx:if="{{item.mytype==3}}">
            <view class='ProductDescline'></view>
          </block>
          <block wx:if="{{item.mytype==2}}">
            <image src='{{hostimg}}{{item.content}}' mode='widthFix'></image>
          </block>
        </block>
相關文章
相關標籤/搜索