@gyenno/nutui-taro
Version:
京东风格的轻量级移动端 Vue2、Vue3 组件库(支持小程序开发)
718 lines (717 loc) • 24.4 kB
JavaScript
import { defineComponent, computed, openBlock, createElementBlock, normalizeClass, unref, normalizeStyle, createElementVNode, ref, toRefs, toDisplayString, createCommentVNode, createTextVNode, withModifiers, Fragment, renderList, renderSlot, reactive, onMounted, watch, provide, resolveComponent, createVNode, withCtx, createBlock } from "vue";
import { c as createComponent, i as isArray } from "./component-25dcca32.js";
import "./style_icon-468bee1d.js";
import { u as useTouch } from "./index-7a7385e4.js";
import { u as useRect } from "./index-29892cda.js";
import { _ as _export_sfc } from "./_plugin-vue_export-helper-cc2b3d55.js";
import "../locale/lang";
const g = ["aria-labelledby"], y = /* @__PURE__ */ createElementVNode("path", {
d: "M1024 657.723H905.846v-126.03c0-228.431-177.23-413.54-393.846-413.54s-393.846 185.109-393.846 413.54v126.03H0v-126.03C0 236.307 228.43 0 512 0s512 236.308 512 531.692v126.031zM196.923 866.462C86.646 866.462 0 779.815 0 669.538s86.646-196.923 196.923-196.923 196.923 86.647 196.923 196.923S307.2 866.462 196.923 866.462zm0-275.693c-43.323 0-78.77 35.446-78.77 78.77s35.447 78.769 78.77 78.769 78.77-35.446 78.77-78.77-35.447-78.769-78.77-78.769zm630.154 275.693c-110.277 0-196.923-86.647-196.923-196.924S716.8 472.615 827.077 472.615 1024 559.262 1024 669.538s-86.646 196.924-196.923 196.924zm0-275.693c-43.323 0-78.77 35.446-78.77 78.77s35.447 78.769 78.77 78.769 78.77-35.446 78.77-78.77-35.447-78.769-78.77-78.769zm-149.662 429.293c-23.63 0-47.261-15.754-55.138-43.324-7.877-31.507 7.877-63.015 39.385-74.83 102.4-31.508 189.046-102.4 236.307-196.923 15.754-27.57 51.2-39.385 78.77-23.631s39.384 51.2 23.63 78.77c-63.015 122.091-177.23 216.614-307.2 256-3.938 3.938-11.815 3.938-15.754 3.938z",
fill: "currentColor",
"fill-opacity": "0.9"
}, null, -1), S = [
y
], z = /* @__PURE__ */ defineComponent({
__name: "Service",
props: {
class: { type: String, default: "" },
name: { type: String, default: "" },
color: { type: String, default: "" },
width: { type: [String, Number], default: "" },
height: { type: [String, Number], default: "" }
},
emits: ["click"],
setup(s, { emit: o }) {
const t = s, l = (e) => {
o("click", e);
}, n = (e) => {
if (e)
return isNaN(Number(e)) ? String(e) : e + "px";
}, i = computed(() => {
const e = "nut-icon";
return {
[t.class]: t.class,
[e]: true,
[e + "-" + t.name]: t.name
};
}), a = computed(() => {
const e = {};
return e.height = n(t.height), e.width = n(t.width), e.color = t.color, e;
});
return (e, _) => (openBlock(), createElementBlock("svg", {
class: normalizeClass(unref(i)),
style: normalizeStyle(unref(a)),
onClick: l,
xmlns: "http://www.w3.org/2000/svg",
viewBox: "0 0 1024 1024",
"aria-labelledby": s.name,
role: "presentation"
}, S, 14, g));
}
});
const { componentName: componentName$1, create: create$1 } = createComponent("range");
const _sfc_main$1 = create$1({
props: {
range: {
type: Boolean,
default: false
},
disabled: Boolean,
activeColor: String,
inactiveColor: String,
buttonColor: String,
vertical: {
type: Boolean,
default: false
},
marks: {
type: Object,
default: {}
},
hiddenRange: {
type: Boolean,
default: false
},
hiddenTag: {
type: Boolean,
default: false
},
min: {
type: [Number, String],
default: 0
},
max: {
type: [Number, String],
default: 100
},
step: {
type: [Number, String],
default: 1
},
modelValue: {
type: [Number, Array],
default: 0
}
},
emits: ["change", "drag-end", "drag-start", "update:modelValue"],
setup(props, { emit }) {
const buttonIndex = ref(0);
let startValue;
let currentValue;
const root = ref();
const dragStatus = ref();
const touch = useTouch();
const marksList = computed(() => {
const { marks, max, min } = props;
const marksKeys = Object.keys(marks);
const list = marksKeys.map(parseFloat).sort((a, b) => a - b).filter((point) => point >= min && point <= max);
return list;
});
const scope = computed(() => Number(props.max) - Number(props.min));
const classes = computed(() => {
const prefixCls = componentName$1;
return {
[prefixCls]: true,
[`${prefixCls}-disabled`]: props.disabled,
[`${prefixCls}-vertical`]: props.vertical,
[`${prefixCls}-show-number`]: !props.hiddenRange
};
});
const containerClasses = computed(() => {
const prefixCls = "nut-range-container";
return {
[prefixCls]: true,
[`${prefixCls}-vertical`]: props.vertical
};
});
const wrapperStyle = computed(() => {
return {
background: props.inactiveColor
};
});
const buttonStyle = computed(() => {
return {
borderColor: props.buttonColor
};
});
const isRange = (val) => !!props.range && Array.isArray(val);
const calcMainAxis = () => {
const { modelValue, min } = props;
if (isRange(modelValue)) {
return `${(modelValue[1] - modelValue[0]) * 100 / scope.value}%`;
}
return `${(modelValue - Number(min)) * 100 / scope.value}%`;
};
const calcOffset = () => {
const { modelValue, min } = props;
if (isRange(modelValue)) {
return `${(modelValue[0] - Number(min)) * 100 / scope.value}%`;
}
return `0%`;
};
const barStyle = computed(() => {
if (props.vertical) {
return {
height: calcMainAxis(),
top: calcOffset(),
background: props.activeColor,
transition: dragStatus.value ? "none" : void 0
};
} else {
return {
width: calcMainAxis(),
left: calcOffset(),
background: props.activeColor,
transition: dragStatus.value ? "none" : void 0
};
}
});
const markClassName = (mark) => {
const classPrefix = "nut-range-mark";
const { modelValue, max, min } = props;
let lowerBound = Number(min);
let upperBound = Number(max);
if (props.range) {
const [left, right] = modelValue;
lowerBound = left;
upperBound = right;
} else {
upperBound = modelValue;
}
let isActive = mark <= upperBound && mark >= lowerBound;
return {
[`${classPrefix}-text`]: true,
[`${classPrefix}-text-active`]: isActive
};
};
const marksStyle = (mark) => {
const { min, vertical } = props;
let style = {
left: `${(mark - Number(min)) / scope.value * 100}%`
};
if (vertical) {
style = {
top: `${(mark - Number(min)) / scope.value * 100}%`
};
}
return style;
};
const tickStyle = (mark) => {
const { modelValue, max, min } = props;
let lowerBound = Number(min);
let upperBound = Number(max);
if (props.range) {
const [left, right] = modelValue;
lowerBound = left;
upperBound = right;
}
let isActive = mark <= upperBound && mark >= lowerBound;
let style = {
background: !isActive ? props.inactiveColor : props.activeColor
};
return style;
};
const format = (value) => {
const { min, max, step } = props;
value = Math.max(+min, Math.min(value, +max));
return Math.round(value / +step) * +step;
};
const isSameValue = (newValue, oldValue) => JSON.stringify(newValue) === JSON.stringify(oldValue);
const handleOverlap = (value) => {
if (value[0] > value[1]) {
return value.slice(0).reverse();
}
return value;
};
const updateValue = (value, end) => {
if (isRange(value)) {
value = handleOverlap(value).map(format);
} else {
value = format(value);
}
if (!isSameValue(value, props.modelValue)) {
emit("update:modelValue", value);
}
if (end && !isSameValue(value, startValue)) {
emit("change", value);
}
};
const onClick = (event) => {
if (props.disabled) {
return;
}
const { min, modelValue } = props;
const rect = useRect(root);
let delta = event.clientX - rect.left;
let total = rect.width;
if (props.vertical) {
delta = event.clientY - rect.top;
total = rect.height;
}
const value = Number(min) + delta / total * scope.value;
if (isRange(modelValue)) {
const [left, right] = modelValue;
const middle = (left + right) / 2;
if (value <= middle) {
updateValue([value, right], true);
} else {
updateValue([left, value], true);
}
} else {
updateValue(value, true);
}
};
const onTouchStart = (event) => {
if (props.disabled) {
return;
}
touch.start(event);
currentValue = props.modelValue;
if (isRange(currentValue)) {
startValue = currentValue.map(format);
} else {
startValue = format(currentValue);
}
dragStatus.value = "start";
};
const onTouchMove = (event) => {
if (props.disabled) {
return;
}
if (dragStatus.value === "start") {
emit("drag-start");
}
touch.move(event);
dragStatus.value = "draging";
const rect = useRect(root);
let delta = touch.deltaX.value;
let total = rect.width;
let diff = delta / total * scope.value;
if (props.vertical) {
delta = touch.deltaY.value;
total = rect.height;
diff = delta / total * scope.value;
}
if (isRange(startValue)) {
currentValue[buttonIndex.value] = startValue[buttonIndex.value] + diff;
} else {
currentValue = startValue + diff;
}
updateValue(currentValue);
event.stopPropagation();
event.preventDefault();
};
const onTouchEnd = () => {
if (props.disabled) {
return;
}
if (dragStatus.value === "draging") {
updateValue(currentValue, true);
emit("drag-end");
}
dragStatus.value = "";
};
const curValue = (idx) => {
const value = isArray(props.modelValue) && typeof idx === "number" ? props.modelValue[idx] : Number(props.modelValue);
return value;
};
return {
root,
classes,
wrapperStyle,
buttonStyle,
onClick,
onTouchStart,
onTouchMove,
onTouchEnd,
...toRefs(props),
barStyle,
curValue,
buttonIndex,
containerClasses,
markClassName,
marksStyle,
marksList,
tickStyle
};
}
});
const _hoisted_1$1 = {
key: 0,
class: "nut-range-min"
};
const _hoisted_2$1 = {
key: 0,
class: "nut-range-mark"
};
const _hoisted_3$1 = ["tabindex", "aria-valuemin", "aria-valuenow", "aria-valuemax", "onTouchstart"];
const _hoisted_4$1 = {
key: 0,
class: "number"
};
const _hoisted_5$1 = ["tabindex", "aria-valuemin", "aria-valuenow", "aria-valuemax"];
const _hoisted_6$1 = {
key: 0,
class: "number"
};
const _hoisted_7$1 = {
key: 1,
class: "nut-range-max"
};
function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) {
return openBlock(), createElementBlock("view", {
class: normalizeClass(_ctx.containerClasses)
}, [
!_ctx.hiddenRange ? (openBlock(), createElementBlock("view", _hoisted_1$1, toDisplayString(+_ctx.min), 1)) : createCommentVNode("", true),
createTextVNode(),
createElementVNode("view", {
ref: "root",
style: normalizeStyle(_ctx.wrapperStyle),
class: normalizeClass(_ctx.classes),
onClick: _cache[9] || (_cache[9] = withModifiers((...args) => _ctx.onClick && _ctx.onClick(...args), ["stop"]))
}, [
_ctx.marksList.length > 0 ? (openBlock(), createElementBlock("view", _hoisted_2$1, [
(openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.marksList, (marks) => {
return openBlock(), createElementBlock("span", {
key: marks,
class: normalizeClass(_ctx.markClassName(marks)),
style: normalizeStyle(_ctx.marksStyle(marks))
}, [
createTextVNode(toDisplayString(marks) + " ", 1),
createElementVNode("span", {
class: "nut-range-tick",
style: normalizeStyle(_ctx.tickStyle(marks))
}, null, 4)
], 6);
}), 128))
])) : createCommentVNode("", true),
createTextVNode(),
createElementVNode("view", {
class: "nut-range-bar",
style: normalizeStyle(_ctx.barStyle)
}, [
_ctx.range ? (openBlock(), createElementBlock(Fragment, { key: 0 }, renderList([0, 1], (index2) => {
return createElementVNode("view", {
key: index2,
role: "slider",
class: normalizeClass({
"nut-range-button-wrapper-left": index2 == 0,
"nut-range-button-wrapper-right": index2 == 1
}),
tabindex: _ctx.disabled ? -1 : 0,
"aria-valuemin": +_ctx.min,
"aria-valuenow": _ctx.curValue(index2),
"aria-valuemax": +_ctx.max,
"aria-orientation": "horizontal",
onTouchstart: withModifiers(
(e) => {
if (typeof index2 === "number") {
_ctx.buttonIndex = index2;
}
_ctx.onTouchStart(e);
},
["stop", "prevent"]
),
onTouchmove: _cache[0] || (_cache[0] = withModifiers((...args) => _ctx.onTouchMove && _ctx.onTouchMove(...args), ["stop", "prevent"])),
onTouchend: _cache[1] || (_cache[1] = withModifiers((...args) => _ctx.onTouchEnd && _ctx.onTouchEnd(...args), ["stop", "prevent"])),
onTouchcancel: _cache[2] || (_cache[2] = withModifiers((...args) => _ctx.onTouchEnd && _ctx.onTouchEnd(...args), ["stop", "prevent"])),
onClick: _cache[3] || (_cache[3] = (e) => e.stopPropagation())
}, [
_ctx.$slots.button ? renderSlot(_ctx.$slots, "button", { key: 0 }) : (openBlock(), createElementBlock("view", {
key: 1,
class: "nut-range-button",
style: normalizeStyle(_ctx.buttonStyle)
}, [
!_ctx.hiddenTag ? (openBlock(), createElementBlock("view", _hoisted_4$1, toDisplayString(_ctx.curValue(index2)), 1)) : createCommentVNode("", true)
], 4))
], 42, _hoisted_3$1);
}), 64)) : (openBlock(), createElementBlock("view", {
key: 1,
role: "slider",
class: "nut-range-button-wrapper",
tabindex: _ctx.disabled ? -1 : 0,
"aria-valuemin": +_ctx.min,
"aria-valuenow": _ctx.curValue(),
"aria-valuemax": +_ctx.max,
"aria-orientation": "horizontal",
onTouchstart: _cache[4] || (_cache[4] = withModifiers(
(e) => {
_ctx.onTouchStart(e);
},
["stop", "prevent"]
)),
onTouchmove: _cache[5] || (_cache[5] = withModifiers((...args) => _ctx.onTouchMove && _ctx.onTouchMove(...args), ["stop", "prevent"])),
onTouchend: _cache[6] || (_cache[6] = withModifiers((...args) => _ctx.onTouchEnd && _ctx.onTouchEnd(...args), ["stop", "prevent"])),
onTouchcancel: _cache[7] || (_cache[7] = withModifiers((...args) => _ctx.onTouchEnd && _ctx.onTouchEnd(...args), ["stop", "prevent"])),
onClick: _cache[8] || (_cache[8] = (e) => e.stopPropagation())
}, [
_ctx.$slots.button ? renderSlot(_ctx.$slots, "button", { key: 0 }) : (openBlock(), createElementBlock("view", {
key: 1,
class: "nut-range-button",
style: normalizeStyle(_ctx.buttonStyle)
}, [
!_ctx.hiddenTag ? (openBlock(), createElementBlock("view", _hoisted_6$1, toDisplayString(_ctx.curValue()), 1)) : createCommentVNode("", true)
], 4))
], 40, _hoisted_5$1))
], 4)
], 6),
createTextVNode(),
!_ctx.hiddenRange ? (openBlock(), createElementBlock("view", _hoisted_7$1, toDisplayString(+_ctx.max), 1)) : createCommentVNode("", true)
], 2);
}
const Range = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["render", _sfc_render$1]]);
const { componentName, create } = createComponent("audio");
const _sfc_main = create({
props: {
url: {
type: String,
default: ""
},
// 静音
muted: {
type: Boolean,
default: false
},
// 自动播放
autoplay: {
type: Boolean,
default: false
},
// 循环播放
loop: {
type: Boolean,
default: false
},
// 是否预加载音频
preload: {
type: String,
default: "auto"
},
/* 总时长秒数 */
second: {
type: Number,
default: 0
},
// 展示的形式 controls 控制面板 progress 进度条 icon 图标 none 自定义
type: {
type: String,
default: "progress"
}
},
components: {
Service: z,
[Range.name]: Range
},
emits: ["fastBack", "play", "forward", "ended", "changeProgress", "mute", "can-play"],
setup(props, { emit, slots }) {
const audioRef = ref(null);
const audioData = reactive({
currentTime: 0,
currentDuration: "00:00:00",
percent: 0,
duration: "00:00:00",
second: 0,
hanMuted: props.muted,
playing: props.autoplay,
handPlaying: false
});
onMounted(() => {
var arr = ["webkitVisibilityState", "visibilitychange"];
try {
for (let i = 0; i < arr.length; i++) {
document.addEventListener(arr[i], () => {
if (document.hidden) {
audioRef.value.pause();
} else {
if (audioData.playing) {
setTimeout(() => {
audioRef.value.play();
}, 200);
}
}
});
}
} catch (e) {
console.log(e.message);
}
});
const onCanplay = (e) => {
const audioR = audioRef.value;
if (props.autoplay) {
if (audioR && audioR.paused) {
audioR.play();
}
}
audioData.second = audioR.duration;
audioData.duration = formatSeconds(audioR.duration);
emit("can-play", e);
};
const onTimeupdate = (e) => {
audioData.currentTime = parseInt(e.target.currentTime);
};
const fastBack = () => {
if (audioData.currentTime > 0) {
audioData.currentTime--;
}
audioRef.value.currentTime = audioData.currentTime;
emit("fastBack", audioData.currentTime);
};
const changeStatus = () => {
const audioR = audioRef.value;
if (audioData.playing) {
audioR.pause();
audioData.handPlaying = false;
} else {
audioR.play();
audioData.handPlaying = true;
}
audioData.playing = !audioData.playing;
emit("play", audioData.playing);
};
const forward = () => {
audioData.currentTime++;
audioRef.value.currentTime = audioData.currentTime;
emit("forward", audioData.currentTime);
};
const handle = (val) => {
audioData.currentDuration = formatSeconds(val);
audioData.percent = val / audioData.second * 100;
};
const audioEnd = () => {
audioData.playing = false;
emit("ended");
};
const progressChange = (val) => {
const ar = audioRef.value;
ar.currentTime = audioData.second * val / 100;
emit("changeProgress", ar.currentTime);
};
const handleMute = () => {
audioData.hanMuted = !audioData.hanMuted;
emit("mute", audioData.hanMuted);
};
const formatSeconds = (value) => {
if (!value) {
return "00:00:00";
}
let time = parseInt(value);
let hours = Math.floor(time / 3600);
let minutes = Math.floor((time - hours * 3600) / 60);
let seconds = time - hours * 3600 - minutes * 60;
let result = "";
result += ("0" + hours.toString()).slice(-2) + ":";
result += ("0" + minutes.toString()).slice(-2) + ":";
result += ("0" + seconds.toString()).slice(-2);
return result;
};
watch(
() => audioData.currentTime,
(value) => {
handle(value);
}
);
provide("audioParent", {
children: [],
props,
audioData,
handleMute,
forward,
fastBack,
changeStatus
});
return {
...toRefs(props),
...toRefs(audioData),
audioRef,
fastBack,
forward,
changeStatus,
progressChange,
audioEnd,
onTimeupdate,
handleMute,
onCanplay,
slots
};
}
});
const _hoisted_1 = { class: "nut-audio" };
const _hoisted_2 = {
key: 0,
class: "nut-audio__progress"
};
const _hoisted_3 = { class: "nut-audio__time" };
const _hoisted_4 = { class: "nut-audio__bar" };
const _hoisted_5 = /* @__PURE__ */ createElementVNode("div", { class: "nut-audio__button--custom" }, null, -1);
const _hoisted_6 = { class: "nut-audio__time" };
const _hoisted_7 = {
key: 1,
class: "nut-audio__icon"
};
const _hoisted_8 = ["controls", "src", "preload", "autoplay", "loop", "muted"];
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
const _component_nut_range = resolveComponent("nut-range");
const _component_Service = resolveComponent("Service");
return openBlock(), createElementBlock("div", _hoisted_1, [
_ctx.type == "progress" ? (openBlock(), createElementBlock("div", _hoisted_2, [
createElementVNode("div", _hoisted_3, toDisplayString(_ctx.currentDuration), 1),
createTextVNode(),
createElementVNode("div", _hoisted_4, [
createVNode(_component_nut_range, {
modelValue: _ctx.percent,
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => _ctx.percent = $event),
"hidden-range": "",
onChange: _ctx.progressChange,
"inactive-color": "#cccccc",
"active-color": "#fa2c19"
}, {
button: withCtx(() => [
_hoisted_5
]),
_: 1
}, 8, ["modelValue", "onChange"])
]),
createTextVNode(),
createElementVNode("div", _hoisted_6, toDisplayString(_ctx.duration), 1)
])) : createCommentVNode("", true),
createTextVNode(),
_ctx.type == "icon" ? (openBlock(), createElementBlock("div", _hoisted_7, [
createElementVNode("div", {
class: normalizeClass(["nut-audio__icon--box", _ctx.playing ? "nut-audio__icon--play" : "nut-audio__icon--stop"]),
onClick: _cache[1] || (_cache[1] = (...args) => _ctx.changeStatus && _ctx.changeStatus(...args))
}, [
_ctx.playing ? (openBlock(), createBlock(_component_Service, {
key: 0,
class: "nut-icon-am-rotate nut-icon-am-infinite"
})) : (openBlock(), createBlock(_component_Service, { key: 1 }))
], 2)
])) : createCommentVNode("", true),
createTextVNode(),
_ctx.type == "none" ? (openBlock(), createElementBlock("div", {
key: 2,
onClick: _cache[2] || (_cache[2] = (...args) => _ctx.changeStatus && _ctx.changeStatus(...args))
}, [
renderSlot(_ctx.$slots, "default")
])) : createCommentVNode("", true),
createTextVNode(),
_ctx.type != "none" ? renderSlot(_ctx.$slots, "default", { key: 3 }) : createCommentVNode("", true),
createTextVNode(),
createElementVNode("audio", {
class: "audioMain",
controls: _ctx.type == "controls",
ref: "audioRef",
src: _ctx.url,
preload: _ctx.preload,
autoplay: _ctx.autoplay,
loop: _ctx.loop,
onTimeupdate: _cache[3] || (_cache[3] = (...args) => _ctx.onTimeupdate && _ctx.onTimeupdate(...args)),
onCanplay: _cache[4] || (_cache[4] = (...args) => _ctx.onCanplay && _ctx.onCanplay(...args)),
onEnded: _cache[5] || (_cache[5] = (...args) => _ctx.audioEnd && _ctx.audioEnd(...args)),
muted: _ctx.hanMuted
}, null, 40, _hoisted_8)
]);
}
const index = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]);
export {
index as default
};