本文將主要講解一下若是經過微信小程序來實現封裝一個富文本編輯器 Editor,可拿來即用。javascript
developers.weixin.qq.com/miniprogram…css
developers.weixin.qq.com/miniprogram…html
richTest.wxmljava
<view class="whole" id="richText">
<view style="height:{{textTool?'200':'100'}}rpx;"></view>
<view class="page-body">
<view class='wrapper'>
<editor id="editor" class="ql-container" placeholder="{{placeholder}}" showImgSize showImgToolbar showImgResize bindstatuschange="onStatusChange" read-only="{{readOnly}}" bindready="onEditorReady" bindfocus='bindfocus' bindblur='bindblur' bindinput='bindinput' >
</editor>
</view>
</view>
<view class="editor-toolbar" bindtap="format">
<view class="toolbar-2">
<view class="tool-item-cell">
<view class="tool-item-box">
<view class="cell-rg-shadow"></view>
<scroll-view scroll-x class="flex-sb" style="height:70rpx;white-space: nowrap;" >
<view class="tool-item">
<i class="iconfont icon-charutupian" data-tool_name='insertImage' bindtap="toolEvent"></i>
</view>
<view class="tool-item">
<i class="iconfont icon-font" data-tool_name='showTextTool' bindtap="toolEvent"></i>
</view>
<view class="tool-item">
<i class="iconfont icon-format-header-1 {{formats.header === 1 ? 'ql-active' : ''}}" data-tool_name='text_H1' data-name="header" data-value="{{1}}" bindtap="toolEvent"></i>
</view>
<view class="tool-item">
<i class="iconfont icon-date" data-tool_name='insertDate' bindtap="toolEvent"></i>
</view>
<view class="tool-item">
<i class="iconfont icon-undo" data-tool_name='undo' bindtap="toolEvent"></i>
</view>
<view class="tool-item">
<i class="iconfont icon-redo" data-tool_name='redo' bindtap="toolEvent"></i>
</view>
<view class="tool-item">
<i class="iconfont icon-shanchu" data-tool_name='clear' bindtap="toolEvent"></i>
</view>
</scroll-view>
</view>
</view>
<lable class='save-icon' style='background:{{appColorConfig.check_color}}' bindtap="getEditorContent" >
{{buttonTxt}}
</lable>
</view>
<view class="toolbar-1" wx:if="{{textTool}}">
<scroll-view scroll-x style="height:70rpx;white-space: nowrap;" >
<view class="tool-item">
<i class="iconfont icon-zitijiacu {{formats.bold ? 'ql-active' : ''}}" data-name="bold"></i>
</view>
<view class="tool-item">
<i class="iconfont icon-zitixieti {{formats.italic ? 'ql-active' : ''}}" data-name="italic"></i>
</view>
<view class="tool-item">
<i class="iconfont icon-zitixiahuaxian {{formats.underline ? 'ql-active' : ''}}" data-name="underline"></i>
</view>
<view class="tool-item">
<i class="iconfont icon-fengexian" bindtap='insertDivider'></i>
</view>
<view class="tool-item">
<i class="iconfont icon-zuoduiqi {{formats.align === 'left' ? 'ql-active' : ''}}" data-name="align" data-value="left"></i>
</view>
<view class="tool-item">
<i class="iconfont icon-juzhongduiqi {{formats.align === 'center' ? 'ql-active' : ''}}" data-name="align" data-value="center"></i>
</view>
<view class="tool-item">
<i class="iconfont icon-youduiqi {{formats.align === 'right' ? 'ql-active' : ''}}" data-name="align" data-value="right"></i>
</view>
<view class="tool-item">
<i class="iconfont icon-zuoyouduiqi {{formats.align === 'justify' ? 'ql-active' : ''}}" data-name="align" data-value="justify"></i>
</view>
<view class="tool-item">
<i class="iconfont icon--checklist" data-name="list" data-value="check"></i>
</view>
<view class="tool-item">
<i class="iconfont icon-youxupailie {{formats.list === 'ordered' ? 'ql-active' : ''}}" data-name="list" data-value="ordered"></i>
</view>
<view class="tool-item">
<i class="iconfont icon-wuxupailie {{formats.list === 'bullet' ? 'ql-active' : ''}}" data-name="list" data-value="bullet"></i>
</view>
</scroll-view>
</view>
</view>
</view>
複製代碼
richTest.wxssgit
@import "./assets/iconfont.wxss";
page {
background: #f8f8f8;
}
.page-body{
padding-bottom: 100rpx;
}
.editor-toolbar {
position: fixed;
top: 0;
left: 0;
width: 100%;
z-index: 9999;
}
.editor-toolbar i {
display: flex;
align-items: center;
justify-content: center;
}
.toolbar-1 {
padding: 5rpx 0;
background: #e4e4e4;
}
.editor-toolbar .tool-item {
display: inline-block;
}
.toolbar-2 {
padding: 5rpx 20px 5rpx 10px;
background: #f4f4f4;
display: flex;
align-items: center;
justify-content:space-between;
position: relative;
}
.toolbar-2 .tool-item-cell{
max-width: 80%;
}
.toolbar-2 .tool-item-box{
position: relative;
}
.toolbar-2 .cell-rg-shadow{
position: absolute;
right: 0;
top: 0;
width: 1px;
height: 100%;
z-index: 999;
background:#dddddd;
}
.iconfont {
display: inline-block;
padding: 8px 8px;
width: 24px;
height: 24px;
cursor: pointer;
font-size: 20px;
}
.toolbar {
box-sizing: border-box;
border-bottom: 0;
font-family: 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif;
}
.ql-container {
box-sizing: border-box;
padding: 12px 15px;
width: 100%;
min-height: 30vh;
height: auto;
background: #fff;
font-size: 16px;
line-height: 1.5;
}
.ql-active {
color: #06c;
}
.save-icon {
padding: 15rpx 30rpx;
font-size: 20rpx;
background: #bf98d2;
color: #fff;
}
.flex{
display: flex;
}
.flex-cc{
display: flex;
align-items: center;
-ms-flex-item-align: center;
justify-content: center;
}
.flex-sb{
display: flex;
align-items: center;
-ms-flex-item-align: center;
justify-content: space-between;
}
.flex-sa{
display: flex;
align-items: center;
-ms-flex-item-align: center;
justify-content: space-around;
}
複製代碼
richTest.jsgithub
富文本工具欄點擊事件json
toolEvent(res) {
let { tool_name } = res.currentTarget.dataset;
switch (tool_name) {
case 'insertImage': // 插入圖片
this.insertImageEvent();
break;
case 'showTextTool': // 展現文字編輯工具
this.showTextTool();
break;
case 'insertDate': // 插入日期
this.insertDate();
break;
case 'undo': // 撤退(向前)
this.undo();
break;
case 'redo': // 撤退(向後)
this.restore();
break;
case 'clear': // 清除
this.clearBeforeEvent();
break;
}
},
複製代碼
編輯器初始化完成時觸發小程序
onEditorReady() {
console.log('編輯器初始化完成時觸發')
this.triggerEvent('onEditorReady');
// 返回一個 SelectorQuery 對象實例。在自定義組件或包含自定義組件的頁面中,應使用this.createSelectorQuery()來代替。
// 對應API:https://developers.weixin.qq.com/miniprogram/dev/api/wxml/wx.createSelectorQuery.html
this.createSelectorQuery().select('#editor').context(res => {
console.log('createSelectorQuery=>', res)
this.editorCtx = res.context;
let rtTxt = '';
this.setContents(rtTxt); // 設置富文本內容
}).exec();
},
複製代碼
事件方法微信小程序
// 設置富文本內容
setContents(rechtext) {
this.editorCtx.setContents({
html: rechtext,
success: res => {
console.log('[setContents success]', res)
}
})
},
// 撤銷
undo() {
this.editorCtx.undo();
this.triggerEvent('undo');
},
// 恢復
restore() {
this.editorCtx.redo();
this.triggerEvent('restore');
},
// 清空編輯器內容
clear() {
this.editorCtx.clear({
success: res => {
this.triggerEvent('clearSuccess');
}
})
},
//清空編輯器內容前的事件
clearBeforeEvent() {
this.triggerEvent('clearBeforeEvent');
},
//清除當前選區的樣式
removeFormat() {
this.editorCtx.removeFormat();
},
//插入圖片事件
insertImageEvent() {
//觸發父組件選擇圖片方法
this.triggerEvent('insertImageEvent', {});
},
//插入日期
insertDate() {
if (supportDateFormat.indexOf(this.data.formatDate) < 0) {
console.error(`Format Date ${this.data.formatDate} error \n It should be one of them [${supportDateFormat}]`)
return;
}
let formatDate = this.getThisDate(this.data.formatDate);
this.editorCtx.insertText({
text: formatDate
})
},
//show展現文本工具欄
showTextTool() {
this.setData({
textTool: !this.data.textTool
})
},
//保存按鈕事件,獲取編輯器內容
getEditorContent() {
this.editorCtx.getContents({
success: res => {
// console.log('[getContents rich text success]', res)
this.triggerEvent('getEditorContent', {
value: res,
});
}
})
},
複製代碼
編輯器事件api
//編輯器聚焦時觸發
bindfocus(res) {
this.triggerEvent('bindfocus', {
value: res,
});
},
//編輯器失去焦點時觸發
bindblur(res) {
this.triggerEvent('bindblur', {
value: res,
});
},
//編輯器輸入中時觸發
bindinput(res) {
this.triggerEvent('bindinput', {
value: res,
});
},
複製代碼
插入圖片方法
/** * 插入圖片方法 * @param {String} path 圖片地址,僅支持 http(s)、base6四、雲圖片(2.8.0)、臨時文件(2.8.3) */
insertImageMethod(path) {
return new Promise((resolve, reject) => {
this.editorCtx.insertImage({
src: path,
data: {
id: 'imgage',
},
success: res => {
resolve(res);
},
fail: res => {
reject(res);
}
})
})
},
複製代碼
返回當前日期的方法
/** * 返回當前日期 * @format {String} 須要返回的日期格式 */
getThisDate(format) {
let date = new Date(),
year = date.getFullYear(),
month = date.getMonth() + 1,
day = date.getDate(),
h = date.getHours(),
m = date.getMinutes();
//數值補0方法
const zero = (value) => {
if (value < 10) return '0' + value;
return value;
}
switch (format) {
case 'YY-MM':
return year + '-' + zero(month);
case 'YY.MM.DD':
return year + '.' + zero(month) + '.' + zero(day);
case 'YY-MM-DD':
return year + '-' + zero(month) + '-' + zero(day);
case 'YY.MM.DD HH:MM':
return year + '.' + zero(month) + '.' + zero(day) + ' ' + zero(h) + ':' + zero(m);
case 'YY/MM/DD HH:MM':
return year + '/' + zero(month) + '/' + zero(day) + ' ' + zero(h) + ':' + zero(m);
case 'YY-MM-DD HH:MM':
return year + '-' + zero(month) + '-' + zero(day) + ' ' + zero(h) + ':' + zero(m);
default:
return year + '/' + zero(month) + '/' + zero(day);
}
}
複製代碼
index.js
編輯器初始化完成時觸發,能夠獲取組件實例
onEditorReady() {
console.log('[onEditorReady callback]')
richText = this.selectComponent('#richText'); //獲取組件實例
},
複製代碼
功能點實現
//設置富文本內容
setContents(rechtext) {
this.editorCtx.setContents({
html: rechtext,
success: res => {
console.log('[setContents success]', res)
}
})
},
//插入圖片
insertImageEvent() {
wx.chooseImage({
count: 1,
success: res => {
let path = res.tempFilePaths[0];
//調用子組件方法,圖片應先上傳再插入,否則預覽時沒法查看圖片。
richText.insertImageMethod(path).then(res => {
console.log('[insert image success callback]=>', res)
}).catch(res => {
console.log('[insert image fail callback]=>', res)
});
}
})
},
//保存,獲取編輯器內容
getEditorContent(res) {
let { value } = res.detail;
wx.showToast({
title: '獲取編輯器內容成功',
icon: 'none',
})
console.log('[getEditorContent callback]=>', value)
},
複製代碼
index.wxml
<richText id='richText' readOnly='{{readOnly}}' placeholder='{{placeholder}}' formatDate='YY/MM/DD' buttonTxt='保存' bind:clearBeforeEvent='clearBeforeEvent' bind:clearSuccess='clearSuccess' bind:undo='undo' bind:restore='restore' bind:onEditorReady='onEditorReady' bind:bindfocus='bindfocus' bind:bindblur='bindblur' bind:bindinput='bindinput' bind:insertImageEvent='insertImageEvent' bind:getEditorContent='getEditorContent'></richText>
<view class="tip">備註:
<view>1.改變圖片大小,按住節點一小會兒再拖動。</view>
<view>2.預覽內容中,圖片僅支持網絡url。</view>
</view>
<view class="preview" bindtap="preview">預覽</view>
複製代碼
歡迎 Star GitHub: https://github.com/jxh1997/Editor 。
因此源代碼均在 Github 上,下載便可使用。
git clone https://github.com/jxh1997/Editor.git
複製代碼
在下載源碼中找到組件目錄:components/richText
,將 richText 整個文件夾複製到你的項目中。
在 page.json
中引入組件
"usingComponents": {
"richText":"../../components/richText/richText"
},
複製代碼
在 page.wxml
中使用組件
<richText
id='richText'
readOnly='{{readOnly}}'
placeholder='{{placeholder}}'
formatDate='YY/MM/DD'
buttonTxt='保存'
bind:clearBeforeEvent='clearBeforeEvent'
bind:clearSuccess='clearSuccess'
bind:undo='undo'
bind:restore='restore'
bind:onEditorReady='onEditorReady'
bind:bindfocus='bindfocus'
bind:bindblur='bindblur'
bind:bindinput='bindinput'
bind:insertImageEvent='insertImageEvent'
bind:getEditorContent='getEditorContent'
> </richText>
複製代碼
在 page.js
中,接受富文本編輯器相關事件。具體執行代碼如上。