uniapp_07_文本截取和canvas
uniapp_07_文本截取和canvas
- uniapp的canvas
- 文本截取
- 获取图片颜色
- renderjs
- 参考
uniapp的canvas
-
uniapp cancas
组件和api请看uniapp的官方文档,咕就不在这里写了,哎早知道当年就好好读书了,现在写个随笔都写不好,标点符号都不会用,果然没救了 canvas组件和canvasApi
-
与html的canvas的区别
- 获取元素 h5:
document
,uniapp:uni.createSelectorQuery()
- 获得渲染上下文和它的绘画功能 h5:
canvas.getContext('2d')
uniapp:uni.createCanvasContext('sign-canvas', this);
- 设置画布大小 h5:
canvas.width, canvas.height
uniapp:<canvas style="width:xx; height:xx;"/>
- 生成BASE64图片: h5:
canvas.toDataURL('image/png')
// 1: 通过 canvas // uni方法用在封装的组件内部时,需要使用.in()方法选取绑定范围, // 例:uni.createSelectorQuery().in(this).select('.sign-canvas') // 不然使用: uni.createSelectorQuery().select('.sign-canvas') // 具体使用请看官方文档 let canvas = uni.createSelectorQuery().in(that).select('.sign-canvas') canvas.boundingClientRect().exec((data) => { let canvasW = Math.ceil(data[0].width); let canvasH = Math.ceil(data[0].height); uni.canvasToTempFilePath({ destWidth: canvasW, destHeight: canvasH, fileType: 'png', canvasId: 'sign-canvas', success: (res)=> { let path = res.tempFilePath; } },this) }) // 2. 通过请求的方式转换 注:这种方式只能使用网络连接 function (path) { // 获取图片后缀名 const suffix = path?.split(".").slice(-1)[0]; uni.request({ url: path, responseType: "arraybuffer", success: (res) => { let base64 = uni.arrayBufferToBase64(res.data); const img = { path: `data:image/${suffix};base64,${base64}` }; } }) }
- 获取元素 h5:
文本截取
- 超出时尾部省略号的
// 无论多行还是一行直接使用css即可 <!-- 普通布局 --> <div class="block">普通布局普通布局普通布局普通布局</div> .block { width: 100px; overflow:hidden; text-overflow:ellipsis; // 加上这两行便是多行 -webkit-line-clamp: 3; -webkit-box-orient: vertical; }
- 超出时中间省略号的
`说下思路:
- 先获取节点宽度、字体大小、字体
- 再使用canvas获取文字宽度
- 使用字体宽度 / 节点宽度 向上取整得到行数
- 节点宽度 / 字体大小 向下取整 得出一行有多少字体
- 先截取字符串尾部需要显示的文本,再截取字符串头部需要显示的字体 中间使用省略号拼接
css多行文本中间省略号
<view class="text">{{title}}</view> <view class="text">{{subTitle}}</view> data() { return { title: "如果只有一行的话可以直接用css实现 等待好像都可以使用css 实现QWQ", subTitle: '' } } // 计算字符串宽度需要 canvas 或 通 DOM 测量,这种方法在字符串中含有多个空格时,测出来的宽度会一样 // 截取字符串 async sliceTitleText (text, className="text") { text = text.replace(/\n/g,"") let styles = await this.getDomWidth(className); let textWidth = this.getActualWidthOfChars(text, { size: styles.size }); // 文字的宽度 >= 节点的宽度 * 行数 if(textWidth >= styles.width * 1) { let sizeNum = Math.floor(styles.width / styles.size) * 1; // 字符数 let tailText = '...'+text.slice(-4); // 尾部字符串 sizeNum = sizeNum - tailText.length; // let cycleText = text.slice(0,-4); // 循环需要的字符串 let result = text.slice(0, sizeNum); this.subTitle = result+tailText; console.log(result+tailText) } } // 获取dom的属性 getDomWidth(className="text") { return new Promise(()=>{ // 组件中使用需要指定 this let dom = uni.createSelectorQuery().in(this).select(eclass); dom.fields({ dataset: true, size: true, computedStyle: ['font-size', 'padding-left', 'padding-right'], },data => { // 没错 返回的数据是带单位的 let size = parseInt(data['font-size']?.slice(0,-2)); let offsetWidth = parseInt(data['width']); let pLeft = parseInt(data['padding-left']?.slice(0,-2)); let pright = parseInt(data['padding-right']?.slice(0,-2)); let width = Math.floor(offsetWidth - pLeft - pright); resolve({size, width}); }).exec() }) } /** * 获取文本宽度 * */ getActualWidthOfChars(text="", options = {}) { const { size = 14, family = "Microsoft YaHei" } = options; let ctx = uni.createCanvasContext('canvas', this); ctx.font = `${size}px ${family}`; const metrics = ctx.measureText(text); return Math.ceil(metrics.width); },
获取图片颜色
最近做项目的时候想到了个好玩的功能,获取图片主体颜色然后,背景颜色跟着变
/**
* 获取图片主题颜色
* @param that
* @param path 图片的路径
* @param success 获取图片颜色成功回调,主题色的RGB颜色值
* @param fail 获取图片颜色失败回调
*/
function canvasGetColor(that, path) {
return new Promise((resolve) => {
// 创建 canvas 对象
const ctx = uni.createCanvasContext('canvas', that);
// 图片绘制尺寸
const imgWidth = 300;
const imgHeight = 150;
ctx.drawImage(path, 0, 0, imgWidth, imgHeight);
ctx.save();
ctx.draw(true, () => {
uni.canvasGetImageData({
canvasId: 'canvas',
x: 0,
y: 0,
width: imgWidth,
height: imgHeight,
success(res) {
let data = res.data;
let r = 1,
g = 1,
b = 1;
// 获取所有像素的累加值
for (let row = 0; row < imgHeight; row++) {
for (let col = 0; col < imgWidth; col++) {
if (row == 0) {
r += data[imgWidth * row + col];
g += data[imgWidth * row + col + 1];
b += data[imgWidth * row + col + 2];
} else {
r += data[(imgWidth * row + col) * 4];
g += data[(imgWidth * row + col) * 4 + 1];
b += data[(imgWidth * row + col) * 4 + 2];
}
}
}
// 求rgb平均值
r /= imgWidth * imgHeight;
g /= imgWidth * imgHeight;
b /= imgWidth * imgHeight;
// 四舍五入
r = Math.round(r);
g = Math.round(g);
b = Math.round(b);
resolve(`rgb(${r},${g},${b})`);
}
}, that)
})
})
}
// rgba 转 16进制
function getHexColor(color) { // 传的color须为字符串
var values = color
.replace(/rgba?\(/, '') // 把 "rgba(" 去掉,变成 "194, 7, 15, 1)"
.replace(/\)/, '') // 把 ")" 去掉,变成 "194, 7, 15, 1"
.replace(/[\s+]/g, '') // 把空格去掉,变成 "194,7,15,1"
?.split(',') // 变成数组 [194,7,15,1]
var a = parseFloat(values[3] || 1), // values[3]是rgba中的a值,没有的话设置a为1,a可能为小数,所以用parseFloat函数
r = Math.floor(a * parseInt(values[0]) + (1 - a) * 255), // 转换为16进制
g = Math.floor(a * parseInt(values[1]) + (1 - a) * 255),
b = Math.floor(a * parseInt(values[2]) + (1 - a) * 255)
return '#' +
('0' + r.toString(16)).slice(-2) + // 转换后的16进制可能为一位,比如 7 就转换为 7 , 15 转换为 f
('0' + g.toString(16)).slice(-2) + // 当为一位的时候就在前面加个 0,
('0' + b.toString(16)).slice(-2) // 若是为两位,加 0 后就变成了三位,所以要用 slice(-2) 截取后两位
}
// 获取
function getImageThemeColor(that, path) {
// 获取图片后缀名
const suffix = path?.split(".").slice(-1)[0];
// #ifdef APP
// 由于getImageInfo存在问题,所以改用base64 注 path必须是网络地址
uni.request({
url: path,
responseType: "arraybuffer",
success: async (res) => {
let base64 = uni.arrayBufferToBase64(res.data);
const img = { path: `data:image/${suffix};base64,${base64}` };
const rgba = canvasGetColor(that, img.path);
}
})
// #endif
// #ifndef APP
uni.getImageInfo({
src: path,
success: (res) => {
// const img = { path: `data:image/${suffix};base64,${base64}` };
const rgba = canvasGetColor(that, res.path);
}
})
// #endif
}
rederjs
这个建议搜下 别人比我写的好 renderjs
<template>
<view class="renderWrap">
<view>
<button type="primary" @click="renderJS.sendData">视图层 发送数据到 逻辑层</button>
<button class="margin-top-md margin-bottom-md" type="warn" @click="changeMsg">逻辑层 修改 msg 值</button>
<button type="primary" @click="renderJS.renderMsg">视图层 修改 逻辑层值</button>
<view class="margin-top-md margin-bottom-md text-center" :msg="msg" :change:msg="renderJS.receiveMsg">
{{msg}}
</view>
</view>
</view>
</template>
<script module="renderJS" lang="renderjs">
export default {
data() {
return {
name: '我是renderjs module!',
message: ''
}
},
methods: {
renderMsg(event, ownerInstance) {
// 调用 Model 层的 renderClick方法,进行传值
ownerInstance.callMethod('renderClick', {
value: 'renderjs 向 Model 层传递数据,并修改了 msg 值'
})
},
// 接收 逻辑层发送的数据
receiveMsg(newValue, oldValue, ownerVm, vm) {
console.log('监听 msg 值:', newValue, oldValue)
},
// 发送数据到 逻辑层
sendData(e, ownerVm) {
ownerVm.callMethod('receiveRenderSendData', this.name)
}
}
}
</script>
<script>
export default {
data() {
return {
msg: '我是Model层的msg'
}
},
methods: {
// 触发逻辑层,renderjs 接收数据
changeMsg() {
this.msg = "修改 msg 值,并执行 receiveMsg 方法";
},
// 接收 renderjs 发送的数据
receiveRenderSendData(val) {
this.msg = `Model 接收 View层 值:${val}`;
},
//接收 renderjs 传递数据
renderClick(e) {
this.msg = e.value
}
}
}
</script>