@icreate/ics-mui
Version:
京东风格的轻量级移动端 Vue2、Vue3 组件库(支持小程序开发)
335 lines (334 loc) • 11.8 kB
JavaScript
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 { reactive, ref, computed, watch, onMounted, toRefs, openBlock, createElementBlock, createElementVNode, normalizeStyle, Fragment, renderList, normalizeClass, toDisplayString, createCommentVNode } from "vue";
import { c as createComponent } from "./component-Dt_P47FR.js";
import { d as preventDefault, e as clamp } from "./util-Eu153hxh.js";
import { p as pxCheck } from "./pxCheck-DN6FYV6q.js";
import { u as useTouch } from "./index-I8tfW3Kf.js";
import { _ as _export_sfc } from "./_plugin-vue_export-helper-1tPrXgE0.js";
const { create } = createComponent("picker-column");
const _sfc_main = create({
props: {
direction: {
type: String,
default: "horizontal"
// vertical旋转90deg方向
},
// 当前选中项
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: {
startX: 0,
startY: 0,
endY: 0,
endX: 0,
startTime: 0,
endTime: 0,
lastX: 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.startX = touch.deltaX.value;
state.touchParams.startTime = Date.now();
state.transformY = state.scrollDistance;
};
const onTouchMove = (event) => {
touch.move(event);
if (touch.isVertical()) {
console.log("touch is vertical");
moving.value = true;
preventDefault(event, true);
}
state.touchParams.lastY = touch.deltaY.value;
state.touchParams.lastX = touch.deltaX.value;
let move = 0;
if (props.direction === "horizontal") {
move = state.touchParams.lastY - state.touchParams.startY;
}
if (props.direction === "vertical") {
move = state.touchParams.startX - state.touchParams.lastX;
}
setMove(move);
};
const onTouchEnd = () => {
state.touchParams.lastY = touch.deltaY.value;
state.touchParams.lastX = touch.deltaX.value;
state.touchParams.lastTime = Date.now();
let move = 0;
if (props.direction === "horizontal") {
move = state.touchParams.lastY - state.touchParams.startY;
}
if (props.direction === "vertical") {
move = state.touchParams.startX - state.touchParams.lastX;
}
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 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 = () => {
if (!moving.value && !touchTime.value)
return;
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,
immediate: true
}
);
onMounted(() => {
modifyStatus(true);
});
return __spreadProps(__spreadValues(__spreadValues({}, toRefs(state)), toRefs(props)), {
setRollerStyle,
isHidden,
roller,
onTouchStart,
onTouchMove,
onTouchEnd,
touchRollerStyle,
touchTileStyle,
setMove,
stopMomentum,
pxCheck,
maskStyles
});
}
});
function _sfc_render(_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),
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]
}]),
style: normalizeStyle({ height: _ctx.pxCheck(_ctx.optionHeight), lineHeight: _ctx.pxCheck(_ctx.optionHeight) })
}, toDisplayString(item[_ctx.fieldNames.text]), 7)) : createCommentVNode("", true)
], 64);
}), 128))
], 36),
createElementVNode("view", {
class: "nut-picker-roller-mask",
style: normalizeStyle(_ctx.maskStyles)
}, null, 4)
], 32);
}
const IcsPickerColumn = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]);
export {
IcsPickerColumn as I
};