choo-taro-ui-vue3
Version:
Taro UI Rewritten in Vue 3.0
306 lines (292 loc) • 12.4 kB
JavaScript
import Taro from '@tarojs/taro';
import { defineComponent, computed, renderList, Fragment, openBlock, createElementBlock, resolveComponent, normalizeStyle, createVNode, mergeProps, withCtx, createBlock, toRef, createCommentVNode, toDisplayString, createTextVNode, normalizeClass } from 'vue';
import { pxTransform, uuid } from '../utils';
const AtLoading = defineComponent({
name: "AtLoading",
props: {
size: { type: [String, Number], default: 0 },
color: [String, Number]
},
setup(props) {
const loadingSize = computed(() => {
return pxTransform(parseInt(`${props.size}`));
});
const sizeStyle = computed(() => ({
width: loadingSize.value,
height: loadingSize.value
}));
const ringStyle = computed(() => ({
...sizeStyle.value,
border: props.color ? `1px solid ${props.color}` : "",
"border-color": props.color ? `${props.color} transparent transparent transparent` : ""
}));
return {
sizeStyle,
ringStyle
};
}
});
// Binding optimization for webpack code-split
const _renderList$1 = renderList, _Fragment$1 = Fragment, _openBlock$1 = openBlock, _createElementBlock$1 = createElementBlock, _resolveComponent$1 = resolveComponent, _normalizeStyle = normalizeStyle, _createVNode$1 = createVNode, _mergeProps$1 = mergeProps, _withCtx$1 = withCtx, _createBlock$1 = createBlock;
function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) {
const _component_taro_view = process.env.TARO_ENV === "h5" ? _resolveComponent$1("taro-view") : "view";
return (_openBlock$1(), _createBlock$1(_component_taro_view, _mergeProps$1(_ctx.$attrs, {
class: "at-loading",
style: _ctx.sizeStyle
}), {
default: _withCtx$1(() => [
(_openBlock$1(), _createElementBlock$1(_Fragment$1, null, _renderList$1(3, (n) => {
return _createVNode$1(_component_taro_view, {
key: n,
style: _normalizeStyle(_ctx.ringStyle),
class: "at-loading__ring"
}, null, 8 /* PROPS */, ["style"])
}), 64 /* STABLE_FRAGMENT */))
]),
_: 1 /* STABLE */
}, 16 /* FULL_PROPS */, ["style"]))
}
AtLoading.render = _sfc_render$1;
const generateMatrix = (files, col, showAddBtn) => {
const matrix = [];
const length = showAddBtn ? files.length + 1 : files.length;
const row = Math.ceil(length / col);
for (let i = 0; i < row; i++) {
if (i === row - 1) {
const lastArr = files.slice(i * col);
if (lastArr.length < col) {
if (showAddBtn) {
lastArr.push({ type: "btn", uuid: uuid() });
}
for (let j = lastArr.length; j < col; j++) {
lastArr.push({ type: "blank", uuid: uuid() });
}
}
matrix.push(lastArr);
} else {
matrix.push(files.slice(i * col, (i + 1) * col));
}
}
return matrix;
};
const ENV = Taro.getEnv();
const modeOptions = [
"scaleToFill",
"aspectFit",
"aspectFill",
"widthFix",
"top",
"bottom",
"center",
"left",
"right",
"top left",
"top right",
"bottom left",
"bottom right"
];
const AtImagePicker = defineComponent({
name: "AtImagePicker",
components: { AtLoading },
emits: {
"change"(args) {
return !!(args.files && Array.isArray(args.files) && args.operationType && ["add", "remove"].includes(args.operationType) && ["undefined", "number"].includes(typeof args.index));
},
"image-click"(index, file) {
return !!(typeof index === "number" && file && typeof file === "object");
},
"fail"(message) {
return !!(message && typeof message === "string");
}
},
props: {
files: {
type: Array,
default: () => []
},
mode: {
type: String,
default: "aspectFill",
validator: (value) => modeOptions.includes(value)
},
showAddBtn: {
type: Boolean,
default: true
},
multiple: Boolean,
length: {
type: Number,
default: 4
},
count: Number,
sizeType: {
type: Array,
default: () => ["original", "compressed"]
},
sourceType: {
type: Array,
default: () => ["album", "camera"]
}
},
setup(props, { emit }) {
const rowLength = computed(() => props.length <= 0 ? 1 : props.length);
const genKey = computed(() => (item, row, col) => {
return item.url ? `preview-${row * props.length + col}` : `add-bar-${row * props.length + col}`;
});
const matrix = computed(() => generateMatrix(props.files, rowLength.value, props.showAddBtn));
function chooseFile() {
const params = {};
const filePathName = ENV === Taro.ENV_TYPE.ALIPAY ? "apFilePaths" : "tempFiles";
if (props.multiple) {
params.count = 99;
}
if (props.count) {
params.count = props.count;
}
if (props.sizeType) {
params.sizeType = props.sizeType;
}
if (props.sourceType) {
params.sourceType = props.sourceType;
}
Taro.chooseImage(params).then((res) => {
const targetFiles = res.tempFilePaths.map((path, i) => ({
url: path,
file: res[filePathName][i]
}));
const newFiles = props.files.concat(targetFiles);
emit("change", { files: newFiles, operationType: "add" });
}).catch((err) => {
emit("fail", err.errMsg);
});
}
function handleImageClick(idx) {
emit("image-click", idx, props.files[idx]);
}
function handleRemoveImg(idx) {
if (ENV === Taro.ENV_TYPE.WEB) {
window.URL.revokeObjectURL(props.files[idx].url);
}
const newFiles = props.files.filter((_, i) => i !== idx);
emit("change", { files: newFiles, operationType: "remove", index: idx });
}
return {
length: toRef(props, "length"),
mode: toRef(props, "mode"),
matrix,
genKey,
chooseFile,
handleRemoveImg,
handleImageClick
};
}
});
// Binding optimization for webpack code-split
const _renderList = renderList, _Fragment = Fragment, _openBlock = openBlock, _createElementBlock = createElementBlock, _createCommentVNode = createCommentVNode, _resolveComponent = resolveComponent, _createVNode = createVNode, _createBlock = createBlock, _toDisplayString = toDisplayString, _createTextVNode = createTextVNode, _normalizeClass = normalizeClass, _withCtx = withCtx, _mergeProps = mergeProps;
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
const _component_taro_view = process.env.TARO_ENV === "h5" ? _resolveComponent("taro-view") : "view";
const _component_taro_image = process.env.TARO_ENV === "h5" ? _resolveComponent("taro-image") : "image";
const _component_at_loading = _resolveComponent("at-loading");
return (_openBlock(), _createBlock(_component_taro_view, _mergeProps(_ctx.$attrs, { class: "at-image-picker" }), {
default: _withCtx(() => [
(_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.matrix, (row, i) => {
return (_openBlock(), _createBlock(_component_taro_view, {
key: i+1,
class: "at-image-picker__flex-box"
}, {
default: _withCtx(() => [
(_openBlock(true), _createElementBlock(_Fragment, null, _renderList(row, (item, j) => {
return (_openBlock(), _createBlock(_component_taro_view, {
key: _ctx.genKey(item, i, j),
class: "at-image-picker__flex-item"
}, {
default: _withCtx(() => [
_createCommentVNode(" image thumb "),
(item.url)
? (_openBlock(), _createBlock(_component_taro_view, {
key: 0,
class: "at-image-picker__item"
}, {
default: _withCtx(() => [
_createVNode(_component_taro_view, {
class: "at-image-picker__remove-btn",
onTap: $event => (_ctx.handleRemoveImg(i * _ctx.length + j))
}, null, 8 /* PROPS */, ["onTap"]),
_createVNode(_component_taro_image, {
class: "at-image-picker__preview-img",
mode: _ctx.mode,
src: item.url,
onTap: $event => (_ctx.handleImageClick(i * _ctx.length + j))
}, null, 8 /* PROPS */, ["mode", "src", "onTap"]),
_createCommentVNode(" upload status "),
(item.status && item.status !== 'done')
? (_openBlock(), _createBlock(_component_taro_view, {
key: 0,
class: "at-image-picker__upload-status"
}, {
default: _withCtx(() => [
_createCommentVNode(" status icon "),
(item.status === 'uploading')
? (_openBlock(), _createBlock(_component_at_loading, {
key: 0,
color: "#fff"
}))
: (_openBlock(), _createBlock(_component_taro_view, {
key: 1,
class: "at-image-picker__status-icon at-image-picker__status-icon--failed"
})),
_createCommentVNode(" status message "),
(item.message)
? (_openBlock(), _createBlock(_component_taro_view, {
key: 2,
class: _normalizeClass(['at-image-picker__status-message', {
'at-image-picker__status-message--uploading': item.status === 'uploading',
'at-image-picker__status-message--failed': item.status !== 'uploading',
}])
}, {
default: _withCtx(() => [
_createTextVNode(_toDisplayString(item.message), 1 /* TEXT */)
]),
_: 2 /* DYNAMIC */
}, 1032 /* PROPS, DYNAMIC_SLOTS */, ["class"]))
: _createCommentVNode("v-if", true)
]),
_: 2 /* DYNAMIC */
}, 1024 /* DYNAMIC_SLOTS */))
: _createCommentVNode("v-if", true)
]),
_: 2 /* DYNAMIC */
}, 1024 /* DYNAMIC_SLOTS */))
: (item.type === 'btn')
? (_openBlock(), _createElementBlock(_Fragment, { key: 1 }, [
_createCommentVNode(" + add bar: choose button "),
_createVNode(_component_taro_view, {
class: "at-image-picker__item at-image-picker__choose-btn",
onTap: _ctx.chooseFile
}, {
default: _withCtx(() => [
(_openBlock(), _createElementBlock(_Fragment, null, _renderList([0, 1], (i) => {
return _createVNode(_component_taro_view, {
key: i,
class: "add-bar"
})
}), 64 /* STABLE_FRAGMENT */))
]),
_: 2 /* DYNAMIC */
}, 1032 /* PROPS, DYNAMIC_SLOTS */, ["onTap"])
], 2112 /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */))
: _createCommentVNode("v-if", true)
]),
_: 2 /* DYNAMIC */
}, 1024 /* DYNAMIC_SLOTS */))
}), 128 /* KEYED_FRAGMENT */))
]),
_: 2 /* DYNAMIC */
}, 1024 /* DYNAMIC_SLOTS */))
}), 128 /* KEYED_FRAGMENT */))
]),
_: 1 /* STABLE */
}, 16 /* FULL_PROPS */))
}
AtImagePicker.render = _sfc_render;
export default AtImagePicker;