者 | 大澈
大家好,我是大澈!
今天的問題,來自于上周末問題留言的朋友 嘻嘻哈哈。
歡迎大家在周末的問題留言推文中,積極進(jìn)行問題留言,把這周工作日遇到的問題,分享給大家瞧瞧,或者直接進(jìn)問答群,一起交流嘮嘮。
遇到難題,遇到有共鳴的問題,一起討論,一起沉淀,一起成長。
ONE
需求分析,問題描述
一、需求
使用富文本進(jìn)行內(nèi)容編輯,要求自定義工具欄菜單順序及其分組,并且要求自定義選擇圖片、自定義選擇視頻。
二、問題
1、如何配置開始使用?
2、如何自定義工具欄菜單的展示?
3、如何自定義工具欄內(nèi)置菜單的功能?
4、如何自定義擴(kuò)展新功能菜單?
TWO
解決問題,答案速覽
實現(xiàn)代碼如下,復(fù)制粘貼即可直接使用。
如果你有時間,具體問題梳理、代碼分析、知識總結(jié),可見第三部分。
一、配置開始使用
1、下載依賴
npm i @wangeditor/editor @wangeditor/editor-for-vue
2、引入css和內(nèi)置組件
// 引入 css
import '@wangeditor/editor/dist/css/style.css'
// 引入 組件
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
// 引入 接口類型
import { IDomEditor, IEditorConfig } from "@wangeditor/editor";
3、使用
<template>
<div style="border: 1px solid #ccc">
<Toolbar
style="border-bottom: 1px solid #ccc"
:editor="editorRef"
:defaultConfig="toolbarConfig"
:mode="mode"
/>
<Editor
style="height: 500px; overflow-y: hidden;"
v-model="valueHtml"
:defaultConfig="editorConfig"
:mode="mode"
@onCreated="handleCreated"
/>
</div>
</template>
<script lang="ts" setup>
import "@wangeditor/editor/dist/css/style.css";
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
import { IDomEditor, IEditorConfig } from "@wangeditor/editor";
import { onBeforeUnmount, ref, shallowRef, onMounted } from 'vue'
// 編輯器實例,必須用 shallowRef
const editorRef=shallowRef()
// 內(nèi)容 HTML
const valueHtml=ref('<p>hello</p>')
// 模擬 ajax 異步獲取內(nèi)容
onMounted(()=> {
setTimeout(()=> {
valueHtml.value='<p>模擬 Ajax 異步設(shè)置內(nèi)容</p>'
}, 1500)
})
// 工具欄配置
const toolbarConfig={
toolbarKeys: []
}
// 編輯器配置
const editorConfig={
placeholder: '請輸入內(nèi)容...',
MENU_CONF: {}
}
// 組件銷毀時,也及時銷毀編輯器
onBeforeUnmount(()=> {
const editor=editorRef.value
if (editor==null) return
editor.destroy()
})
// 組件創(chuàng)建時
const handleCreated=(editor)=> {
editorRef.value=editor // 記錄 editor 實例,重要!
}
</script>
二、自定義工具欄菜單的展示
工具欄菜單的展示,如菜單的順序和分組、添加刪除。
如果想要自定義,只需修改工具欄配置對象的toolbarKeys屬性。toolbarKeys屬性值是一個數(shù)組,內(nèi)部填寫菜單的key,使用官方API接口editor.getAllMenuKeys()可查詢?nèi)績?nèi)置菜單的key。
// 工具欄配置
const toolbarConfig={
toolbarKeys: [
// 一些常用的菜單 key
'bold', // 加粗
'italic', // 斜體
'through', // 刪除線
'underline', // 下劃線
'bulletedList', // 無序列表
'numberedList', // 有序列表
'color', // 文字顏色
'insertLink', // 插入鏈接
'fontSize', // 字體大小
'lineHeight', // 行高
'uploadImage', // 上傳圖片
'uploadVideo',//上傳視頻
'delIndent', // 縮進(jìn)
'indent', // 增進(jìn)
'deleteImage',//刪除圖片
'divider', // 分割線
'insertTable', // 插入表格
'justifyCenter', // 居中對齊
'justifyJustify', // 兩端對齊
'justifyLeft', // 左對齊
'justifyRight', // 右對齊
'undo', // 撤銷
'redo', // 重做
'clearStyle', // 清除格式
'fullScreen' // 全屏
]
}
三、自定義工具欄內(nèi)置菜單的功能
工具欄菜單的功能,如鏈接、上傳圖片、上傳視頻。
如果想要自定義,只需修改編輯器配置對象的MENU_CONF屬性。不同的功能都對應(yīng)著不同的MENU_CONF屬性值,這里我以問題提出者的問題為示例,具體請參考官方文檔,寫的非常不錯的,放下面吧。
https://www.wangeditor.com/v5/menu-config.html
// 編輯器配置
const editorConfig={
placeholder: '請輸入內(nèi)容...',
MENU_CONF: {
// 上傳圖片
uploadImage: {
// 自定義選擇圖片
async customBrowseAndUpload(insertFn: InsertFnType) {
// 打開圖片素材庫
photoGalleryDialogVisible.value=true
},
},
// 上傳視頻
uploadVideo: {
// 自定義選擇視頻
async customBrowseAndUpload(insertFn: InsertFnType) {
// 打開視頻素材庫
videoGalleryDialogVisible.value=true
},
},
}
}
四、自定義擴(kuò)展新功能菜單
1、定義菜單class
目前可以自定義擴(kuò)展的功能菜單有按鈕、下拉、下拉面板、模態(tài)框。
新建myButtonMenu.ts文件,把下面代碼放進(jìn)去。
import { IButtonMenu, IDomEditor } from '@wangeditor/editor'
class MyButtonMenu implements IButtonMenu { // TS 語法
// class MyButtonMenu { // JS 語法
constructor() {
this.title='My menu title' // 自定義菜單標(biāo)題
// this.iconSvg='<svg>...</svg>' // 可選
this.tag='button'
}
// 獲取菜單執(zhí)行時的 value ,用不到則返回空 字符串或 false
getValue(editor: IDomEditor): string | boolean { // TS 語法
// getValue(editor) { // JS 語法
return ' hello '
}
// 菜單是否需要激活(如選中加粗文本,“加粗”菜單會激活),用不到則返回 false
isActive(editor: IDomEditor): boolean { // TS 語法
// isActive(editor) { // JS 語法
return false
}
// 菜單是否需要禁用(如選中 H1 ,“引用”菜單被禁用),用不到則返回 false
isDisabled(editor: IDomEditor): boolean { // TS 語法
// isDisabled(editor) { // JS 語法
return false
}
// 點(diǎn)擊菜單時觸發(fā)的函數(shù)
exec(editor: IDomEditor, value: string | boolean) { // TS 語法
// exec(editor, value) { // JS 語法
if (this.isDisabled(editor)) return
editor.insertText(value) // value 即 this.value(editor) 的返回值
}
}
2、注冊和插入菜單
定義菜單key時,要保證key唯一,不能和內(nèi)置菜單key重復(fù)。插入菜單時,將對應(yīng)的菜單key放在toolbarKeys想要的順序位置即可。
import { Boot } from '@wangeditor/editor'
import MyButtonMenu from './myButtonMenu'
// 工具欄配置
const toolbarConfig={
toolbarKeys: [
// 插入菜單key
'menu1',
]
}
// 組件創(chuàng)建時
const handleCreated=(editor: IDomEditor)=> {
editorRef.value=editor;
const menu1Conf={
key: 'menu1', // 定義 menu key :要保證唯一、不重復(fù)(重要)
factory() {
return new MyButtonMenu() // 替換為你菜單的 class
},
}
// 注冊菜單
Boot.registerMenu(menu1Conf)
};
THREE
問題解析,知識總結(jié)
一、如何配置開始使用?
補(bǔ)充幾點(diǎn)注意事項吧,這也是官方提醒:
1、editorRef 必須用 shallowRef定義。具體原因待研究,用ref似乎也行。
2、組件銷毀時,要及時銷毀編輯器。
二、如何自定義工具欄菜單的展示?
這里補(bǔ)充幾個官方API:
1、editor.getAllMenuKeys() 查詢編輯器注冊的所有菜單 key (可能有的不在工具欄上)
2、toolbar.getConfig().toolbarKeys 查看當(dāng)前菜單排序和分組
3、這塊其它API挺雞肋的,不用看了就,寫上搞得代碼很亂,直接在工具欄配置對象里操作就好了,比較清晰,自我感覺哈。
import { DomEditor } from '@wangeditor/editor'
const toolbar=DomEditor.getToolbar(editor)
const toolbarConfig=toolbar.getConfig()
// 查看當(dāng)前菜單排序和分組
console.log( toolbarConfig.toolbarKeys )
三、如何自定義工具欄內(nèi)置菜單的功能?
這里有通用的操作,參考官方,分兩步實現(xiàn):
四、如何自定義擴(kuò)展新功能菜單?
這里官方提供了三處參考:定義新菜單、定義插件、定義新元素。
我認(rèn)為定義新菜單是比較常用的,這樣其實已經(jīng)就很靈活了。至于其他兩項有需求的朋友,可以自行研究一番,可能比較燒哈。
最后插一句,WangEditor這個庫,寫的真是挺不錯的!
- END -
里對于設(shè)置支付寶賬號和配置就不做說明,網(wǎng)上很多配置信息和應(yīng)用上線的文章
做第三方接口首先得看官方文檔,支付寶的官方文檔非常清晰:
首先登錄支付寶的開放文檔,下載支付寶SDK和demo,鏈接:
https://docs.open.alipay.com/54/106370/
將jar包導(dǎo)入項目,在Java服務(wù)端生成訂單信息:
//實例化客戶端
AlipayClient alipayClient=new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", APP_ID, APP_PRIVATE_KEY, "json", CHARSET, ALIPAY_PUBLIC_KEY, "RSA2");
//實例化具體API對應(yīng)的request類,類名稱和接口名稱對應(yīng),當(dāng)前調(diào)用接口名稱:alipay.trade.app.pay
AlipayTradeAppPayRequest request=new AlipayTradeAppPayRequest();
//SDK已經(jīng)封裝掉了公共參數(shù),這里只需要傳入業(yè)務(wù)參數(shù)。以下方法為sdk的model入?yún)⒎绞?model和biz_content同時存在的情況下取biz_content)。
AlipayTradeAppPayModel model=new AlipayTradeAppPayModel();
model.setBody("我是測試數(shù)據(jù)");
model.setSubject("App支付測試Java");
model.setOutTradeNo(outtradeno);//更換為自己的訂單編號
model.setTimeoutExpress("30m");
model.setTotalAmount("0.01");//訂單價格
model.setProductCode("QUICK_MSECURITY_PAY");
request.setBizModel(model);
request.setNotifyUrl("商戶外網(wǎng)可以訪問的異步地址");//回調(diào)地址不可以帶參數(shù)
String orderStr="";
try {
//這里和普通的接口調(diào)用不同,使用的是sdkExecute
AlipayTradeAppPayResponse response=alipayClient.sdkExecute(request);
orderStr=response.getBody();
System.out.println(orderStr);//就是orderString 可以直接給客戶端請求,無需再做處理。
} catch (AlipayApiException e) {
e.printStackTrace();
}
說的簡直太詳細(xì),只需要替換自己的訂單ID和價格就可以了,這里我們只需要把orderStr返回給客戶端就可以了,我是通過json返回的,當(dāng)然客戶端完成支付之后,服務(wù)端還需要知道支付結(jié)果,或者將支付的訂單信息存入數(shù)據(jù)庫,那么我們需要設(shè)置回調(diào)地址,即setNotifyUrl,支付寶服務(wù)端通過這個地址將支付結(jié)果返回給后臺服務(wù)端,在這里我們可以更改訂單狀態(tài),插入訂單信息等等。(注:這個的回調(diào)地址必須是外網(wǎng)可以訪問的,不然收不到支付寶返回的信息,這個地址即我們在開發(fā)配置中設(shè)置的授權(quán)回調(diào)地址)
回調(diào)頁面內(nèi)容嚴(yán)格按照支付寶規(guī)定:
<%@ page language="java" contentType="text/html; charset=gbk" pageEncoding="gbk"%>
<%@page import="com.alipay.api.internal.util.AlipaySignature"%>
<%@ page import="java.util.*"%>
<%@ page import="java.util.Map"%>
<%@ page import="com.alipay.*"%>
<%@ page import="com.alipay.api.*"%>
<%
//獲取支付寶POST過來反饋信息
Map<String,String> params=new HashMap<String,String>();
System.out.println("異步通知參數(shù):");
Map<String,String[]> requestParams=request.getParameterMap();
for (Iterator<String> iter=requestParams.keySet().iterator(); iter.hasNext();) {
String name=(String) iter.next();
String[] values=(String[]) requestParams.get(name);
String valueStr="";
for (int i=0; i < values.length; i++) {
valueStr=(i==values.length - 1) ? valueStr + values[i]
: valueStr + values[i] + ",";
}
if(name.equals("trade_status")){
System.out.println("交易狀態(tài)為:"+valueStr);
}
//亂碼解決,這段代碼在出現(xiàn)亂碼時使用。如果mysign和sign不相等也可以使用這段代碼轉(zhuǎn)化
//valueStr=new String(valueStr.getBytes("ISO-8859-1"), "gbk");
params.put(name, valueStr);
}
System.out.println("params"+params);
String pk="自己的支付寶公鑰";
//獲取支付寶的通知返回參數(shù)
//商戶訂單號
String out_trade_no=new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");
//支付寶交易號
String trade_no=new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");
//客戶訂單編號
String auth_app_id=new String(request.getParameter("auth_app_id").getBytes("ISO-8859-1"),"UTF-8");
//買家登錄支付寶id
String buyer_logon_id=new String(request.getParameter("buyer_logon_id").getBytes("ISO-8859-1"),"UTF-8");
//交易時間
String gmt_payment=new String(request.getParameter("gmt_payment").getBytes("ISO-8859-1"),"UTF-8");
//交易金額
String invoice_amount=new String(request.getParameter("invoice_amount").getBytes("ISO-8859-1"),"UTF-8");
boolean verify_result=AlipaySignature.rsaCheckV1(params,pk, "UTF-8", "RSA2");
//這里可以做處理修改訂單狀態(tài)
if(verify_result){//驗證成功
//支付成功只需要返回success
System.out.println(1);
out.println("success"); //請不要修改或刪除
}else{//驗證失敗
System.out.println(2);
out.println("fail");
}
%>
需要修改訂單狀態(tài)時在回調(diào)頁面根據(jù)out_trade_no改變訂單狀態(tài)就可以。
xcel 中除了使用查找替換功能批量替換字符外,還可以使用文本替換類函數(shù)將字符串中的部分或全部內(nèi)容替換成新的字符串。文本替換類函數(shù)包括SUBSTITUTE函數(shù)、REPLACE函數(shù),以及用于區(qū)分雙字節(jié)字符的REPLACEB函數(shù)。
一、 字符替換函數(shù)SUBSTITUTE
SUBSTITUTE函數(shù)用于將字符串中指定的字符替換為新的文本字符串。函數(shù)語法如下SUBSTITUTE(text,old text,new_text,[instance_num])
第一參數(shù)text是必需參數(shù),為需要替換其中字符的原始文本或單元格引用。
第二參數(shù)old_text是必需參數(shù),為需要被替換的“舊文本”。如果第一參數(shù)的字符串中入包含該參數(shù)的字符串,則返回原始文本。
第三參數(shù)new_text是必需參數(shù),為用于替換的“新文本”。如果該參數(shù)為空文本或省路參數(shù)的值僅保留參數(shù)之前的逗號時,相當(dāng)于將需要替換的“舊文本”刪除。
第四參數(shù)instance_num是可選參數(shù),表示替換第幾個“舊文本”。如果省略該參數(shù),所有“舊文本”都會被替換。示例如下:
例:使用SUBSTITUTE函數(shù)計算平均分
上圖中,B列的數(shù)據(jù)記錄不規(guī)范,有的單元格中僅包含數(shù)字,有的單元格最后包含“分”字,需要在D2單元格中計算平均分。
在D2單元格中輸入以下數(shù)組公式,按<Ctrl+Shift+Enter>組合鍵。
{=ROUND(AVERAGE(--SUBSTITUTE(B2:B7,"分",)),2)}
公式中SUBSTITUTE函數(shù)的第三參數(shù)省略,表示將B2:B7單元格中的“分”字替換為空。不包含“分”字的單元格將不受影響,返回原有的內(nèi)容。使用“--”(兩個負(fù)號)將SUBSTITUTE函數(shù)的結(jié)果由文本轉(zhuǎn)換為數(shù)值,再由AVERAGE函數(shù)進(jìn)行求平均數(shù),用ROUND函數(shù)保留二位小數(shù)。
提示:
本例僅作為SUBSTITUTE函數(shù)的一項使用方法說明,不代表所有不規(guī)范的數(shù)據(jù)都能夠通過函數(shù)的方法完成計算。實際輸入數(shù)據(jù)時可將不同類別的數(shù)據(jù)單獨(dú)一列存放,數(shù)值后面不加文本。如果使用類似“1箱54只”“3包22個”的數(shù)據(jù)輸入形式,將對后續(xù)的匯總帶來極大的麻煩。
例:使用SUBSTITUTE函數(shù)計算部門人數(shù)
下圖為某單位人員名單的部分內(nèi)容,B列中每個單元格中有多個人員編號,中間用半角逗號作為分隔。需要在C列計算每個部門的人數(shù)。
在C2單元格中輸入以下公式,向下復(fù)制到C6單元格。
=LEN(B2)-LEN(SUBSTITUTE(B2,”,",))+1
公式第一部分LEN(B2)用于計算B2單元格中的字符數(shù)。
公式第二部分先用SUBSTITUTE函數(shù)將B2單元格中的逗號“,”替換為空文本,等于將所有逗號“,”從原始文本中刪除,再用LEN函數(shù)計算替換后的文本字符數(shù)。
最后用第一部分的原始字符數(shù)減去逗號“,”被刪數(shù)后的字符數(shù),即得到原始字符串中一共有幾個逗號“,”。由于每個單元格中的人數(shù)總是比逗號數(shù)量多一個,因此,最后再在公式中加1,即得到每個部門的人數(shù)。
例:借助SUBSTITUTE函數(shù)提取產(chǎn)品批號中的工廠碼
下圖為某公司產(chǎn)品的批號,其格式為字母數(shù)字的組合,中間用“_”分隔不同的信息。其中第二個和第三個“_”之間的內(nèi)容為產(chǎn)品的工廠碼,需要將其提取至B列。
在B2單元格中輸入以下公式,向下復(fù)制到B5單元格。
=TRIM(MID(SUBSTITUTE(A2,"-",REPT(” ",99)),99*2,99))
REPT函數(shù)將指定文本重復(fù)多次組成字符串,基本語法如下。
REPT(text,number_times)
第一參數(shù)text為需要重復(fù)的內(nèi)容,可以是字符串或單元格引用
第二參數(shù)number_times為將第一參數(shù)重復(fù)的次數(shù)。
公式中REPT(“ "99)的作用是生成99個空格。
用SUBSTITUTE函數(shù)將A2單元格中的“_”替換為99個空格。這里用99個空格的目的是將原始字符中的各段文本用足夠多的空格分開構(gòu)成新的字符串。新的字符串相當(dāng)于如下。
DSF (99個空格) 25 (99個空格) D24 (99個空格) 50
因為要提取的字符在原始文本的第3段,所以用MID函數(shù)在以上字符串中第99*2個字符開始,提取99個字符,返回的結(jié)果相當(dāng)于如下字符串。
(9個空格) D24 (87個空格)
最后再用TRIM函數(shù)清除文本兩端多余的空格,即得到需要的工廠碼。
二、用REPLACE函數(shù)替換字符串
REPLACE函數(shù)用于將部分文本字符串替換為新的字符串,與SUBSTITUTE函數(shù)的區(qū)別是,SUBSTITUTE函數(shù)是針對字符串中的指定字符內(nèi)容進(jìn)行替換,REPLACE函數(shù)是針對符串中的指定字符位置進(jìn)行替換,其語法如下:
REPLACE(old_text,start_num,num_chars,new_text)
第一參數(shù)old_text表示要替換其部分字符的源文本。
第二參數(shù)start_num指定源文本中要替換為新字符的位置。
第三參數(shù)num_chars表示使用新字符串替換源字符串中的字符數(shù),如果該參數(shù)為0或省略參數(shù)值,可以實現(xiàn)類似插入字符(串)的功能。
第四參數(shù)new_text表示用于替換源文本中字符的文本。
例:使用REPLACE函數(shù)隱藏手機(jī)號碼中間4位
在下圖中需要將B列手機(jī)號碼中間4位數(shù)字用星號“****”隱藏。
在C2單元格中輸入以下公式,向下復(fù)制到C10單元格。
=REPLACE(B2,4,4,”****”)
公式中使用REPLACE函數(shù)從B2單元格的第4個字符起,將4個字符替換為“****”
例:使用REPLACE函數(shù)將銀行卡號分段顯示
下圖為某單位客戶收款的銀行卡號,為便于讀取和核對,需要將銀行卡號數(shù)字分段顯示。
在B2單元格中輸入以下公式,向下復(fù)制到B10單元格.
=REPLACE(REPLACE(REPLACE(REPLACE(A2,5,0," "),10,0," "),15,0," "),20,0," ")
REPLACE函數(shù)第三參數(shù)為0表示插入字符。公式中使用了四次REPLACE函數(shù),第一次先用REPLACE函數(shù)在A2單元格第5個字符前插入一個空格。生成的新字符串再作為第二個REPLACE函數(shù)的第一參數(shù),在新字符串的第10個字符前再次插入一個空格。依此類推,形成每四個數(shù)字為一組的分段顯示方式。
三、用CLEAN函數(shù)和TRIM函數(shù)清理非打印字符和多余空格
部分從網(wǎng)頁、ERP系統(tǒng)或從其他軟件中導(dǎo)出的文本會存在一些非打印字符,影響正常數(shù)據(jù)查找及匯總計算。此外,由于數(shù)據(jù)錄入時的疏忽,可能會在英文單詞或中文姓名之間入多個空格。
CLEAN函數(shù)用于刪除文本中的部分非打印字符(ASCII碼的值為0~31)
使用TRIM函數(shù)能夠清除文本中除了單詞之間的單個空格外的所有空格。
它們的語法別為:
CLEAN(text)
TRIM(text)
四、使用NUMBERVALUE 函數(shù)轉(zhuǎn)換不規(guī)范數(shù)字
在整理表格數(shù)據(jù)的過程中,經(jīng)常會有一些不規(guī)范的數(shù)字影響數(shù)據(jù)的匯總分析。例如,在數(shù)字中混有空格,或者夾雜有全角數(shù)字及文本型數(shù)字等。對于文本數(shù)據(jù),可以使用TRIM函數(shù)清理多余空格,使用ASC函數(shù)將全角字符轉(zhuǎn)換為半角字符。對于數(shù)字內(nèi)容,使用NUMBERVALUE函數(shù)可以兼容以上兩種功能。
NUMBERVALUE函數(shù)較VALUE函數(shù)在功能上有一定的提升。該函數(shù)不僅可以實現(xiàn)VALUE函數(shù)日期轉(zhuǎn)換為數(shù)值序列、文本型數(shù)字轉(zhuǎn)換為數(shù)值型數(shù)字、全角數(shù)字轉(zhuǎn)換為半角數(shù)字等功能,還可以處理混雜空格的數(shù)值及符號混亂等特殊情況。
對于“7430%”這樣的數(shù)據(jù),NUMBERVALUE函數(shù)能夠?qū)⑵滢D(zhuǎn)換為74.3而使用VALUE函數(shù),則返回錯誤值#VALUE!。
*請認(rèn)真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。