瀏覽代碼

Merge branch 'yb8.0'

jwyu 2 年之前
父節點
當前提交
7a4969da40

+ 1 - 1
api/user.js

@@ -49,7 +49,7 @@ export const apiUserLogin=params=>{
  * @param permission 选择的权限
  * @param real_name 姓名
  * @param source 来源:我的1、活动2、图库3、研报4
- * @param source_agent 来源平台:1:小程序、2:pc
+ * @param source_agent 来源平台:1:小程序、2:小程序(pc)、3:公众号、4:官网web(pc)
  * @param from_page 来源页面: '活动列表'、'活动详情'等
  */
 export const apiApplyPermission=params=>{

+ 15 - 0
api/video.js

@@ -0,0 +1,15 @@
+// 视频模块
+
+import { httpGet, httpPost } from "@/utils/request.js";
+
+/**
+ * 视频列表
+ * @param page_index
+ * @param page_size
+ * @param keywords
+ * @param video_id
+ * @param chart_permission_id
+ */
+export const apiVideoList=params=>{
+    return httpGet('/community/video/list',params)
+}

+ 120 - 0
components/searchBox/searchBox.vue

@@ -0,0 +1,120 @@
+<template>
+    <view :class="['flex search-box',isFocus||searchVal?'search-focus':'']">
+        <image 
+            class="search-icon" 
+            :src="isFocus||searchVal?'../../static/search-icon-s.png':'../../static/search-icon.png'" 
+            mode="aspectFill"
+        />
+        <input 
+            type="text" 
+            :maxlength="-1"
+            v-model="searchVal" 
+            :placeholder="placeholder" 
+            :focus="isFocus" 
+            @focus="handelFocus"
+            @blur="handelBlur"
+            @confirm="handleSearch"
+            @input="handleInput"
+            confirm-type="search"
+            :disabled="disabled"
+        />
+        <image 
+            class="search-clear" 
+            src="../../static/search-del.png" 
+            mode="aspectFill"
+            v-if="searchVal"
+            @click="handleClearSearch"
+        />
+        <view class="right-btn" v-if="hasRightBtn&&searchVal" @click="handleSearch">搜索</view>
+    </view>
+</template>
+
+<script>
+export default {
+    props: {
+        hasRightBtn:{
+            type:Boolean,
+            default:true
+        },
+        placeholder:{
+            type:String,
+            default:'请输入搜索关键词'
+        },
+        focus:{
+            type:Boolean,
+            default:false
+        },
+        disabled:{
+            type:Boolean,
+            default:false
+        }
+    },
+    data () {
+        return {
+            searchVal:'',
+            isFocus:this.focus
+        }
+    },
+    methods: {
+        handleClearSearch(){
+            this.searchVal=''
+            this.$emit('change',this.searchVal)
+            this.$emit('search')
+        },
+
+        handleInput(){
+            this.$emit('change',this.searchVal)
+        },
+
+        handelFocus(){
+            this.isFocus=true
+        },
+
+        handelBlur(){
+            this.isFocus=false
+        },
+
+        handleSearch(){
+            this.$emit('search')
+        }
+    }
+}
+</script>
+
+<style lang="scss" scoped>
+.search-box{
+    border: 1px solid #E5E5E5;
+    align-items: center;
+    background-color: #F6F6F6;
+    border-radius: 43rpx;
+    padding: 0 30rpx;
+    height: 70rpx;
+    .search-icon{
+        width: 48rpx;
+        height: 48rpx;
+        flex-shrink: 0;
+        margin-right: 5rpx;
+    }
+    input{
+        flex: 1;
+    }
+    .search-clear{
+        width: 40rpx;
+        height: 40rpx;
+        flex-shrink: 0;
+        margin-left: 5rpx;
+        margin-right: 20rpx;
+    }
+    .right-btn{
+        font-size: 28rpx;
+        color: #E3B377;
+        flex-shrink: 0;
+        border-left: 1px solid #999999;
+        padding-left: 20rpx;
+    }
+}
+.search-focus{
+    border-color: #E3B377;
+    background-color: #fff;
+}
+</style>

+ 1 - 1
mixin/index.js

@@ -5,7 +5,7 @@ moment.locale('zh-cn');
 import {globalImgUrls} from "../utils/config"
 import store from '@/store'
 
-const tabbarPathList=['pages/activity/activity','pages/pricedriven/pricedriven','pages/report/report','pages/question/question']
+const tabbarPathList=['pages/activity/activity','pages/pricedriven/pricedriven','pages/video/videoList','pages/report/report','pages/question/question']
 
 module.exports = {
   watch: {

+ 22 - 3
pages.json

@@ -59,6 +59,19 @@
 			"style":{
 				"navigationBarTitleText":"价格驱动"
 			}
+		},
+		{
+			"path": "pages/video/videoList",
+			"style": {
+				"navigationBarTitleText": "视频社区",
+				"enablePullDownRefresh": true
+			}
+		},
+		{
+			"path": "pages/video/videoSearch",
+			"style": {
+				"navigationBarTitleText": "视频社区"
+			}
 		}
 	],
 	"subPackages":[
@@ -265,6 +278,12 @@
 				"iconPath": "./static/tabbar/price.png",
 				"selectedIconPath": "./static/tabbar/price-s.png"
 			},
+			{
+				"pagePath": "pages/video/videoList",
+				"text": "视频社区",
+				"iconPath": "./static/tabbar/video.png",
+				"selectedIconPath": "./static/tabbar/video-s.png"
+			},
 			{
 				"pagePath": "pages/activity/activity",
 				"text": "活动",
@@ -297,16 +316,16 @@
 			"van-icon": "/wxcomponents/vant/icon/index",
 			"van-radio": "/wxcomponents/vant/radio/index",
 			"van-tab": "/wxcomponents/vant/tab/index",
-  		"van-tabs": "/wxcomponents/vant/tabs/index",
+  			"van-tabs": "/wxcomponents/vant/tabs/index",
 			"van-count-down": "/wxcomponents/vant/count-down/index",
 			"van-empty": "/wxcomponents/vant/empty/index",
 			"van-checkbox": "/wxcomponents/vant/checkbox/index",
 			"van-transition": "/wxcomponents/vant/transition/index",
 			"van-collapse": "/wxcomponents/vant/collapse/index",
-  		"van-collapse-item": "/wxcomponents/vant/collapse-item/index",
+  			"van-collapse-item": "/wxcomponents/vant/collapse-item/index",
 			"van-tag": "/wxcomponents/vant/tag/index",
 			"van-row": "/wxcomponents/vant/row/index",
-  		"van-col": "/wxcomponents/vant/col/index",
+  			"van-col": "/wxcomponents/vant/col/index",
 			"van-progress": "/wxcomponents/vant/progress/index",
 			"van-dialog": "/wxcomponents/vant/dialog/index"
 		}

+ 1 - 0
pages/pc.vue

@@ -17,6 +17,7 @@ const mapObj=new Map([
     ['pages-report/chapterDetail','/report/chapterdetail'],
     ['pages-report/specialColumn/list','/report/specialcolumnlist'],
     ['pages-report/specialColumn/detail','/report/specialcolumndetail'],
+    ['pages/video/videoList','/video/list']
 ])//map映射小程序页面路径对应h5页面路径
 import {apiUserInfo} from '@/api/user'
 import {apiGetSceneToParams} from '@/api/common'

+ 354 - 0
pages/video/videoList.vue

@@ -0,0 +1,354 @@
+<template>
+    <view class="video-list-page">
+        <van-sticky style="background: #fff">
+            <view class="flex search-wrap">
+                <view @click="goSearchPage" style="flex:1;margin-right:30rpx" >
+                    <searchBox 
+                        placeholder="关键字搜索" 
+                        :hasRightBtn="false" 
+                        :disabled="true"
+                    ></searchBox>
+                </view>
+                <view class="flex" @click="showFilter=true">
+                    <image style="width:50rpx;height:50rpx" src="@/static/filter-icon.png" mode="aspectFill"/>
+                    <text style="color:#E3B377;font-size:32rpx">筛选</text>
+                </view>
+            </view>
+        </van-sticky>
+        <view class="empty-box" v-if="list.length==0&&finished">
+            <image
+                :src="globalImgUrls.activityNoAuth"
+                mode="widthFix"
+            />
+            <view>暂无数据</view>
+        </view>
+        <view class="list-wrap">
+            <view class="item" v-for="item in list" :key="item.community_video_id">
+                <view class="title-box">
+                    <text class="tag">{{item.chart_permission_name}}</text>
+                    <text class="title">{{item.title}}</text>
+                </view>
+                <button 
+                    class="share-btn" 
+                    open-type="share" 
+                    :data-item="item">
+                    <image class="share-img" src="@/static/share-icon.png" mode="aspectFill"/>
+                </button>
+                <video
+                    autoplay
+                    object-fit="cover"
+                    show-mute-btn
+                    :poster="item.cover_img_url"
+                    :src="item.video_url"
+                    enable-play-gesture
+                    :id="item.community_video_id"
+                    v-if="item.community_video_id==curVideoId"
+                ></video>
+                <image @click="handelClickPlay(item)" v-else class="poster" :src="item.cover_img_url" mode="aspectFill" lazy-load/>
+                <view class="time">发布时间:{{item.publish_time}}</view>
+            </view>
+        </view>
+
+        <!-- 筛选 -->
+        <van-popup 
+            :show="showFilter" 
+            position="bottom" 
+            :safe-area-inset-bottom="true" 
+            round 
+            @close="showFilter=false"
+        >
+            <view class="filter-wrap">
+                <view class="flex top">
+                    <text style="color:#000">全部筛选</text>
+                    <text style="color:#E3B377" @click="showFilter=false">取消</text>
+                </view>
+                <view class="list-box">
+                    <van-collapse accordion @change="change" :value="active" :border="false">
+                        <van-collapse-item 
+                            :title="item.ClassifyName" 
+                            :name='item.ClassifyName' 
+                            :border="false"
+                            v-for="item in options"
+                            :key="item.ClassifyName"
+                        >
+                            <van-row gutter="5">
+                                <van-col 
+                                    :span="_item.PermissionName.length>7?16:8" 
+                                    v-for="_item in item.Items" 
+                                    :key="_item.PermissionId"
+                                >
+                                    <text 
+                                        :class="['list-item',_item.PermissionId==selectPerId&&'list-item-active']" 
+                                        @click="handleSelectPerItem(_item)"
+                                    >{{_item.PermissionName}}</text>
+                                </van-col>
+                            </van-row>
+                        </van-collapse-item>
+                    </van-collapse>
+                </view>
+            </view>
+        </van-popup>
+    </view>
+    
+</template>
+<script>
+import {apiVideoList} from '@/api/video'
+import {apiOptionList} from '@/api/question'
+export default {
+    data() {
+        return {
+            showFilter:false,
+            active:'',
+            options:[],
+            selectPerId:0,
+
+            videoId:0,
+            page:1,
+            pageSize:10,
+            finished:false,
+            list:[],
+
+            curVideoId:0,
+        }
+    },
+    onLoad(options){
+        this.videoId=options.videoId||0
+        this.getList()
+        this.getPermissionList()
+    },
+    onHide(){
+        this.showFilter=false
+        this.curVideoId=0
+    },
+    onShareAppMessage({from,target}) {
+        console.log(from,target);
+        let path='/pages/video/videoList?videoId=0'
+        let title='FICC视频社区'
+        let imageUrl=''
+        if(from=='button'){
+            title=`${target.dataset.item.chart_permission_name}:${target.dataset.item.title}`
+            path=`/pages/video/videoList?videoId=${target.dataset.item.community_video_id}`
+            imageUrl=target.dataset.item.cover_img_url
+        }
+        return {
+            title:title,
+            path:path,
+            imageUrl:imageUrl
+        }
+    },
+    onPullDownRefresh(){
+        this.videoId=0
+        this.selectPerId=0
+        this.page=1
+        this.list=[]
+        this.finished=false
+        this.getList()
+        setTimeout(() => {
+            uni.stopPullDownRefresh()
+        }, 1500)
+    },
+    methods: {
+        goSearchPage(){
+            uni.navigateTo({
+                url: '/pages/video/videoSearch',
+            });
+        },
+        change(e){
+            this.active=e.detail
+        },
+
+        //点击分类某项
+        handleSelectPerItem(item){
+            if(this.selectPerId==item.PermissionId){
+                this.selectPerId=0
+            }else{
+                this.selectPerId=item.PermissionId
+            }
+            
+            this.videoId=0//重置掉分享进入的状态
+            this.curVideoId=0
+            this.page=1
+            this.list=[]
+            this.finished=false
+            this.getList()
+            this.showFilter=false
+        },
+
+        async getList(){
+            const res=await apiVideoList({
+                page_index:Number(this.page),
+                page_size:Number(this.pageSize),
+                video_id:Number(this.videoId),
+                chart_permission_id:Number(this.selectPerId)
+            })
+            if(res.code===200){
+                let arr=res.data||[]
+                this.list=[...this.list,...arr]
+                if(arr.length===0){
+                    this.finished=true
+                }
+            }
+        },
+
+        //获取筛选项
+        async getPermissionList(){
+            const res=await apiOptionList()
+            if(res.code===200){
+                this.options=res.data
+            }
+        },
+
+        handelClickPlay(item){
+            this.curVideoId=item.community_video_id
+        }
+    },
+}
+</script>
+
+<style lang='scss'>
+.search-wrap .van-search{
+    padding: 0 !important;
+}
+
+.video-list-page{
+    .filter-wrap{
+        .van-cell__title, .van-cell__value{
+            flex: none !important;
+        }
+        .van-cell:after{
+            border: none !important;
+        }
+        .van-cell__title{
+            font-size: 14px;
+        }
+        .van-hairline--top:after{
+            border-top-width: 0 !important;
+        }
+    }
+}
+</style>
+<style lang="scss" scoped>
+.video-list-page{
+    .search-wrap {
+        background-color: #fff;
+        padding: 30rpx 34rpx;
+        align-items: center;
+        .menu-icon{
+            width: 52rpx;
+            height: 40rpx;
+            display: block;
+            flex-shrink: 0;
+            margin-left: 30rpx;
+        }
+    } 
+    
+    .list-wrap{
+        .item{
+            border-top: 10rpx solid #f9f9f9;
+            padding: 30rpx 34rpx;
+            position: relative;
+            .title-box{
+                padding-right: 40rpx;
+            }
+            .share-btn{
+                position: absolute;
+                top: 34rpx;
+                right: 34rpx;
+                background-color: transparent;
+                width: 36rpx;
+                height: 36rpx;
+                line-height: 1;
+                padding: 0;
+                &::after{
+                    border: none;
+                }
+            }
+            .share-img{
+                width: 32.5rpx;
+                height: 32rpx;
+            }
+            .tag{
+                color: #E4B478;
+                background-color: #333;
+                padding: 5rpx 20rpx;
+                border-radius: 20rpx;
+                font-size: 24rpx;
+                margin-right: 26rpx;
+            }
+            .title{
+                font-size: 32rpx;
+                color: #000;
+            }
+            video{
+                width: 100%;
+                height: 400rpx;
+                margin: 30rpx 0 20rpx 0;
+                border-radius: 20rpx;
+            }
+            .poster{
+                width: 100%;
+                height: 400rpx;
+                margin: 30rpx 0 20rpx 0;
+                border-radius: 20rpx;
+                position: relative;
+                &::after{
+                    content:'';
+                    display: block;
+                    position: absolute;
+                    width: 120rpx;
+                    height: 120rpx;
+                    top: 50%;
+                    left: 50%;
+                    transform: translate(-50%,-50%);
+                    background-image: url('@/static/video-play-btn.png');
+                    background-size: cover;
+                }
+            }
+            .time{
+                font-size: 28rpx;
+                color: #999;
+            }
+        }
+    }
+
+    .empty-box{
+        text-align: center;
+        font-size: 32rpx;
+        color: #999;
+        padding-top: 150rpx;
+        image{
+            width: 80vw;
+            margin-bottom: 57rpx;
+        }
+    }
+}
+
+.filter-wrap{
+    background-color: #fff;
+    padding-top: 53rpx;
+    padding-bottom: 100rpx;
+    .top{
+        font-size: 32rpx;
+        justify-content: space-between;
+        margin-bottom: 40rpx;
+        padding: 0 34rpx;
+    }
+    .list-box{
+        min-height: 30vh;
+        max-height: 60vh;
+        .list-item{
+            display: block;
+            margin: 10rpx;
+            height: 76rpx;
+            line-height: 76rpx;
+            color: #000;
+            background: #F6F6F6;
+            border-radius: 4px 4px 4px 4px;
+            text-align: center;
+        }
+        .list-item-active{
+            background-color: #FAEEDE;
+        }
+    }
+}
+</style>

+ 232 - 0
pages/video/videoSearch.vue

@@ -0,0 +1,232 @@
+<template>
+    <view class="video-search-page">
+        <van-sticky style="background: #fff">
+            <view style="padding:30rpx 34rpx">
+            <searchBox 
+                :focus="focus" 
+                placeholder="关键字搜索" 
+                @change="onChange"
+                @search="onSearch"
+            ></searchBox>
+            </view>
+        </van-sticky>
+        <view class="empty-box" v-if="list.length==0&&finished">
+            <image
+                :src="globalImgUrls.activityNoAuth"
+                mode="widthFix"
+            />
+            <view>暂无数据,试试别的搜索词吧~</view>
+        </view>
+        <view class="list-wrap">
+            <view class="item" v-for="item in list" :key="item.community_video_id">
+                <view class="title-box">
+                    <text class="tag">{{item.chart_permission_name}}</text>
+                    <text class="title">{{item.title}}</text>
+                </view>
+                <button 
+                    class="share-btn" 
+                    open-type="share" 
+                    :data-item="item">
+                    <image class="share-img" src="@/static/share-icon.png" mode="aspectFill"/>
+                </button>
+                <video
+                    autoplay
+                    object-fit="cover"
+                    show-mute-btn
+                    :poster="item.cover_img_url"
+                    :src="item.video_url"
+                    enable-play-gesture
+                    :id="item.community_video_id"
+                    v-if="item.community_video_id==curVideoId"
+                ></video>
+                <image @click="handelClickPlay(item)" v-else class="poster" :src="item.cover_img_url" mode="aspectFill" lazy-load/>
+                <view class="time">发布时间:{{item.publish_time}}</view>
+            </view>
+        </view>
+    </view>
+</template>
+
+<script>
+import searchBox from '@/components/searchBox/searchBox.vue'
+import {apiVideoList} from '@/api/video'
+export default {
+    components: {
+        searchBox
+    },
+    data() {
+        return {
+            searchVal:'',
+            focus:true,
+            list:[],
+            finished:false,
+            page:1,
+            pageSize:10,
+
+            curVideoId:0,
+        }
+    },
+    onReachBottom() {
+        if(this.finished) return
+        this.page++
+        this.getList()
+    },
+    onShareAppMessage({from,target}) {
+        console.log(from,target);
+        let path='/pages/video/videoList?videoId=0'
+        let title='FICC视频社区'
+        let imageUrl=''
+        if(from=='button'){
+            title=target.dataset.item.title
+            path=`/pages/video/videoList?videoId=${target.dataset.item.community_video_id}`
+            imageUrl=target.dataset.item.cover_img_url
+        }
+        return {
+            title:title,
+            path:path,
+            imageUrl:imageUrl
+        }
+    },
+    methods: {
+        onChange(e){
+            this.searchVal=e
+        },
+
+        async onSearch(){
+            this.finished=false
+            this.page=1
+            this.list=[]
+            if(!this.searchVal){
+                this.finished=true
+                return
+            }
+            this.getList()
+        },
+
+        async getList(){
+            this.curVideoId=0
+            const res=await apiVideoList({
+                page_index:Number(this.page),
+                page_size:Number(this.pageSize),
+                keywords:this.searchVal
+            })
+            if(res.code===200){
+                let arr=res.data||[]
+                this.list=[...this.list,...arr]
+                if(arr.length===0){
+                    this.finished=true
+                }
+            }
+        },
+
+        handelClickPlay(item){
+            this.curVideoId=item.community_video_id
+        }
+    },
+}
+</script>
+
+<style>
+.van-sticky-wrap--fixed{
+  background-color: #fff;
+}
+page{
+    padding-bottom: 0;
+}
+</style>
+
+<style lang="scss" scoped>
+.video-search-page{
+    .search-wrap {
+        background-color: #fff;
+        padding: 30rpx 34rpx;
+        align-items: center;
+        .menu-icon{
+            width: 52rpx;
+            height: 40rpx;
+            display: block;
+            flex-shrink: 0;
+            margin-left: 30rpx;
+        }
+    } 
+    
+    .list-wrap{
+        .item{
+            border-top: 10rpx solid #f9f9f9;
+            padding: 30rpx 34rpx;
+            position: relative;
+            .title-box{
+                padding-right: 40rpx;
+            }
+            .share-btn{
+                position: absolute;
+                top: 34rpx;
+                right: 34rpx;
+                background-color: transparent;
+                width: 32rpx;
+                height: 32rpx;
+                line-height: 1;
+                padding: 0;
+                &::after{
+                    border: none;
+                }
+            }
+            .share-img{
+                width: 32rpx;
+                height: 32rpx;
+            }
+            .tag{
+                color: #E4B478;
+                background-color: #333;
+                padding: 5rpx 20rpx;
+                border-radius: 20rpx;
+                font-size: 24rpx;
+                margin-right: 26rpx;
+            }
+            .title{
+                font-size: 32rpx;
+                color: #000;
+            }
+            video{
+                width: 100%;
+                height: 400rpx;
+                margin: 30rpx 0 20rpx 0;
+                border-radius: 20rpx;
+            }
+            .poster{
+                width: 100%;
+                height: 400rpx;
+                margin: 30rpx 0 20rpx 0;
+                border-radius: 20rpx;
+                position: relative;
+                &::after{
+                    content:'';
+                    display: block;
+                    position: absolute;
+                    width: 120rpx;
+                    height: 120rpx;
+                    top: 50%;
+                    left: 50%;
+                    transform: translate(-50%,-50%);
+                    background-image: url('@/static/video-play-btn.png');
+                    background-size: cover;
+                }
+            }
+            .time{
+                font-size: 28rpx;
+                color: #999;
+            }
+        }
+    }
+
+    .empty-box{
+        text-align: center;
+        font-size: 32rpx;
+        color: #999;
+        padding-top: 150rpx;
+        image{
+            width: 80vw;
+            margin-bottom: 57rpx;
+        }
+    }
+}
+</style>

二進制
static/filter-icon.png


二進制
static/search-del.png


二進制
static/search-icon-s.png


二進制
static/search-icon.png


二進制
static/share-icon.png


二進制
static/tabbar/video-s.png


二進制
static/tabbar/video.png


二進制
static/video-play-btn.png


+ 0 - 182
uni_modules/mp-html/README.md

@@ -1,182 +0,0 @@
-## 功能介绍
-- 全端支持(含 `v3、NVUE`)
-- 支持丰富的标签(包括 `table`、`video`、`svg` 等)
-- 支持丰富的事件效果(自动预览图片、链接处理等)
-- 支持设置占位图(加载中、出错时、预览时)
-- 支持锚点跳转、长按复制等丰富功能
-- 支持大部分 *html* 实体
-- 丰富的插件(关键词搜索、内容 **编辑** 等)
-- 效率高、容错性强且轻量化
-
-查看 [功能介绍](https://jin-yufeng.gitee.io/mp-html/#/overview/feature) 了解更多
-
-## 使用方法
-- `uni_modules` 方式  
-  1. 点击右上角的 `使用 HBuilder X 导入插件` 按钮直接导入项目或点击 `下载插件 ZIP` 按钮下载插件包并解压到项目的 `uni_modules/mp-html` 目录下  
-  2. 在需要使用页面的 `(n)vue` 文件中添加  
-     ```html
-     <!-- 不需要引入,可直接使用 -->
-     <mp-html :content="html" />
-     ```
-     ```javascript
-     export default {
-       data() {
-         return {
-           html: '<div>Hello World!</div>'
-         }
-       }
-     }
-     ```
-  3. 需要更新版本时在 `HBuilder X` 中右键 `uni_modules/mp-html` 目录选择 `从插件市场更新` 即可  
-
-- 源码方式  
-  1. 从 [github](https://github.com/jin-yufeng/mp-html/tree/master/dist/uni-app) 或 [gitee](https://gitee.com/jin-yufeng/mp-html/tree/master/dist/uni-app) 下载源码  
-     插件市场的 **非 uni_modules 版本** 无法更新,不建议从插件市场获取  
-  2. 在需要使用页面的 `(n)vue` 文件中添加  
-     ```html
-     <mp-html :content="html" />
-     ```
-     ```javascript
-     import mpHtml from '@/components/mp-html/mp-html'
-     export default {
-       // HBuilderX 2.5.5+ 可以通过 easycom 自动引入
-       components: {
-         mpHtml
-       },
-       data() {
-         return {
-           html: '<div>Hello World!</div>'
-         }
-       }
-     }
-     ```
-
-- npm 方式  
-  1. 在项目根目录下执行  
-     ```bash
-     npm install mp-html
-     ```
-  2. 在需要使用页面的 `(n)vue` 文件中添加  
-     ```html
-     <mp-html :content="html" />
-     ```
-     ```javascript
-     import mpHtml from 'mp-html/dist/uni-app/components/mp-html/mp-html'
-     export default {
-       // 不可省略
-       components: {
-         mpHtml
-       },
-       data() {
-         return {
-           html: '<div>Hello World!</div>'
-         }
-       }
-     }
-     ```
-  3. 需要更新版本时执行以下命令即可  
-     ```bash
-     npm update mp-html
-     ```
-  
-  使用 *cli* 方式运行的项目,通过 *npm* 方式引入时,需要在 *vue.config.js* 中配置 *transpileDependencies*,详情可见 [#330](https://github.com/jin-yufeng/mp-html/issues/330#issuecomment-913617687)  
-  如果在 **nvue** 中使用还要将 `dist/uni-app/static` 目录下的内容拷贝到项目的 `static` 目录下,否则无法运行  
-
-查看 [快速开始](https://jin-yufeng.gitee.io/mp-html/#/overview/quickstart) 了解更多
-
-## 组件属性
-
-| 属性 | 类型 | 默认值 | 说明 |
-|:---:|:---:|:---:|---|
-| container-style | String |  | 容器的样式([2.1.0+](https://jin-yufeng.gitee.io/mp-html/#/changelog/changelog#v210)) |
-| content | String |  | 用于渲染的 html 字符串 |
-| copy-link | Boolean | true | 是否允许外部链接被点击时自动复制 |
-| domain | String |  | 主域名(用于链接拼接) |
-| error-img | String |  | 图片出错时的占位图链接 |
-| lazy-load | Boolean | false | 是否开启图片懒加载 |
-| loading-img | String |  | 图片加载过程中的占位图链接 |
-| pause-video | Boolean | true | 是否在播放一个视频时自动暂停其他视频 |
-| preview-img | Boolean | true | 是否允许图片被点击时自动预览 |
-| scroll-table | Boolean | false | 是否给每个表格添加一个滚动层使其能单独横向滚动 |
-| selectable | Boolean | false | 是否开启文本长按复制 |
-| set-title | Boolean | true | 是否将 title 标签的内容设置到页面标题 |
-| show-img-menu | Boolean | true | 是否允许图片被长按时显示菜单 |
-| tag-style | Object |  | 设置标签的默认样式 |
-| use-anchor | Boolean | false | 是否使用锚点链接 |
-
-查看 [属性](https://jin-yufeng.gitee.io/mp-html/#/basic/prop) 了解更多
-
-## 组件事件
-
-| 名称 | 触发时机 |
-|:---:|---|
-| load | dom 树加载完毕时 |
-| ready | 图片加载完毕时 |
-| error | 发生渲染错误时 |
-| imgtap | 图片被点击时 |
-| linktap | 链接被点击时 |
-
-查看 [事件](https://jin-yufeng.gitee.io/mp-html/#/basic/event) 了解更多
-
-## api
-组件实例上提供了一些 `api` 方法可供调用
-
-| 名称 | 作用 |
-|:---:|---|
-| in | 将锚点跳转的范围限定在一个 scroll-view 内 |
-| navigateTo | 锚点跳转 |
-| getText | 获取文本内容 |
-| getRect | 获取富文本内容的位置和大小 |
-| setContent | 设置富文本内容 |
-| imgList | 获取所有图片的数组 |
-
-查看 [api](https://jin-yufeng.gitee.io/mp-html/#/advanced/api) 了解更多
-
-## 插件扩展  
-除基本功能外,本组件还提供了丰富的扩展,可按照需要选用
-
-| 名称 | 作用 |
-|:---:|---|
-| audio | 音乐播放器 |
-| editable | 富文本 **编辑**([示例项目](https://6874-html-foe72-1259071903.tcb.qcloud.la/editable.zip?sign=cc0017be203fb3dbca62d33a0c15792e&t=1608447445)) |
-| emoji | 解析 emoji |
-| highlight | 代码块高亮显示 |
-| markdown | 渲染 markdown |
-| search | 关键词搜索 |
-| style | 匹配 style 标签中的样式 |
-| txv-video | 使用腾讯视频 |
-| img-cache | 图片缓存 by [@PentaTea](https://github.com/PentaTea) |
-
-从插件市场导入的包中 **不含有** 扩展插件,需要使用插件参考以下方法:  
-1. 获取完整组件包  
-   ```bash
-   npm install mp-html
-   ```
-2. 编辑 `tools/config.js` 中的 `plugins` 项,选择需要的插件  
-3. 生成新的组件包  
-   在 `node_modules/mp-html` 目录下执行  
-   ```bash
-   npm install
-   npm run build:uni-app
-   ```
-4. 拷贝 `dist/uni-app` 中的内容到项目根目录  
-
-查看 [插件](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin) 了解更多
-
-## 示例体验
-![富文本插件](https://gitee.com/jin-yufeng/mp-html/raw/master/docs/assets/case/富文本插件.jpg)
-
-## 关于 nvue
-`nvue` 使用原生渲染,不支持部分 `css` 样式,为实现和 `html` 相同的效果,组件内部通过 `web-view` 进行渲染,性能上差于原生,根据 `weex` 官方建议,`web` 标签仅应用在非常规的降级场景。因此,如果通过原生的方式(如 `richtext`)能够满足需要,则不建议使用本组件,如果有较多的富文本内容,则可以直接使用 `vue` 页面  
-由于渲染方式与其他端不同,有以下限制:  
-1. 不支持 `lazy-load` 属性
-2. 视频不支持全屏播放
-
-纯 `nvue` 模式下,[此问题](https://ask.dcloud.net.cn/question/119678) 修复前,不支持通过 `uni_modules` 引入,需要本地引入(将 [dist/uni-app](https://github.com/jin-yufeng/mp-html/tree/master/dist/uni-app) 中的内容拷贝到项目根目录下)  
-
-## 问题反馈
-遇到问题时,请先查阅 [常见问题](https://jin-yufeng.gitee.io/mp-html/#/question/faq) 和 [issue](https://github.com/jin-yufeng/mp-html/issues) 中是否已有相同的问题  
-可通过 [issue](https://github.com/jin-yufeng/mp-html/issues/new/choose) 、插件问答或发送邮件到 [mp_html@126.com](mailto:mp_html@126.com) 提问,不建议在评论区提问(不方便回复)  
-提问请严格按照 [issue 模板](https://github.com/jin-yufeng/mp-html/issues/new/choose) ,描述清楚使用环境、`html` 内容或可复现的 `demo` 项目以及复现方式,对于 **描述不清**、**无法复现** 或重复的问题将不予回复  
-
-查看 [问题反馈](https://jin-yufeng.gitee.io/mp-html/#/question/feedback) 了解更多

+ 0 - 75
uni_modules/mp-html/changelog.md

@@ -1,75 +0,0 @@
-## v2.2.2(2022-02-26)
-1. `A` 增加了 [pauseMedia](https://jin-yufeng.gitee.io/mp-html/#/advanced/api#pauseMedia) 的 `api`,可用于暂停播放音视频 [详细](https://github.com/jin-yufeng/mp-html/issues/317)
-2. `U` 优化了长内容的加载速度  
-3. `U` 适配 `vue3` [#389](https://github.com/jin-yufeng/mp-html/issues/389)、[#398](https://github.com/jin-yufeng/mp-html/pull/398) by [@zhouhuafei](https://github.com/zhouhuafei)、[#400](https://github.com/jin-yufeng/mp-html/issues/400)
-4. `F` 修复了小程序端图片高度设置为百分比时可能不显示的问题
-5. `F` 修复了 `highlight` 插件部分情况下可能显示不完整的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/403)
-## v2.2.1(2021-12-24)
-1. `A` `editable` 插件增加上下移动标签功能
-2. `U` `editable` 插件支持在文本中间光标处插入内容
-3. `F` 修复了 `nvue` 端设置 `margin` 后可能导致高度不正确的问题
-4. `F` 修复了 `highlight` 插件使用压缩版的 `prism.css` 可能导致背景失效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/367)
-5. `F` 修复了编辑状态下使用 `emoji` 插件内容为空时可能报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/371)
-6. `F` 修复了使用 `editable` 插件后将 `selectable` 属性设置为 `force` 不生效的问题
-## v2.2.0(2021-10-12)
-1. `A` 增加 `customElements` 配置项,便于添加自定义功能性标签 [详细](https://github.com/jin-yufeng/mp-html/issues/350)
-2. `A` `editable` 插件增加切换音视频自动播放状态的功能 [详细](https://github.com/jin-yufeng/mp-html/pull/341) by [@leeseett](https://github.com/leeseett)
-3. `A` `editable` 插件删除媒体标签时触发 `remove` 事件,便于删除已上传的文件
-4. `U` `editable` 插件 `insertImg` 方法支持同时插入多张图片 [详细](https://github.com/jin-yufeng/mp-html/issues/342)
-5. `U` `editable` 插入图片和音视频时支持拼接 `domian` 主域名
-6. `F` 修复了内部链接参数中包含 `://` 时被认为是外部链接的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/356)
-7. `F` 修复了部分 `svg` 标签名或属性名大小写不正确时不生效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/351)
-8. `F` 修复了 `nvue` 页面运行到非 `app` 平台时可能样式错误的问题
-## v2.1.5(2021-08-13)
-1. `A` 增加支持标签的 `dir` 属性
-2. `F` 修复了 `ruby` 标签文字与拼音没有居中对齐的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/325)
-3. `F` 修复了音视频标签内有 `a` 标签时可能无法播放的问题
-4. `F` 修复了 `externStyle` 中的 `class` 名包含下划线或数字时可能失效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/326)
-5. `F` 修复了 `h5` 端引入 `externStyle` 可能不生效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/326)
-## v2.1.4(2021-07-14)
-1. `F` 修复了 `rt` 标签无法设置样式的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/318)
-2. `F` 修复了表格中有单元格同时合并行和列时可能显示不正确的问题
-3. `F` 修复了 `app` 端无法关闭图片长按菜单的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/322)
-4. `F` 修复了 `editable` 插件只能添加图片链接不能修改的问题 [详细](https://github.com/jin-yufeng/mp-html/pull/312) by [@leeseett](https://github.com/leeseett)
-## v2.1.3(2021-06-12)
-1. `A` `editable` 插件增加 `insertTable` 方法
-2. `U` `editable` 插件支持编辑表格中的空白单元格 [详细](https://github.com/jin-yufeng/mp-html/issues/310)
-3. `F` 修复了 `externStyle` 中使用伪类可能失效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/298)
-4. `F` 修复了多个组件同时使用时 `tag-style` 属性时可能互相影响的问题 [详细](https://github.com/jin-yufeng/mp-html/pull/305) by [@woodguoyu](https://github.com/woodguoyu)
-5. `F` 修复了包含 `linearGradient` 的 `svg` 可能无法显示的问题
-6. `F` 修复了编译到头条小程序时可能报错的问题
-7. `F` 修复了 `nvue` 端不触发 `click` 事件的问题
-8. `F` 修复了 `editable` 插件尾部插入时无法撤销的问题
-9. `F` 修复了 `editable` 插件的 `insertHtml` 方法只能在末尾插入的问题
-10. `F` 修复了 `editable` 插件插入音频不显示的问题
-## v2.1.2(2021-04-24)
-1. `A` 增加了 [img-cache](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin#img-cache) 插件,可以在 `app` 端缓存图片 [详细](https://github.com/jin-yufeng/mp-html/issues/292) by [@PentaTea](https://github.com/PentaTea)
-2. `U` 支持通过 `container-style` 属性设置 `white-space` 来保留连续空格和换行符 [详细](https://jin-yufeng.gitee.io/mp-html/#/question/faq#space)
-3. `U` 代码风格符合 [standard](https://standardjs.com) 标准
-4. `U` `editable` 插件编辑状态下支持预览视频 [详细](https://github.com/jin-yufeng/mp-html/issues/286)
-5. `F` 修复了 `svg` 标签内嵌 `svg` 时无法显示的问题
-6. `F` 修复了编译到支付宝和头条小程序时部分区域不可复制的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/291)
-## v2.1.1(2021-04-09)
-1. 修复了对 `p` 标签设置 `tag-style` 可能不生效的问题
-2. 修复了 `svg` 标签中的文本无法显示的问题
-3. 修复了使用 `editable` 插件编辑表格时可能报错的问题
-4. 修复了使用 `highlight` 插件运行到头条小程序时可能没有样式的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/280)
-5. 修复了使用 `editable` 插件 `editable` 属性为 `false` 时会报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/284)
-6. 修复了 `style` 插件连续子选择器失效的问题
-7. 修复了 `editable` 插件无法修改图片和字体大小的问题
-## v2.1.0.2(2021-03-21)
-修复了 `nvue` 端使用可能报错的问题
-## v2.1.0(2021-03-20)
-1. `A` 增加了 [container-style](https://jin-yufeng.gitee.io/mp-html/#/basic/prop#container-style) 属性 [详细](https://gitee.com/jin-yufeng/mp-html/pulls/1)
-2. `A` 增加支持 `strike` 标签
-3. `A` `editable` 插件增加 `placeholder` 属性 [详细](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin#editable)
-4. `A` `editable` 插件增加 `insertHtml` 方法 [详细](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin#editable)
-5. `U` 外部样式支持标签名选择器 [详细](https://jin-yufeng.gitee.io/mp-html/#/overview/quickstart#setting)
-6. `F` 修复了 `nvue` 端部分情况下可能不显示的问题
-## v2.0.5(2021-03-12)
-1. `U` [linktap](https://jin-yufeng.gitee.io/mp-html/#/basic/event#linktap) 事件增加返回内部文本内容 `innerText` [详细](https://github.com/jin-yufeng/mp-html/issues/271)
-2. `U` [selectable](https://jin-yufeng.gitee.io/mp-html/#/basic/prop#selectable) 属性设置为 `force` 时能够在微信 `iOS` 端生效(文本块会变成 `inline-block`) [详细](https://github.com/jin-yufeng/mp-html/issues/267)
-3. `F` 修复了部分情况下竖向无法滚动的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/182)
-4. `F` 修复了多次修改富文本数据时部分内容可能不显示的问题
-5. `F` 修复了 [腾讯视频](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin#txv-video) 插件可能无法播放的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/265)
-6. `F` 修复了 [highlight](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin#highlight) 插件没有设置高亮语言时没有应用默认样式的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/276) by [@fuzui](https://github.com/fuzui)

+ 0 - 458
uni_modules/mp-html/components/mp-html/mp-html.vue

@@ -1,458 +0,0 @@
-<template>
-  <view id="_root" :class="(selectable?'_select ':'')+'_root'" :style="containerStyle">
-    <slot v-if="!nodes[0]" />
-    <!-- #ifndef APP-PLUS-NVUE -->
-    <node v-else :childs="nodes" :opts="[lazyLoad,loadingImg,errorImg,showImgMenu]" name="span" />
-    <!-- #endif -->
-    <!-- #ifdef APP-PLUS-NVUE -->
-    <web-view ref="web" src="/uni_modules/mp-html/static/app-plus/mp-html/local.html" :style="'margin-top:-2px;height:' + height + 'px'" @onPostMessage="_onMessage" />
-    <!-- #endif -->
-  </view>
-</template>
-
-<script>
-/**
- * mp-html v2.2.2
- * @description 富文本组件
- * @tutorial https://github.com/jin-yufeng/mp-html
- * @property {String} container-style 容器的样式
- * @property {String} content 用于渲染的 html 字符串
- * @property {Boolean} copy-link 是否允许外部链接被点击时自动复制
- * @property {String} domain 主域名,用于拼接链接
- * @property {String} error-img 图片出错时的占位图链接
- * @property {Boolean} lazy-load 是否开启图片懒加载
- * @property {string} loading-img 图片加载过程中的占位图链接
- * @property {Boolean} pause-video 是否在播放一个视频时自动暂停其他视频
- * @property {Boolean} preview-img 是否允许图片被点击时自动预览
- * @property {Boolean} scroll-table 是否给每个表格添加一个滚动层使其能单独横向滚动
- * @property {Boolean | String} selectable 是否开启长按复制
- * @property {Boolean} set-title 是否将 title 标签的内容设置到页面标题
- * @property {Boolean} show-img-menu 是否允许图片被长按时显示菜单
- * @property {Object} tag-style 标签的默认样式
- * @property {Boolean | Number} use-anchor 是否使用锚点链接
- * @event {Function} load dom 结构加载完毕时触发
- * @event {Function} ready 所有图片加载完毕时触发
- * @event {Function} imgTap 图片被点击时触发
- * @event {Function} linkTap 链接被点击时触发
- * @event {Function} error 媒体加载出错时触发
- */
-// #ifndef APP-PLUS-NVUE
-import node from './node/node'
-// #endif
-import Parser from './parser'
-const plugins=[]
-// #ifdef APP-PLUS-NVUE
-const dom = weex.requireModule('dom')
-// #endif
-export default {
-  name: 'mp-html',
-  data () {
-    return {
-      nodes: [],
-      // #ifdef APP-PLUS-NVUE
-      height: 3
-      // #endif
-    }
-  },
-  props: {
-    containerStyle: {
-      type: String,
-      default: ''
-    },
-    content: {
-      type: String,
-      default: ''
-    },
-    copyLink: {
-      type: [Boolean, String],
-      default: true
-    },
-    domain: String,
-    errorImg: {
-      type: String,
-      default: ''
-    },
-    lazyLoad: {
-      type: [Boolean, String],
-      default: false
-    },
-    loadingImg: {
-      type: String,
-      default: ''
-    },
-    pauseVideo: {
-      type: [Boolean, String],
-      default: true
-    },
-    previewImg: {
-      type: [Boolean, String],
-      default: true
-    },
-    scrollTable: [Boolean, String],
-    selectable: [Boolean, String],
-    setTitle: {
-      type: [Boolean, String],
-      default: true
-    },
-    showImgMenu: {
-      type: [Boolean, String],
-      default: true
-    },
-    tagStyle: Object,
-    useAnchor: [Boolean, Number]
-  },
-  // #ifdef VUE3
-  emits: ['load', 'ready', 'imgtap', 'linktap', 'error'],
-  // #endif
-  // #ifndef APP-PLUS-NVUE
-  components: {
-    node
-  },
-  // #endif
-  watch: {
-    content (content) {
-      this.setContent(content)
-    }
-  },
-  created () {
-    this.plugins = []
-    for (let i = plugins.length; i--;) {
-      this.plugins.push(new plugins[i](this))
-    }
-  },
-  mounted () {
-    if (this.content && !this.nodes.length) {
-      this.setContent(this.content)
-    }
-  },
-  beforeDestroy () {
-    this._hook('onDetached')
-    clearInterval(this._timer)
-  },
-  methods: {
-    /**
-     * @description 将锚点跳转的范围限定在一个 scroll-view 内
-     * @param {Object} page scroll-view 所在页面的示例
-     * @param {String} selector scroll-view 的选择器
-     * @param {String} scrollTop scroll-view scroll-top 属性绑定的变量名
-     */
-    in (page, selector, scrollTop) {
-      // #ifndef APP-PLUS-NVUE
-      if (page && selector && scrollTop) {
-        this._in = {
-          page,
-          selector,
-          scrollTop
-        }
-      }
-      // #endif
-    },
-
-    /**
-     * @description 锚点跳转
-     * @param {String} id 要跳转的锚点 id
-     * @param {Number} offset 跳转位置的偏移量
-     * @returns {Promise}
-     */
-    navigateTo (id, offset) {
-      return new Promise((resolve, reject) => {
-        if (!this.useAnchor) {
-          reject(Error('Anchor is disabled'))
-          return
-        }
-        offset = offset || parseInt(this.useAnchor) || 0
-        // #ifdef APP-PLUS-NVUE
-        if (!id) {
-          dom.scrollToElement(this.$refs.web, {
-            offset
-          })
-          resolve()
-        } else {
-          this._navigateTo = {
-            resolve,
-            reject,
-            offset
-          }
-          this.$refs.web.evalJs('uni.postMessage({data:{action:"getOffset",offset:(document.getElementById(' + id + ')||{}).offsetTop}})')
-        }
-        // #endif
-        // #ifndef APP-PLUS-NVUE
-        let deep = ' '
-        // #ifdef MP-WEIXIN || MP-QQ || MP-TOUTIAO
-        deep = '>>>'
-        // #endif
-        const selector = uni.createSelectorQuery()
-          // #ifndef MP-ALIPAY
-          .in(this._in ? this._in.page : this)
-          // #endif
-          .select((this._in ? this._in.selector : '._root') + (id ? `${deep}#${id}` : '')).boundingClientRect()
-        if (this._in) {
-          selector.select(this._in.selector).scrollOffset()
-            .select(this._in.selector).boundingClientRect()
-        } else {
-          // 获取 scroll-view 的位置和滚动距离
-          selector.selectViewport().scrollOffset() // 获取窗口的滚动距离
-        }
-        selector.exec(res => {
-          if (!res[0]) {
-            reject(Error('Label not found'))
-            return
-          }
-          const scrollTop = res[1].scrollTop + res[0].top - (res[2] ? res[2].top : 0) + offset
-          if (this._in) {
-            // scroll-view 跳转
-            this._in.page[this._in.scrollTop] = scrollTop
-          } else {
-            // 页面跳转
-            uni.pageScrollTo({
-              scrollTop,
-              duration: 300
-            })
-          }
-          resolve()
-        })
-        // #endif
-      })
-    },
-
-    /**
-     * @description 获取文本内容
-     * @return {String}
-     */
-    getText (nodes) {
-      let text = '';
-      (function traversal (nodes) {
-        for (let i = 0; i < nodes.length; i++) {
-          const node = nodes[i]
-          if (node.type === 'text') {
-            text += node.text.replace(/&amp;/g, '&')
-          } else if (node.name === 'br') {
-            text += '\n'
-          } else {
-            // 块级标签前后加换行
-            const isBlock = node.name === 'p' || node.name === 'div' || node.name === 'tr' || node.name === 'li' || (node.name[0] === 'h' && node.name[1] > '0' && node.name[1] < '7')
-            if (isBlock && text && text[text.length - 1] !== '\n') {
-              text += '\n'
-            }
-            // 递归获取子节点的文本
-            if (node.children) {
-              traversal(node.children)
-            }
-            if (isBlock && text[text.length - 1] !== '\n') {
-              text += '\n'
-            } else if (node.name === 'td' || node.name === 'th') {
-              text += '\t'
-            }
-          }
-        }
-      })(nodes || this.nodes)
-      return text
-    },
-
-    /**
-     * @description 获取内容大小和位置
-     * @return {Promise}
-     */
-    getRect () {
-      return new Promise((resolve, reject) => {
-        uni.createSelectorQuery()
-          // #ifndef MP-ALIPAY
-          .in(this)
-          // #endif
-          .select('#_root').boundingClientRect().exec(res => res[0] ? resolve(res[0]) : reject(Error('Root label not found')))
-      })
-    },
-
-    /**
-     * @description 暂停播放媒体
-     */
-    pauseMedia () {
-      for (let i = (this._videos || []).length; i--;) {
-        this._videos[i].pause()
-      }
-      // #ifdef APP-PLUS
-      const command = 'for(var e=document.getElementsByTagName("video"),i=e.length;i--;)e[i].pause()'
-      // #ifndef APP-PLUS-NVUE
-      let page = this.$parent
-      while (!page.$scope) page = page.$parent
-      page.$scope.$getAppWebview().evalJS(command)
-      // #endif
-      // #ifdef APP-PLUS-NVUE
-      this.$refs.web.evalJs(command)
-      // #endif
-      // #endif
-    },
-
-    /**
-     * @description 设置内容
-     * @param {String} content html 内容
-     * @param {Boolean} append 是否在尾部追加
-     */
-    setContent (content, append) {
-      if (!append || !this.imgList) {
-        this.imgList = []
-      }
-      const nodes = new Parser(this).parse(content)
-      // #ifdef APP-PLUS-NVUE
-      if (this._ready) {
-        this._set(nodes, append)
-      }
-      // #endif
-      this.$set(this, 'nodes', append ? (this.nodes || []).concat(nodes) : nodes)
-
-      // #ifndef APP-PLUS-NVUE
-      this._videos = []
-      this.$nextTick(() => {
-        this._hook('onLoad')
-        this.$emit('load')
-      })
-
-      // 等待图片加载完毕
-      let height
-      clearInterval(this._timer)
-      this._timer = setInterval(() => {
-        this.getRect().then(rect => {
-          // 350ms 总高度无变化就触发 ready 事件
-          if (rect.height === height) {
-            this.$emit('ready', rect)
-            clearInterval(this._timer)
-          }
-          height = rect.height
-        }).catch(() => { })
-      }, 350)
-      // #endif
-    },
-
-    /**
-     * @description 调用插件钩子函数
-     */
-    _hook (name) {
-      for (let i = plugins.length; i--;) {
-        if (this.plugins[i][name]) {
-          this.plugins[i][name]()
-        }
-      }
-    },
-
-    // #ifdef APP-PLUS-NVUE
-    /**
-     * @description 设置内容
-     */
-    _set (nodes, append) {
-      this.$refs.web.evalJs('setContent(' + JSON.stringify(nodes) + ',' + JSON.stringify([this.containerStyle.replace(/(?:margin|padding)[^;]+/g, ''), this.errorImg, this.loadingImg, this.pauseVideo, this.scrollTable, this.selectable]) + ',' + append + ')')
-    },
-
-    /**
-     * @description 接收到 web-view 消息
-     */
-    _onMessage (e) {
-      const message = e.detail.data[0]
-      switch (message.action) {
-        // web-view 初始化完毕
-        case 'onJSBridgeReady':
-          this._ready = true
-          if (this.nodes) {
-            this._set(this.nodes)
-          }
-          break
-        // 内容 dom 加载完毕
-        case 'onLoad':
-          this.height = message.height
-          this._hook('onLoad')
-          this.$emit('load')
-          break
-        // 所有图片加载完毕
-        case 'onReady':
-          this.getRect().then(res => {
-            this.$emit('ready', res)
-          }).catch(() => { })
-          break
-        // 总高度发生变化
-        case 'onHeightChange':
-          this.height = message.height
-          break
-        // 图片点击
-        case 'onImgTap':
-          this.$emit('imgtap', message.attrs)
-          if (this.previewImg) {
-            uni.previewImage({
-              current: parseInt(message.attrs.i),
-              urls: this.imgList
-            })
-          }
-          break
-        // 链接点击
-        case 'onLinkTap': {
-          const href = message.attrs.href
-          this.$emit('linktap', message.attrs)
-          if (href) {
-            // 锚点跳转
-            if (href[0] === '#') {
-              if (this.useAnchor) {
-                dom.scrollToElement(this.$refs.web, {
-                  offset: message.offset
-                })
-              }
-            } else if (href.includes('://')) {
-              // 打开外链
-              if (this.copyLink) {
-                plus.runtime.openWeb(href)
-              }
-            } else {
-              uni.navigateTo({
-                url: href,
-                fail () {
-                  uni.switchTab({
-                    url: href
-                  })
-                }
-              })
-            }
-          }
-          break
-        }
-        // 获取到锚点的偏移量
-        case 'getOffset':
-          if (typeof message.offset === 'number') {
-            dom.scrollToElement(this.$refs.web, {
-              offset: message.offset + this._navigateTo.offset
-            })
-            this._navigateTo.resolve()
-          } else {
-            this._navigateTo.reject(Error('Label not found'))
-          }
-          break
-        // 点击
-        case 'onClick':
-          this.$emit('tap')
-          this.$emit('click')
-          break
-        // 出错
-        case 'onError':
-          this.$emit('error', {
-            source: message.source,
-            attrs: message.attrs
-          })
-      }
-    }
-    // #endif
-  }
-}
-</script>
-
-<style>
-/* #ifndef APP-PLUS-NVUE */
-/* 根节点样式 */
-._root {
-  padding: 1px 0;
-  overflow-x: auto;
-  overflow-y: hidden;
-  -webkit-overflow-scrolling: touch;
-}
-
-/* 长按复制 */
-._select {
-  user-select: text;
-}
-/* #endif */
-</style>

+ 0 - 536
uni_modules/mp-html/components/mp-html/node/node.vue

@@ -1,536 +0,0 @@
-<template>
-  <view :id="attrs.id" :class="'_block _'+name+' '+attrs.class" :style="attrs.style">
-    <block v-for="(n, i) in childs" v-bind:key="i">
-      <!-- 图片 -->
-      <!-- 占位图 -->
-      <image v-if="n.name==='img'&&((opts[1]&&!ctrl[i])||ctrl[i]<0)" class="_img" :style="n.attrs.style" :src="ctrl[i]<0?opts[2]:opts[1]" mode="widthFix" />
-      <!-- 显示图片 -->
-      <!-- #ifdef H5 || (APP-PLUS && VUE2) -->
-      <img v-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl[i]===-1?'display:none;':'')+n.attrs.style" :src="n.attrs.src||(ctrl.load?n.attrs['data-src']:'')" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
-      <!-- #endif -->
-      <!-- #ifdef APP-PLUS && VUE3 -->
-      <image v-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl[i]===-1?'display:none;':'')+'width:'+(ctrl[i]||1)+'px;'+n.attrs.style" :src="n.attrs.src||(ctrl.load?n.attrs['data-src']:'')" :mode="n.h?'':'widthFix'" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
-      <!-- #endif -->
-      <!-- #ifndef H5 || APP-PLUS -->
-      <image v-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl[i]===-1?'display:none;':'')+'width:'+(ctrl[i]||1)+'px;height:1px;'+n.attrs.style" :src="n.attrs.src" :mode="n.h?'':'widthFix'" :lazy-load="opts[0]" :webp="n.webp" :show-menu-by-longpress="opts[3]&&!n.attrs.ignore" :image-menu-prevent="!opts[3]||n.attrs.ignore" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
-      <!-- #endif -->
-      <!-- 文本 -->
-      <!-- #ifndef MP-BAIDU || MP-ALIPAY || MP-TOUTIAO -->
-      <text v-else-if="n.text" :user-select="n.us" decode>{{n.text}}</text>
-      <!-- #endif -->
-      <text v-else-if="n.name==='br'">\n</text>
-      <!-- 链接 -->
-      <view v-else-if="n.name==='a'" :id="n.attrs.id" :class="(n.attrs.href?'_a ':'')+n.attrs.class" hover-class="_hover" :style="'display:inline;'+n.attrs.style" :data-i="i" @tap.stop="linkTap">
-        <node name="span" :childs="n.children" :opts="opts" style="display:inherit" />
-      </view>
-      <!-- 视频 -->
-      <!-- #ifdef APP-PLUS -->
-      <view v-else-if="n.html" :id="n.attrs.id" :class="'_video '+n.attrs.class" :style="n.attrs.style" v-html="n.html" />
-      <!-- #endif -->
-      <!-- #ifndef APP-PLUS -->
-      <video v-else-if="n.name==='video'" :id="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style" :autoplay="n.attrs.autoplay" :controls="n.attrs.controls" :loop="n.attrs.loop" :muted="n.attrs.muted" :poster="n.attrs.poster" :src="n.src[ctrl[i]||0]" :data-i="i" @play="play" @error="mediaError" />
-      <!-- #endif -->
-      <!-- #ifdef H5 || APP-PLUS -->
-      <iframe v-else-if="n.name==='iframe'" :style="n.attrs.style" :allowfullscreen="n.attrs.allowfullscreen" :frameborder="n.attrs.frameborder" :src="n.attrs.src" />
-      <embed v-else-if="n.name==='embed'" :style="n.attrs.style" :src="n.attrs.src" />
-      <!-- #endif -->
-      <!-- #ifndef MP-TOUTIAO || ((H5 || APP-PLUS) && VUE3) -->
-      <!-- 音频 -->
-      <audio v-else-if="n.name==='audio'" :id="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style" :author="n.attrs.author" :controls="n.attrs.controls" :loop="n.attrs.loop" :name="n.attrs.name" :poster="n.attrs.poster" :src="n.src[ctrl[i]||0]" :data-i="i" @play="play" @error="mediaError" />
-      <!-- #endif -->
-      <view v-else-if="(n.name==='table'&&n.c)||n.name==='li'" :id="n.attrs.id" :class="'_'+n.name+' '+n.attrs.class" :style="n.attrs.style">
-        <node v-if="n.name==='li'" :childs="n.children" :opts="opts" />
-        <view v-else v-for="(tbody, x) in n.children" v-bind:key="x" :class="'_'+tbody.name+' '+tbody.attrs.class" :style="tbody.attrs.style">
-          <node v-if="tbody.name==='td'||tbody.name==='th'" :childs="tbody.children" :opts="opts" />
-          <block v-else v-for="(tr, y) in tbody.children" v-bind:key="y">
-            <view v-if="tr.name==='td'||tr.name==='th'" :class="'_'+tr.name+' '+tr.attrs.class" :style="tr.attrs.style">
-              <node :childs="tr.children" :opts="opts" />
-            </view>
-            <view v-else :class="'_'+tr.name+' '+tr.attrs.class" :style="tr.attrs.style">
-              <view v-for="(td, z) in tr.children" v-bind:key="z" :class="'_'+td.name+' '+td.attrs.class" :style="td.attrs.style">
-                <node :childs="td.children" :opts="opts" />
-              </view>
-            </view>
-          </block>
-        </view>
-      </view>
-      
-      <!-- 富文本 -->
-      <!-- #ifdef H5 || ((MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE2) -->
-      <rich-text v-else-if="handler.use(n)" :id="n.attrs.id" :style="n.f" :nodes="[n]" />
-      <!-- #endif -->
-      <!-- #ifndef H5 || ((MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE2) -->
-      <rich-text v-else-if="!n.c" :id="n.attrs.id" :style="n.f+';display:inline'" :preview="false" :nodes="[n]" />
-      <!-- #endif -->
-      <!-- 继续递归 -->
-      <view v-else-if="n.c===2" :id="n.attrs.id" :class="'_block _'+n.name+' '+n.attrs.class" :style="n.f+';'+n.attrs.style">
-        <node v-for="(n2, j) in n.children" v-bind:key="j" :style="n2.f" :name="n2.name" :attrs="n2.attrs" :childs="n2.children" :opts="opts" />
-      </view>
-      <node v-else :style="n.f" :name="n.name" :attrs="n.attrs" :childs="n.children" :opts="opts" />
-    </block>
-  </view>
-</template>
-<script module="handler" lang="wxs">
-// 行内标签列表
-var inlineTags = {
-  abbr: true,
-  b: true,
-  big: true,
-  code: true,
-  del: true,
-  em: true,
-  i: true,
-  ins: true,
-  label: true,
-  q: true,
-  small: true,
-  span: true,
-  strong: true,
-  sub: true,
-  sup: true
-}
-/**
- * @description 是否使用 rich-text 显示剩余内容
- */
-module.exports = {
-  use: function (item) {
-    if (item.c) return false
-    // 微信和 QQ 的 rich-text inline 布局无效
-    return !inlineTags[item.name] && (item.attrs.style || '').indexOf('display:inline') == -1
-  }
-}
-</script>
-<script>
-
-import node from './node'
-export default {
-  name: 'node',
-  options: {
-    // #ifdef MP-WEIXIN
-    virtualHost: true,
-    // #endif
-    // #ifdef MP-TOUTIAO
-    addGlobalClass: false
-    // #endif
-  },
-  data () {
-    return {
-      ctrl: {}
-    }
-  },
-  props: {
-    name: String,
-    attrs: {
-      type: Object,
-      default () {
-        return {}
-      }
-    },
-    childs: Array,
-    opts: Array
-  },
-  // #ifndef H5 && VUE3
-  components: {
-
-    node
-  },
-  // #endif
-  mounted () {
-    this.$nextTick(() => {
-      for (this.root = this.$parent; this.root.$options.name !== 'mp-html'; this.root = this.root.$parent);
-    })
-    // #ifdef H5 || APP-PLUS
-    if (this.opts[0]) {
-      let i
-      for (i = this.childs.length; i--;) {
-        if (this.childs[i].name === 'img') break
-      }
-      if (i !== -1) {
-        this.observer = uni.createIntersectionObserver(this).relativeToViewport({
-          top: 500,
-          bottom: 500
-        })
-        this.observer.observe('._img', res => {
-          if (res.intersectionRatio) {
-            this.$set(this.ctrl, 'load', 1)
-            this.observer.disconnect()
-          }
-        })
-      }
-    }
-    // #endif
-  },
-  beforeDestroy () {
-    // #ifdef H5 || APP-PLUS
-    if (this.observer) {
-      this.observer.disconnect()
-    }
-    // #endif
-  },
-  methods:{
-    // #ifdef MP-WEIXIN
-    toJSON () { },
-    // #endif
-    /**
-     * @description 播放视频事件
-     * @param {Event} e
-     */
-    play (e) {
-      // #ifndef APP-PLUS
-      if (this.root.pauseVideo) {
-        let flag = false; const id = e.target.id
-        for (let i = this.root._videos.length; i--;) {
-          if (this.root._videos[i].id === id) {
-            flag = true
-          } else {
-            this.root._videos[i].pause() // 自动暂停其他视频
-          }
-        }
-        // 将自己加入列表
-        if (!flag) {
-          const ctx = uni.createVideoContext(id
-            // #ifndef MP-BAIDU
-            , this
-            // #endif
-          )
-          ctx.id = id
-          this.root._videos.push(ctx)
-        }
-      }
-      // #endif
-    },
-
-    /**
-     * @description 图片点击事件
-     * @param {Event} e
-     */
-    imgTap (e) {
-      const node = this.childs[e.currentTarget.dataset.i]
-      if (node.a) {
-        this.linkTap(node.a)
-        return
-      }
-      if (node.attrs.ignore) return
-      // #ifdef H5 || APP-PLUS
-      node.attrs.src = node.attrs.src || node.attrs['data-src']
-      // #endif
-      this.root.$emit('imgtap', node.attrs)
-      // 自动预览图片
-      if (this.root.previewImg) {
-        uni.previewImage({
-          current: parseInt(node.attrs.i),
-          urls: this.root.imgList
-        })
-      }
-    },
-
-    /**
-     * @description 图片长按
-     */
-    imgLongTap (e) {
-      // #ifdef APP-PLUS
-      const attrs = this.childs[e.currentTarget.dataset.i].attrs
-      if (this.opts[3] && !attrs.ignore) {
-        uni.showActionSheet({
-          itemList: ['保存图片'],
-          success: () => {
-            const save = path => {
-              uni.saveImageToPhotosAlbum({
-                filePath: path,
-                success () {
-                  uni.showToast({
-                    title: '保存成功'
-                  })
-                }
-              })
-            }
-            if (this.root.imgList[attrs.i].startsWith('http')) {
-              uni.downloadFile({
-                url: this.root.imgList[attrs.i],
-                success: res => save(res.tempFilePath)
-              })
-            } else {
-              save(this.root.imgList[attrs.i])
-            }
-          }
-        })
-      }
-      // #endif
-    },
-
-    /**
-     * @description 图片加载完成事件
-     * @param {Event} e
-     */
-    imgLoad (e) {
-      const i = e.currentTarget.dataset.i
-      /* #ifndef H5 || (APP-PLUS && VUE2) */
-      if (!this.childs[i].w) {
-        // 设置原宽度
-        this.$set(this.ctrl, i, e.detail.width)
-      } else /* #endif */ if ((this.opts[1] && !this.ctrl[i]) || this.ctrl[i] === -1) {
-        // 加载完毕,取消加载中占位图
-        this.$set(this.ctrl, i, 1)
-      }
-    },
-
-    /**
-     * @description 链接点击事件
-     * @param {Event} e
-     */
-    linkTap (e) {
-      const node = e.currentTarget ? this.childs[e.currentTarget.dataset.i] : {}
-      const attrs = node.attrs || e
-      const href = attrs.href
-      this.root.$emit('linktap', Object.assign({
-        innerText: this.root.getText(node.children || []) // 链接内的文本内容
-      }, attrs))
-      if (href) {
-        if (href[0] === '#') {
-          // 跳转锚点
-          this.root.navigateTo(href.substring(1)).catch(() => { })
-        } else if (href.split('?')[0].includes('://')) {
-          // 复制外部链接
-          if (this.root.copyLink) {
-            // #ifdef H5
-            window.open(href)
-            // #endif
-            // #ifdef MP
-            uni.setClipboardData({
-              data: href,
-              success: () =>
-                uni.showToast({
-                  title: '链接已复制'
-                })
-            })
-            // #endif
-            // #ifdef APP-PLUS
-            plus.runtime.openWeb(href)
-            // #endif
-          }
-        } else {
-          // 跳转页面
-          uni.navigateTo({
-            url: href,
-            fail () {
-              uni.switchTab({
-                url: href,
-                fail () { }
-              })
-            }
-          })
-        }
-      }
-    },
-
-    /**
-     * @description 错误事件
-     * @param {Event} e
-     */
-    mediaError (e) {
-      const i = e.currentTarget.dataset.i
-      const node = this.childs[i]
-      // 加载其他源
-      if (node.name === 'video' || node.name === 'audio') {
-        let index = (this.ctrl[i] || 0) + 1
-        if (index > node.src.length) {
-          index = 0
-        }
-        if (index < node.src.length) {
-          this.$set(this.ctrl, i, index)
-          return
-        }
-      } else if (node.name === 'img') {
-        // #ifdef H5 && VUE3
-        if (this.opts[0] && !this.ctrl.load) return
-        // #endif
-        // 显示错误占位图
-        if (this.opts[2]) {
-          this.$set(this.ctrl, i, -1)
-        }
-      }
-      if (this.root) {
-        this.root.$emit('error', {
-          source: node.name,
-          attrs: node.attrs,
-          // #ifndef H5 && VUE3
-          errMsg: e.detail.errMsg
-          // #endif
-        })
-      }
-    }
-  }
-}
-</script>
-<style>
-/* a 标签默认效果 */
-._a {
-  padding: 1.5px 0 1.5px 0;
-  color: #366092;
-  word-break: break-all;
-}
-
-/* a 标签点击态效果 */
-._hover {
-  text-decoration: underline;
-  opacity: 0.7;
-}
-
-/* 图片默认效果 */
-._img {
-  max-width: 100%;
-  -webkit-touch-callout: none;
-}
-
-/* 内部样式 */
-
-._block {
-  display: block;
-}
-
-._b,
-._strong {
-  font-weight: bold;
-}
-
-._code {
-  font-family: monospace;
-}
-
-._del {
-  text-decoration: line-through;
-}
-
-._em,
-._i {
-  font-style: italic;
-}
-
-._h1 {
-  font-size: 2em;
-}
-
-._h2 {
-  font-size: 1.5em;
-}
-
-._h3 {
-  font-size: 1.17em;
-}
-
-._h5 {
-  font-size: 0.83em;
-}
-
-._h6 {
-  font-size: 0.67em;
-}
-
-._h1,
-._h2,
-._h3,
-._h4,
-._h5,
-._h6 {
-  display: block;
-  font-weight: bold;
-}
-
-._image {
-  height: 1px;
-}
-
-._ins {
-  text-decoration: underline;
-}
-
-._li {
-  display: list-item;
-}
-
-._ol {
-  list-style-type: decimal;
-}
-
-._ol,
-._ul {
-  display: block;
-  padding-left: 40px;
-  margin: 1em 0;
-}
-
-._q::before {
-  content: '"';
-}
-
-._q::after {
-  content: '"';
-}
-
-._sub {
-  font-size: smaller;
-  vertical-align: sub;
-}
-
-._sup {
-  font-size: smaller;
-  vertical-align: super;
-}
-
-._thead,
-._tbody,
-._tfoot {
-  display: table-row-group;
-}
-
-._tr {
-  display: table-row;
-}
-
-._td,
-._th {
-  display: table-cell;
-  vertical-align: middle;
-}
-
-._th {
-  font-weight: bold;
-  text-align: center;
-}
-
-._ul {
-  list-style-type: disc;
-}
-
-._ul ._ul {
-  margin: 0;
-  list-style-type: circle;
-}
-
-._ul ._ul ._ul {
-  list-style-type: square;
-}
-
-._abbr,
-._b,
-._code,
-._del,
-._em,
-._i,
-._ins,
-._label,
-._q,
-._span,
-._strong,
-._sub,
-._sup {
-  display: inline;
-}
-
-/* #ifdef APP-PLUS */
-._video {
-  width: 300px;
-  height: 225px;
-}
-/* #endif */
-</style>

+ 0 - 1260
uni_modules/mp-html/components/mp-html/parser.js

@@ -1,1260 +0,0 @@
-/**
- * @fileoverview html 解析器
- */
-
-// 配置
-const config = {
-  // 信任的标签(保持标签名不变)
-  trustTags: makeMap('a,abbr,ad,audio,b,blockquote,br,code,col,colgroup,dd,del,dl,dt,div,em,fieldset,h1,h2,h3,h4,h5,h6,hr,i,img,ins,label,legend,li,ol,p,q,ruby,rt,source,span,strong,sub,sup,table,tbody,td,tfoot,th,thead,tr,title,ul,video'),
-
-  // 块级标签(转为 div,其他的非信任标签转为 span)
-  blockTags: makeMap('address,article,aside,body,caption,center,cite,footer,header,html,nav,pre,section'),
-
-  // #ifdef (MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE3
-  // 行内标签
-  inlineTags: makeMap('abbr,b,big,code,del,em,i,ins,label,q,small,span,strong,sub,sup'),
-  // #endif
-
-  // 要移除的标签
-  ignoreTags: makeMap('area,base,canvas,embed,frame,head,iframe,input,link,map,meta,param,rp,script,source,style,textarea,title,track,wbr'),
-
-  // 自闭合的标签
-  voidTags: makeMap('area,base,br,col,circle,ellipse,embed,frame,hr,img,input,line,link,meta,param,path,polygon,rect,source,track,use,wbr'),
-
-  // html 实体
-  entities: {
-    lt: '<',
-    gt: '>',
-    quot: '"',
-    apos: "'",
-    ensp: '\u2002',
-    emsp: '\u2003',
-    nbsp: '\xA0',
-    semi: ';',
-    ndash: '–',
-    mdash: '—',
-    middot: '·',
-    lsquo: '‘',
-    rsquo: '’',
-    ldquo: '“',
-    rdquo: '”',
-    bull: '•',
-    hellip: '…'
-  },
-
-  // 默认的标签样式
-  tagStyle: {
-    // #ifndef APP-PLUS-NVUE
-    address: 'font-style:italic',
-    big: 'display:inline;font-size:1.2em',
-    caption: 'display:table-caption;text-align:center',
-    center: 'text-align:center',
-    cite: 'font-style:italic',
-    dd: 'margin-left:40px',
-    mark: 'background-color:yellow',
-    pre: 'font-family:monospace;white-space:pre',
-    s: 'text-decoration:line-through',
-    small: 'display:inline;font-size:0.8em',
-    strike: 'text-decoration:line-through',
-    u: 'text-decoration:underline'
-    // #endif
-  },
-
-  // svg 大小写对照表
-  svgDict: {
-    animatetransform: 'animateTransform',
-    lineargradient: 'linearGradient',
-    viewbox: 'viewBox',
-    attributename: 'attributeName',
-    repeatcount: 'repeatCount',
-    repeatdur: 'repeatDur'
-  }
-}
-const tagSelector={}
-const {
-  windowWidth,
-  // #ifdef MP-WEIXIN
-  system
-  // #endif
-} = uni.getSystemInfoSync()
-const blankChar = makeMap(' ,\r,\n,\t,\f')
-let idIndex = 0
-
-// #ifdef H5 || APP-PLUS
-config.ignoreTags.iframe = undefined
-config.trustTags.iframe = true
-config.ignoreTags.embed = undefined
-config.trustTags.embed = true
-// #endif
-// #ifdef APP-PLUS-NVUE
-config.ignoreTags.source = undefined
-config.ignoreTags.style = undefined
-// #endif
-
-/**
- * @description 创建 map
- * @param {String} str 逗号分隔
- */
-function makeMap (str) {
-  const map = Object.create(null)
-  const list = str.split(',')
-  for (let i = list.length; i--;) {
-    map[list[i]] = true
-  }
-  return map
-}
-
-/**
- * @description 解码 html 实体
- * @param {String} str 要解码的字符串
- * @param {Boolean} amp 要不要解码 &amp;
- * @returns {String} 解码后的字符串
- */
-function decodeEntity (str, amp) {
-  let i = str.indexOf('&')
-  while (i !== -1) {
-    const j = str.indexOf(';', i + 3)
-    let code
-    if (j === -1) break
-    if (str[i + 1] === '#') {
-      // &#123; 形式的实体
-      code = parseInt((str[i + 2] === 'x' ? '0' : '') + str.substring(i + 2, j))
-      if (!isNaN(code)) {
-        str = str.substr(0, i) + String.fromCharCode(code) + str.substr(j + 1)
-      }
-    } else {
-      // &nbsp; 形式的实体
-      code = str.substring(i + 1, j)
-      if (config.entities[code] || (code === 'amp' && amp)) {
-        str = str.substr(0, i) + (config.entities[code] || '&') + str.substr(j + 1)
-      }
-    }
-    i = str.indexOf('&', i + 1)
-  }
-  return str
-}
-
-/**
- * @description html 解析器
- * @param {Object} vm 组件实例
- */
-function Parser (vm) {
-  this.options = vm || {}
-  this.tagStyle = Object.assign({}, config.tagStyle, this.options.tagStyle)
-  this.imgList = vm.imgList || []
-  this.plugins = vm.plugins || []
-  this.attrs = Object.create(null)
-  this.stack = []
-  this.nodes = []
-  this.pre = (this.options.containerStyle || '').includes('white-space') && this.options.containerStyle.includes('pre') ? 2 : 0
-}
-
-/**
- * @description 执行解析
- * @param {String} content 要解析的文本
- */
-Parser.prototype.parse = function (content) {
-  // 插件处理
-  for (let i = this.plugins.length; i--;) {
-    if (this.plugins[i].onUpdate) {
-      content = this.plugins[i].onUpdate(content, config) || content
-    }
-  }
-
-  new Lexer(this).parse(content)
-  // 出栈未闭合的标签
-  while (this.stack.length) {
-    this.popNode()
-  }
-  return this.nodes
-}
-
-/**
- * @description 将标签暴露出来(不被 rich-text 包含)
- */
-Parser.prototype.expose = function () {
-  // #ifndef APP-PLUS-NVUE
-  for (let i = this.stack.length; i--;) {
-    const item = this.stack[i]
-    if (item.c || item.name === 'a' || item.name === 'video' || item.name === 'audio') return
-    item.c = 1
-  }
-  // #endif
-}
-
-/**
- * @description 处理插件
- * @param {Object} node 要处理的标签
- * @returns {Boolean} 是否要移除此标签
- */
-Parser.prototype.hook = function (node) {
-  for (let i = this.plugins.length; i--;) {
-    if (this.plugins[i].onParse && this.plugins[i].onParse(node, this) === false) {
-      return false
-    }
-  }
-  return true
-}
-
-/**
- * @description 将链接拼接上主域名
- * @param {String} url 需要拼接的链接
- * @returns {String} 拼接后的链接
- */
-Parser.prototype.getUrl = function (url) {
-  const domain = this.options.domain
-  if (url[0] === '/') {
-    if (url[1] === '/') {
-      // // 开头的补充协议名
-      url = (domain ? domain.split('://')[0] : 'http') + ':' + url
-    } else if (domain) {
-      // 否则补充整个域名
-      url = domain + url
-    }
-  } else if (domain && !url.includes('data:') && !url.includes('://')) {
-    url = domain + '/' + url
-  }
-  return url
-}
-
-/**
- * @description 解析样式表
- * @param {Object} node 标签
- * @returns {Object}
- */
-Parser.prototype.parseStyle = function (node) {
-  const attrs = node.attrs
-  const list = (this.tagStyle[node.name] || '').split(';').concat((attrs.style || '').split(';'))
-  const styleObj = {}
-  let tmp = ''
-
-  if (attrs.id && !this.xml) {
-    // 暴露锚点
-    if (this.options.useAnchor) {
-      this.expose()
-    } else if (node.name !== 'img' && node.name !== 'a' && node.name !== 'video' && node.name !== 'audio') {
-      attrs.id = undefined
-    }
-  }
-
-  // 转换 width 和 height 属性
-  if (attrs.width) {
-    styleObj.width = parseFloat(attrs.width) + (attrs.width.includes('%') ? '%' : 'px')
-    attrs.width = undefined
-  }
-  if (attrs.height) {
-    styleObj.height = parseFloat(attrs.height) + (attrs.height.includes('%') ? '%' : 'px')
-    attrs.height = undefined
-  }
-
-  for (let i = 0, len = list.length; i < len; i++) {
-    const info = list[i].split(':')
-    if (info.length < 2) continue
-    const key = info.shift().trim().toLowerCase()
-    let value = info.join(':').trim()
-    if ((value[0] === '-' && value.lastIndexOf('-') > 0) || value.includes('safe')) {
-      // 兼容性的 css 不压缩
-      tmp += `;${key}:${value}`
-    } else if (!styleObj[key] || value.includes('import') || !styleObj[key].includes('import')) {
-      // 重复的样式进行覆盖
-      if (value.includes('url')) {
-        // 填充链接
-        let j = value.indexOf('(') + 1
-        if (j) {
-          while (value[j] === '"' || value[j] === "'" || blankChar[value[j]]) {
-            j++
-          }
-          value = value.substr(0, j) + this.getUrl(value.substr(j))
-        }
-      } else if (value.includes('rpx')) {
-        // 转换 rpx(rich-text 内部不支持 rpx)
-        value = value.replace(/[0-9.]+\s*rpx/g, $ => parseFloat($) * windowWidth / 750 + 'px')
-      }
-      styleObj[key] = value
-    }
-  }
-
-  node.attrs.style = tmp
-  return styleObj
-}
-
-/**
- * @description 解析到标签名
- * @param {String} name 标签名
- * @private
- */
-Parser.prototype.onTagName = function (name) {
-  this.tagName = this.xml ? name : name.toLowerCase()
-  if (this.tagName === 'svg') {
-    this.xml = (this.xml || 0) + 1 // svg 标签内大小写敏感
-  }
-}
-
-/**
- * @description 解析到属性名
- * @param {String} name 属性名
- * @private
- */
-Parser.prototype.onAttrName = function (name) {
-  name = this.xml ? name : name.toLowerCase()
-  if (name.substr(0, 5) === 'data-') {
-    if (name === 'data-src' && !this.attrs.src) {
-      // data-src 自动转为 src
-      this.attrName = 'src'
-    } else if (this.tagName === 'img' || this.tagName === 'a') {
-      // a 和 img 标签保留 data- 的属性,可以在 imgtap 和 linktap 事件中使用
-      this.attrName = name
-    } else {
-      // 剩余的移除以减小大小
-      this.attrName = undefined
-    }
-  } else {
-    this.attrName = name
-    this.attrs[name] = 'T' // boolean 型属性缺省设置
-  }
-}
-
-/**
- * @description 解析到属性值
- * @param {String} val 属性值
- * @private
- */
-Parser.prototype.onAttrVal = function (val) {
-  const name = this.attrName || ''
-  if (name === 'style' || name === 'href') {
-    // 部分属性进行实体解码
-    this.attrs[name] = decodeEntity(val, true)
-  } else if (name.includes('src')) {
-    // 拼接主域名
-    this.attrs[name] = this.getUrl(decodeEntity(val, true))
-  } else if (name) {
-    this.attrs[name] = val
-  }
-}
-
-/**
- * @description 解析到标签开始
- * @param {Boolean} selfClose 是否有自闭合标识 />
- * @private
- */
-Parser.prototype.onOpenTag = function (selfClose) {
-  // 拼装 node
-  const node = Object.create(null)
-  node.name = this.tagName
-  node.attrs = this.attrs
-  // 避免因为自动 diff 使得 type 被设置为 null 导致部分内容不显示
-  if (this.options.nodes.length) {
-    node.type = 'node'
-  }
-  this.attrs = Object.create(null)
-
-  const attrs = node.attrs
-  const parent = this.stack[this.stack.length - 1]
-  const siblings = parent ? parent.children : this.nodes
-  const close = this.xml ? selfClose : config.voidTags[node.name]
-
-  // 替换标签名选择器
-  if (tagSelector[node.name]) {
-    attrs.class = tagSelector[node.name] + (attrs.class ? ' ' + attrs.class : '')
-  }
-
-  // 转换 embed 标签
-  if (node.name === 'embed') {
-    // #ifndef H5 || APP-PLUS
-    const src = attrs.src || ''
-    // 按照后缀名和 type 将 embed 转为 video 或 audio
-    if (src.includes('.mp4') || src.includes('.3gp') || src.includes('.m3u8') || (attrs.type || '').includes('video')) {
-      node.name = 'video'
-    } else if (src.includes('.mp3') || src.includes('.wav') || src.includes('.aac') || src.includes('.m4a') || (attrs.type || '').includes('audio')) {
-      node.name = 'audio'
-    }
-    if (attrs.autostart) {
-      attrs.autoplay = 'T'
-    }
-    attrs.controls = 'T'
-    // #endif
-    // #ifdef H5 || APP-PLUS
-    this.expose()
-    // #endif
-  }
-
-  // #ifndef APP-PLUS-NVUE
-  // 处理音视频
-  if (node.name === 'video' || node.name === 'audio') {
-    // 设置 id 以便获取 context
-    if (node.name === 'video' && !attrs.id) {
-      attrs.id = 'v' + idIndex++
-    }
-    // 没有设置 controls 也没有设置 autoplay 的自动设置 controls
-    if (!attrs.controls && !attrs.autoplay) {
-      attrs.controls = 'T'
-    }
-    // 用数组存储所有可用的 source
-    node.src = []
-    if (attrs.src) {
-      node.src.push(attrs.src)
-      attrs.src = undefined
-    }
-    this.expose()
-  }
-  // #endif
-
-  // 处理自闭合标签
-  if (close) {
-    if (!this.hook(node) || config.ignoreTags[node.name]) {
-      // 通过 base 标签设置主域名
-      if (node.name === 'base' && !this.options.domain) {
-        this.options.domain = attrs.href
-      } /* #ifndef APP-PLUS-NVUE */ else if (node.name === 'source' && parent && (parent.name === 'video' || parent.name === 'audio') && attrs.src) {
-        // 设置 source 标签(仅父节点为 video 或 audio 时有效)
-        parent.src.push(attrs.src)
-      } /* #endif */
-      return
-    }
-
-    // 解析 style
-    const styleObj = this.parseStyle(node)
-
-    // 处理图片
-    if (node.name === 'img') {
-      if (attrs.src) {
-        // 标记 webp
-        if (attrs.src.includes('webp')) {
-          node.webp = 'T'
-        }
-        // data url 图片如果没有设置 original-src 默认为不可预览的小图片
-        if (attrs.src.includes('data:') && !attrs['original-src']) {
-          attrs.ignore = 'T'
-        }
-        if (!attrs.ignore || node.webp || attrs.src.includes('cloud://')) {
-          for (let i = this.stack.length; i--;) {
-            const item = this.stack[i]
-            if (item.name === 'a') {
-              node.a = item.attrs
-              break
-            }
-            // #ifndef H5 || APP-PLUS
-            const style = item.attrs.style || ''
-            if (style.includes('flex:') && !style.includes('flex:0') && !style.includes('flex: 0') && (!styleObj.width || !styleObj.width.includes('%'))) {
-              styleObj.width = '100% !important'
-              styleObj.height = ''
-              for (let j = i + 1; j < this.stack.length; j++) {
-                this.stack[j].attrs.style = (this.stack[j].attrs.style || '').replace('inline-', '')
-              }
-            } else if (style.includes('flex') && styleObj.width === '100%') {
-              for (let j = i + 1; j < this.stack.length; j++) {
-                const style = this.stack[j].attrs.style || ''
-                if (!style.includes(';width') && !style.includes(' width') && style.indexOf('width') !== 0) {
-                  styleObj.width = ''
-                  break
-                }
-              }
-            } else if (style.includes('inline-block')) {
-              if (styleObj.width && styleObj.width[styleObj.width.length - 1] === '%') {
-                item.attrs.style += ';max-width:' + styleObj.width
-                styleObj.width = ''
-              } else {
-                item.attrs.style += ';max-width:100%'
-              }
-            }
-            // #endif
-            item.c = 1
-          }
-          attrs.i = this.imgList.length.toString()
-          let src = attrs['original-src'] || attrs.src
-          // #ifndef H5 || MP-ALIPAY || APP-PLUS || MP-360
-          if (this.imgList.includes(src)) {
-            // 如果有重复的链接则对域名进行随机大小写变换避免预览时错位
-            let i = src.indexOf('://')
-            if (i !== -1) {
-              i += 3
-              let newSrc = src.substr(0, i)
-              for (; i < src.length; i++) {
-                if (src[i] === '/') break
-                newSrc += Math.random() > 0.5 ? src[i].toUpperCase() : src[i]
-              }
-              newSrc += src.substr(i)
-              src = newSrc
-            }
-          }
-          // #endif
-          this.imgList.push(src)
-          // #ifdef H5 || APP-PLUS
-          if (this.options.lazyLoad) {
-            attrs['data-src'] = attrs.src
-            attrs.src = undefined
-          }
-          // #endif
-        }
-      }
-      if (styleObj.display === 'inline') {
-        styleObj.display = ''
-      }
-      // #ifndef APP-PLUS-NVUE
-      if (attrs.ignore) {
-        styleObj['max-width'] = styleObj['max-width'] || '100%'
-        attrs.style += ';-webkit-touch-callout:none'
-      }
-      // #endif
-      // 设置的宽度超出屏幕,为避免变形,高度转为自动
-      if (parseInt(styleObj.width) > windowWidth) {
-        styleObj.height = undefined
-      }
-      // 记录是否设置了宽高
-      if (styleObj.width) {
-        if (styleObj.width.includes('auto')) {
-          styleObj.width = ''
-        } else {
-          node.w = 'T'
-          if (!isNaN(parseInt(styleObj.height)) && (!styleObj.height.includes('%') || (parent && (parent.attrs.style || '').includes('height')))) {
-            node.h = 'T'
-          }
-        }
-      }
-    } else if (node.name === 'svg') {
-      siblings.push(node)
-      this.stack.push(node)
-      this.popNode()
-      return
-    }
-    for (const key in styleObj) {
-      if (styleObj[key]) {
-        attrs.style += `;${key}:${styleObj[key].replace(' !important', '')}`
-      }
-    }
-    attrs.style = attrs.style.substr(1) || undefined
-  } else {
-    if ((node.name === 'pre' || ((attrs.style || '').includes('white-space') && attrs.style.includes('pre'))) && this.pre !== 2) {
-      this.pre = node.pre = 1
-    }
-    node.children = []
-    this.stack.push(node)
-  }
-
-  // 加入节点树
-  siblings.push(node)
-}
-
-/**
- * @description 解析到标签结束
- * @param {String} name 标签名
- * @private
- */
-Parser.prototype.onCloseTag = function (name) {
-  // 依次出栈到匹配为止
-  name = this.xml ? name : name.toLowerCase()
-  let i
-  for (i = this.stack.length; i--;) {
-    if (this.stack[i].name === name) break
-  }
-  if (i !== -1) {
-    while (this.stack.length > i) {
-      this.popNode()
-    }
-  } else if (name === 'p' || name === 'br') {
-    const siblings = this.stack.length ? this.stack[this.stack.length - 1].children : this.nodes
-    siblings.push({
-      name,
-      attrs: {
-        class: tagSelector[name],
-        style: this.tagStyle[name]
-      }
-    })
-  }
-}
-
-/**
- * @description 处理标签出栈
- * @private
- */
-Parser.prototype.popNode = function () {
-  const node = this.stack.pop()
-  let attrs = node.attrs
-  const children = node.children
-  const parent = this.stack[this.stack.length - 1]
-  const siblings = parent ? parent.children : this.nodes
-
-  if (!this.hook(node) || config.ignoreTags[node.name]) {
-    // 获取标题
-    if (node.name === 'title' && children.length && children[0].type === 'text' && this.options.setTitle) {
-      uni.setNavigationBarTitle({
-        title: children[0].text
-      })
-    }
-    siblings.pop()
-    return
-  }
-
-  if (node.pre && this.pre !== 2) {
-    // 是否合并空白符标识
-    this.pre = node.pre = undefined
-    for (let i = this.stack.length; i--;) {
-      if (this.stack[i].pre) {
-        this.pre = 1
-      }
-    }
-  }
-
-  const styleObj = {}
-
-  // 转换 svg
-  if (node.name === 'svg') {
-    if (this.xml > 1) {
-      // 多层 svg 嵌套
-      this.xml--
-      return
-    }
-    // #ifdef APP-PLUS-NVUE
-    (function traversal (node) {
-      if (node.name) {
-        // 调整 svg 的大小写
-        node.name = config.svgDict[node.name] || node.name
-        for (const item in node.attrs) {
-          if (config.svgDict[item]) {
-            node.attrs[config.svgDict[item]] = node.attrs[item]
-            node.attrs[item] = undefined
-          }
-        }
-        for (let i = 0; i < (node.children || []).length; i++) {
-          traversal(node.children[i])
-        }
-      }
-    })(node)
-    // #endif
-    // #ifndef APP-PLUS-NVUE
-    let src = ''
-    const style = attrs.style
-    attrs.style = ''
-    attrs.xmlns = 'http://www.w3.org/2000/svg';
-    (function traversal (node) {
-      if (node.type === 'text') {
-        src += node.text
-        return
-      }
-      const name = config.svgDict[node.name] || node.name
-      src += '<' + name
-      for (const item in node.attrs) {
-        const val = node.attrs[item]
-        if (val) {
-          src += ` ${config.svgDict[item] || item}="${val}"`
-        }
-      }
-      if (!node.children) {
-        src += '/>'
-      } else {
-        src += '>'
-        for (let i = 0; i < node.children.length; i++) {
-          traversal(node.children[i])
-        }
-        src += '</' + name + '>'
-      }
-    })(node)
-    node.name = 'img'
-    node.attrs = {
-      src: 'data:image/svg+xml;utf8,' + src.replace(/#/g, '%23'),
-      style,
-      ignore: 'T'
-    }
-    node.children = undefined
-    // #endif
-    this.xml = false
-    return
-  }
-
-  // #ifndef APP-PLUS-NVUE
-  // 转换 align 属性
-  if (attrs.align) {
-    if (node.name === 'table') {
-      if (attrs.align === 'center') {
-        styleObj['margin-inline-start'] = styleObj['margin-inline-end'] = 'auto'
-      } else {
-        styleObj.float = attrs.align
-      }
-    } else {
-      styleObj['text-align'] = attrs.align
-    }
-    attrs.align = undefined
-  }
-
-  // 转换 dir 属性
-  if (attrs.dir) {
-    styleObj.direction = attrs.dir
-    attrs.dir = undefined
-  }
-
-  // 转换 font 标签的属性
-  if (node.name === 'font') {
-    if (attrs.color) {
-      styleObj.color = attrs.color
-      attrs.color = undefined
-    }
-    if (attrs.face) {
-      styleObj['font-family'] = attrs.face
-      attrs.face = undefined
-    }
-    if (attrs.size) {
-      let size = parseInt(attrs.size)
-      if (!isNaN(size)) {
-        if (size < 1) {
-          size = 1
-        } else if (size > 7) {
-          size = 7
-        }
-        styleObj['font-size'] = ['x-small', 'small', 'medium', 'large', 'x-large', 'xx-large', 'xxx-large'][size - 1]
-      }
-      attrs.size = undefined
-    }
-  }
-  // #endif
-
-  // 一些编辑器的自带 class
-  if ((attrs.class || '').includes('align-center')) {
-    styleObj['text-align'] = 'center'
-  }
-
-  Object.assign(styleObj, this.parseStyle(node))
-
-  if (node.name !== 'table' && parseInt(styleObj.width) > windowWidth) {
-    styleObj['max-width'] = '100%'
-    styleObj['box-sizing'] = 'border-box'
-  }
-
-  // #ifndef APP-PLUS-NVUE
-  if (config.blockTags[node.name]) {
-    node.name = 'div'
-  } else if (!config.trustTags[node.name] && !this.xml) {
-    // 未知标签转为 span,避免无法显示
-    node.name = 'span'
-  }
-
-  if (node.name === 'a' || node.name === 'ad'
-    // #ifdef H5 || APP-PLUS
-    || node.name === 'iframe' // eslint-disable-line
-    // #endif
-  ) {
-    this.expose()
-  } /* #ifdef APP-PLUS */ else if (node.name === 'video') {
-    let str = '<video style="width:100%;height:100%"'
-    for (const item in attrs) {
-      if (attrs[item]) {
-        str += ' ' + item + '="' + attrs[item] + '"'
-      }
-    }
-    if (this.options.pauseVideo) {
-      str += ' onplay="for(var e=document.getElementsByTagName(\'video\'),t=0;t<e.length;t++)e[t]!=this&&e[t].pause()"'
-    }
-    str += '>'
-    for (let i = 0; i < node.src.length; i++) {
-      str += '<source src="' + node.src[i] + '">'
-    }
-    str += '</video>'
-    node.html = str
-  } /* #endif */ else if ((node.name === 'ul' || node.name === 'ol') && node.c) {
-    // 列表处理
-    const types = {
-      a: 'lower-alpha',
-      A: 'upper-alpha',
-      i: 'lower-roman',
-      I: 'upper-roman'
-    }
-    if (types[attrs.type]) {
-      attrs.style += ';list-style-type:' + types[attrs.type]
-      attrs.type = undefined
-    }
-    for (let i = children.length; i--;) {
-      if (children[i].name === 'li') {
-        children[i].c = 1
-      }
-    }
-  } else if (node.name === 'table') {
-    // 表格处理
-    // cellpadding、cellspacing、border 这几个常用表格属性需要通过转换实现
-    let padding = parseFloat(attrs.cellpadding)
-    let spacing = parseFloat(attrs.cellspacing)
-    const border = parseFloat(attrs.border)
-    if (node.c) {
-      // padding 和 spacing 默认 2
-      if (isNaN(padding)) {
-        padding = 2
-      }
-      if (isNaN(spacing)) {
-        spacing = 2
-      }
-    }
-    if (border) {
-      attrs.style += ';border:' + border + 'px solid gray'
-    }
-    if (node.flag && node.c) {
-      // 有 colspan 或 rowspan 且含有链接的表格通过 grid 布局实现
-      styleObj.display = 'grid'
-      if (spacing) {
-        styleObj['grid-gap'] = spacing + 'px'
-        styleObj.padding = spacing + 'px'
-      } else if (border) {
-        // 无间隔的情况下避免边框重叠
-        attrs.style += ';border-left:0;border-top:0'
-      }
-
-      const width = [] // 表格的列宽
-      const trList = [] // tr 列表
-      const cells = [] // 保存新的单元格
-      const map = {}; // 被合并单元格占用的格子
-
-      (function traversal (nodes) {
-        for (let i = 0; i < nodes.length; i++) {
-          if (nodes[i].name === 'tr') {
-            trList.push(nodes[i])
-          } else {
-            traversal(nodes[i].children || [])
-          }
-        }
-      })(children)
-
-      for (let row = 1; row <= trList.length; row++) {
-        let col = 1
-        for (let j = 0; j < trList[row - 1].children.length; j++, col++) {
-          const td = trList[row - 1].children[j]
-          if (td.name === 'td' || td.name === 'th') {
-            // 这个格子被上面的单元格占用,则列号++
-            while (map[row + '.' + col]) {
-              col++
-            }
-            let style = td.attrs.style || ''
-            const start = style.indexOf('width') ? style.indexOf(';width') : 0
-            // 提取出 td 的宽度
-            if (start !== -1) {
-              let end = style.indexOf(';', start + 6)
-              if (end === -1) {
-                end = style.length
-              }
-              if (!td.attrs.colspan) {
-                width[col] = style.substring(start ? start + 7 : 6, end)
-              }
-              style = style.substr(0, start) + style.substr(end)
-            }
-            style += (border ? `;border:${border}px solid gray` + (spacing ? '' : ';border-right:0;border-bottom:0') : '') + (padding ? `;padding:${padding}px` : '')
-            // 处理列合并
-            if (td.attrs.colspan) {
-              style += `;grid-column-start:${col};grid-column-end:${col + parseInt(td.attrs.colspan)}`
-              if (!td.attrs.rowspan) {
-                style += `;grid-row-start:${row};grid-row-end:${row + 1}`
-              }
-              col += parseInt(td.attrs.colspan) - 1
-            }
-            // 处理行合并
-            if (td.attrs.rowspan) {
-              style += `;grid-row-start:${row};grid-row-end:${row + parseInt(td.attrs.rowspan)}`
-              if (!td.attrs.colspan) {
-                style += `;grid-column-start:${col};grid-column-end:${col + 1}`
-              }
-              // 记录下方单元格被占用
-              for (let rowspan = 1; rowspan < td.attrs.rowspan; rowspan++) {
-                for (let colspan = 0; colspan < (td.attrs.colspan || 1); colspan++) {
-                  map[(row + rowspan) + '.' + (col - colspan)] = 1
-                }
-              }
-            }
-            if (style) {
-              td.attrs.style = style
-            }
-            cells.push(td)
-          }
-        }
-        if (row === 1) {
-          let temp = ''
-          for (let i = 1; i < col; i++) {
-            temp += (width[i] ? width[i] : 'auto') + ' '
-          }
-          styleObj['grid-template-columns'] = temp
-        }
-      }
-      node.children = cells
-    } else {
-      // 没有使用合并单元格的表格通过 table 布局实现
-      if (node.c) {
-        styleObj.display = 'table'
-      }
-      if (!isNaN(spacing)) {
-        styleObj['border-spacing'] = spacing + 'px'
-      }
-      if (border || padding) {
-        // 遍历
-        (function traversal (nodes) {
-          for (let i = 0; i < nodes.length; i++) {
-            const td = nodes[i]
-            if (td.name === 'th' || td.name === 'td') {
-              if (border) {
-                td.attrs.style = `border:${border}px solid gray;${td.attrs.style || ''}`
-              }
-              if (padding) {
-                td.attrs.style = `padding:${padding}px;${td.attrs.style || ''}`
-              }
-            } else if (td.children) {
-              traversal(td.children)
-            }
-          }
-        })(children)
-      }
-    }
-    // 给表格添加一个单独的横向滚动层
-    if (this.options.scrollTable && !(attrs.style || '').includes('inline')) {
-      const table = Object.assign({}, node)
-      node.name = 'div'
-      node.attrs = {
-        style: 'overflow:auto'
-      }
-      node.children = [table]
-      attrs = table.attrs
-    }
-  } else if ((node.name === 'td' || node.name === 'th') && (attrs.colspan || attrs.rowspan)) {
-    for (let i = this.stack.length; i--;) {
-      if (this.stack[i].name === 'table') {
-        this.stack[i].flag = 1 // 指示含有合并单元格
-        break
-      }
-    }
-  } else if (node.name === 'ruby') {
-    // 转换 ruby
-    node.name = 'span'
-    for (let i = 0; i < children.length - 1; i++) {
-      if (children[i].type === 'text' && children[i + 1].name === 'rt') {
-        children[i] = {
-          name: 'div',
-          attrs: {
-            style: 'display:inline-block;text-align:center'
-          },
-          children: [{
-            name: 'div',
-            attrs: {
-              style: 'font-size:50%;' + (children[i + 1].attrs.style || '')
-            },
-            children: children[i + 1].children
-          }, children[i]]
-        }
-        children.splice(i + 1, 1)
-      }
-    }
-  } else if (node.c) {
-    node.c = 2
-    for (let i = node.children.length; i--;) {
-      const child = node.children[i]
-      // #ifdef (MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE3
-      if (child.name && (config.inlineTags[child.name] || (child.attrs.style || '').includes('inline'))) {
-        child.c = 1
-      }
-      // #endif
-      if (!child.c || child.name === 'table') {
-        node.c = 1
-      }
-    }
-  }
-
-  if ((styleObj.display || '').includes('flex') && !node.c) {
-    for (let i = children.length; i--;) {
-      const item = children[i]
-      if (item.f) {
-        item.attrs.style = (item.attrs.style || '') + item.f
-        item.f = undefined
-      }
-    }
-  }
-  // flex 布局时部分样式需要提取到 rich-text 外层
-  const flex = parent && (parent.attrs.style || '').includes('flex')
-    // #ifdef MP-WEIXIN
-    // 检查基础库版本 virtualHost 是否可用
-    && !(node.c && wx.getNFCAdapter) // eslint-disable-line
-    // #endif
-    // #ifndef MP-WEIXIN || MP-QQ || MP-BAIDU || MP-TOUTIAO
-    && !node.c // eslint-disable-line
-  // #endif
-  if (flex) {
-    node.f = ';max-width:100%'
-  }
-
-  // 优化长内容加载速度
-  if (children.length >= 50 && node.c && !(styleObj.display || '').includes('flex')) {
-    let i = children.length - 1
-    for (let j = i; j >= -1; j--) {
-      // 合并多个块级标签
-      if (j === -1 || children[j].c || !children[j].name || (children[j].name !== 'div' && children[j].name !== 'p' && children[j].name[0] !== 'h') || (children[j].attrs.style || '').includes('inline')) {
-        if (i - j >= 5) {
-          children.splice(j + 1, i - j, {
-            name: 'div',
-            attrs: {},
-            children: node.children.slice(j + 1, i + 1)
-          })
-        }
-        i = j - 1
-      }
-    }
-  }
-  // #endif
-
-  for (const key in styleObj) {
-    if (styleObj[key]) {
-      const val = `;${key}:${styleObj[key].replace(' !important', '')}`
-      /* #ifndef APP-PLUS-NVUE */
-      if (flex && ((key.includes('flex') && key !== 'flex-direction') || key === 'align-self' || styleObj[key][0] === '-' || (key === 'width' && val.includes('%')))) {
-        node.f += val
-        if (key === 'width') {
-          attrs.style += ';width:100%'
-        }
-      } else /* #endif */ {
-        attrs.style += val
-      }
-    }
-  }
-  attrs.style = attrs.style.substr(1) || undefined
-  // #ifdef (MP-WEIXIN || MP-QQ) && VUE3
-  if (!attrs.style) {
-    delete attrs.style
-  }
-  // #endif
-}
-
-/**
- * @description 解析到文本
- * @param {String} text 文本内容
- */
-Parser.prototype.onText = function (text) {
-  if (!this.pre) {
-    // 合并空白符
-    let trim = ''
-    let flag
-    for (let i = 0, len = text.length; i < len; i++) {
-      if (!blankChar[text[i]]) {
-        trim += text[i]
-      } else {
-        if (trim[trim.length - 1] !== ' ') {
-          trim += ' '
-        }
-        if (text[i] === '\n' && !flag) {
-          flag = true
-        }
-      }
-    }
-    // 去除含有换行符的空串
-    if (trim === ' ' && flag) return
-    text = trim
-  }
-  const node = Object.create(null)
-  node.type = 'text'
-  // #ifdef (MP-BAIDU || MP-ALIPAY || MP-TOUTIAO) && VUE3
-  node.attrs = {}
-  // #endif
-  node.text = decodeEntity(text)
-  if (this.hook(node)) {
-    // #ifdef MP-WEIXIN
-    if (this.options.selectable === 'force' && system.includes('iOS')) {
-      this.expose()
-      node.us = 'T'
-    }
-    // #endif
-    const siblings = this.stack.length ? this.stack[this.stack.length - 1].children : this.nodes
-    siblings.push(node)
-  }
-}
-
-/**
- * @description html 词法分析器
- * @param {Object} handler 高层处理器
- */
-function Lexer (handler) {
-  this.handler = handler
-}
-
-/**
- * @description 执行解析
- * @param {String} content 要解析的文本
- */
-Lexer.prototype.parse = function (content) {
-  this.content = content || ''
-  this.i = 0 // 标记解析位置
-  this.start = 0 // 标记一个单词的开始位置
-  this.state = this.text // 当前状态
-  for (let len = this.content.length; this.i !== -1 && this.i < len;) {
-    this.state()
-  }
-}
-
-/**
- * @description 检查标签是否闭合
- * @param {String} method 如果闭合要进行的操作
- * @returns {Boolean} 是否闭合
- * @private
- */
-Lexer.prototype.checkClose = function (method) {
-  const selfClose = this.content[this.i] === '/'
-  if (this.content[this.i] === '>' || (selfClose && this.content[this.i + 1] === '>')) {
-    if (method) {
-      this.handler[method](this.content.substring(this.start, this.i))
-    }
-    this.i += selfClose ? 2 : 1
-    this.start = this.i
-    this.handler.onOpenTag(selfClose)
-    if (this.handler.tagName === 'script') {
-      this.i = this.content.indexOf('</', this.i)
-      if (this.i !== -1) {
-        this.i += 2
-        this.start = this.i
-      }
-      this.state = this.endTag
-    } else {
-      this.state = this.text
-    }
-    return true
-  }
-  return false
-}
-
-/**
- * @description 文本状态
- * @private
- */
-Lexer.prototype.text = function () {
-  this.i = this.content.indexOf('<', this.i) // 查找最近的标签
-  if (this.i === -1) {
-    // 没有标签了
-    if (this.start < this.content.length) {
-      this.handler.onText(this.content.substring(this.start, this.content.length))
-    }
-    return
-  }
-  const c = this.content[this.i + 1]
-  if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
-    // 标签开头
-    if (this.start !== this.i) {
-      this.handler.onText(this.content.substring(this.start, this.i))
-    }
-    this.start = ++this.i
-    this.state = this.tagName
-  } else if (c === '/' || c === '!' || c === '?') {
-    if (this.start !== this.i) {
-      this.handler.onText(this.content.substring(this.start, this.i))
-    }
-    const next = this.content[this.i + 2]
-    if (c === '/' && ((next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z'))) {
-      // 标签结尾
-      this.i += 2
-      this.start = this.i
-      this.state = this.endTag
-      return
-    }
-    // 处理注释
-    let end = '-->'
-    if (c !== '!' || this.content[this.i + 2] !== '-' || this.content[this.i + 3] !== '-') {
-      end = '>'
-    }
-    this.i = this.content.indexOf(end, this.i)
-    if (this.i !== -1) {
-      this.i += end.length
-      this.start = this.i
-    }
-  } else {
-    this.i++
-  }
-}
-
-/**
- * @description 标签名状态
- * @private
- */
-Lexer.prototype.tagName = function () {
-  if (blankChar[this.content[this.i]]) {
-    // 解析到标签名
-    this.handler.onTagName(this.content.substring(this.start, this.i))
-    while (blankChar[this.content[++this.i]]);
-    if (this.i < this.content.length && !this.checkClose()) {
-      this.start = this.i
-      this.state = this.attrName
-    }
-  } else if (!this.checkClose('onTagName')) {
-    this.i++
-  }
-}
-
-/**
- * @description 属性名状态
- * @private
- */
-Lexer.prototype.attrName = function () {
-  let c = this.content[this.i]
-  if (blankChar[c] || c === '=') {
-    // 解析到属性名
-    this.handler.onAttrName(this.content.substring(this.start, this.i))
-    let needVal = c === '='
-    const len = this.content.length
-    while (++this.i < len) {
-      c = this.content[this.i]
-      if (!blankChar[c]) {
-        if (this.checkClose()) return
-        if (needVal) {
-          // 等号后遇到第一个非空字符
-          this.start = this.i
-          this.state = this.attrVal
-          return
-        }
-        if (this.content[this.i] === '=') {
-          needVal = true
-        } else {
-          this.start = this.i
-          this.state = this.attrName
-          return
-        }
-      }
-    }
-  } else if (!this.checkClose('onAttrName')) {
-    this.i++
-  }
-}
-
-/**
- * @description 属性值状态
- * @private
- */
-Lexer.prototype.attrVal = function () {
-  const c = this.content[this.i]
-  const len = this.content.length
-  if (c === '"' || c === "'") {
-    // 有冒号的属性
-    this.start = ++this.i
-    this.i = this.content.indexOf(c, this.i)
-    if (this.i === -1) return
-    this.handler.onAttrVal(this.content.substring(this.start, this.i))
-  } else {
-    // 没有冒号的属性
-    for (; this.i < len; this.i++) {
-      if (blankChar[this.content[this.i]]) {
-        this.handler.onAttrVal(this.content.substring(this.start, this.i))
-        break
-      } else if (this.checkClose('onAttrVal')) return
-    }
-  }
-  while (blankChar[this.content[++this.i]]);
-  if (this.i < len && !this.checkClose()) {
-    this.start = this.i
-    this.state = this.attrName
-  }
-}
-
-/**
- * @description 结束标签状态
- * @returns {String} 结束的标签名
- * @private
- */
-Lexer.prototype.endTag = function () {
-  const c = this.content[this.i]
-  if (blankChar[c] || c === '>' || c === '/') {
-    this.handler.onCloseTag(this.content.substring(this.start, this.i))
-    if (c !== '>') {
-      this.i = this.content.indexOf('>', this.i)
-      if (this.i === -1) return
-    }
-    this.start = ++this.i
-    this.state = this.text
-  } else {
-    this.i++
-  }
-}
-
-export default Parser

+ 0 - 79
uni_modules/mp-html/package.json

@@ -1,79 +0,0 @@
-{
-    "id": "mp-html",
-    "displayName": "mp-html 富文本组件【全端支持,可编辑】",
-    "version": "v2.2.2",
-    "description": "一个强大的富文本组件,高效轻量,功能丰富",
-    "keywords": [
-        "富文本",
-        "编辑器",
-        "html",
-        "rich-text",
-        "editor"
-    ],
-    "repository": "https://github.com/jin-yufeng/mp-html",
-    "dcloudext": {
-        "category": [
-            "前端组件",
-            "通用组件"
-        ],
-        "sale": {
-            "regular": {
-                "price": "0.00"
-            },
-            "sourcecode": {
-                "price": "0.00"
-            }
-        },
-        "contact": {
-            "qq": ""
-        },
-        "declaration": {
-            "ads": "无",
-            "data": "无",
-            "permissions": "无"
-        },
-        "npmurl": "https://www.npmjs.com/package/mp-html"
-    },
-    "uni_modules": {
-        "platforms": {
-            "cloud": {
-                "tcb": "y",
-                "aliyun": "y"
-            },
-            "client": {
-                "App": {
-                    "app-vue": "y",
-                    "app-nvue": "y"
-                },
-                "H5-mobile": {
-                    "Safari": "y",
-                    "Android Browser": "y",
-                    "微信浏览器(Android)": "y",
-                    "QQ浏览器(Android)": "y"
-                },
-                "H5-pc": {
-                    "Chrome": "y",
-                    "IE": "u",
-                    "Edge": "y",
-                    "Firefox": "y",
-                    "Safari": "y"
-                },
-                "小程序": {
-                    "微信": "y",
-                    "阿里": "y",
-                    "百度": "y",
-                    "字节跳动": "y",
-                    "QQ": "y"
-                },
-                "快应用": {
-                    "华为": "y",
-                    "联盟": "y"
-                },
-                "Vue": {
-                    "vue2": "y",
-                    "vue3": "y"
-                }
-            }
-        }
-    }
-}

文件差異過大導致無法顯示
+ 0 - 0
uni_modules/mp-html/static/app-plus/mp-html/js/handler.js


文件差異過大導致無法顯示
+ 0 - 0
uni_modules/mp-html/static/app-plus/mp-html/js/uni.webview.min.js


+ 0 - 1
uni_modules/mp-html/static/app-plus/mp-html/local.html

@@ -1 +0,0 @@
-<head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"><style>body,html{width:100%;height:100%;overflow-x:scroll;overflow-y:hidden}body{margin:0}video{width:300px;height:225px}img{max-width:100%;-webkit-touch-callout:none}</style></head><body><div id="content" style="overflow:hidden"></div><script type="text/javascript" src="./js/uni.webview.min.js"></script><script type="text/javascript" src="./js/handler.js"></script></body>

+ 7 - 7
utils/config.js

@@ -50,13 +50,13 @@ const defaultTabBarListConfig=[
 		iconPath: "../static/tabbar/price.png",
 		selectedIconPath: "../static/tabbar/price-s.png"
 	},
-    // {
-    //     key: "chart",
-    //     pagePath: "pages/chart/chart",
-    //     text: "图库",
-    //     iconPath: "../static/tabbar/chart.png",
-    //     selectedIconPath: "../static/tabbar/chart-s.png",
-    // },
+    {
+        key: "video",
+        pagePath: "pages/video/videoList",
+        text: "视频社区",
+        iconPath: "../static/tabbar/video.png",
+        selectedIconPath: "../static/tabbar/video-s.png",
+    },
     {
         key: "question",
         pagePath: "pages/question/question",

部分文件因文件數量過多而無法顯示