uniapp_07_文本截取和canvas

uniapp_07_文本截取和canvas

  • uniapp的canvas
  • 文本截取
  • 获取图片颜色
  • renderjs
  • 参考

uniapp的canvas

  1. uniapp cancas

    组件和api请看uniapp的官方文档,咕就不在这里写了,哎早知道当年就好好读书了,现在写个随笔都写不好,标点符号都不会用,果然没救了 canvas组件canvasApi

  2. 与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}` };
          }
        })
      }      
      

文本截取

  1. 超出时尾部省略号的
    // 无论多行还是一行直接使用css即可
    <!-- 普通布局 -->
    <div class="block">普通布局普通布局普通布局普通布局</div>
    .block {
      width: 100px;
      overflow:hidden;
      text-overflow:ellipsis;
      // 加上这两行便是多行
      -webkit-line-clamp: 3;
      -webkit-box-orient: vertical;
    }
    
  2. 超出时中间省略号的

    `说下思路:

    1. 先获取节点宽度、字体大小、字体
    2. 再使用canvas获取文字宽度
    3. 使用字体宽度 / 节点宽度 向上取整得到行数
    4. 节点宽度 / 字体大小 向下取整 得出一行有多少字体
    5. 先截取字符串尾部需要显示的文本,再截取字符串头部需要显示的字体 中间使用省略号拼接 注:如果只有一行的话可以直接用css实现 等待好像都可以使用css 实现QWQ 加上吧`
      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>

参考

posted @ 2024-05-22 15:27  tsuru  阅读(147)  评论(0编辑  收藏  举报