赞
踩
这个裁剪方法可以裁剪圆形、矩形,可以二开,放心食用
- // cropper--index.vue
-
-
- <template>
- <view>
- <canvas class="fyj_canvas" canvas-id="myCanvas" :style="{width:'100%', height:canvasHeight+'px',}"/>
- <movable-area class="fyj_movable_area text-center hidden" :style="{width:'100%', height:canvasHeight+'px',}">
- <movable-view v-if="src" :style="{width:cutWidth +'px', height:cutHeight + 'px'}" class="fyj_movable_view" :x="x"
- :y="y" direction="all" :scale="true" @change="movableChange" @scale="handleScale"></movable-view>
- <image class="fyj_photo" id="fyj_photo" :src="src" mode="widthFix"/>
- </movable-area>
- <!--</canvas>-->
- <view style="margin-top:20rpx; padding:0 20rpx;">
- <button class="pull-left" type="warn" size="mini" @click="getPhoto">选择照片/拍照</button>
- <button class="pull-right" type="primary" size="mini" @click="cut">裁剪</button>
- <view class="clearfix"></view>
- </view>
- </view>
- </template>
-
- <script setup>
- import {ref, reactive, watch, nextTick, getCurrentInstance} from 'vue'
-
- const {aspectRatio} = defineProps({
- // 这里定义了innerText属性,属性值可以在组件使用时指定
- //宽高比 TODO 这个要求裁剪框是矩形的,如果裁剪框是圆形的,这个属性宽高比一定得是1
- aspectRatio: {
- type: Number,
- default: 5 / 7,
- },
- })
-
- const screenWidth = ref(uni.getSystemInfoSync().windowWidth)
- const canvasHeight = ref(300)
- const x = ref(0)
- const y = ref(0)
- const src = ref('')
- const cut_src = ref('')
- const cutWidth = ref(0)
- const cutHeight = ref(0)
-
- const tempImage = ref('')
-
- const {proxy} = getCurrentInstance()
-
- const emits = defineEmits(['getTempFilePath'])
- // 这里是一个自定义方法
- //选择照片
- const getPhoto = () => {
- const ctx = uni.createCanvasContext('myCanvas', proxy)
- let obj = uni.createSelectorQuery();
- uni.chooseImage({
- count: 1,
- sizeType: ['original', 'compressed'],
- sourceType: ['album', 'camera'],
- success(res) {
- //清空之前的剪切图
- emits('getTempFilePath', {cut_src: '', cutWidth: cutWidth.value, cutHeight: cutHeight.value})
-
- // tempFilePath可以作为img标签的src属性显示图片
- const tempFilePaths = res.tempFilePaths[0];
- src.value = tempFilePaths
- // 这个变量是为了下面圆形裁剪框使用的 可以结合一个配置项判断是否要使用
- tempImage.value = tempFilePaths
- cut_src.value = ''
-
- setTimeout(function () {
- // TODO 这里也可以换成小程序获取图片信息的那个api方法
- uni.createSelectorQuery().in(proxy).select('#fyj_photo').boundingClientRect(function (rect) {
- console.log(rect);
- console.log('图片的信息', rect.height);
- canvasHeight.value = rect.height
- setCut();
- // TODO 矩形裁剪框使用的是这个
- // ctx.drawImage(tempFilePaths, 0, 0, screenWidth.value, canvasHeight.value)
- // ctx.draw()
-
- // 放到上面去了,防止一开始拿不到
- // setCut();
- //确保不同大小的图片,切图不会变形
- x.value = 0
- y.value = 0
- }).exec()
- }, 100)
- }
- })
- }
-
- //获取图片高度 暂时没用到
- // const getHeight = () => {
- // const query = uni.createSelectorQuery().in(proxy)
- // query.selectAll('#fyj_photo').boundingClientRect()
- // query.exec(function (rect) {
- // console.log(rect);
- // console.log(rect[0].height);
- // canvasHeight.value = rect[0].height
- // // TODO ...
- // ctx.drawImage(tempFilePaths[0], 0, 0, screenWidth.value, canvasHeight.value)
- // ctx.draw();
- // setCut();
- // })
- // }
-
- //裁剪框移动事件
- const movableChange = debounce((e) => {
- console.log('裁剪框移动', e);
- x.value = e.detail.x
- y.value = e.detail.y
-
-
- // TODO 这部分可以抽成一个方法配合一个配置项 圆形裁剪框
- const ctx = uni.createCanvasContext('myCanvas', proxy)
- setTimeout(function () {
- // TODO 这里也可以换成小程序获取图片信息的那个api方法
- uni.createSelectorQuery().in(proxy).select('#fyj_photo').boundingClientRect(function (rect) {
- console.log(rect);
- console.log('图片的信息', rect.height);
- canvasHeight.value = rect.height
- setCut();
-
-
- // TODO 圆形裁剪框 裁剪圆形的图片
- // 开始一个新的路径
- ctx.save()
- ctx.beginPath();
- // 创建一个圆形路径
- ctx.arc((x.value + (cutWidth.value / 2)), (y.value + (cutWidth.value / 2)), cutWidth.value / 2, 0, Math.PI * 2, false);
- // 设置当前路径为剪切路径
- ctx.clip();
-
- // 再次绘制图片,只有在剪切路径内的部分会被绘制
- ctx.drawImage(tempImage.value, 0, 0, screenWidth.value, canvasHeight.value);
- ctx.restore();
- ctx.draw();
-
- // 这个放到上面去了,防止一开始拿不到
- // setCut();
- // TODO 圆形裁剪框时是不需要的 确保不同大小的图片,切图不会变形
- // x.value = 0
- // y.value = 0
- // TODO 防止第二次圆形绘制失效
- ctx.clearRect(0, 0, screenWidth.value, canvasHeight.value)
- }).exec()
- }, 100)
- }, 500)
-
- //截图
- const cut = () => {
- console.log(cutHeight.value);
- uni.canvasToTempFilePath({
- // TODO 不管是绘制圆形还是矩形,这里的配置都是一样的
- x: x.value,
- y: y.value,
- width: cutWidth.value,
- height: cutHeight.value,
- destWidth: cutWidth.value,
- destHeight: cutHeight.value,
- canvasId: 'myCanvas',
- success(res) {
- console.log(res.tempFilePath);
- cut_src.value = res.tempFilePath
- emits('getTempFilePath', {cut_src: cut_src.value, cutWidth: cutWidth.value, cutHeight: cutHeight.value})
- }
- }, proxy)
- }
-
- //动态设置裁剪框大小,确定高度不得超过canvas的高度
- const setCut = () => {
- // TODO 这里比较重要
- cutWidth.value = uni.getSystemInfoSync().windowWidth * 0.8
- cutHeight.value = uni.getSystemInfoSync().windowWidth * 0.8 / aspectRatio
-
- if (cutHeight.value - 4 > canvasHeight.value) {
- console.log(cutHeight.value);
- console.log(canvasHeight.value);
- cutHeight.value = canvasHeight.value - 4
- cutWidth.value = (canvasHeight.value - 4) * aspectRatio
- } else {
- cutWidth.value = uni.getSystemInfoSync().windowWidth * 0.8
- cutHeight.value = uni.getSystemInfoSync().windowWidth * 0.8 / aspectRatio
- }
- console.log('裁剪框的宽', cutWidth.value);
- console.log('裁剪框的高', cutHeight.value);
- }
-
- // 裁剪框缩放事件
- const handleScale = debounce((e) => {
- console.log('裁剪框缩放', e);
- cutWidth.value = cutWidth.value * e.detail.scale
- cutHeight.value = cutWidth.value * e.detail.scale
- }, 500)
-
-
- // 防抖
- function debounce(func, wait, immediate=false) {
- let timeout;
-
- return function executedFunction() {
- const context = this;
- const args = arguments;
-
- const later = function() {
- timeout = null;
- if (!immediate) func.apply(context, args);
- };
-
- const callNow = immediate && !timeout;
-
- clearTimeout(timeout);
-
- timeout = setTimeout(later, wait);
-
- if (callNow) func.apply(context, args);
- };
- }
-
- </script>
-
-
- <style scoped lang="scss">
- // TODO 隐藏画布可以吧注释放开
- .fyj_canvas {
- //position: absolute;
- //left: 0;
- //top: -71vh;
- //z-index: -1;
- //opacity: 0;
- }
-
- .fyj_movable_area {
- width: 100%;
- height: auto;
- position: relative;
- background: rgba(0, 0, 0, 0.3);
- z-index: 99;
- }
-
- .fyj_movable_view {
- border: 2px dashed red;
- // TODO 圆形裁剪框时使用的
- border-radius: 50%;
- }
-
- .fyj_photo {
- width: 100%;
- }
-
- .fyj_footer {
- margin-top: 20rpx 0;
- }
-
- .fyj_footerBtn {
- width: 100%;
- display: inline-block;
- color: #fff;
- border-radius: 0;
- font-size: 32rpx;
- }
-
- .fyj_sure {
- background: #fc6b47;
- }
-
- .pull-left {
- float: left;
- }
-
- .pull-right {
- float: right;
- }
-
- .clearfix {
- clear: both;
- }
-
- .text-center {
- text-align: center;
- }
- </style>
- // testCropper--index.vue
-
-
- <template>
- <view>
- <!-- aspectRatio 剪裁图片的宽高比 -->
- <cropper :aspectRatio="1" @getTempFilePath="getCutsrc"></cropper>
- <view v-if="cut_src" class="fyj_cutDiv text-center">
- <image :style="{width: cutWidth + 'px', height: cutHeight + 'px'}" class="fyj_cut_photo" :src="cut_src" mode="widthFix"/>
- </view>
- <view v-if="cut_src" class="fyj_footer text-center">
- <button class="fyj_footerBtn fyj_sure" @click='sure'>确定</button>
- </view>
- </view>
- </template>
-
- <script setup>
- import {ref} from 'vue'
- import cropper from '../components/cropper/index.vue'
-
- const cut_src = ref('');
- const cutWidth = ref(0);
- const cutHeight = ref(0);
-
- const getCutsrc = (e) => {
- console.log('子组件的传值', e)
- cut_src.value = e.cut_src;
- cutWidth.value = e.cutWidth;
- cutHeight.value = e.cutHeight;
- }
-
- </script>
-
-
- <style scoped lang="scss">
- .fyj_footer {
- margin-top: 20rpx 0;
- }
-
- .fyj_footerBtn {
- width: 100%;
- display: inline-block;
- color: #fff;
- border-radius: 0;
- font-size: 32rpx;
- }
-
- .fyj_sure {
- background: #fc6b47;
- }
-
- .fyj_cutDiv {
- margin: 20rpx 0;
- }
- </style>
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。