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

js控制文字溢出显示省略号

.text{display: -webkit-box;overflow: hidden;white-space: normal;text-overflow: ellipsis;word-wrap: break-word;-webkit-line-clamp: 2;-webkit-box-orient: vertical;
}

本人有个需求就是在一个盒子内有一段文本,然后控制文本显示两行,第二行要显示省略号,本人通过以上方式通过css解决了
但是有个问题,因为这个区域要被截图保存下来,本人使用html-to-image插件去完成了截图操作,但就在这时,bug出现了,例如在真机上面显示省略号,但是在截图上面并没有省略号,而是完整的显示出了两行文字,可能由于这个文字大小在当前机型上面刚好溢出,但是没有达到截图的容器的溢出条件,就出现了一个尴尬的事情,截图没省略号,真机有,然后如果多补充点文字,截图虽然显示了省略号,但是省略号前面还是比真机多几个字,,,因此后面不考虑使用css来做了,改成js来做,具体步骤如下:

方式

下面提供了两种方式实现这个,主要是使用js可以解决很多问题,使用jQuery版本就不行,例如遇到uniapp这种标签皆为组件的就不行了,根本设置不了,因此像uniapp这种建议使用原生js判断

依赖于jQuery

  • 方式一(静态内容非常推荐)
    • 好处
      • 适用于内容固定的情况,直接在页面写死换行的就行
    • 坏处
      • 依赖于jqueryjQuery.ellipsis两个插件,需要引入一下
      • 不适用于内容动态变化情况
  • 方式二(动态内容非常推荐)
    • 好处
      • 适用于页面内容动态变换的情况
    • 坏处
      • 依赖于jqueryjQuery.ellipsis两个插件,需要引入一下
      • 需要几行就要判断几行文字

直接使用原生js处理

  • 方式一(动态内容比较推荐)
    • 好处
      • 适用于页面内容动态变换的情况
      • 不依赖于jqueryjQuery.ellipsis两个插件
    • 坏处
      • 行数较多的情况,需要一个一个判断
      • 除了上述jquery方式二的(需要几行就要判断几行文字)以外,还要判断是否满行显示省略号等(不想判断可以使用jquery的方式二,这个内部已经判断好了)
  • 方式二(静态内容比较推荐)
    • 好处
      • 适用于内容固定的情况,直接写死就行
      • 不依赖于jqueryjQuery.ellipsis两个插件
    • 坏处
      • 行数较多的情况,需要一个一个判断

依赖于jQuery

使用jQueryjQuery.ellipsis.js来解决

jQuery的代码各位可以百度,这里提供一个CDN地址: https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js

jQuery.ellipsis.js代码如下:

