weex 实现富文本

首先介绍一下什么叫做富文本

后台常常要用到一个编辑器叫做富文本编辑器,例如淘宝和电商等等的详情页面编辑等等,这个编辑器可以参考

http://ueditor.baidu.com/website/onlinedemo.html

它编辑出来的文本我们可以看到

是一个

<p>

<span>

</span>

</p>

这样的一段内容,如果在前端显示这个就太容易了

<div v-html="ritchtextstyle="font-size:32px;" v-if="!platform></div>

这样一行代码就搞定了,然而到 app上,就不是那么简单了

这时候有几种方案可供选择

1:如果内容没有嵌套很多的话,直接把里面所有的 文字标签换成 text 标签  img 标签全部换成 image标签就可以了

但是 weex 还有一个很麻烦的问题,text标签不呢个有子标签

呈现代码宏出错: 参数'firstline'的值无效
<p>aaa<span>bbb<span>ccc</span></span></p>

,如果富文本是这样的的话,那么 替换就无能为力了。image 必须指定图片宽高,否则就不能显示,所以这种方案局限性就太大了

2:使用 vue 来定一个一个组件可以解析显示这样的富文本内容

尝试写了一个

richtext
<template>
    <div class="rich-text">
        <div v-for="(child, index) in children" :key="index">
            <div v-if="child.tag === 'text'">
                <text class="product-text" :style="child.style">{{child.text}}</text>
            </div>
            <div v-if="child.tag === 'image'" class="image-wrapper">
                <image
                    :src="child.src" resize="stretch" class="product-image"
                    :style="{width: child.width, height: child.height}"
                ></image>
            </div>
            <div v-if="child.tag === 'br'">
                <text class="br"></text>
            </div>
        </div>
    </div>
</template>
<style>
    .rich-text {
        margin-top: 30px;
    }
    .product-text, .image-wrapper {
        padding-left: 20px;
        padding-right: 20px;
    }
    .br {
        height: 20px;
    }
</style>
<script>
    import { html2json } from 'html2json'
    import { translateJSON } from '../utils'
    export default {
        props: {
            content: {
                type: String,
                required: true
            },
            imgSize: {
                type: Object,
                required: true
            }
        },
        computed: {
            children() {
                const json = html2json(this.content)
                console.error('json = '+json)
                console.error('json = '+json)
                return translateJSON(json, this.imgSize)
            }
        }
    }
</script>
解析工具
export function throttle (func, wait) {
    let last = 0
    return function (...args) {
        const context = this
        const time = new Date().getTime()
        if (time - last > wait) {
            func.apply(context, args)
            last = time
        }
    }
}
export const translateJSON = (node, imgSize) => {
    const result = []
    const translate = (node, styleList) => {
        const styleL = node.attr && node.attr.style ? [...styleList, node.attr.style] : styleList
        if (node.tag && node.tag === 'img') {
            console.error('node.attr = '+node.attr.src)
            console.error('node.imgSize = '+imgSize)
            if(typeof(imgSize) === 'undefined' || typeof(node) === 'undefined' || typeof(node.attr) === 'undefined' ){
                return
            }
            const obj = imgSize[node.attr.src] || '{width: 710, height: 500}'
            const {width, height} = JSON.parse(obj)
            result.push({
                tag: 'image',
                src: node.attr.src,
                width: '710px',
                height: (710 * height / width) + 'px'
            })
        else if (node.tag && node.tag === 'br') {
            result.push({
                tag: 'br'
            })
        else if (!node.tag && node.node === 'text') {
            const style = styleL.map(s => {
                var str = ''
                 try {
                    str = (/font-size:/.test(s)) ? s.replace(/\d+/g, 2 * parseInt(s.split(':')[1], 10)) : s                   
                  catch(error) {
                      // 此处是负责例外处理的语句
                  } finally {
                      return str
                  }               
                  
            }).reduce((acc, s) => {
                var tokens = ''
                var key = ''
                 try {
                    tokens = s.split(':')
                    key = tokens[0].replace(/\-([a-z]{1})/, (str, $1) => $1.toUpperCase())
                    const value = tokens[1].split(';')[0]
                    acc[key] = value 
                catch(error) {
                      // 此处是负责例外处理的语句
                }                  
 
                return acc
            }, {})
            result.push({
                tag: 'text',
                style,
                text: node.text.replace(/&[a-z]{3,4};/g, '')
            })
        }
        if (node.child && node.child.length) {
            node.child.forEach(c => translate(c, styleL))
        }
    }
    translate(node, [])
    return result
}

用下来会发现需要处理的问题之复杂远远超过了想像

当然期望网上还有一些其他的第三方解决方案,不过weex的并没有,只有一个小程序的富文本解决方案,并没有什么用

https://weappdev.com/t/wxparse-version0-2-html-markdown/326

有兴趣可以看看

所以综合1-2来看,期望在 js 中把这个问题处理掉难度貌似很大


所以我想,依赖第三种解决方案

3:weex 原生组件拓展

那么就去 android 和ios 上分别实现一个这样的扩展 组件就好了

https://github.com/zzhoujay/RichText 

就使用这个解决方案

首先 在 gradle 中添加依赖

compile 'com.zzhoujay.richtext:richtext:2.5.4'

然后自定义组件 

自定义组件
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package com.alibaba.weex.extend.component;
 
import android.content.Context;
import android.support.annotation.NonNull;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.method.LinkMovementMethod;
import android.text.style.URLSpan;
import android.view.LayoutInflater;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
 
import com.alibaba.weex.R;
import com.taobao.weex.WXSDKInstance;
import com.taobao.weex.dom.WXDomObject;
import com.taobao.weex.ui.component.WXComponent;
import com.taobao.weex.ui.component.WXComponentProp;
import com.taobao.weex.ui.component.WXVContainer;
import com.zzhoujay.richtext.RichText;
 
public class RichTextView extends WXComponent<RelativeLayout> {
 
  public RichTextView(WXSDKInstance instance, WXDomObject dom, WXVContainer parent) {
    super(instance, dom, parent);
  }
 
  @Override
  protected RelativeLayout initComponentHostView(@NonNull Context context) {
    LayoutInflater inflater = LayoutInflater.from(context);
    RelativeLayout gifview = (RelativeLayout)inflater.inflate(R.layout.ritchtext_layout,null);
    return gifview;
  }
 
  @WXComponentProp(name = "richtext")
  public void setRichtextLink(String richtext){
    RichText.from(richtext).autoPlay(true).into((TextView) getHostView().findViewById(R.id.rich_text));
  }
}

然后在android 项目中注册组件

WXSDKEngine.registerComponent("richtext", RichTextView.class);


最后可以在weex 的 vue 文件中去使用这个组件了

       <richtext  :richtext="ritchtext"  style="width:750px;height:25000px" ></richtext>

这里已然会有一个非常头疼的问题,你必须给这个组件指定一个高度,然而富文本具体有多高又未知,所以这个也是一个麻烦的问题,不过至少在效果上,这个处理比较理性

所以一个不成熟的框架会有n多问题可能需要去解决


ios 自定义富文本等使用苹果电脑的时候写完更新上来

展开阅读全文

没有更多推荐了,返回首页