当前位置: 首页 > news >正文

(五)、编辑页面-发布长文-富文本编辑【uniapp+uinicloud多用户社区博客实战项目(完整开发文档-从零到完整项目)】

1,edit页面

1.1 新建edit页面

在这里插入图片描述

1.2 从本地相册选择图片或使用相机拍照。

uni.chooseImage(OBJECT)

1.3 直接上传文件到云存储。

uploadFile(Object object)

1.4 从富文本编辑器获取编辑器内容

editorContext.getContents(OBJECT)

首页富文本编辑器初始化完成时,在 onEditReady()方法中通过uni.createSelectorQuery()获取富文本编辑器的上下文( this.editorCtx):

      //编辑器初始化完成时触发onEditReady() {uni.createSelectorQuery().in(this).select('.myEdit').fields({size: true,context: true}, res => {console.log(res)this.editorCtx = res.context}).exec()},

打印出的内容:
在这里插入图片描述

1.5 data中定义文章数据结构
        artObj: {title: "",//标题content: "",//内容description: "",//80字描述picurls: "",//图片province: ""//省份地址}
1.6 点击确认发布方法

点击确认按钮,首先获取富文本编辑器中的内容,然后赋值给artObj对象
具体代码:

      //点击提交按钮onSubmit() {this.editorCtx.getContents({success: res => {console.log(res)this.artObj.description = res.text.slice(0, 80);this.artObj.content = res.html;this.artObj.picurls = getImgSrc(res.html)uni.showLoading({title: "发布中..."})console.log(this.artObj)//this.addData();}})},
1.7 封装一个从html中获取image的方法

方法写在utils/tools.js中,然后使用进行引入。

//获取富文本内的图片url地址
export function getImgSrc(richtext, num = 3) {let imgList = [];richtext.replace(/<img [^>]*src=['"]([^'"]+)[^>]*>/g, (match, capture) => {imgList.push(capture);});imgList = imgList.slice(0, num)return imgList;
}

注明:num是获取图片的数量。

1.8 封装一个利用高德地图ip的api获取省份地址的方法

需要注册高德web服务api高德web服务api
在这里插入图片描述

IP定位
P定位是一套简单的HTTP接口,根据用户输入的IP地址,能够快速的帮用户定位IP的所在位置。
在这里插入图片描述

//获取高德地图ip的api接口,通过ip获取所在地址省市
function getIp() {return new Promise((resolve, reject) => {uni.request({url: "https://restapi.amap.com/v3/ip?key=自己创建应用的对应key",success: res => {console.log("向高德地图发送网络请求,通过ip获取所在地址省市")console.log(res)let str = ""//处理ip不是国内ip时,返回的地址为自定义的火星地址typeof(res.data.province) == "string" ? str = res.data.province: str = "火星"resolve(str)let obj = {province: str,time: Date.now()}uni.setStorageSync("historyProvince", obj);},fail: err => {reject(err)}})})
}

两个重点:1,判断返回的省份地址数据类型如果是字符串,就赋值给str,如果不是字符串,省份地址用“火星”代替。
2,省份地址数据结构中加入当前日期信息,只允许在时间范围内发送网络请求(用此防止高频重复请求问题)。
在这里插入图片描述

//向外导出省份
export function getProvince() {return new Promise((resolve, reject) => {let historyProvince = uni.getStorageSync("historyProvince");//判读是否在本地缓存中有地址if (historyProvince) {//判断超过1天时间 ,重新发起网络请求if ((Date.now() - historyProvince.time) > 1000 * 10) {getIp().then(res => {console.log("重新网络请求")resolve(res)}).catch(err => {reject(err)})} else {console.log("直接从本地缓存中读取")resolve(historyProvince.province);}} else { //缓存中没存地址 调用发送网络请求的方法(返回的一个promise对象)getIp().then(res => {console.log("第一次网络请求")console.log(res)resolve(res)}).catch(err => {reject(err)})}})
}

业务逻辑:首先判断本地缓存中是否存在省份地址数据,如果存在,再判断本地缓存中的数据日期是否在1天内,如果超过1天了,重新发送网络请求,如果没有超过1天,直接从本地缓存读取数据(减少发送网络请求的频次);缓存中没存地址 调用发送网络请求的方法,请求数据(返回的一个promise对象)。

在onload中调用方法:

    onLoad() {//获取省份地址 从高德api 通过ip地址getProvince().then(res => {this.artObj.province = res})},
1.4 完整代码
<template><view class="edit"><!-- 文章标题 --><view class="title"><input type="text" v-model="artObj.title" placeholder="请输入完整的标题" placeholder-class="placeholderClass"></view><!-- 文章内容 --><view class="content"><editor class="myEdit" placeholder="写点什么吧~~" show-img-size show-img-toolbar show-img-resize @focus="onFocus"@ready="onEditReady" @statuschange="onStatuschange"></editor></view><!-- 确认发布按钮 --><view class="btnGroup"><u-button @click="onSubmit" type="primary" :disabled="!artObj.title.length" text="确认发表"></u-button></view><!-- 工具栏  富文本编辑器 --><view class="tools" v-if="toolShow"><view class="item" @click="clickHead"><text class="iconfont icon-zitibiaoti" :class="headShow ? 'active' : ''"></text></view><view class="item" @click="clickBold"><text class="iconfont icon-zitijiacu" :class="boldShow ? 'active': ''"></text></view><view class="item" @click="clickItalic"><text class="iconfont icon-zitixieti" :class="italicShow ? 'active' : ''"></text></view><view class="item" @click="clickDivider"><text class="iconfont icon-fengexian"></text> </view><view class="item" @click="clickInsertImage"><text class="iconfont icon-charutupian"></text> </view><view class="item" @click="editOk"><text class="iconfont icon-duigou_kuai"></text> </view></view></view>
</template><script>import {getImgSrc,getProvince} from "@/utils/tools.js"const db = uniCloud.database()export default {data() {return {toolShow: false,headShow: false,boldShow: false,italicShow: false,artObj: {title: "",content: "",description: "",picurls: "",province: ""}};},onLoad() {//获取省份地址 从高德api 通过ip地址getProvince().then(res => {this.artObj.province = res})},methods: {//点击提交按钮onSubmit() {this.editorCtx.getContents({success: res => {console.log(res)this.artObj.description = res.text.slice(0, 80);this.artObj.content = res.html;this.artObj.picurls = getImgSrc(res.html)uni.showLoading({title: "发布中..."})console.log(this.artObj)this.addData();}})},//添加数据到云数据库quanzi_articlesaddData() {db.collection("quanzi_articles").add({...this.artObj}).then(res => {uni.hideLoading();uni.showToast({title: "发布成功"})setTimeout(() => {uni.reLaunch({url: "/pages/index/index"})}, 800)})},//富文本标签中的初始化onEditReady() {uni.createSelectorQuery().in(this).select('.myEdit').fields({size: true,context: true}, res => {console.log(res)this.editorCtx = res.context}).exec()},//检查样式改变的状态checkStatus(name, detail, obj) {if (detail.hasOwnProperty(name)) {this[obj] = true;} else {this[obj] = false;}},// 当样式发生改变的时候onStatuschange(e) {let detail = e.detailthis.checkStatus("header", detail, "headShow");this.checkStatus("bold", detail, "boldShow");this.checkStatus("italic", detail, "italicShow");},//添加图像clickInsertImage() {uni.chooseImage({success: async res => {uni.showLoading({title: "上传中请稍后",mask: true})for (let item of res.tempFiles) {let suffix = item.path.substring(item.path.lastIndexOf("."));let randomName = Date.now() + "" + String(Math.random()).substr(3, 6) + suffixlet res = await uniCloud.uploadFile({filePath: item.path,cloudPath: item.name || randomName})this.editorCtx.insertImage({src: res.fileID})}uni.hideLoading()}})},//点击工具条的确认editOk() {this.toolShow = false;},//加粗clickBold() {this.boldShow = !this.boldShowthis.editorCtx.format("bold")},//设置倾斜clickItalic() {this.italicShow = !this.italicShow;this.editorCtx.format("italic")},//添加大标题clickHead() {this.headShow = !this.headShowthis.editorCtx.format("header", this.headShow ? 'H2' : false)},//添加分割线clickDivider() {this.editorCtx.insertDivider();},//离开焦点onFocus() {this.toolShow = true},}}
</script><style lang="scss">/deep/ .ql-blank::before {font-style: normal;color: #e0e0e0;}.edit {padding: 30rpx;.title {input {height: 120rpx;font-size: 46rpx;border-bottom: 1px solid #e4e4e4;margin-bottom: 30rpx;color: #000;}.placeholderClass {color: #e0e0e0;}}.content {.myEdit {height: calc(100vh - 500rpx);margin-bottom: 30rpx;}}.tools {width: 100%;height: 80rpx;background: #fff;border-top: 1rpx solid #f4f4f4;position: fixed;left: 0;bottom: 0;display: flex;justify-content: space-around;align-items: center;.iconfont {font-size: 36rpx;color: #333;&.active {color: #0199FE}}}}
</style>

2,工具类tools.js

//获取富文本内的图片url地址
export function getImgSrc(richtext, num = 3) {let imgList = [];richtext.replace(/<img [^>]*src=['"]([^'"]+)[^>]*>/g, (match, capture) => {imgList.push(capture);});imgList = imgList.slice(0, num)return imgList;
}//向外导出省份
export function getProvince() {return new Promise((resolve, reject) => {let historyProvince = uni.getStorageSync("historyProvince");//判读是否在本地缓存中有地址if (historyProvince) {//判断超过1天时间 ,重新发起网络请求if ((Date.now() - historyProvince.time) > 1000 * 10) {getIp().then(res => {console.log("重新网络请求")resolve(res)}).catch(err => {reject(err)})} else {console.log("直接从本地缓存中读取")resolve(historyProvince.province);}} else { //缓存中没存地址 调用发送网络请求的方法(返回的一个promise对象)getIp().then(res => {console.log("第一次网络请求")console.log(res)resolve(res)}).catch(err => {reject(err)})}})
}//获取高德地图ip的api接口,通过ip获取所在地址省市
function getIp() {return new Promise((resolve, reject) => {uni.request({url: "https://restapi.amap.com/v3/ip?key=2eae11112968b53f162a109960d4efd1",success: res => {console.log("向高德地图发送网络请求,通过ip获取所在地址省市")console.log(res)let str = ""//处理ip不是国内ip时,返回的地址为自定义的火星地址typeof(res.data.province) == "string" ? str = res.data.province: str = "火星"resolve(str)let obj = {province: str,time: Date.now()}uni.setStorageSync("historyProvince", obj);},fail: err => {reject(err)}})})
}//获取昵称
export function giveName(item) {return item.user_id[0].nickname || item.user_id[0].username || item.user_id[0].mobile || "请设置昵称"
}//获取默认头像
export function giveAvatar(item) {return item.user_id[0]?.avatar_file?.url ?? '../../static/images/user-default.jpg'
}const db = uniCloud.database();
const utilsObj = uniCloud.importObject("utilsObj", {customUI: true
});//点赞操作数据库的方法
export async function likeFun(artid) {let count = await db.collection("quanzi_like").where(`article_id=="${artid}" && user_id==$cloudEnv_uid`).count()if (count.result.total) {db.collection("quanzi_like").where(`article_id=="${artid}" && user_id==$cloudEnv_uid`).remove();utilsObj.operation("quanzi_article", "like_count", artid, -1)} else {db.collection("quanzi_like").add({article_id: artid})utilsObj.operation("quanzi_article", "like_count", artid, 1)}
}

3,uniapp内置富文本编辑器edit组件的刨析

3.1 支持平台差异说明

在这里插入图片描述

3.2 属性

在这里插入图片描述

3.3 支持的标签

在这里插入图片描述

3.4 支持的内联样式

在这里插入图片描述

3.5 相关 api—editorContext

editor 组件对应的 editorContext 实例,可通过 uni.createSelectorQuery 获取

代码示例:

      //编辑器初始化完成时触发onEditReady() {uni.createSelectorQuery().in(this).select('.myEdit').fields({size: true,context: true}, res => {console.log(res)this.editorCtx = res.context}).exec()},
3.6 节点参数说明

在这里插入图片描述

4,edit页面效果

在这里插入图片描述

相关文章:

(五)、编辑页面-发布长文-富文本编辑【uniapp+uinicloud多用户社区博客实战项目(完整开发文档-从零到完整项目)】

1&#xff0c;edit页面 1.1 新建edit页面 1.2 从本地相册选择图片或使用相机拍照。 uni.chooseImage(OBJECT) 1.3 直接上传文件到云存储。 uploadFile(Object object) 1.4 从富文本编辑器获取编辑器内容 editorContext.getContents(OBJECT) 首页富文本编辑器初始化完成时…...

你是真的“C”——【经典面试知识点】数据在内存中的大小端存储方式

你是真的“C”——【经典面试知识点】数据在内存中的大小端存储方式&#x1f60e;前言&#x1f64c;大小端介绍&#x1f64c;什么大端小端呢&#xff1f;&#xff1a;大小端存储的标准定义&#xff1a;大端和小端存在的意义经典的面试题目&#x1f64c;总结撒花&#x1f49e;&a…...

从零开始的数模(二十六)单因素方差分析

目录 一、概念 1.1相关概念 1.2用途 1.3数据要求&#xff1a;独立性/正态性/方差齐性 1.4步骤 ​编辑1.5专业名词 二、基于python的单因素方差分析 2.2单因素方差分析的作用 一、概念 1.1相关概念 单因素方差分析是一种常用的统计分析方法&#xff0c;它用于比较一个因…...

C++变量类型

目录 一、c中的变量定义 二、c中的变量声明 三、c中的左值和右值 一、c中的变量定义 变量定义就是告诉编译器在何处创建变量的存储&#xff0c;以及如何创建变量的存储。 变量定义指定一个数据类型&#xff0c;并包含了该类型的一个或多个变量的列表&#xff0c;如下所示&…...

win10 安装 vs2015(社区版本)以及opencv-4.5.5

一、下载vs2015以及opencv-4.5.5从https://msdn.itellyou.cn/ 网站下载vs2015&#xff08;社区版本&#xff09;从https://opencv.org/releases/网站下载opencv-4.5.5二、安装vs2015和opencv-4.5.5解压后双击exe安装文件&#xff0c;完成安装&#xff08;默认&#xff09;双击下…...

867. 转置矩阵

给你一个二维整数数组 matrix&#xff0c; 返回 matrix 的 转置矩阵 。矩阵的 转置 是指将矩阵的主对角线翻转&#xff0c;交换矩阵的行索引与列索引。示例 1&#xff1a;输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]]输出&#xff1a;[[1,4,7],[2,5,8],[3,6,9]]示例 2&a…...

Datawahle组队学习——妙趣横生大数据 Day1

妙趣横生大数据 Day1[妙趣横生大数据 Juicy Big Data](https://datawhalechina.github.io/juicy-bigdata/#/?id妙趣横生大数据-juicy-big-data)一、大数据概述大数据——第三次信息化浪潮大数据概念大数据应用大数据关键技术二、Hadoop背景介绍特性项目架构实验1. 准备工作2. …...

网友眼中越老越吃香的行业,果然是风向变了!

越老越吃香的行业&#xff0c;一直都是被热议的话题。对于年轻人来说&#xff0c;找到一个适合自己的并且具有前景的工作&#xff0c;不是一件容易的事情。 最近&#xff0c;看到有人在平台上问相关的问题&#xff0c;本着认真看一看的态度点进去&#xff0c;却差点被热评第一…...

为什么时间序列预测这么难?本文将给你答案

机器学习和深度学习已越来越多应用在时序预测中。ARIMA 或指数平滑等经典预测方法正在被 XGBoost、高斯过程或深度学习等机器学习回归算法所取代。 尽管时序模型越来越复杂&#xff0c;但人们对时序模型的性能表示怀疑。有研究表明&#xff0c;复杂的时序模型并不一定会比时序…...

STC15系列单片机通过串口多字节数据读写EEPROM操作

STC15系列单片机通过串口多字节数据读写EEPROM操作&#x1f4cc;相关篇《STC15系列单片机EEPROM读写示例》 ⛳手册勘误信息注意事项 ⚡在手册上面描述STC15F2K60S2及STC15L2K60S2系列单片机内部EEPROM还可以用MOVC指令读&#xff0c;但此时首地址不再是0000H&#xff0c;而是程…...

计算机网络-ip数据报

在图中&#xff0c;网络层包含了四种协议&#xff1a;ARP、IP、ICMP、IGMP&#xff0c;由上下关系表明&#xff0c;ARP为IP协议服务&#xff0c;IP为ICMP和IGMP服务。 IP数据报格式 此处不区分数据报和分组的概念&#xff1a;当数据部分过长时&#xff0c;将数据部分拆分&…...

从零开始学C

以下是 该如何学习C语言的【思维导图】以及部分重点知识点的【博客链接】。其实C语言并不难&#xff0c;难的是没有人去教&#xff0c;没有耐心去学。不知道从哪下手学习&#xff0c;我将C的知识点做成一个思维导图&#xff0c;以供迷茫的小白参考&#xff0c;哪里不会&#xf…...

【云原生】手把手带你从零开始搭建kubernetes最新版本实战

文章目录前言一. 实验环境二. k8s 的介绍三 . k8s的安装3.1 搭建实验环境3.1.1 硬件层面的要求3.1.2 软件层面环境配置3.2 docker的安装3.2.1 搭建docker3.2.2 部署 cri-dockerd3.3 部署k8s3.3.1 配置添加阿里云的yum源3.3.2 安装kubeadm kubelet kubectl3.3.3 k8s-master节点初…...

trivy os软件包扫描原理分析

具体可以基于之前的博客来做 基于trivy获取基础镜像 参数修改一下&#xff1a; cliOpt.ListAllPkgs true 结果中会带有如下格式的结果&#xff1a; "Results":[{"Target":"192.168.1.94:443/test22/centos:7 (centos 7.9.2009)","Clas…...

算法训练营 day48 动态规划 完全背包 零钱兑换 II 组合总和 Ⅳ

算法训练营 day48 动态规划 完全背包 零钱兑换 II 组合总和 Ⅳ 完全背包 有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品都有无限个&#xff08;也就是可以放入背包多次&#xff09;&#xff0c;求解将哪些物…...

Java 基础(1)—泛型简单使用

一、泛型定义及作用 泛型是一种编程机制&#xff0c;允许在编写代码时使用参数化类型&#xff0c;以在编译时实现类型安全。 以下是泛型作用&#xff1a; 增强代码可读性和可维护性&#xff1a;通过在代码中使用泛型参数&#xff0c;可以使代码更清晰、更具有可读性和可维护性…...

内存卡损坏了怎么恢复?

内存卡损坏了怎么恢复?现在我们身边有不少电子设备都是用存储卡来存储数据的。一旦需要方便我们直接导出使用。但这存储的数据也不是一定安全的&#xff0c;当我们将内存卡连接到电脑时&#xff0c;难免会碰到病毒、格式化等提示&#xff0c;在这些情况下&#xff0c;可能会导…...

Mysql使用规范(纯技术和实战建议)

1、事务隔级别: &#xff08;强制&#xff09;&#xff1a;Repeatable-Read&#xff08;重复读&#xff09;&#xff0c;且不能在会话操作时临时开启隔离级别。 注&#xff1a; Repeatable-Read&#xff08;重复读&#xff09;隔离级别解决不了幻读。 可用 show variables l…...

Netty源码解读-EventLoop(二)

一、简介 NioEventLoop的重要组成&#xff1a;Selector、线程、任务队列&#xff0c;他既会处理io事件&#xff0c;也会处理普通任务和定时任务. 1.下面是Selector&#xff0c;注意有两个哦后面会讲 2.下面的爷爷类提供的Thread变量&#xff0c;其实下面发excutor用的就是这个…...

OSI模型详解

今天&#xff0c;我们详解OSI&#xff08;Open System Inter-connection Reference Model&#xff09;模型&#xff0c;来看看工业物联网的网络互联和数据互通。 OSI模型 1984年&#xff0c;国际标准化组织&#xff08;International Organization for Standardization&#…...

基于算法竞赛的c++编程(28)结构体的进阶应用

结构体的嵌套与复杂数据组织 在C中&#xff0c;结构体可以嵌套使用&#xff0c;形成更复杂的数据结构。例如&#xff0c;可以通过嵌套结构体描述多层级数据关系&#xff1a; struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件&#xff0c;常用于在两个集合之间进行数据转移&#xff0c;如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model&#xff1a;绑定右侧列表的值&…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中&#xff0c;高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术&#xff0c;实现年省电费15%-60%&#xff0c;且不改动原有装备、安装快捷、…...

Map相关知识

数据结构 二叉树 二叉树&#xff0c;顾名思义&#xff0c;每个节点最多有两个“叉”&#xff0c;也就是两个子节点&#xff0c;分别是左子 节点和右子节点。不过&#xff0c;二叉树并不要求每个节点都有两个子节点&#xff0c;有的节点只 有左子节点&#xff0c;有的节点只有…...

优选算法第十二讲:队列 + 宽搜 优先级队列

优选算法第十二讲&#xff1a;队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台

🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...

有限自动机到正规文法转换器v1.0

1 项目简介 这是一个功能强大的有限自动机&#xff08;Finite Automaton, FA&#xff09;到正规文法&#xff08;Regular Grammar&#xff09;转换器&#xff0c;它配备了一个直观且完整的图形用户界面&#xff0c;使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

Web 架构之 CDN 加速原理与落地实践

文章目录 一、思维导图二、正文内容&#xff08;一&#xff09;CDN 基础概念1. 定义2. 组成部分 &#xff08;二&#xff09;CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 &#xff08;三&#xff09;CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 &#xf…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习

禁止商业或二改转载&#xff0c;仅供自学使用&#xff0c;侵权必究&#xff0c;如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

Java线上CPU飙高问题排查全指南

一、引言 在Java应用的线上运行环境中&#xff0c;CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时&#xff0c;通常会导致应用响应缓慢&#xff0c;甚至服务不可用&#xff0c;严重影响用户体验和业务运行。因此&#xff0c;掌握一套科学有效的CPU飙高问题排查方法&…...