/*!* jQuery.ellipsis* https://github.com/jjenzz/jquery.ellipsis* --------------------------------------------------------------------------* Copyright (c) 2013 J. Smith (@jjenzz)* Dual licensed under the MIT and GPL licenses:* https://www.opensource.org/licenses/mit-license.php* http://www.gnu.org/licenses/gpl.html** adds a class to the last 'allowed' line of text so you can apply* text-overflow: ellipsis;*/
(function (a) { if (typeof define === "function" && define.amd) { define(["jquery"], a) } else { a(jQuery) } }(function (d) { var c = "ellipsis", b = '<span style="white-space: nowrap;">', e = { lines: "auto", ellipClass: "ellip", responsive: false }; function a(h, q) { var m = this, w = 0, g = [], k, p, i, f, j, n, s; m.$cont = d(h); m.opts = d.extend({}, e, q); function o() { m.text = m.$cont.text(); m.opts.ellipLineClass = m.opts.ellipClass + "-line"; m.$el = d('<span class="' + m.opts.ellipClass + '" />'); m.$el.text(m.text); m.$cont.empty().append(m.$el); t() } function t() { if (typeof m.opts.lines === "number" && m.opts.lines < 2) { m.$el.addClass(m.opts.ellipLineClass); return } n = m.$cont.height(); if (m.opts.lines === "auto" && m.$el.prop("scrollHeight") <= n) { return } if (!k) { return } s = d.trim(m.text).split(/\s+/); m.$el.html(b + s.join("</span> " + b) + "</span>"); m.$el.find("span").each(k); if (p != null) { u(p) } } function u(x) { s[x] = '<span class="' + m.opts.ellipLineClass + '">' + s[x]; s.push("</span>"); m.$el.html(s.join(" ")) } if (m.opts.lines === "auto") { var r = function (y, A) { var x = d(A), z = x.position().top; j = j || x.height(); if (z === f) { g[w].push(x) } else { f = z; w += 1; g[w] = [x] } if (z + j > n) { p = y - g[w - 1].length; return false } }; k = r } if (typeof m.opts.lines === "number" && m.opts.lines > 1) { var l = function (y, A) { var x = d(A), z = x.position().top; if (z !== f) { f = z; w += 1 } if (w === m.opts.lines) { p = y; return false } }; k = l } if (m.opts.responsive) { var v = function () { g = []; w = 0; f = null; p = null; m.$el.html(m.text); clearTimeout(i); i = setTimeout(t, 100) }; d(window).on("resize." + c, v) } o() } d.fn[c] = function (f) { return this.each(function () { try { d(this).data(c, (new a(this, f))) } catch (g) { if (window.console) { console.error(c + ": " + g) } } }) } }));

引入到页面使用

