1. 实现效果
具体需求:顶部是搜索栏,包括搜索结果个数,目前跳到第几个,包含上一个、下一个按钮。富文本区域关键词高亮黄色,当前关键词为高亮橙色。如图
2. 版本号
用到vue3 和 uniapp , mp-html 插件版本是v2.5.0,
插件地址:https://ext.dcloud.net.cn/plugin?id=805
用npm方式打包放到compenonts文件,如图,打包步骤详见官方文档。
3. 页面具体代码
<template><view class="htmlparsePage"><view class="fixedTop"><topbar :config="barConfig"></topbar><view class="search-bar-container"><view class="weui-search-bar__form"><view class="weui-search-bar__box"><icon class="weui-icon-search_in-box" type="search" size="14"></icon><inputclass="weui-search-bar__input"placeholder-style="color:#b9babd;"placeholder="请输入需要搜索的关键词"v-model="keyWord"confirm-type="search"@confirm="searchSelf(keyWord)"/><viewclass="weui-icon-clear"v-if="keyWord?.length > 0"@click="() => {keyWord = ''searchSelf('')}"><icon type="clear" size="14"></icon></view></view></view><view class="a-search" style="margin-left: 10rpx; margin-right: 10rpx" v-if="searchRes?.num"><view class="searchNum">{{ searchIndex }}/{{ searchRes?.num }}</view></view><view class="a-search" style="margin-right: 10rpx" v-if="searchRes?.num" @click="preSearch"><image mode="widthFix" src="../../static/img/up.svg"></image></view><view class="a-search" @click="nextSearch" v-if="searchRes?.num"><image mode="widthFix" src="../../static/img/down.svg"></image></view></view></view><view v-if="show && data.content" class="mpHtmlRef"><mp-htmlref="mp"use-anchorsearchcontainer-style="padding:10px":content="data.content"@linktap="navigate"@preview-img="false"@show-img-menu="false":selectable="true":tag-style="{table: 'border-collapse: collapse;border: solid black 1px',tr: 'border: solid black 1px',td: 'border: solid black 1px',}"@load="onMpLoaded"></mp-html></view><view v-else class="emptyBox"><empty /></view></view> </template><script setup> import empty from '../../components/empty/empty' import mpHtml from '../../components/mp-html/mp-html' // 引入 import { getDocDetail } from '../../api/filterList' import topbar from '../../components/topbar/topbar.vue' import { onLoad, onUnload, onShareAppMessage } from '@dcloudio/uni-app' import { ref, reactive, onMounted, nextTick } from 'vue' const mp = ref(null) //富文本对象 const id = ref('') const show = ref(true) const keyWord = ref('') const data = reactive({content: '', }) const barConfig = reactive({bg_color: 'transparent',color: '#000',flag: 1,name: '法规详情', }) const searchRes = ref(null) const searchIndex = ref(1)function navigate(e) {this.$nextTick(() => {uni.navigateTo({url: '../detail/analysis?id=' + e.href,success: function (res) {},fail: function (res) {},complete: function (res) {},})}) }onUnload(() => {uni.hideLoading() })onLoad((options) => {id.value = options.idkeyWord.value = options.searchInput || '' // 关键词高亮 getData() })
// 获取文本数据 const getData = async () => {uni.showLoading()getDocDetail({ id: id.value }).then((res) => {if (res.code === 200) {data.content = res.data.contentuni.hideLoading()}}).catch((e) => {uni.hideLoading()uni.showToast({title: '文档详情获取失败',icon: 'none',})}) }// 处理 mp-html 加载完成 const onMpLoaded = async () => {if (keyWord.value) {searchSelf(keyWord.value)} }const searchSelf = (key) => {mp.value.search(key, true).then((res) => {searchRes.value = ressearchIndex.value = 1if (res.num === 0) {uni.showToast({title: '没有了',icon: 'none',duration: 2000,})} else {show.value = falseres.highlight(1)res.jump(1, -343) // 高亮第 1 个结果并跳转到该位置,偏移量show.value = true}}) } // 下一个关键词 const nextSearch = () => {show.value = falseif (searchIndex.value < searchRes.value?.num) {searchIndex.value++searchRes.value.highlight(searchIndex.value)searchRes.value.jump(searchIndex.value, -343)show.value = true} else {uni.showToast({title: '没有了',icon: 'none',duration: 2000,})show.value = true} }
// 上一个关键词 const preSearch = () => {show.value = falseif (searchIndex.value > 1 && searchIndex.value <= searchRes.value.num) {searchIndex.value--searchRes.value.highlight(searchIndex.value)searchRes.value.jump(searchIndex.value, -343)show.value = true} else {uni.showToast({title: '没有了',icon: 'none',duration: 2000,})show.value = true} } </script><style> .htmlparsePage {height: 100%;background: #e5f7fe; } .fixedTop {background: #e5f7fe;padding-bottom: 10rpx;position: fixed;top: 0;left: 0;height: 266rpx;z-index: 999; } .mpHtmlRef {height: calc(100% - 273rpx);margin-top: 273rpx;overflow-y: auto;background: #ffffff;border-radius: 48rpx 48rpx 0px 0px; } .emptyBox {margin-top: 30vh; } .emptyBox .emptyCon image {width: 280rpx;height: 280rpx; }.search-bar-container {background: #e5f7fe;padding: 15rpx 20rpx 0;height: 60rpx;display: flex; } .weui-search-bar__input {height: 60rpx;line-height: 28px;font-size: 24rpx;color: #939699; } .weui-search-bar__form {border: unset;border-radius: 30rpx;height: 60rpx; }.weui-search-bar__box {padding-left: 70rpx;height: 60rpx; }.weui-icon-search_in-box {left: 30rpx;float: left;top: 20rpx; }.a-search {height: 60rpx;display: flex;align-items: center;background-color: #fff;border-radius: 30px;padding: 0 15rpx; }.a-search image {height: 28rpx;width: 34rpx; } .searchNum {color: #858687; } </style>