富文本實現格式化,格式化的時候保留圖文、文字換行、樣式。html
有一個需求,粘貼的時候格式化富文本內容,可是保留圖文、文字換行、樣式。node
一開始我作的時候是所有格式化,也就是粘貼的時候拿到html(怎麼拿到百度下就有了,通常你們也都是對別人的富文本進行改造。),而後轉DOM,而後getInnerText.大功告成。這時候產品說,保留圖文和換行哦。nginx
因而修改下。web
這個比較簡單,看下就好了。跨域
不作解析。 (核心代碼就這些) bash
雖然比較簡單,可是也有幾個地方須要注意的是服務器
main.js微信
const error_img_url = 'https://hongqiaojiaoyu.oss-cn-shenzhen.aliyuncs.com/huazhang/imgs/error.png'
const Koa = require('koa');
const app = new Koa();
const get_url_buffer = require('./js/get_url_buffer')
const port = 3024
// 響應
app.use(async (ctx, next) => {
const path = ctx.request.path
console.log(path)
if(path.match(/^\/_proxy\/.*/)){
var body = await new Promise(function(resolve, reject) {
get_url_buffer(
(path.match(/(?:(?<=\/_proxy\/)).*/) || [error_img_url])[0],
(body) => {
resolve(body)
},
(uri) => {
console.log(uri)
}
)
})
ctx.set("Access-Control-Allow-Origin", "*")
ctx.status = 200
ctx.type = 'jpg'
ctx.length = Buffer.byteLength(body)
ctx.body = body
}
});
app.listen(port);
console.log(`啓動完成 端口${port}`)
複製代碼
get_url_buffer.jsapp
var http = require('http')
var https = require('https')
const url = require('url')
/**
* 獲取圖片buffer
* @param {*} _url 要轉換的地址
* @param {*} success 成功 success(buffer)
* @param {*} fail 失敗 fail(uri)
*/
var get_url_buffer = (_url, success, fail) => {
var uri = url.parse(_url)
// console.log(uri)
console.log(_url)
var option = {
...uri,
method: 'GET',
}
var handle_cb = (res) => {
if(res.statusCode === 301){
const url = res.headers['location']
console.log('重定向', url)
get_url_buffer(url, success, fail)
return
}
var img = []
var size = 0
res.on("data", (chunk) => {
img.push(chunk)
size += chunk.length
})
res.on("end", () => {
// console.log(size)
const buffer = Buffer.concat(img, size)
success(buffer)
})
}
if(uri.protocol === 'https:'){
return https.request(option, handle_cb).end()
}
if(uri.protocol === 'http:'){
return http.request(option, handle_cb).end()
}
console.log('協議異常', uri)
fail(uri)
}
module.exports = get_url_buffer
複製代碼
到這裏,咱們實現了第一個功能dom
可是這時候需求添加了一條,以下
這時候咱們很差下手,咱們須要作一個抉擇
若是已經有必定修改這時候換富文本不太合適,只能去抄別人富文本的或者去找插件。
可是我遇到了以下兩個問題,因此仍是決定本身來
slate-paste-html-plugin
,可是用起來一堆報錯,就放棄了1: 要去掉垃圾代碼,咱們就須要重組html格式
2: 去掉html可是樣式不會影響
3: 要計算出換行
這個不太好說,我畫了一張圖
左側那個是dom樹,右側是修改規則 (可是這個是理想狀態,實際獲取到的代碼不會這麼理想,稍後再說怎麼解決)
有了思路,就能夠實現了
咱們須要先遞歸獲取每個節點,若是是最後一個,那麼就計算。 (嗯,很完美
but, 剛剛不是說了,有些不是很符合理想,好比長這樣
<p>
我是文字
<span>我也是</span>
</p>
複製代碼
按照思路,咱們不該該拿這樣的dom
因此須要先轉下, 代碼以下,相信大家能夠看懂。
補全span
/** * 補全span * @param {*} html html片斷 */
function tag_full(html){
const tag = 'span'
const reg1 = /(?<=\<(?:\/\w|\w).*>)([^<|>]*)(?=<\w.*>)/g
const reg2 = /(?<=\<(?:\/\w).*>)([^<|>]*)(?=<\/\w.*>)/g
const replace_value = (_, p1) => (p1.replace(/\s|\S|t|r/, '') == '' ? '' : `<${tag}>${p1}</${tag}>`)
return html.replace(reg1, replace_value).replace(reg2, replace_value)
}
複製代碼
轉完以後,咱們拿最後的節點,可是咱們還缺乏紅色路徑。
可是,紅色路徑怎麼拿,看起來有點複雜,咱們先拿到當前節點路徑再說,就讓其餘的事情隨風吧。
遞歸獲取節點
function traverse_tree(node, path){
if (!node) return
if (node.children && node.children.length > 0) {
for (let i = 0; i < node.children.length; i++) {
let next_node = node.children[i]
traverse_tree(next_node, [...path, {node: node, index: i}])
}
}else{
// 其餘代碼...
}
}
複製代碼
經過遞歸,咱們遍歷的時候順手拿下節點路徑和每一個路徑下面的節點。
拿到以後,咱們和上面一個node節點(這裏指的是最後節點)計算分叉位置, 代碼以下
獲取分叉點
/** * 獲取分叉點 * @param {*} old_path [number] * @param {*} path [number] */
function get_path_diff_index(old_path, path){
let index = 0
let k = 0
for(let item of path){
old_path[k] === item && index++
k++
}
return index
}
複製代碼
而後計算什麼類型就能夠了。
這時候,咱們就能夠再對img、等標籤處理了,還有樣式。
樣式代碼送上
設置樣式
/** * 根據style設置style * @param {*} node node節點 * @param {<filter_styles>} styles ['bold'] */
function set_style(node, filter_styles){
let style = {}
for(let item of filter_styles){
switch(item){
case 'bold': {
let key = 'font-weight'
let value = get_style(node, key)
value >= 600 && (style[key] = item)
break
}
case 'color': {
let value = get_style(node, item)
console.log(node, value)
style[item] = value
break
}
}
... 其餘
}
return style
}
複製代碼
而後
合併HTML
/**
* 合併html
* @param {*} html_arr
*/
function merge_html(html_arr){
function get_style_string(style){
let style_string = ''
for(let key in style){
style_string += `${key}:${style[key]};`
}
return style_string ? ` style="${style_string}"` : ''
}
const res = html_arr
.map(e =>
e.tag === 'img' ? `<p><img src="${e.src}" class="userChoosImg" style="max-width:100%;display: inline-block;" /></p>` :
block_element_tags.includes(e.tag) ?
// 忽略空白文本
(e.text === '' ? '' :
`<${e.tag}${get_style_string(e.style)}>${e.text}</${e.tag}>`) :
``
)
.join('')
console.log('html_format_res: ', res)
return res
}
複製代碼
而後再循環判斷img,把img合併處理,既然走以前的處理圖片方法便可。
點個贊再走唄
--完--