方式一(固定内容推荐,非动态内容不推荐)
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script><script src="./jQuery.ellipsis.js"></script><style>.aaa,.aaa2 {background: #eee;border: 1px solid #ccc;width: 130px;margin-left: 200px;}.aaa2{margin-top: 50px;}/* 下面这三个css不能删,否则不起作用了 */.ellip {display: block;height: 100%;}.ellip-line {display: inline-block;text-overflow: ellipsis;white-space: nowrap;word-wrap: normal;}.ellip,.ellip-line {position: relative;overflow: hidden;max-width: 100%;}</style>
</head><body><div class="aaa">你哈哈哈哈哈哈啊哈哈哈哈哈哈哈颇大开发跑我就发很日入好闺女诶欧哈你噶IEUR</div><div class="aaa2">你哈哈哈哈哈哈啊&nbsp;哈哈哈哈哈哈哈颇大开发跑我就发很日入好闺女诶欧哈你噶IEUR</div><script>$('.aaa').ellipsis({ lines: 2 });  // 控制第二行溢出显示省略号$('.aaa2').ellipsis({ lines: 2 }); // // 控制第二行溢出显示省略号</script>
</body></html>

上面内容可以看到,需要换行的部分必须手动在html里面加换行或者&nbsp;,因此这种方式适合静态的,不适用于动态的,可以看下面这个

方式二(动态内容推荐)
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script><script src="./jQuery.ellipsis.js"></script><style>.aaa {background: #eee;border: 1px solid #ccc;width: 150px;}/* 下面这三个css不能删,否则不起作用了 */.ellip {display: block;height: 100%;}.ellip-line {display: inline-block;text-overflow: ellipsis;white-space: nowrap;word-wrap: normal;}.ellip,.ellip-line {position: relative;overflow: hidden;max-width: 100%;}</style>
</head><body><div class="aaa">abababababa我还得覅维护诶哈哈哈哈哈哈颇大开发跑我就发很日入好闺女诶欧哈你噶IEUR个</div><script>function getTextWidth(text, font) {// 计算字符串的宽// 创建临时canvas元素var canvas = document.createElement("canvas");var context = canvas.getContext("2d");context.font = font;return context.measureText(text).width;}let aaa = document.querySelector('.aaa'); // 获取容器let aaawidth = aaa.clientWidth;  // 拿到容器的宽度let text = aaa.innerText;let font = getComputedStyle(aaa).font; // 获取元素的实际字体样式(为了算文字大小,这个跟字符串的宽有影响,如果容器上面加了字体,这里同样会返回这个字体,可以打印font查看,也就是说,这个方法兼容带字体的情况)let textWidth = getTextWidth(text, font); // 计算字符串的宽度console.log(aaawidth,textWidth);  // 容器的宽和字符串的宽度let textarr = text.split('') // 将字符串分割成数组进行遍历let start_str = '' // 第一行的文字内容let end_str = '' // 第二行的文字内容(还可以加其他更多的行,只需要在下面多几个判断就好)let linshistr = '' // 临时存储用于计算的字符串textarr.forEach((item)=>{linshistr += item // 每次循环都让临时字符串累加// 下面如果有第二行第三行的话直接判断 > n*aaawidth 即可if(getTextWidth(linshistr, font) > aaawidth){// 如果小于容器容器宽度,让第一行的字符串进行累加end_str += item   }else{// 如果超出容器,都是在第二行,直接让第二行元素累加start_str+= item}})console.log(start_str, end_str); // 获取第一行和第二行元素内容aaa.innerHTML = start_str + '&nbsp;' + end_str // 加个&nbsp;可以换行,就像方式一写死的一样$('.aaa').ellipsis({ lines: 2 }); // 再去使用jQuery.ellipsis.js的ellipsis方法让第二行显示省略号</script>
</body></html>

直接使用js

方式一(动态内容推荐)

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>.aaa {background: #eee;border: 1px solid #ccc;width: 154px;}</style>
</head><body><div class="aaa"><div class="son"></div><div class="son2"></div></div><script>// let str = 'a我还得覅维护诶好啊' // 获取文本内容(一行满的情况)// let str = 'a我还得覅维护诶' // 获取文本内容(一行不满的情况)// let str = 'a我还得覅维护诶哈哈哈哈i和ID号次我深有感触' // 获取文本内容(两行满的情况)// let str = 'a我还得覅维护诶哈哈哈你好啊我爱你' // 获取文本内容(两行不满的情况)function getTextWidth(text, font) {// 计算文本字符串的宽// 创建临时canvas元素var canvas = document.createElement("canvas");var context = canvas.getContext("2d");context.font = font;return context.measureText(text).width;}// 获取元素实际的容器let aaa = document.querySelector('.aaa');let aaawidth = aaa.clientWidth; // 获取容器宽度let font = getComputedStyle(aaa).font; // 获取元素的实际字体样式,(为了算文字大小,这个跟字符串的宽有影响,会返回字体的大小和字体名称,如果是固定的话也可以直接写死,这个是从容器上面获取的字体大小和字体名称)let textWidth = getTextWidth(str, font); // // 计算字符串的宽度console.log(aaawidth, textWidth); // // 容器的宽和字符串的宽度let textarr = str.split('')  // 将字符串分割成数组进行遍历let start_str = '' // 第一行的文字内容let end_str = '' // 第二行的文字内容(还可以加其他更多的行,只需要在下面多几个判断就好)let linshistr = '' // 临时存储用于计算的字符串textarr.forEach((item) => {linshistr += item// 第一行的判断if (getTextWidth(linshistr, font) < aaawidth) {start_str += item}// 第二行的判断if (getTextWidth(linshistr, font) > aaawidth && getTextWidth(linshistr, font) < 2 * aaawidth) {end_str += item}// 第n行的判断// if (getTextWidth(linshistr, font) > ( n - 1 ) * aaawidth &&getTextWidth(linshistr, font) > n * aaawidth) {}})console.log(start_str, end_str); // 输出第一行和第二行的文字内容// 如果第二行不存在,就只显示一行// 这里需要判断是否占满容器(这里我判断容器宽度减去10像素如果小于文字宽度大小就加省略号,否则原样输出,这里的10大家可以根据项目自行改)if (end_str == '') {document.querySelector('.son').innerHTML = aaawidth - 10 < getTextWidth(start_str, font) ? start_str.substring(0, start_str.length - 1) + '...' : start_str;} else {// 第二行存在,则第一行肯定会存在document.querySelector('.son').innerHTML = start_strdocument.querySelector('.son2').innerHTML = aaawidth - 10 < getTextWidth(end_str, font) ? end_str.substring(0, end_str.length - 1) + '...' : end_str;}</script>
</body></html>

方式二(固定内容推荐,非动态内容不推荐)

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>.aaa {background: #eee;border: 1px solid #ccc;width: 154px;}</style>
</head>
<body><div class="aaa"><div class="son"></div><div class="son2"></div></div><script>let aaa = document.querySelector('.aaa');let son = document.querySelector('.son');let son2 = document.querySelector('.son2');let str = 'a我还得覅维护诶ha'// 这种方式比较暴力,直接截取字符串(适用于静态内容)if (str.length < 10) {son.innerHTML = str.substring(0, 10)}else if(str.length == 10){son.innerHTML = str.substring(0, 10)+'...'}else if(str.length > 10&&str.length < 20){son.innerHTML = str.substring(0, 10)son2.innerHTML = str.substring(10,20)}else if(str.length >= 20){son.innerHTML = str.substring(0, 10)son2.innerHTML = str.substring(10,20)+'...'}</script>
</body>
</html>

相关文章:

js控制文字溢出显示省略号

.text{display: -webkit-box;overflow: hidden;white-space: normal;text-overflow: ellipsis;word-wrap: break-word;-webkit-line-clamp: 2;-webkit-box-orient: vertical; }本人有个需求就是在一个盒子内有一段文本&#xff0c;然后控制文本显示两行&#xff0c;第二行要显示…...

WPF+MVVM案例实战与特效(四十七)-实现一个路径绘图的自定义按钮控件

文章目录 1、案例效果2、创建自定义 PathButton 控件1、定义 PathButton 类2、设计样式与控件模板3、代码解释3、控件使用4、直接在 XAML 中绑定命令3、源代码获取4、总结1、案例效果 2、创建自定义 PathButton 控件 1、定义 PathButton 类 首先,我们需要创建一个新的类 Pat…...

操作002:HelloWorld

文章目录 操作002&#xff1a;HelloWorld一、目标二、具体操作1、创建Java工程①消息发送端&#xff08;生产者&#xff09;②消息接收端&#xff08;消费者&#xff09;③添加依赖 2、发送消息①Java代码②查看效果 3、接收消息①Java代码②控制台打印③查看后台管理界面 操作…...

odoo中@api.model, @api.depends和@api.onchange 装饰器的区别

文章目录 1. api.model用途特点示例 2. api.depends用途特点示例 3. api.onchange用途特点示例 总结 在 Odoo 中&#xff0c;装饰器&#xff08;decorators&#xff09;用于修饰方法&#xff0c;以指定它们的行为和触发条件。api.model、api.depends 和 api.onchange 是三个常用…...

有哪些精益工具可以帮助企业实现转型?

为了在激烈的市场竞争中立于不败之地&#xff0c;许多企业开始寻求通过精益转型来优化运营、降低成本、提高效率和客户满意度。然而&#xff0c;精益转型并非一蹴而就&#xff0c;而是需要一系列精益工具的辅助&#xff0c;这些工具能够帮助企业识别浪费、优化流程、提升质量&a…...

以太网帧结构

以太网帧结构 目前&#xff0c;我们局域网当中应用最广的技术或者协议啊&#xff0c;就是以太网。我们首先来看一下以太网的真结构。这块内容这里边再系统的来给大家去展开说一下&#xff0c;以太网真格式就如下面这个图。所示前面有八个字节&#xff0c;是用于时钟同步的&…...

QT调用Sqlite数据库

QT设计UI界面&#xff0c;后台访问数据库&#xff0c;实现数据库数据的增删改查。 零售商店系统 数据库表&#xff1a; 分别是顾客表&#xff0c;订单详情表&#xff0c;订单表&#xff0c;商品表 表内字段详情如下&#xff1a; 在QT的Pro文件中添加sql&#xff0c;然后添加头…...

前端

前端页面 Web页面 PC端程序页面 移动端APP页面 ... HTML页面 HTML超文本标记页面 超文本&#xff1a;文本&#xff0c;声音&#xff0c;图片&#xff0c;视频&#xff0c;表格&#xff0c;链接 标记&#xff1a;由许多标签组成 HTML页面运行到浏览器上面 vscode便捷插件使用 vs…...

【Git】—— 使用git操作远程仓库(gitee)

目录 一、远程仓库常用命令 1、从远程仓库克隆项目 2、查看关联的远程仓库 3、添加关联的远程仓库 4、移除关联的远程仓库 5、将本地仓库推送到远程仓库 6、从远程仓库拉取项目 二、分支命令 1、查询分支 2、创建分支 3、切换分支 4、推送到远程分支 5、合并分支 …...

Paddler负载均衡器

Paddler负载均衡器 Paddler本身是用Go语言编写的,没有直接的Python接口,但可以通过以下方式在Python中使用: 执行命令行调用 在Python中可以使用 subprocess 模块来调用Paddler的命令行工具,实现负载均衡功能 。例如: import subprocessdef start_paddler_agent():com…...

OSCP - Proving Grounds - Slort

主要知识点 文件包含 windows的reveseshell 具体步骤 执行nmap,依旧是很多端口开放&#xff0c;尝试了ftp,smb等均失败 Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-10-13 12:00 UTC Nmap scan report for 192.168.53.53 Host is up (0.00095s latency). Not sho…...

YoloV9改进策略:Head改进|DynamicHead,利用注意力机制统一目标检测头部|即插即用

摘要 论文介绍 本文介绍了一种名为DynamicHead的模块,该模块旨在通过注意力机制统一目标检测头部,以提升目标检测的性能。论文详细阐述了DynamicHead的工作原理,并通过实验证明了其在COCO基准测试上的有效性和效率。 创新点 DynamicHead模块的创新之处在于它首次尝试在一…...

BFD综合详细实验配置案例

前言 本实验的目的是通过配置BGP&#xff08;边界网关协议&#xff09;、OSPF&#xff08;开放式最短路径优先协议&#xff09;、VRRP&#xff08;虚拟路由冗余协议&#xff09;以及BFD&#xff08;双向转发检测&#xff09;等网络协议&#xff0c;模拟企业级网络环境中的多协…...

自然语言处理与知识图谱的融合与应用

目录 前言1. 知识图谱与自然语言处理的关系1.1 知识图谱的定义与特点1.2 自然语言处理的核心任务1.3 二者的互补性 2. NLP在知识图谱构建中的应用2.1 信息抽取2.1.1 实体识别2.1.2 关系抽取2.1.3 属性抽取 2.2 知识融合2.3 知识推理 3. NLP与知识图谱融合的实际应用3.1 智能问答…...

c# RSA加解密工具,.netRSA加解密工具

软件介绍 名称: c# RSA加解密工具,.netRSA加解密工具依赖.net版本: .net 8.0工具类型: WinForm源码下载 c# RSA加解密工具,.netRSA加解密工具 依赖项 WinFormsRSA.csproj <Project...

Metricbeat安装教程——Linux——Metricbeat监控ES集群

Metricbeat安装教程——Linux 一、安装 下载安装包&#xff1a; 官网下载地址&#xff1a;https://www.elastic.co/cn/downloads/beats/metricbeat 上传包到linux 切换到安装目录下 解压&#xff1a;tar -zxvf metricbeat-7.17.1-linux-x86_64.tar.gz 重命名安装文件夹 mv met…...

一万多字拆解java中——“ 注解 ”的一切(三)(已完结)

前言&#xff1a; 咱们书接上回&#xff0c;上次按照框架讲了 第一篇&#xff0c;我们讲到了&#xff1a; ①注解的引入&#xff08;简单概述&#xff09;&#xff1a;在jdk5.0的时候 ②注解与注释的区别&#xff1a; 注释 是为了帮助人类阅读代码&#xff0c;不会对程序的执…...

记一次rac故障原因分析(虚拟化平台)

一 现象描述 XX客户于1月14号凌晨业务中断&#xff0c;检查数据库发现数据库集群宕机。 XX客户于2月14号春节初五早上业务异常&#xff0c;连接数据库无响应。 二 问题详细诊断 1月14号故障 1月14号凌晨2点&#xff0c;客户反馈业务中断&#xff0c;发现节点1无法连接&…...

Vue CLI 3 项目构建

Vue CLI 是一个功能强大、易于使用的工具&#xff0c;可以极大地简化 Vue.js 应用的开发过程。通过快速创建项目、灵活的插件系统和丰富的配置选项&#xff0c;开发者可以更专注于业务逻辑&#xff0c;而不是底层配置。无论是新手还是经验丰富的开发者&#xff0c;Vue CLI 都是…...

1114 Family Property (25)

This time, you are supposed to help us collect the data for family-owned property. Given each persons family members, and the estate&#xff08;房产&#xff09;info under his/her own name, we need to know the size of each family, and the average area and n…...

19c补丁后oracle属主变化,导致不能识别磁盘组

补丁后服务器重启&#xff0c;数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后&#xff0c;存在与用户组权限相关的问题。具体表现为&#xff0c;Oracle 实例的运行用户&#xff08;oracle&#xff09;和集…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻

在如今就业市场竞争日益激烈的背景下&#xff0c;越来越多的求职者将目光投向了日本及中日双语岗位。但是&#xff0c;一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧&#xff1f;面对生疏的日语交流环境&#xff0c;即便提前恶补了…...

学校招生小程序源码介绍

基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码&#xff0c;专为学校招生场景量身打造&#xff0c;功能实用且操作便捷。 从技术架构来看&#xff0c;ThinkPHP提供稳定可靠的后台服务&#xff0c;FastAdmin加速开发流程&#xff0c;UniApp则保障小程序在多端有良好的兼…...

Nuxt.js 中的路由配置详解

Nuxt.js 通过其内置的路由系统简化了应用的路由配置&#xff0c;使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

C++ 基础特性深度解析

目录 引言 一、命名空间&#xff08;namespace&#xff09; C 中的命名空间​ 与 C 语言的对比​ 二、缺省参数​ C 中的缺省参数​ 与 C 语言的对比​ 三、引用&#xff08;reference&#xff09;​ C 中的引用​ 与 C 语言的对比​ 四、inline&#xff08;内联函数…...

初学 pytest 记录

安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

Springboot社区养老保险系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;社区养老保险系统小程序被用户普遍使用&#xff0c;为方…...

七、数据库的完整性

七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

【JVM面试篇】高频八股汇总——类加载和类加载器

目录 1. 讲一下类加载过程&#xff1f; 2. Java创建对象的过程&#xff1f; 3. 对象的生命周期&#xff1f; 4. 类加载器有哪些&#xff1f; 5. 双亲委派模型的作用&#xff08;好处&#xff09;&#xff1f; 6. 讲一下类的加载和双亲委派原则&#xff1f; 7. 双亲委派模…...

腾讯云V3签名

想要接入腾讯云的Api&#xff0c;必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口&#xff0c;但总是卡在签名这一步&#xff0c;最后放弃选择SDK&#xff0c;这次终于自己代码实现。 可能腾讯云翻新了接口文档&#xff0c;现在阅读起来&#xff0c;清晰了很多&…...