UNPKG

@gyenno/nutui-taro

Version:

京东风格的轻量级移动端 Vue2、Vue3 组件库(支持小程序开发)

718 lines (717 loc) 24.4 kB
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 };