Skip to content

Commit

Permalink
feat: 头像裁剪组件-taro版本
Browse files Browse the repository at this point in the history
  • Loading branch information
yi-boide committed Sep 22, 2023
1 parent 2ae48e3 commit df410b1
Show file tree
Hide file tree
Showing 9 changed files with 907 additions and 7 deletions.
9 changes: 8 additions & 1 deletion packages/nutui-taro-demo/project.private.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@
"condition": {
"miniprogram": {
"list": [
{
"name": "AvatarCropper",
"pathName": "business/pages/avatarcropper/index",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "exhibition/pages/imagepreview/index",
"pathName": "exhibition/pages/imagepreview/index",
Expand Down Expand Up @@ -65,4 +72,4 @@
},
"projectname": "vue4.x",
"libVersion": "2.27.1"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default {
navigationBarTitleText: 'AvatarCropper'
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<template>
<div class="demo barrage-demo" :class="{ web: env === 'WEB' }">
<Header v-if="env === 'WEB'" />
<h2>基础用法</h2>
<nut-cell>
<nut-avatar-cropper @confirm="cutImage">
<nut-avatar size="large">
<img :src="imageUrl" />
</nut-avatar>
</nut-avatar-cropper>
</nut-cell>
<h2>裁剪区域toolbar插槽</h2>
<nut-cell>
<nut-avatar-cropper ref="avatarCropperRef" toolbar-position="top" edit-text="修改" @confirm="cutImage">
<nut-avatar size="large">
<img :src="imageUrl" />
</nut-avatar>
<template #toolbar>
<div class="toolbar">
<nut-button type="primary" @click="avatarCropperRef.cancel()">取消</nut-button>
<nut-button type="primary" @click="avatarCropperRef.reset()">重置</nut-button>
<nut-button type="primary" @click="avatarCropperRef.rotate()">旋转</nut-button>
<nut-button type="primary" @click="avatarCropperRef.confirm()">确认</nut-button>
</div>
</template>
</nut-avatar-cropper>
</nut-cell>
</div>
</template>

<script lang="ts" setup>
import { ref } from 'vue';
import Taro from '@tarojs/taro';
import Header from '../../../components/header.vue';
const env = Taro.getEnv();
const imageUrl = ref(
'https://img12.360buyimg.com/imagetools/jfs/t1/196430/38/8105/14329/60c806a4Ed506298a/e6de9fb7b8490f38.png'
);
const avatarCropperRef = ref();
const cutImage = (url: string) => {
imageUrl.value = url;
};
</script>

<style>
.toolbar {
display: flex;
justify-content: space-between;
}
</style>
4 changes: 1 addition & 3 deletions src/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -1309,9 +1309,7 @@
"show": true,
"cName": "头像裁剪",
"desc": "仿微信头像裁剪功能",
"taro": false,
"exportEmpty": false,
"exportEmptyTaro": false,
"taro": true,
"author": "Marvin"
}
]
Expand Down
99 changes: 99 additions & 0 deletions src/packages/__VUE/avatarcropper/canvas-util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import Taro from '@tarojs/taro';
import CanvasContext = Taro.CanvasContext;

const compareVersion = (v1Old: string, v2Old: string) => {
let v1 = v1Old.split('.');
let v2 = v2Old.split('.');
const len = Math.max(v1.length, v2.length);

while (v1.length < len) {
v1.push('0');
}
while (v2.length < len) {
v2.push('0');
}

for (let i = 0; i < len; i++) {
const num1 = parseInt(v1[i]);
const num2 = parseInt(v2[i]);

if (num1 > num2) {
return 1;
} else if (num1 < num2) {
return -1;
}
}

return 0;
};

const isWeapp = () => {
return process.env.TARO_ENV === 'weapp';
};

//////////////////////////////////////////////////////////////////////////////////
//////// 微信小程序自1.9.90起废除若干个CanvasContext的函数,改为属性,以下为兼容代码
//////////////////////////////////////////////////////////////////////////////////

function _easyCanvasContextBase(
systemInfo: any,
lowCallback: () => void,
highCallback: () => void,
targetVersion: string = '1.9.90'
) {
if (isWeapp() && compareVersion(systemInfo.SDKVersion, targetVersion) >= 0) {
highCallback();
} else {
lowCallback();
}
}
/**
*
* 基础库 1.9.90 开始支持,低版本需做兼容处理。填充颜色。用法同 CanvasContext.setFillStyle()。
* @param systemInfo
* @param canvasContext
* @param color
*/
function easySetStrokeStyle(systemInfo: any, canvasContext: CanvasContext, color: string | CanvasGradient) {
_easyCanvasContextBase(
systemInfo,
() => {
canvasContext.setStrokeStyle(color);
console.log('???');
},
() => {
if (typeof color === 'string') {
canvasContext.strokeStyle = color;
}
console.log('2333');
}
);
}

function easySetLineWidth(systemInfo: any, canvasContext: CanvasContext, lineWidth: number) {
_easyCanvasContextBase(
systemInfo,
() => {
canvasContext.setLineWidth(lineWidth);
},
() => {
canvasContext.lineWidth = lineWidth;
}
);
}

function easySetFillStyle(systemInfo: any, canvasContext: CanvasContext, color: string | CanvasGradient) {
_easyCanvasContextBase(
systemInfo,
() => {
canvasContext.setFillStyle(color);
},
() => {
if (typeof color === 'string') {
canvasContext.fillStyle = color;
}
}
);
}

export { easySetStrokeStyle, easySetLineWidth, easySetFillStyle };
121 changes: 120 additions & 1 deletion src/packages/__VUE/avatarcropper/doc.taro.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,123 @@

### 介绍

后续再进行开发
用来对头像进行剪切生成一张新的图片。

### 安装

```js
import { createApp } from 'vue';
import { AvatarCropper } from '@nutui/nutui';

const app = createApp();
app.use(AvatarCropper);
```

### 基础用法

中间直接使用avatar组件,裁剪后图片内容会被替换为新的。

:::demo

```vue
<template>
<nut-avatar-cropper>
<nut-avatar size="large" @confirm="cutImage">
<img :src="imageUrl" />
</nut-avatar>
</nut-avatar-cropper>
</template>
<script setup>
import { ref } from 'vue';
const imageUrl = ref(
'https://img12.360buyimg.com/imagetools/jfs/t1/196430/38/8105/14329/60c806a4Ed506298a/e6de9fb7b8490f38.png'
);
const cutImage = (url) => {
imageUrl.value = url;
};
</script>
```

:::

### 裁剪区域toolbar插槽

自定义裁剪区域工具栏,toolbar-position控制工具栏位置

:::demo

```vue
<template>
<nut-avatar-cropper ref="avatarCropperRef" toolbar-position="top" edit-text="修改" @confirm="cutImage">
<nut-avatar size="large">
<img :src="imageUrl" />
</nut-avatar>
<template #toolbar>
<div class="toolbar">
<nut-button type="primary" @click="avatarCropperRef.cancel()">取消</nut-button>
<nut-button type="primary" @click="avatarCropperRef.reset()">重置</nut-button>
<nut-button type="primary" @click="avatarCropperRef.rotate()">旋转</nut-button>
<nut-button type="primary" @click="avatarCropperRef.confirm()">确认</nut-button>
</div>
</template>
</nut-avatar-cropper>
</template>
<script setup>
import { ref } from 'vue';
const imageUrl = ref(
'https://img12.360buyimg.com/imagetools/jfs/t1/196430/38/8105/14329/60c806a4Ed506298a/e6de9fb7b8490f38.png'
);
const avatarCropperRef = ref();
const cutImage = (url) => {
imageUrl.value = url;
};
</script>
<style>
.toolbar {
display: flex;
justify-content: space-between;
}
</style>
```

:::

## API

### AvatarCropper Props

| 参数 | 说明 | 类型 | 默认值 |
| ---------------- | -------------------------------------------------- | ------ | -------------------------- |
| max-zoom | 最大缩放倍数 | number | 3 |
| space | 裁剪区域两边预留的间隙 | number | 10 |
| toolbar-position | 裁剪区域工具栏位置,可选值为:`top` `bottom` | string | bottom |
| edit-text | 中间的文字内容 | string | 编辑 |
| cancel-text | 取消按钮的文字 | string | 取消 |
| cancel-confirm | 确认按钮的文字 | string | 确认 |
| size-type | 所选的图片的尺寸: 可选值:`original` `compressed` | Array | ['original', 'compressed'] |
| source-type | 选择图片的来源: 可选值:`album` `camera` | Array | ['album', 'camera'] |

### AvatarCropper Slots

| 名称 | 描述 |
| ------- | ----------------------------------------------------------- |
| default | 默认插槽,可放置图片、图标、文本等元素 |
| toolbar | 选择文件后裁剪弹窗底部元素可以自定义,通过ref调用组件的方法 |

### AvatarCropper Events

| 名称 | 描述 | 回调参数 |
| ------- | ------------------ | ------------------ |
| confirm | 裁剪后点击确认触发 | url:裁剪后的base64 |
| cancel | 点击取消触发 | - |

### AvatarCropper Ref

| 事件名 | 说明 |
| ------- | --------- |
| cancel | 取消裁剪 |
| reset | 重置为0度 |
| rotate | 旋转90度 |
| confirm | 确定裁剪 |
14 changes: 12 additions & 2 deletions src/packages/__VUE/avatarcropper/index.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.nut-avatar-cropper {
position: relative;
&::after {
&::after,
&__edit-text {
content: attr(data-edit-text);
position: absolute;
top: 0;
Expand All @@ -14,6 +15,11 @@
justify-content: center;
align-items: center;
}
&.taro {
&::after {
content: none;
}
}
&__input {
position: absolute;
top: 0;
Expand All @@ -34,14 +40,18 @@
height: 100%;
background: var(--nut-overlay-bg-color, rgba(0, 0, 0, 0.7));
z-index: 1000;
&__canvas {
&__canvas,
&__cut-canvas {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
&__cut-canvas {
z-index: 0;
}
&__toolbar {
position: absolute;
bottom: 0;
Expand Down
Loading

0 comments on commit df410b1

Please sign in to comment.