UNPKG

nutui-taro-upgrade

Version:

@nutui/nutui-taro 对京东风格组件库的taro4 版本支持

716 lines (715 loc) 24.2 kB
var __defProp = Object.defineProperty; var __defProps = Object.defineProperties; var __getOwnPropDescs = Object.getOwnPropertyDescriptors; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); import { c as createComponent } from "../component-669c158a.js"; import { reactive, computed, ref, watch, toRefs, onMounted, openBlock, createElementBlock, createElementVNode, normalizeStyle, Fragment, renderList, normalizeClass, toDisplayString, createCommentVNode, createTextVNode, resolveComponent, renderSlot, mergeProps, createVNode } from "vue"; import Taro from "@tarojs/taro"; import { p as pxCheck } from "../pxCheck-a27490eb.js"; import { a as preventDefault, c as clamp } from "../util-f26975e1.js"; import { u as useTouch } from "../index-7a7385e4.js"; import { _ as _export_sfc } from "../_plugin-vue_export-helper-cc2b3d55.js"; import { u as useLocale } from "../index-3b6ff56c.js"; import "nutui-taro-upgrade/dist/packages/locale/lang"; const DEFAULT_FILED_NAMES = { text: "text", value: "value", children: "children", className: "className" }; const usePicker = (props, emit) => { const state = reactive({ formattedColumns: props.columns }); const columnFieldNames = computed(() => { return __spreadValues(__spreadValues({}, DEFAULT_FILED_NAMES), props.fieldNames); }); const defaultValues = ref([]); const defaultIndexes = computed(() => { const fields = columnFieldNames.value; return columnsList.value.map((column, index) => { const targetIndex = column.findIndex((item) => item[fields.value] === defaultValues.value[index]); return targetIndex === -1 ? 0 : targetIndex; }); }); const pickerColumn = ref([]); const swipeRef = (el) => { if (el && pickerColumn.value.length < columnsList.value.length) { pickerColumn.value.push(el); } }; const selectedOptions = computed(() => { const fields = columnFieldNames.value; return columnsList.value.map((column, index) => { return column.find((item) => item[fields.value] === defaultValues.value[index]) || column[0]; }); }); const columnsType = computed(() => { const firstColumn = state.formattedColumns[0]; const fields = columnFieldNames.value; if (firstColumn) { if (Array.isArray(firstColumn)) { return "multiple"; } if (fields.children in firstColumn) { return "cascade"; } } return "single"; }); const columnsList = computed(() => { let result = []; switch (columnsType.value) { case "multiple": result = state.formattedColumns; break; case "cascade": result = formatCascade(state.formattedColumns, defaultValues.value ? defaultValues.value : []); break; default: result = [state.formattedColumns]; break; } return result; }); const formatCascade = (columns, defaultValues2) => { const formatted = []; const fields = columnFieldNames.value; let cursor = { text: "", value: "", [fields.children]: columns }; let columnIndex = 0; while (cursor && cursor[fields.children]) { const options = cursor[fields.children]; const value = defaultValues2[columnIndex]; let index = options.findIndex((columnItem) => columnItem[fields.value] === value); if (index === -1) index = 0; cursor = cursor[fields.children][index]; columnIndex++; formatted.push(options); } return formatted; }; const cancel = () => { emit("cancel", { selectedValue: defaultValues.value, selectedOptions: selectedOptions.value }); }; const changeHandler = (columnIndex, option) => { var _a; const fields = columnFieldNames.value; if (option && Object.keys(option).length) { defaultValues.value = defaultValues.value ? defaultValues.value : []; if (columnsType.value === "cascade") { defaultValues.value[columnIndex] = (_a = option[fields.value]) != null ? _a : ""; let index = columnIndex; let cursor = option; while (cursor && cursor[fields.children] && cursor[fields.children][0]) { defaultValues.value[index + 1] = cursor[fields.children][0][fields.value]; index++; cursor = cursor[fields.children][0]; } if (cursor && cursor[fields.children] && cursor[fields.children].length === 0) { defaultValues.value = defaultValues.value.slice(0, index + 1); } } else { defaultValues.value[columnIndex] = Object.prototype.hasOwnProperty.call(option, fields.value) ? option[fields.value] : ""; } emit("change", { columnIndex, selectedValue: defaultValues.value, selectedOptions: selectedOptions.value }); } }; const confirm = () => { const fields = columnFieldNames.value; if (defaultValues.value && !defaultValues.value.length) { columnsList.value.forEach((columns) => { defaultValues.value.push(columns[0][fields.value]); }); } emit("confirm", { selectedValue: defaultValues.value, selectedOptions: selectedOptions.value }); }; const isSameValue = (valA, valB) => JSON.stringify(valA) === JSON.stringify(valB); watch( () => props.modelValue, (newValues) => { if (!isSameValue(newValues, defaultValues.value)) { defaultValues.value = newValues; } }, { deep: true, immediate: true } ); watch( defaultValues, (newValues) => { if (!isSameValue(newValues, props.modelValue)) { emit("update:modelValue", newValues); } }, { deep: true } ); watch( () => props.columns, (val) => { state.formattedColumns = val; } ); return __spreadProps(__spreadValues({}, toRefs(state)), { columnsType, columnsList, columnFieldNames, cancel, changeHandler, confirm, defaultValues, defaultIndexes, pickerColumn, swipeRef, selectedOptions, isSameValue }); }; const { create: create$1 } = createComponent("picker-column"); const _sfc_main$1 = create$1({ props: { // 当前选中项 value: [String, Number], columnsType: String, column: { type: Array, default: () => [] }, // 是否开启3D效果 threeDimensional: { type: Boolean, default: true }, swipeDuration: { type: [Number, String], default: 1e3 }, visibleOptionNum: { type: [Number, String], default: 7 }, optionHeight: { type: [Number, String], default: 36 }, fieldNames: { type: Object, default: () => ({}) }, // 特殊环境判断 taro: { type: Boolean, default: false } }, emits: ["click", "change"], setup(props, { emit }) { const touch = useTouch(); const state = reactive({ touchParams: { startY: 0, endY: 0, startTime: 0, endTime: 0, lastY: 0, lastTime: 0 }, currIndex: 1, transformY: 0, scrollDistance: 0, rotation: 20 }); const roller = ref(null); const moving = ref(false); const touchDeg = ref(0); const touchTime = ref(0); const DEFAULT_DURATION = 200; const INERTIA_TIME = 300; const INERTIA_DISTANCE = 15; const touchRollerStyle = computed(() => { return { transition: `transform ${touchTime.value}ms cubic-bezier(0.17, 0.89, 0.45, 1)`, transform: `rotate3d(1, 0, 0, ${touchDeg.value})`, top: `calc(50% - ${+props.optionHeight / 2}px)` }; }); const touchTileStyle = computed(() => { const { optionHeight } = props; return { transition: `transform ${touchTime.value}ms cubic-bezier(0.17, 0.89, 0.45, 1)`, transform: `translate3d(0, ${state.scrollDistance}px, 0)`, top: `calc(50% - ${+optionHeight / 2}px)`, height: `${optionHeight}px` }; }); const setRollerStyle = (index) => { return `transform: rotate3d(1, 0, 0, ${-state.rotation * index}deg) translate3d(0px, 0px, 104px)`; }; const maskStyles = computed(() => { return { backgroundSize: `100% ${(+props.visibleOptionNum - 1) * +props.optionHeight / 2}px` }; }); const onTouchStart = (event) => { touch.start(event); if (moving.value && !props.taro) { const dom = roller.value; const { transform } = window.getComputedStyle(dom); if (props.threeDimensional) { const circle = Math.floor(parseInt(touchDeg.value) / 360); const cos = +transform.split(", ")[5]; const sin = +transform.split(", ")[6] < 0 ? 180 : 0; const endDeg = circle * 360 + Math.acos(cos) / Math.PI * 180 + sin; state.scrollDistance = -Math.abs((endDeg / state.rotation - 1) * +props.optionHeight); } else { state.scrollDistance = +transform.slice(7, transform.length - 1).split(", ")[5]; } } preventDefault(event, true); state.touchParams.startY = touch.deltaY.value; state.touchParams.startTime = Date.now(); state.transformY = state.scrollDistance; }; const onTouchMove = (event) => { touch.move(event); if (touch.isVertical()) { moving.value = true; preventDefault(event, true); } state.touchParams.lastY = touch.deltaY.value; let move = state.touchParams.lastY - state.touchParams.startY; setMove(move); }; const onTouchEnd = () => { state.touchParams.lastY = touch.deltaY.value; state.touchParams.lastTime = Date.now(); let move = state.touchParams.lastY - state.touchParams.startY; let moveTime = state.touchParams.lastTime - state.touchParams.startTime; if (moveTime <= INERTIA_TIME && Math.abs(move) > INERTIA_DISTANCE) { const distance = momentum(move, moveTime); setMove(distance, "end", +props.swipeDuration); return; } else { setMove(move, "end"); } setTimeout(() => { touch.reset(); moving.value = false; }, 0); }; const momentum = (distance, duration) => { const speed = Math.abs(distance / duration); distance = speed / 3e-3 * (distance < 0 ? -1 : 1); return distance; }; const isHidden = (index) => { if (index >= state.currIndex + 8 || index <= state.currIndex - 8) { return true; } else { return false; } }; const isCurrPick = (index) => { return index == state.currIndex; }; const setTransform = (translateY = 0, type, time = DEFAULT_DURATION, deg) => { if (type === "end") { touchTime.value = time; } else { touchTime.value = 0; } touchDeg.value = deg; state.scrollDistance = translateY; }; const setMove = (move, type, time) => { const { optionHeight } = props; let updateMove = move + state.transformY; if (type === "end") { if (updateMove > 0) { updateMove = 0; } if (updateMove < -(props.column.length - 1) * +optionHeight) { updateMove = -(props.column.length - 1) * +optionHeight; } let endMove = Math.round(updateMove / +optionHeight) * +optionHeight; let deg = `${(Math.abs(Math.round(endMove / +optionHeight)) + 1) * state.rotation}deg`; setTransform(endMove, type, time, deg); state.currIndex = Math.abs(Math.round(endMove / +optionHeight)) + 1; } else { let deg = 0; let currentDeg = (-updateMove / +optionHeight + 1) * state.rotation; const maxDeg = (props.column.length + 1) * state.rotation; const minDeg = 0; deg = clamp(currentDeg, minDeg, maxDeg); if (minDeg < deg && deg < maxDeg) { setTransform(updateMove, null, void 0, deg + "deg"); state.currIndex = Math.abs(Math.round(updateMove / +optionHeight)) + 1; } } }; const setChooseValue = () => { emit("change", props.column[state.currIndex - 1]); }; const modifyStatus = (type) => { const { column } = props; let index = column.findIndex((columnItem) => columnItem[props.fieldNames.value] === props.value); state.currIndex = index === -1 ? 1 : index + 1; let move = index === -1 ? 0 : index * +props.optionHeight; type && setChooseValue(); setMove(-move); }; const stopMomentum = () => { moving.value = false; touchTime.value = 0; setChooseValue(); }; watch( () => props.column, () => { if (props.column && props.column.length > 0) { state.transformY = 0; modifyStatus(false); } }, { deep: true } ); watch( () => props.value, () => { state.transformY = 0; modifyStatus(false); }, { deep: true } ); onMounted(() => { modifyStatus(true); }); return __spreadProps(__spreadValues(__spreadValues({}, toRefs(state)), toRefs(props)), { setRollerStyle, isHidden, isCurrPick, roller, onTouchStart, onTouchMove, onTouchEnd, touchRollerStyle, touchTileStyle, setMove, stopMomentum, pxCheck, maskStyles }); } }); function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) { return openBlock(), createElementBlock("view", { class: "nut-picker__list", onTouchstart: _cache[1] || (_cache[1] = (...args) => _ctx.onTouchStart && _ctx.onTouchStart(...args)), onTouchmove: _cache[2] || (_cache[2] = (...args) => _ctx.onTouchMove && _ctx.onTouchMove(...args)), onTouchend: _cache[3] || (_cache[3] = (...args) => _ctx.onTouchEnd && _ctx.onTouchEnd(...args)) }, [ createElementVNode("view", { ref: "roller", class: "nut-picker-roller", style: normalizeStyle(_ctx.threeDimensional ? _ctx.touchRollerStyle : _ctx.touchTileStyle), onTransitionend: _cache[0] || (_cache[0] = (...args) => _ctx.stopMomentum && _ctx.stopMomentum(...args)) }, [ (openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.column, (item, index) => { var _a; return openBlock(), createElementBlock(Fragment, { key: (_a = item[_ctx.fieldNames.value]) != null ? _a : index }, [ item && item[_ctx.fieldNames.text] && _ctx.threeDimensional ? (openBlock(), createElementBlock("view", { key: 0, class: normalizeClass(["nut-picker-roller-item", { "nut-picker-roller-item-hidden": _ctx.isHidden(index + 1), [item[_ctx.fieldNames.className]]: item[_ctx.fieldNames.className] }]), style: normalizeStyle(_ctx.setRollerStyle(index + 1)) }, toDisplayString(item[_ctx.fieldNames.text]), 7)) : createCommentVNode("", true), _cache[4] || (_cache[4] = createTextVNode()), item && item[_ctx.fieldNames.text] && !_ctx.threeDimensional ? (openBlock(), createElementBlock("view", { key: 1, class: normalizeClass(["nut-picker-roller-item-tile", { [item[_ctx.fieldNames.className]]: item[_ctx.fieldNames.className], "nut-picker-roller-item-selected": _ctx.isCurrPick(index + 1) }]), style: normalizeStyle({ height: _ctx.pxCheck(_ctx.optionHeight), lineHeight: _ctx.pxCheck(_ctx.optionHeight) }) }, toDisplayString(item[_ctx.fieldNames.text]), 7)) : createCommentVNode("", true) ], 64); }), 128)) ], 36), _cache[5] || (_cache[5] = createTextVNode()), createElementVNode("view", { class: "nut-picker-roller-mask", style: normalizeStyle(_ctx.maskStyles) }, null, 4) ], 32); } const NutPickerColumn = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["render", _sfc_render$1]]); const baseProps = { modelValue: { type: Array, default: () => [] }, title: { type: String, default: "" }, cancelText: { type: String, default: "" }, okText: { type: String, default: "" }, columns: { type: Array, default: () => { return []; } }, threeDimensional: { type: Boolean, default: false }, swipeDuration: { type: [Number, String], default: 1e3 }, showToolbar: { type: Boolean, default: true }, visibleOptionNum: { type: [Number, String], default: 7 }, optionHeight: { type: [Number, String], default: 36 }, fieldNames: { type: Object, default: () => ({}) } }; const { create } = createComponent("picker"); const cN = "NutPicker"; const _sfc_main = create({ components: { NutPickerColumn }, props: baseProps, emits: ["cancel", "change", "confirm", "update:modelValue"], setup(props, { emit }) { const translate = useLocale(cN); const { changeHandler, confirm, defaultValues, defaultIndexes, columnsList, columnsType, columnFieldNames, cancel } = usePicker(props, emit); const state = reactive({ show: false, picking: false, ENV: Taro.getEnv(), ENV_TYPE: Taro.ENV_TYPE }); const pickerColumn = ref([]); const swipeRef = (el) => { if (el && pickerColumn.value.length < columnsList.value.length) { pickerColumn.value.push(el); } }; const confirmHandler = () => { if (Taro.getEnv() === Taro.ENV_TYPE.WEB) { pickerColumn.value.length > 0 && pickerColumn.value.forEach((column) => { column.stopMomentum(); }); confirm(); } else { if (state.picking) { setTimeout(() => { confirm(); }, 0); } else { confirm(); } } }; const pickerViewStyles = computed(() => { const styles = {}; styles.height = `${+props.visibleOptionNum * +props.optionHeight}px`; styles["--lineHeight"] = `${+props.optionHeight}px`; return styles; }); const tileChange = (data) => { var _a, _b; const prevDefaultValue = defaultIndexes.value; let changeIndex = 0; for (let i = 0; i < ((_a = data.detail.value) == null ? void 0 : _a.length); i++) { if (prevDefaultValue[i] !== ((_b = data.detail.value) == null ? void 0 : _b[i])) { changeIndex = i; break; } } changeHandler(changeIndex, columnsList.value[changeIndex][data.detail.value[changeIndex]]); }; const handlePickstart = () => { state.picking = true; }; const handlePickend = () => { state.picking = false; }; return __spreadProps(__spreadValues({}, toRefs(state)), { columnsType, columnsList, columnFieldNames, cancel, changeHandler, confirmHandler, defaultValues, pickerColumn, swipeRef, defaultIndexes, tileChange, handlePickstart, translate, handlePickend, pickerViewStyles, pxCheck }); } }); const _hoisted_1 = { class: "nut-picker" }; const _hoisted_2 = { key: 0, class: "nut-picker__bar" }; const _hoisted_3 = { class: "nut-picker__title" }; const _hoisted_4 = ["indicator-style", "value"]; const _hoisted_5 = ["filed-names"]; function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { const _component_nut_picker_column = resolveComponent("nut-picker-column"); return openBlock(), createElementBlock("view", _hoisted_1, [ _ctx.showToolbar ? (openBlock(), createElementBlock("view", _hoisted_2, [ createElementVNode("view", { class: "nut-picker__cancel nut-picker__left nut-picker__button", onClick: _cache[0] || (_cache[0] = (...args) => _ctx.cancel && _ctx.cancel(...args)) }, toDisplayString(_ctx.cancelText || _ctx.translate("cancel")), 1), _cache[5] || (_cache[5] = createTextVNode()), createElementVNode("view", _hoisted_3, toDisplayString(_ctx.title), 1), _cache[6] || (_cache[6] = createTextVNode()), createElementVNode("view", { class: "nut-picker__confirm nut-picker__right nut-picker__button", onClick: _cache[1] || (_cache[1] = (...args) => _ctx.confirmHandler && _ctx.confirmHandler(...args)) }, toDisplayString(_ctx.okText || _ctx.translate("confirm")), 1) ])) : createCommentVNode("", true), _cache[7] || (_cache[7] = createTextVNode()), renderSlot(_ctx.$slots, "top"), _cache[8] || (_cache[8] = createTextVNode()), _ctx.ENV != _ctx.ENV_TYPE.WEB ? (openBlock(), createElementBlock("picker-view", mergeProps({ key: 1, "indicator-style": `height:${_ctx.optionHeight}px`, value: _ctx.defaultIndexes, style: _ctx.pickerViewStyles }, _ctx.$attrs, { "immediate-change": true, onChange: _cache[2] || (_cache[2] = (...args) => _ctx.tileChange && _ctx.tileChange(...args)), onPickstart: _cache[3] || (_cache[3] = (...args) => _ctx.handlePickstart && _ctx.handlePickstart(...args)), onPickend: _cache[4] || (_cache[4] = (...args) => _ctx.handlePickend && _ctx.handlePickend(...args)) }), [ (openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.columnsList, (column, columnIndex) => { return openBlock(), createElementBlock("picker-view-column", { key: columnIndex, "filed-names": _ctx.columnFieldNames }, [ (openBlock(true), createElementBlock(Fragment, null, renderList(column, (item, index) => { var _a; return openBlock(), createElementBlock("view", { key: (_a = item[_ctx.columnFieldNames.value]) != null ? _a : index, class: normalizeClass(["nut-picker-roller-item-tarotile", { [item[_ctx.columnFieldNames.className]]: item[_ctx.columnFieldNames.className] }]), style: normalizeStyle({ lineHeight: _ctx.pxCheck(_ctx.optionHeight) }) }, toDisplayString(item[_ctx.columnFieldNames.text]), 7); }), 128)) ], 8, _hoisted_5); }), 128)) ], 16, _hoisted_4)) : (openBlock(), createElementBlock("view", { key: 2, class: "nut-picker__column", style: normalizeStyle(_ctx.pickerViewStyles) }, [ (openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.columnsList, (column, columnIndex) => { return openBlock(), createElementBlock("view", { key: columnIndex, class: "nut-picker__columnitem" }, [ createVNode(_component_nut_picker_column, { ref_for: true, ref: _ctx.swipeRef, column, "columns-type": _ctx.columnsType, "field-names": _ctx.columnFieldNames, value: _ctx.defaultValues[columnIndex], "three-dimensional": false, "swipe-duration": _ctx.swipeDuration, "visible-option-num": _ctx.visibleOptionNum, "option-height": _ctx.optionHeight, taro: "", onChange: (option) => { _ctx.changeHandler(columnIndex, option); } }, null, 8, ["column", "columns-type", "field-names", "value", "swipe-duration", "visible-option-num", "option-height", "onChange"]) ]); }), 128)) ], 4)), _cache[9] || (_cache[9] = createTextVNode()), renderSlot(_ctx.$slots, "default") ]); } const NutPicker = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]); export { NutPicker as default };