提交 67f68d9e 编写于 作者: Q qiang

refactor: picker-view, picker-view-column

上级 7bbac70f
......@@ -12,8 +12,8 @@ import Label from './label/index'
import MovableArea from './movable-area/index'
import MovableView from './movable-view/index'
import Navigator from './navigator/index.vue'
// import PickerView from './picker-view/index.vue'
// import PickerViewColumn from './picker-view-column/index.vue'
import PickerView from './picker-view/index'
import PickerViewColumn from './picker-view-column/index'
import Progress from './progress/index'
import Radio from './radio/index'
import RadioGroup from './radio-group/index'
......@@ -42,8 +42,8 @@ export {
MovableArea,
MovableView,
Navigator,
// PickerView,
// PickerViewColumn,
PickerView,
PickerViewColumn,
Progress,
Radio,
RadioGroup,
......
import {
defineComponent,
Ref,
ref,
watch,
onMounted,
computed,
reactive,
inject,
getCurrentInstance,
ComponentInternalInstance,
nextTick,
} from 'vue'
import { useScroller } from '../../helpers/scroller'
import { Friction } from '../../helpers/scroller/Friction'
import { Spring } from '../../helpers/scroller/Spring'
import { Scroller } from '../../helpers/scroller/Scroller'
import { initScrollBounce, disableScrollBounce } from '../../helpers/scroll'
import { useTouchtrack } from '../../helpers/useTouchtrack'
import { useScopedAttrs } from '../../helpers/useScopedAttrs'
import { flatVNode } from '../../helpers/flatVNode'
import ResizeSensor from '../resize-sensor/index'
import {
GetPickerViewColumn,
GetPickerViewProps,
GetPickerViewState,
} from '../picker-view'
let scopedIndex = 0
function useScopedClass(indicatorHeightRef: Ref<number>) {
const className = `uni-picker-view-content-${scopedIndex++}`
function updateStyle() {
const style = document.createElement('style')
style.innerText = `.uni-picker-view-content.${className}>*{height: ${indicatorHeightRef.value}px;overflow: hidden;}`
document.head.appendChild(style)
}
watch(() => indicatorHeightRef.value, updateStyle)
return className
}
function useCustomClick(dom: HTMLElement) {
type CustomClickProps =
| 'screenX'
| 'screenY'
| 'clientX'
| 'clientY'
| 'pageX'
| 'pageY'
interface CustomClick
extends CustomEvent,
Partial<Record<CustomClickProps, number>> {}
const MAX_MOVE = 20
let x = 0
let y = 0
dom.addEventListener('touchstart', (event) => {
const info = event.changedTouches[0]
x = info.clientX
y = info.clientY
})
dom.addEventListener('touchend', (event: TouchEvent) => {
const info = event.changedTouches[0]
if (
Math.abs(info.clientX - x) < MAX_MOVE &&
Math.abs(info.clientY - y) < MAX_MOVE
) {
const options: any = {
bubbles: true,
cancelable: true,
target: event.target,
currentTarget: event.currentTarget,
}
const customClick: CustomClick = new CustomEvent('click', options)
const props: CustomClickProps[] = [
'screenX',
'screenY',
'clientX',
'clientY',
'pageX',
'pageY',
]
props.forEach((key) => {
customClick[key] = info[key]
})
event.target!.dispatchEvent(customClick)
}
})
}
export default /*#__PURE__*/ defineComponent({
name: 'PickerViewColumn',
setup(props, { slots, emit }) {
const rootRef: Ref<HTMLElement | null> = ref(null)
const contentRef: Ref<HTMLElement | null> = ref(null)
const getPickerViewColumn: GetPickerViewColumn | undefined = inject(
'getPickerViewColumn'
)
const instance = getCurrentInstance() as ComponentInternalInstance
const currentRef = getPickerViewColumn
? getPickerViewColumn(instance)
: ref(0)
const getPickerViewProps: GetPickerViewProps = inject(
'getPickerViewProps'
) as GetPickerViewProps
const pickerViewProps = getPickerViewProps()
const getPickerViewState: GetPickerViewState = inject(
'getPickerViewState'
) as GetPickerViewState
const pickerViewState = getPickerViewState()
const indicatorHeight = ref(34)
const maskSize = computed(
() => (pickerViewState.height - indicatorHeight.value) / 2
)
const { state: scopedAttrsState } = useScopedAttrs()
const className = useScopedClass(indicatorHeight)
let scroller: Scroller
const state = reactive({
current: currentRef.value,
length: 0,
})
function updatesScroller() {
if (scroller) {
nextTick(() => {
let current = Math.min(state.current, state.length - 1)
current = Math.max(current, 0)
scroller.update(
current * indicatorHeight.value,
undefined,
indicatorHeight.value
)
})
}
}
watch(
() => currentRef.value,
(current) => {
if (current !== state.current) {
state.current = current
updatesScroller()
}
}
)
watch(
() => state.current,
(current) => (currentRef.value = current)
)
watch([() => indicatorHeight.value, () => state.length], updatesScroller)
let oldDeltaY = 0
function handleWheel(event: Event) {
const deltaY = oldDeltaY + (event as WheelEvent).deltaY
if (Math.abs(deltaY) > 10) {
oldDeltaY = 0
let current = Math.min(
state.current + (deltaY < 0 ? -1 : 1),
state.length - 1
)
state.current = current = Math.max(current, 0)
scroller.scrollTo(current * indicatorHeight.value)
} else {
oldDeltaY = deltaY
}
event.preventDefault()
}
function handleTap({ clientY }: MouseEvent) {
const el = rootRef.value as HTMLElement
if (!scroller.isScrolling()) {
const rect = el.getBoundingClientRect()
const r = clientY - rect.top - pickerViewState.height / 2
const o = indicatorHeight.value / 2
if (!(Math.abs(r) <= o)) {
const a = Math.ceil((Math.abs(r) - o) / indicatorHeight.value)
const s = r < 0 ? -a : a
let current = Math.min(state.current + s, state.length - 1)
state.current = current = Math.max(current, 0)
scroller.scrollTo(current * indicatorHeight.value)
}
}
}
onMounted(() => {
const el = rootRef.value as HTMLElement
const content = contentRef.value as HTMLElement
const {
scroller: scrollerOrigin,
handleTouchStart,
handleTouchMove,
handleTouchEnd,
} = useScroller(content, {
enableY: true,
enableX: false,
enableSnap: true,
itemSize: indicatorHeight.value,
friction: new Friction(0.0001),
spring: new Spring(2, 90, 20),
onSnap: (index) => {
if (!isNaN(index) && index !== state.current) {
state.current = index
}
},
})
scroller = scrollerOrigin
useTouchtrack(
el,
(e) => {
switch (e.detail.state) {
case 'start':
handleTouchStart(e)
disableScrollBounce({
disable: true,
})
break
case 'move':
handleTouchMove(e)
break
case 'end':
case 'cancel':
handleTouchEnd(e)
disableScrollBounce({
disable: false,
})
}
},
true
)
useCustomClick(el)
initScrollBounce()
updatesScroller()
})
return () => {
const defaultSlots = slots.default && slots.default()
state.length = flatVNode(defaultSlots).length
const padding = `${maskSize.value}px 0`
return (
<uni-picker-view-column ref={rootRef}>
<div
onWheel={handleWheel}
onClick={handleTap}
class="uni-picker-view-group"
>
<div
{...scopedAttrsState.attrs}
class={['uni-picker-view-mask', pickerViewProps.maskClass]}
style={`background-size: 100% ${maskSize.value}px;${pickerViewProps.maskStyle}`}
></div>
<div
{...scopedAttrsState.attrs}
class={[
'uni-picker-view-indicator',
pickerViewProps.indicatorClass,
]}
style={pickerViewProps.indicatorStyle}
>
<ResizeSensor
initial
onResize={({ height }: { height: number }) =>
(indicatorHeight.value = height)
}
></ResizeSensor>
</div>
<div
ref={contentRef}
class={['uni-picker-view-content', className]}
style={{ padding: padding }}
>
{defaultSlots}
</div>
</div>
</uni-picker-view-column>
)
}
},
})
<script>
import touchtrack from '../../mixins/touchtrack'
import scroller from '../../mixins/scroller/index'
import {
Friction
} from '../../mixins/scroller/Friction'
import {
Spring
} from '../../mixins/scroller/Spring'
import {disableScrollBounce} from '../../helpers/disable-scroll-bounce'
function initClick (dom) {
const MAX_MOVE = 20
let x = 0
let y = 0
dom.addEventListener('touchstart', (event) => {
const info = event.changedTouches[0]
x = info.clientX
y = info.clientY
})
dom.addEventListener('touchend', (event) => {
const info = event.changedTouches[0]
if (Math.abs(info.clientX - x) < MAX_MOVE && Math.abs(info.clientY - y) < MAX_MOVE) {
const customEvent = new CustomEvent('click', {
bubbles: true,
cancelable: true,
target: event.target,
currentTarget: event.currentTarget
});
['screenX', 'screenY', 'clientX', 'clientY', 'pageX', 'pageY'].forEach(key => {
customEvent[key] = info[key]
})
event.target.dispatchEvent(customEvent)
}
})
}
export default {
name: 'PickerViewColumn',
mixins: [touchtrack, scroller],
data () {
return {
scope: `picker-view-column-${Date.now()}`,
inited: false,
indicatorStyle: '',
indicatorClass: '',
indicatorHeight: 34,
maskStyle: '',
maskClass: '',
current: this.$parent.getItemValue(this),
length: 0
}
},
computed: {
height () {
return this.$parent.height
},
maskSize () {
return (this.height - this.indicatorHeight) / 2
}
},
watch: {
indicatorHeight (val) {
this._setItemHeight(val)
if (this.inited) {
this.update()
}
},
current (val) {
this.$parent.setItemValue(this, val)
},
length (val) {
if (this.inited) {
this.update(val)
}
}
},
created: function () {
var $parent = this.$parent
this.indicatorStyle = $parent.indicatorStyle
this.indicatorClass = $parent.indicatorClass
this.maskStyle = $parent.maskStyle
this.maskClass = $parent.maskClass
this.deltaY = 0
},
mounted: function () {
this.touchtrack(this.$refs.main, '_handleTrack', true)
this.setCurrent(this.current)
this.$nextTick(() => {
this.init()
this.update()
})
initClick(this.$el)
},
methods: {
_setItemHeight (height) {
var style = document.createElement('style')
style.innerText = `.uni-picker-view-content.${this.scope}>*{height: ${height}px;overflow: hidden;}`
document.head.appendChild(style)
},
_handleTrack: function (e) {
if (this._scroller) {
switch (e.detail.state) {
case 'start':
this._handleTouchStart(e)
disableScrollBounce({
disable: true
})
break
case 'move':
this._handleTouchMove(e)
break
case 'end':
case 'cancel':
this._handleTouchEnd(e)
disableScrollBounce({
disable: false
})
}
}
},
_handleTap: function ({
clientY
}) {
if (!this._scroller.isScrolling()) {
var rect = this.$el.getBoundingClientRect()
var r = clientY - rect.top - this.height / 2
var o = this.indicatorHeight / 2
if (!(Math.abs(r) <= o)) {
var a = Math.ceil((Math.abs(r) - o) / this.indicatorHeight)
var s = r < 0 ? -a : a
var current = Math.min(this.current + s, this.length - 1)
this.current = current = Math.max(current, 0)
this._scroller.scrollTo(current * this.indicatorHeight)
}
}
},
_handleWheel ($event) {
const deltaY = this.deltaY + $event.deltaY
if (Math.abs(deltaY) > 10) {
this.deltaY = 0
var current = Math.min(this.current + (deltaY < 0 ? -1 : 1), this.length - 1)
this.current = current = Math.max(current, 0)
this._scroller.scrollTo(current * this.indicatorHeight)
} else {
this.deltaY = deltaY
}
$event.preventDefault()
},
setCurrent: function (current) {
if (current !== this.current) {
this.current = current
if (this.inited) {
this.update()
}
}
},
init: function () {
this.initScroller(this.$refs.content, {
enableY: true,
enableX: false,
enableSnap: true,
itemSize: this.indicatorHeight,
friction: new Friction(0.0001),
spring: new Spring(2, 90, 20),
onSnap: (index) => {
if ((!isNaN(index)) && index !== this.current) {
this.current = index
}
}
})
this.inited = true
},
update: function () {
this.$nextTick(() => {
var current = Math.min(this.current, this.length - 1)
current = Math.max(current, 0)
this._scroller.update(current * this.indicatorHeight, undefined, this.indicatorHeight)
})
},
_resize ({
height
}) {
this.indicatorHeight = height
}
},
render (createElement) {
this.length = (this.$slots.default && this.$slots.default.length) || 0
return createElement('uni-picker-view-column', {
on: {
on: this.$listeners
}
}, [
createElement('div', {
ref: 'main',
staticClass: 'uni-picker-view-group',
on: {
wheel: this._handleWheel,
click: this._handleTap
}
},
[
createElement('div', {
ref: 'mask',
staticClass: 'uni-picker-view-mask',
class: this.maskClass,
style: `background-size: 100% ${this.maskSize}px;${this.maskStyle}`
}),
createElement('div', {
ref: 'indicator',
staticClass: 'uni-picker-view-indicator',
class: this.indicatorClass,
style: this.indicatorStyle
}, [createElement('v-uni-resize-sensor', {
attrs: {
initial: true
},
on: {
resize: this._resize
}
})]),
createElement('div', {
ref: 'content',
staticClass: 'uni-picker-view-content',
class: this.scope,
style: `padding: ${this.maskSize}px 0;`
},
[this.$slots.default]
)
])
])
}
}
</script>
\ No newline at end of file
import {
defineComponent,
Ref,
ref,
watch,
provide,
ComputedRef,
computed,
reactive,
VNode,
SetupContext,
PropType,
ComponentInternalInstance,
} from 'vue'
import ResizeSensor from '../resize-sensor/index'
import { useCustomEvent } from '../../helpers/useEvent'
const props = {
value: {
type: Array as PropType<number[]>,
default() {
return []
},
validator: function (val: any) {
return (
Array.isArray(val) &&
val.filter((val) => typeof val === 'number').length === val.length
)
},
},
indicatorStyle: {
type: String,
default: '',
},
indicatorClass: {
type: String,
default: '',
},
maskStyle: {
type: String,
default: '',
},
maskClass: {
type: String,
default: '',
},
}
type Props = Record<keyof typeof props, any>
interface State {
value: number[]
height: number
}
function useState(props: Props): State {
const value: number[] = reactive([...props.value])
const state = {
value,
height: 34,
}
watch(
() => props.value,
(val: number[], oldVal: number[]) => {
if (
__PLATFORM__ !== 'app' ||
val === oldVal ||
val.length !== oldVal.length ||
val.findIndex((item, index) => item !== oldVal[index]) >= 0
) {
state.value.length = val.length
val.forEach((val, index) => {
if (val !== state.value[index]) {
state.value.splice(index, 1, val)
}
})
}
}
)
return state
}
export type GetPickerViewColumn = (
columnInstance: ComponentInternalInstance
) => ComputedRef<number>
export type GetPickerViewProps = () => Props
export type GetPickerViewState = () => State
export default /*#__PURE__*/ defineComponent({
name: 'PickerView',
props,
emits: ['change', 'pickstart', 'pickend', 'update:value'],
setup(props, { slots, emit }) {
const rootRef: Ref<HTMLElement | null> = ref(null)
const trigger = useCustomEvent(rootRef, emit as SetupContext['emit'])
const state = useState(props)
let columnVNodes: VNode[] = []
function getItemIndex(vnode: VNode): number {
return columnVNodes.indexOf(vnode)
}
const getPickerViewColumn: GetPickerViewColumn = function (columnInstance) {
const ref: ComputedRef<number> = computed({
get() {
const index = getItemIndex(columnInstance.vnode)
return state.value[index] || 0
},
set(current: number) {
const index = getItemIndex(columnInstance.vnode)
const oldCurrent = state.value[index]
if (oldCurrent !== current) {
state.value.splice(index, 1, current)
// 避免外部直接对此值进行修改
const value = state.value.map((val) => val)
emit('update:value', value)
trigger('change', {} as Event, {
value,
})
}
},
})
return ref
}
provide('getPickerViewColumn', getPickerViewColumn)
const getPickerViewProps: GetPickerViewProps = () => {
return props
}
provide('getPickerViewProps', getPickerViewProps)
const getPickerViewState: GetPickerViewState = () => {
return state
}
provide('getPickerViewState', getPickerViewState)
return () => {
const defaultSlots = slots.default && slots.default()
// TODO filter
columnVNodes = columnVNodes = defaultSlots || []
return (
<uni-picker-view ref={rootRef}>
<ResizeSensor
initial
onResize={({ height }: { height: number }) =>
(state.height = height)
}
></ResizeSensor>
<div class="uni-picker-view-wrapper">{columnVNodes}</div>
</uni-picker-view>
)
}
},
})
<script>
import { deepClone } from 'uni-shared'
export default {
name: 'PickerView',
props: {
value: {
type: Array,
default () {
return []
},
validator: function (val) {
return Array.isArray(val) && val.filter(val => typeof val === 'number').length === val.length
}
},
indicatorStyle: {
type: String,
default: ''
},
indicatorClass: {
type: String,
default: ''
},
maskStyle: {
type: String,
default: ''
},
maskClass: {
type: String,
default: ''
}
},
data () {
return {
valueSync: [...this.value],
height: 34,
items: [],
changeSource: ''
}
},
watch: {
value (val, oldVal) {
if (__PLATFORM__ !== 'app' || val === oldVal || val.length !== oldVal.length || val.findIndex((item, index) => item !== oldVal[index]) >= 0) {
this.valueSync.length = val.length
val.forEach((val, index) => {
if (val !== this.valueSync[index]) {
this.$set(this.valueSync, index, val)
}
})
}
},
valueSync: {
deep: true,
handler (val, oldVal) {
if (this.changeSource === '') {
this._valueChanged(val)
} else {
this.changeSource = ''
// 避免外部直接对此值进行修改
const value = val.map(val => val)
this.$emit('update:value', value)
this.$trigger('change', {}, {
value
})
}
}
}
},
methods: {
getItemIndex (vnode) {
return this.items.indexOf(vnode)
},
getItemValue (vm) {
return this.valueSync[this.getItemIndex(vm.$vnode)] || 0
},
setItemValue (vm, val) {
var index = this.getItemIndex(vm.$vnode)
var oldVal = this.valueSync[index]
if (oldVal !== val) {
this.changeSource = 'touch'
this.$set(this.valueSync, index, val)
}
},
_valueChanged (val) {
this.items.forEach(function (item, index) {
item.componentInstance.setCurrent(val[index] || 0)
})
},
_resize ({
height
}) {
this.height = height
}
},
render (createElement) {
var items = []
if (this.$slots.default) {
deepClone(this.$slots.default, createElement).forEach(vnode => {
if (vnode.componentOptions && vnode.componentOptions.tag === 'v-uni-picker-view-column') {
items.push(vnode)
}
})
}
this.items = items
return createElement(
'uni-picker-view',
{
on: this.$listeners
}, [createElement('v-uni-resize-sensor', {
attrs: {
initial: true
},
on: {
resize: this._resize
}
}),
createElement('div', {
ref: 'wrapper',
class: 'uni-picker-view-wrapper'
}, items)
])
}
}
</script>
\ No newline at end of file
......@@ -4,22 +4,26 @@ let webview
let pullToRefreshStyle
export function initScrollBounce() {
plusReady(() => {
if (!webview) {
webview = plus.webview.currentWebview()
}
if (!pullToRefreshStyle) {
pullToRefreshStyle = (webview.getStyle() || {}).pullToRefresh || {}
}
})
if (__PLATFORM__ === 'app') {
plusReady(() => {
if (!webview) {
webview = plus.webview.currentWebview()
}
if (!pullToRefreshStyle) {
pullToRefreshStyle = (webview.getStyle() || {}).pullToRefresh || {}
}
})
}
}
export function disableScrollBounce({ disable }) {
if (pullToRefreshStyle && pullToRefreshStyle.support) {
webview.setPullToRefresh(
Object.assign({}, pullToRefreshStyle, {
support: !disable,
})
)
if (__PLATFORM__ === 'app') {
if (pullToRefreshStyle && pullToRefreshStyle.support) {
webview.setPullToRefresh(
Object.assign({}, pullToRefreshStyle, {
support: !disable,
})
)
}
}
}
export class Friction {
_drag: number
_dragLog: number
_x: number
_v: number
_startTime: number
_dt?: number
_powDragDt?: number
constructor(drag: number) {
this._drag = drag
this._dragLog = Math.log(drag)
this._x = 0
this._v = 0
this._startTime = 0
}
set(x: number, v: number) {
this._x = x
this._v = v
this._startTime = new Date().getTime()
}
setVelocityByEnd(e: number) {
this._v = ((e - this._x) * this._dragLog) / (Math.pow(this._drag, 100) - 1)
}
x(e?: number) {
if (e === undefined) {
e = (new Date().getTime() - this._startTime) / 1e3
}
const t =
e === this._dt && this._powDragDt
? this._powDragDt
: (this._powDragDt = Math.pow(this._drag, e))
this._dt = e
return this._x + (this._v * t) / this._dragLog - this._v / this._dragLog
}
dx(e?: number) {
if (e === undefined) {
e = (new Date().getTime() - this._startTime) / 1e3
}
const t =
e === this._dt && this._powDragDt
? this._powDragDt
: (this._powDragDt = Math.pow(this._drag, e))
this._dt = e
return this._v * t
}
done() {
return Math.abs(this.dx()) < 3
}
reconfigure(e: number) {
const t = this.x()
const n = this.dx()
this._drag = e
this._dragLog = Math.log(e)
this.set(t, n)
}
configuration() {
const e = this
return [
{
label: 'Friction',
read: function () {
return e._drag
},
write: function (t: number) {
e.reconfigure(t)
},
min: 0.001,
max: 0.1,
step: 0.001,
},
]
}
}
import { Friction } from './Friction'
import { Spring } from './Spring'
export class Scroll {
_extent: number
_friction: Friction
_spring: Spring
_startTime: number
_springing: boolean
_springOffset: number
_lastTime?: number
_lastDx?: number
constructor(extent: number, friction?: Friction, spring?: Spring) {
this._extent = extent
this._friction = friction || new Friction(0.01)
this._spring = spring || new Spring(1, 90, 20)
this._startTime = 0
this._springing = false
this._springOffset = 0
}
snap(e: number, t: number) {
this._springOffset = 0
this._springing = true
this._spring.snap(e)
this._spring.setEnd(t)
}
set(e: number, t: number) {
this._friction.set(e, t)
if (e > 0 && t >= 0) {
this._springOffset = 0
this._springing = true
this._spring.snap(e)
this._spring.setEnd(0)
} else {
if (e < -this._extent && t <= 0) {
this._springOffset = 0
this._springing = true
this._spring.snap(e)
this._spring.setEnd(-this._extent)
} else {
this._springing = false
}
}
this._startTime = new Date().getTime()
}
x(e: number) {
if (!this._startTime) {
return 0
}
if (!e) {
e = (new Date().getTime() - this._startTime) / 1e3
}
if (this._springing) {
return this._spring.x() + this._springOffset
}
let t = this._friction.x(e)
let n = this.dx(e)
if ((t > 0 && n >= 0) || (t < -this._extent && n <= 0)) {
this._springing = true
this._spring.setEnd(0, n)
if (t < -this._extent) {
this._springOffset = -this._extent
} else {
this._springOffset = 0
}
t = this._spring.x() + this._springOffset
}
return t
}
dx(e: number) {
let t: number
if (this._lastTime === e) {
t = this._lastDx as number
} else {
t = this._springing ? this._spring.dx(e) : this._friction.dx(e)
}
this._lastTime = e
this._lastDx = t
return t
}
done() {
return this._springing ? this._spring.done() : this._friction.done()
}
setVelocityByEnd(e: number) {
this._friction.setVelocityByEnd(e)
}
configuration() {
const e: any[] = this._friction.configuration()
e.push.apply(e, this._spring.configuration())
return e
}
}
import { Friction } from './Friction'
import { Spring } from './Spring'
import { Scroll } from './Scroll'
interface Animation {
cancel(): void
model: Scroll
}
function createAnimation(
scroll: Scroll,
onScroll: Function,
onEnd: Function
): Animation {
interface State {
id: number
cancelled: boolean
}
const state: State = {
id: 0,
cancelled: false,
}
function startAnimation(
state: State,
scroll: Scroll,
onScroll: Function,
onEnd: Function
) {
if (!state || !state.cancelled) {
onScroll(scroll)
const isDone = scroll.done()
if (!isDone) {
if (!state.cancelled) {
state.id = requestAnimationFrame(
startAnimation.bind(null, state, scroll, onScroll, onEnd)
)
}
}
if (isDone && onEnd) {
onEnd(scroll)
}
}
}
function cancel(state: State) {
if (state && state.id) {
cancelAnimationFrame(state.id)
}
if (state) {
state.cancelled = true
}
}
startAnimation(state, scroll, onScroll, onEnd)
return {
cancel: cancel.bind(null, state),
model: scroll,
}
}
interface OnScrollEvent {
target: {
scrollLeft: number
scrollTop: number
scrollHeight: number
scrollWidth: number
offsetHeight: number
offsetWidth: number
}
}
export interface Options {
enableSnap?: boolean
itemSize?: number
enableX?: boolean
enableY?: boolean
scrollWidth?: number
scrollHeight?: number
friction?: Friction
spring?: Spring
onScroll?: (event: OnScrollEvent) => void
onSnap?: (index: number) => void
}
export class Scroller {
_element: HTMLElement
_options: Options
_enableSnap
_itemSize
_enableX
_enableY
_shouldDispatchScrollEvent
_extent
_scrollWidth?: number
_scrollHeight?: number
_position: number
_scroll: Scroll
_onTransitionEnd: () => void
_startPosition?: number
_lastChangePos?: number
_animation?: Animation
_scrolling?: boolean
_lastTime?: number
_lastDelay?: number
_lastIdx?: number
_snapping?: boolean
_lastPos?: number
constructor(element: HTMLElement, options: Options) {
options = options || {}
this._element = element
this._options = options
this._enableSnap = options.enableSnap || false
this._itemSize = options.itemSize || 0
this._enableX = options.enableX || false
this._enableY = options.enableY || false
this._shouldDispatchScrollEvent = !!options.onScroll
if (this._enableX) {
this._extent =
(options.scrollWidth || this._element.offsetWidth) -
this._element.parentElement!.offsetWidth
this._scrollWidth = options.scrollWidth
} else {
this._extent =
(options.scrollHeight || this._element.offsetHeight) -
this._element.parentElement!.offsetHeight
this._scrollHeight = options.scrollHeight
}
this._position = 0
this._scroll = new Scroll(this._extent, options.friction, options.spring)
this._onTransitionEnd = this.onTransitionEnd.bind(this)
this.updatePosition()
}
onTouchStart() {
this._startPosition = this._position
this._lastChangePos = this._startPosition
if (this._startPosition > 0) {
this._startPosition /= 0.5
} else {
if (this._startPosition < -this._extent) {
this._startPosition =
(this._startPosition + this._extent) / 0.5 - this._extent
}
}
if (this._animation) {
this._animation.cancel()
this._scrolling = false
}
this.updatePosition()
}
onTouchMove(x: number, y: number) {
let startPosition = this._startPosition!
if (this._enableX) {
startPosition += x
} else if (this._enableY) {
startPosition += y
}
if (startPosition > 0) {
startPosition *= 0.5
} else if (startPosition < -this._extent) {
startPosition = 0.5 * (startPosition + this._extent) - this._extent
}
this._position = startPosition
this.updatePosition()
this.dispatchScroll()
}
onTouchEnd(x: number, y: number, o: { x: number; y: number }) {
if (
this._enableSnap &&
this._position > -this._extent &&
this._position < 0
) {
if (
this._enableY &&
((Math.abs(y) < this._itemSize && Math.abs(o.y) < 300) ||
Math.abs(o.y) < 150)
) {
this.snap()
return
}
if (
this._enableX &&
((Math.abs(x) < this._itemSize && Math.abs(o.x) < 300) ||
Math.abs(o.x) < 150)
) {
this.snap()
return
}
}
if (this._enableX) {
this._scroll.set(this._position, o.x)
} else if (this._enableY) {
this._scroll.set(this._position, o.y)
}
let c: number
if (this._enableSnap) {
const s = this._scroll._friction.x(100)
const l = s % this._itemSize
c =
Math.abs(l) > this._itemSize / 2
? s - (this._itemSize - Math.abs(l))
: s - l
if (c <= 0 && c >= -this._extent) {
this._scroll.setVelocityByEnd(c)
}
}
this._lastTime = Date.now()
this._lastDelay = 0
this._scrolling = true
this._lastChangePos = this._position
this._lastIdx = Math.floor(Math.abs(this._position / this._itemSize))
this._animation = createAnimation(
this._scroll,
() => {
const e = Date.now()
const i = (e - this._scroll._startTime) / 1e3
const r = this._scroll.x(i)
this._position = r
this.updatePosition()
const o = this._scroll.dx(i)
if (
this._shouldDispatchScrollEvent &&
e - this._lastTime! > this._lastDelay!
) {
this.dispatchScroll()
this._lastDelay = Math.abs(2e3 / o)
this._lastTime = e
}
},
() => {
if (this._enableSnap) {
if (c <= 0 && c >= -this._extent) {
this._position = c
this.updatePosition()
}
if (typeof this._options.onSnap === 'function') {
this._options.onSnap(
Math.floor(Math.abs(this._position) / this._itemSize)
)
}
}
if (this._shouldDispatchScrollEvent) {
this.dispatchScroll()
}
this._scrolling = false
}
)
}
onTransitionEnd() {
this._element.style.webkitTransition = ''
this._element.style.transition = ''
this._element.removeEventListener('transitionend', this._onTransitionEnd)
if (this._snapping) {
this._snapping = false
}
this.dispatchScroll()
}
snap() {
const itemSize = this._itemSize
const position = this._position % itemSize
const i =
Math.abs(position) > this._itemSize / 2
? this._position - (itemSize - Math.abs(position))
: this._position - position
if (this._position !== i) {
this._snapping = true
this.scrollTo(-i)
if (typeof this._options.onSnap === 'function') {
this._options.onSnap(
Math.floor(Math.abs(this._position) / this._itemSize)
)
}
}
}
scrollTo(position: number, time?: number) {
if (this._animation) {
this._animation.cancel()
this._scrolling = false
}
if (typeof position === 'number') {
this._position = -position
}
if (this._position < -this._extent) {
this._position = -this._extent
} else {
if (this._position > 0) {
this._position = 0
}
}
const transition = 'transform ' + (time || 0.2) + 's ease-out'
this._element.style.webkitTransition = '-webkit-' + transition
this._element.style.transition = transition
this.updatePosition()
this._element.addEventListener('transitionend', this._onTransitionEnd)
}
dispatchScroll() {
if (
typeof this._options.onScroll === 'function' &&
Math.round(Number(this._lastPos)) !== Math.round(this._position)
) {
this._lastPos = this._position
const event: OnScrollEvent = {
target: {
scrollLeft: this._enableX ? -this._position : 0,
scrollTop: this._enableY ? -this._position : 0,
scrollHeight: this._scrollHeight || this._element.offsetHeight,
scrollWidth: this._scrollWidth || this._element.offsetWidth,
offsetHeight: this._element.parentElement!.offsetHeight,
offsetWidth: this._element.parentElement!.offsetWidth,
},
}
this._options.onScroll(event)
}
}
update(height: number, scrollHeight?: number, itemSize?: number) {
let extent = 0
const position = this._position
if (this._enableX) {
extent = this._element.childNodes.length
? (scrollHeight || this._element.offsetWidth) -
this._element.parentElement!.offsetWidth
: 0
this._scrollWidth = scrollHeight
} else {
extent = this._element.childNodes.length
? (scrollHeight || this._element.offsetHeight) -
this._element.parentElement!.offsetHeight
: 0
this._scrollHeight = scrollHeight
}
if (typeof height === 'number') {
this._position = -height
}
if (this._position < -extent) {
this._position = -extent
} else {
if (this._position > 0) {
this._position = 0
}
}
this._itemSize = itemSize || this._itemSize
this.updatePosition()
if (position !== this._position) {
this.dispatchScroll()
if (typeof this._options.onSnap === 'function') {
this._options.onSnap(
Math.floor(Math.abs(this._position) / this._itemSize)
)
}
}
this._extent = extent
this._scroll._extent = extent
}
updatePosition() {
let transform = ''
if (this._enableX) {
transform = 'translateX(' + this._position + 'px) translateZ(0)'
} else {
if (this._enableY) {
transform = 'translateY(' + this._position + 'px) translateZ(0)'
}
}
this._element.style.webkitTransform = transform
this._element.style.transform = transform
}
isScrolling() {
return this._scrolling || this._snapping
}
}
function o(e: any, t: number, n: number) {
return e > t - n && e < t + n
}
function a(e: any, t: number) {
return o(e, 0, t)
}
interface Solution {
_t?: number
_powER1T?: number
_powER2T?: number
x: (e: number) => number
dx: (e: number) => number
}
export class Spring {
_m: number
_k: number
_c: number
_solution: Solution | null
_endPosition: number
_startTime: number
constructor(m: number, k: number, c: number) {
this._m = m
this._k = k
this._c = c
this._solution = null
this._endPosition = 0
this._startTime = 0
}
_solve(e: number, t: number): Solution {
const n = this._c
const i = this._m
const r = this._k
const o = n * n - 4 * i * r
if (o === 0) {
const a = -n / (2 * i)
const s = e
const l = t / (a * e)
return {
x: function (e: number) {
return (s + l * e) * Math.pow(Math.E, a * e)
},
dx: function (e: number) {
const t = Math.pow(Math.E, a * e)
return a * (s + l * e) * t + l * t
},
}
}
if (o > 0) {
const c = (-n - Math.sqrt(o)) / (2 * i)
const u = (-n + Math.sqrt(o)) / (2 * i)
const l = (t - c * e) / (u - c)
const s = e - l
return {
x: function (e: number): number {
let t
let n
if (e === this._t) {
t = this._powER1T
n = this._powER2T
}
this._t = e
if (!t) {
t = this._powER1T = Math.pow(Math.E, c * e)
}
if (!n) {
n = this._powER2T = Math.pow(Math.E, u * e)
}
return s * t + l * n
},
dx: function (e: number): number {
let t
let n
if (e === this._t) {
t = this._powER1T
n = this._powER2T
}
this._t = e
if (!t) {
t = this._powER1T = Math.pow(Math.E, c * e)
}
if (!n) {
n = this._powER2T = Math.pow(Math.E, u * e)
}
return s * c * t + l * u * n
},
}
}
const d = Math.sqrt(4 * i * r - n * n) / (2 * i)
const a = (-n / 2) * i
const s = e
const l = (t - a * e) / d
return {
x: function (e: number): number {
return (
Math.pow(Math.E, a * e) * (s * Math.cos(d * e) + l * Math.sin(d * e))
)
},
dx: function (e: number): number {
const t = Math.pow(Math.E, a * e)
const n = Math.cos(d * e)
const i = Math.sin(d * e)
return t * (l * d * n - s * d * i) + a * t * (l * i + s * n)
},
}
}
x(e?: number) {
if (e === undefined) {
e = (new Date().getTime() - this._startTime) / 1e3
}
return this._solution ? this._endPosition + this._solution.x(e) : 0
}
dx(e?: number) {
if (e === undefined) {
e = (new Date().getTime() - this._startTime) / 1e3
}
return this._solution ? this._solution.dx(e) : 0
}
setEnd(e: number, t?: number, n?: number) {
if (!n) {
n = new Date().getTime()
}
if (e !== this._endPosition || !a(t, 0.4)) {
t = t || 0
let i = this._endPosition
if (this._solution) {
if (a(t, 0.4)) {
t = this._solution.dx((n - this._startTime) / 1e3)
}
i = this._solution.x((n - this._startTime) / 1e3)
if (a(t, 0.4)) {
t = 0
}
if (a(i, 0.4)) {
i = 0
}
i += this._endPosition
}
if (!(this._solution && a(i - e, 0.4) && a(t, 0.4))) {
this._endPosition = e
this._solution = this._solve(i - this._endPosition, t)
this._startTime = n
}
}
}
snap(e: number) {
this._startTime = new Date().getTime()
this._endPosition = e
this._solution = {
x: function () {
return 0
},
dx: function () {
return 0
},
}
}
done(e?: number) {
if (!e) {
e = new Date().getTime()
}
return o(this.x(), this._endPosition, 0.4) && a(this.dx(), 0.4)
}
reconfigure(e: number, t: number, n: number) {
this._m = e
this._k = t
this._c = n
if (!this.done()) {
this._solution = this._solve(this.x() - this._endPosition, this.dx())
this._startTime = new Date().getTime()
}
}
springConstant() {
return this._k
}
damping() {
return this._c
}
configuration() {
function e(e: Spring, t: number) {
e.reconfigure(1, t, e.damping())
}
function t(e: Spring, t: number) {
e.reconfigure(1, e.springConstant(), t)
}
return [
{
label: 'Spring Constant',
read: this.springConstant.bind(this),
write: e.bind(this, this),
min: 100,
max: 1e3,
},
{
label: 'Damping',
read: this.damping.bind(this),
write: t.bind(this, this),
min: 1,
max: 500,
},
]
}
}
import { Scroller, Options } from './Scroller'
import { TouchtrackEvent } from '../useTouchtrack'
export function useScroller(element: HTMLElement, options: Options) {
interface TouchInfo {
trackingID: number | string
maxDy: number
maxDx: number
x?: number
y?: number
historyX?: number[]
historyY?: number[]
historyTime?: number[]
listener?: Scroller | null
}
const touchInfo: TouchInfo = {
trackingID: -1,
maxDy: 0,
maxDx: 0,
}
const scroller = new Scroller(element, options)
function findDelta(event: TouchtrackEvent | MouseEvent) {
const touchtrackEvent: TouchtrackEvent = event as TouchtrackEvent
const mouseEvent: MouseEvent = event as MouseEvent
return touchtrackEvent.detail.state === 'move' ||
touchtrackEvent.detail.state === 'end'
? {
x: touchtrackEvent.detail.dx,
y: touchtrackEvent.detail.dy,
}
: {
x: mouseEvent.screenX - touchInfo.x!,
y: mouseEvent.screenY - touchInfo.y!,
}
}
function handleTouchStart(event: TouchtrackEvent | MouseEvent) {
const touchtrackEvent: TouchtrackEvent = event as TouchtrackEvent
const mouseEvent: MouseEvent = event as MouseEvent
if (touchtrackEvent.detail.state === 'start') {
touchInfo.trackingID = 'touch'
touchInfo.x = touchtrackEvent.detail.x
touchInfo.y = touchtrackEvent.detail.y
} else {
touchInfo.trackingID = 'mouse'
touchInfo.x = mouseEvent.screenX
touchInfo.y = mouseEvent.screenY
}
touchInfo.maxDx = 0
touchInfo.maxDy = 0
touchInfo.historyX = [0]
touchInfo.historyY = [0]
touchInfo.historyTime = [
touchtrackEvent.detail.timeStamp || mouseEvent.timeStamp,
]
touchInfo.listener = scroller
if (scroller.onTouchStart) {
scroller.onTouchStart()
}
event.preventDefault()
}
function handleTouchMove(event: TouchtrackEvent | MouseEvent) {
const touchtrackEvent: TouchtrackEvent = event as TouchtrackEvent
const mouseEvent: MouseEvent = event as MouseEvent
if (touchInfo.trackingID !== -1) {
event.preventDefault()
const delta = findDelta(event)
if (delta) {
for (
touchInfo.maxDy = Math.max(touchInfo.maxDy, Math.abs(delta.y)),
touchInfo.maxDx = Math.max(touchInfo.maxDx, Math.abs(delta.x)),
touchInfo.historyX!.push(delta.x),
touchInfo.historyY!.push(delta.y),
touchInfo.historyTime!.push(
touchtrackEvent.detail.timeStamp || mouseEvent.timeStamp
);
touchInfo.historyTime!.length > 10;
) {
touchInfo.historyTime!.shift()
touchInfo.historyX!.shift()
touchInfo.historyY!.shift()
}
if (touchInfo.listener && touchInfo.listener.onTouchMove) {
touchInfo.listener.onTouchMove(delta.x, delta.y)
}
}
}
}
function handleTouchEnd(event: TouchtrackEvent | MouseEvent) {
if (touchInfo.trackingID !== -1) {
event.preventDefault()
const delta = findDelta(event)
if (delta) {
const listener = touchInfo.listener
touchInfo.trackingID = -1
touchInfo.listener = null
const length = touchInfo.historyTime!.length
const o = {
x: 0,
y: 0,
}
if (length > 2) {
for (
let i = touchInfo.historyTime!.length - 1,
time1 = touchInfo.historyTime![i],
x = touchInfo.historyX![i],
y = touchInfo.historyY![i];
i > 0;
) {
i--
const time0 = touchInfo.historyTime![i]
const time = time1 - time0
if (time > 30 && time < 50) {
o.x = (x - touchInfo.historyX![i]) / (time / 1e3)
o.y = (y - touchInfo.historyY![i]) / (time / 1e3)
break
}
}
}
touchInfo.historyTime = []
touchInfo.historyX = []
touchInfo.historyY = []
if (listener && listener.onTouchEnd) {
listener.onTouchEnd(delta.x, delta.y, o)
}
}
}
}
return {
scroller,
handleTouchStart,
handleTouchMove,
handleTouchEnd,
}
}
......@@ -1154,7 +1154,7 @@ function initHistory() {
return vueRouter.createMemoryHistory(__uniConfig.router.base);
}
}
var index$q = {
var index$s = {
install(app) {
initApp$1(app);
if (__UNI_FEATURE_PAGES__) {
......@@ -1528,7 +1528,7 @@ function useBooleanAttr(props2, keys) {
}, Object.create(null));
}
const uniFormKey = PolySymbol(process.env.NODE_ENV !== "production" ? "uniForm" : "uf");
var index$p = /* @__PURE__ */ vue.defineComponent({
var index$r = /* @__PURE__ */ vue.defineComponent({
name: "Form",
setup(_props, {
slots,
......@@ -1567,7 +1567,7 @@ function provideForm(emit2) {
});
return fields;
}
var index$o = /* @__PURE__ */ vue.defineComponent({
var index$q = /* @__PURE__ */ vue.defineComponent({
name: "Button",
props: {
id: {
......@@ -2230,15 +2230,15 @@ function _sfc_render$6(_ctx, _cache, $props, $setup, $data, $options) {
}
_sfc_main$6.render = _sfc_render$6;
const uniCheckGroupKey = PolySymbol(process.env.NODE_ENV !== "production" ? "uniCheckGroup" : "ucg");
const props$o = {
const props$p = {
name: {
type: String,
default: ""
}
};
var index$n = /* @__PURE__ */ vue.defineComponent({
var index$p = /* @__PURE__ */ vue.defineComponent({
name: "CheckboxGroup",
props: props$o,
props: props$p,
emits: ["change"],
setup(props2, {
emit: emit2,
......@@ -2291,15 +2291,15 @@ function useProvideCheckGroup(props2, trigger) {
return getFieldsValue;
}
const uniLabelKey = PolySymbol(process.env.NODE_ENV !== "production" ? "uniLabel" : "ul");
const props$n = {
const props$o = {
for: {
type: String,
default: ""
}
};
var index$m = /* @__PURE__ */ vue.defineComponent({
var index$o = /* @__PURE__ */ vue.defineComponent({
name: "Label",
props: props$n,
props: props$o,
setup(props2, {
emit: emit2,
slots
......@@ -2344,7 +2344,7 @@ function useProvideLabel() {
});
return handlers;
}
const props$m = {
const props$n = {
checked: {
type: [Boolean, String],
default: false
......@@ -2366,9 +2366,9 @@ const props$m = {
default: ""
}
};
var index$l = /* @__PURE__ */ vue.defineComponent({
var index$n = /* @__PURE__ */ vue.defineComponent({
name: "Checkbox",
props: props$m,
props: props$n,
setup(props2, {
slots
}) {
......@@ -2437,7 +2437,7 @@ function useCheckboxInject(checkboxChecked, checkboxValue, reset) {
let resetTimer;
function iosHideKeyboard() {
}
const props$l = {
const props$m = {
cursorSpacing: {
type: [Number, String],
default: 0
......@@ -2607,7 +2607,7 @@ function useQuill(props2, rootRef, trigger) {
});
useSubscribe();
}
const props$k = /* @__PURE__ */ Object.assign({}, props$l, {
const props$l = /* @__PURE__ */ Object.assign({}, props$m, {
id: {
type: String,
default: ""
......@@ -2633,9 +2633,9 @@ const props$k = /* @__PURE__ */ Object.assign({}, props$l, {
default: false
}
});
var index$k = /* @__PURE__ */ vue.defineComponent({
var index$m = /* @__PURE__ */ vue.defineComponent({
name: "Editor",
props: props$k,
props: props$l,
emit: ["ready", "focus", "blur", "input", "statuschange", ...emit$1],
setup(props2, {
emit: emit2
......@@ -2694,7 +2694,7 @@ const ICONS = {
c: GREY_COLOR
}
};
var index$j = /* @__PURE__ */ vue.defineComponent({
var index$l = /* @__PURE__ */ vue.defineComponent({
name: "Icon",
props: {
type: {
......@@ -2721,7 +2721,7 @@ var index$j = /* @__PURE__ */ vue.defineComponent({
};
}
});
const props$j = {
const props$k = {
src: {
type: String,
default: ""
......@@ -2758,9 +2758,9 @@ const IMAGE_MODES = {
"bottom left": ["left bottom"],
"bottom right": ["right bottom"]
};
var index$i = /* @__PURE__ */ vue.defineComponent({
var index$k = /* @__PURE__ */ vue.defineComponent({
name: "Image",
props: props$j,
props: props$k,
setup(props2, {
emit: emit2
}) {
......@@ -2972,7 +2972,7 @@ function useFormField(nameKey, value) {
function getValueString(value) {
return value === null ? "" : String(value);
}
const props$i = /* @__PURE__ */ Object.assign({}, {
const props$j = /* @__PURE__ */ Object.assign({}, {
name: {
type: String,
default: ""
......@@ -3033,7 +3033,7 @@ const props$i = /* @__PURE__ */ Object.assign({}, {
type: String,
default: "done"
}
}, props$l);
}, props$m);
const emit = ["input", "focus", "blur", ...emit$1];
function useBase(props2, rootRef, emit2) {
const fieldRef = vue.ref(null);
......@@ -3209,7 +3209,7 @@ function useField(props2, rootRef, emit2, beforeInput) {
trigger
};
}
const props$h = /* @__PURE__ */ Object.assign({}, props$i, {
const props$i = /* @__PURE__ */ Object.assign({}, props$j, {
placeholderClass: {
type: String,
default: "input-placeholder"
......@@ -3217,7 +3217,7 @@ const props$h = /* @__PURE__ */ Object.assign({}, props$i, {
});
var Input = /* @__PURE__ */ vue.defineComponent({
name: "Input",
props: props$h,
props: props$i,
emit: ["confirm", ...emit],
setup(props2, {
emit: emit2
......@@ -3315,35 +3315,16 @@ var Input = /* @__PURE__ */ vue.defineComponent({
};
}
});
let webview;
let pullToRefreshStyle;
function initScrollBounce() {
uniShared.plusReady(() => {
if (!webview) {
webview = plus.webview.currentWebview();
}
if (!pullToRefreshStyle) {
pullToRefreshStyle = (webview.getStyle() || {}).pullToRefresh || {};
}
});
}
function disableScrollBounce({disable}) {
if (pullToRefreshStyle && pullToRefreshStyle.support) {
webview.setPullToRefresh(Object.assign({}, pullToRefreshStyle, {
support: !disable
}));
}
}
const props$g = {
const props$h = {
scaleArea: {
type: Boolean,
default: false
}
};
var index$h = /* @__PURE__ */ vue.defineComponent({
var index$j = /* @__PURE__ */ vue.defineComponent({
inheritAttrs: false,
name: "MovableArea",
props: props$g,
props: props$h,
setup(props2, {
slots
}) {
......@@ -3447,9 +3428,6 @@ function useMovableAreaState(props2, rootRef) {
return get(target);
}
const _onTouchstart = withWebEvent((t2) => {
disableScrollBounce({
disable: true
});
let i2 = t2.touches;
if (i2) {
if (i2.length > 1) {
......@@ -3487,9 +3465,6 @@ function useMovableAreaState(props2, rootRef) {
}
});
const _onTouchend = withWebEvent((e2) => {
disableScrollBounce({
disable: false
});
let t2 = e2.touches;
if (!(t2 && t2.length)) {
if (e2.changedTouches) {
......@@ -3832,7 +3807,7 @@ STD.prototype.reconfigure = function(e2, t2, n) {
this._springY.reconfigure(e2, t2, n);
this._springScale.reconfigure(e2, t2, n);
};
const props$f = {
const props$g = {
direction: {
type: String,
default: "none"
......@@ -3886,9 +3861,9 @@ const props$f = {
default: true
}
};
var index$g = /* @__PURE__ */ vue.defineComponent({
var index$i = /* @__PURE__ */ vue.defineComponent({
name: "MovableView",
props: props$f,
props: props$g,
emits: ["change", "scale"],
setup(props2, {
slots,
......@@ -4358,6 +4333,234 @@ function _sfc_render$5(_ctx, _cache, $props, $setup, $data, $options) {
]));
}
_sfc_main$5.render = _sfc_render$5;
const props$f = {
value: {
type: Array,
default() {
return [];
},
validator: function(val) {
return Array.isArray(val) && val.filter((val2) => typeof val2 === "number").length === val.length;
}
},
indicatorStyle: {
type: String,
default: ""
},
indicatorClass: {
type: String,
default: ""
},
maskStyle: {
type: String,
default: ""
},
maskClass: {
type: String,
default: ""
}
};
function useState$1(props2) {
const value = vue.reactive([...props2.value]);
const state = {
value,
height: 34
};
vue.watch(() => props2.value, (val, oldVal) => {
{
state.value.length = val.length;
val.forEach((val2, index2) => {
if (val2 !== state.value[index2]) {
state.value.splice(index2, 1, val2);
}
});
}
});
return state;
}
var index$h = /* @__PURE__ */ vue.defineComponent({
name: "PickerView",
props: props$f,
emits: ["change", "pickstart", "pickend", "update:value"],
setup(props2, {
slots,
emit: emit2
}) {
const rootRef = vue.ref(null);
const trigger = useCustomEvent(rootRef, emit2);
const state = useState$1(props2);
let columnVNodes = [];
function getItemIndex(vnode) {
return columnVNodes.indexOf(vnode);
}
const getPickerViewColumn = function(columnInstance) {
const ref = vue.computed({
get() {
const index2 = getItemIndex(columnInstance.vnode);
return state.value[index2] || 0;
},
set(current) {
const index2 = getItemIndex(columnInstance.vnode);
const oldCurrent = state.value[index2];
if (oldCurrent !== current) {
state.value.splice(index2, 1, current);
const value = state.value.map((val) => val);
emit2("update:value", value);
trigger("change", {}, {
value
});
}
}
});
return ref;
};
vue.provide("getPickerViewColumn", getPickerViewColumn);
const getPickerViewProps = () => {
return props2;
};
vue.provide("getPickerViewProps", getPickerViewProps);
const getPickerViewState = () => {
return state;
};
vue.provide("getPickerViewState", getPickerViewState);
return () => {
const defaultSlots = slots.default && slots.default();
columnVNodes = columnVNodes = defaultSlots || [];
return vue.createVNode("uni-picker-view", {
ref: rootRef
}, [vue.createVNode(ResizeSensor, {
initial: true,
onResize: ({
height
}) => state.height = height
}, null, 8, ["initial", "onResize"]), vue.createVNode("div", {
class: "uni-picker-view-wrapper"
}, [columnVNodes])], 512);
};
}
});
function flatVNode(nodes) {
const array = [];
if (Array.isArray(nodes)) {
nodes.forEach((vnode) => {
if (vue.isVNode(vnode)) {
if (vnode.type === vue.Fragment) {
array.push(...flatVNode(vnode.children));
} else {
array.push(vnode);
}
}
});
}
return array;
}
let scopedIndex = 0;
function useScopedClass(indicatorHeightRef) {
const className = `uni-picker-view-content-${scopedIndex++}`;
function updateStyle() {
const style = document.createElement("style");
style.innerText = `.uni-picker-view-content.${className}>*{height: ${indicatorHeightRef.value}px;overflow: hidden;}`;
document.head.appendChild(style);
}
vue.watch(() => indicatorHeightRef.value, updateStyle);
return className;
}
var index$g = /* @__PURE__ */ vue.defineComponent({
name: "PickerViewColumn",
setup(props2, {
slots,
emit: emit2
}) {
const rootRef = vue.ref(null);
const contentRef = vue.ref(null);
const getPickerViewColumn = vue.inject("getPickerViewColumn");
const instance = vue.getCurrentInstance();
const currentRef = getPickerViewColumn ? getPickerViewColumn(instance) : vue.ref(0);
const getPickerViewProps = vue.inject("getPickerViewProps");
const pickerViewProps = getPickerViewProps();
const getPickerViewState = vue.inject("getPickerViewState");
const pickerViewState = getPickerViewState();
const indicatorHeight = vue.ref(34);
const maskSize = vue.computed(() => (pickerViewState.height - indicatorHeight.value) / 2);
const {
state: scopedAttrsState
} = useScopedAttrs();
const className = useScopedClass(indicatorHeight);
let scroller2;
const state = vue.reactive({
current: currentRef.value,
length: 0
});
function updatesScroller() {
}
vue.watch(() => currentRef.value, (current) => {
if (current !== state.current) {
state.current = current;
}
});
vue.watch(() => state.current, (current) => currentRef.value = current);
vue.watch([() => indicatorHeight.value, () => state.length], updatesScroller);
let oldDeltaY = 0;
function handleWheel(event) {
const deltaY = oldDeltaY + event.deltaY;
if (Math.abs(deltaY) > 10) {
oldDeltaY = 0;
let current = Math.min(state.current + (deltaY < 0 ? -1 : 1), state.length - 1);
state.current = current = Math.max(current, 0);
scroller2.scrollTo(current * indicatorHeight.value);
} else {
oldDeltaY = deltaY;
}
event.preventDefault();
}
function handleTap({
clientY
}) {
const el = rootRef.value;
if (!scroller2.isScrolling()) {
const rect = el.getBoundingClientRect();
const r = clientY - rect.top - pickerViewState.height / 2;
const o2 = indicatorHeight.value / 2;
if (!(Math.abs(r) <= o2)) {
const a2 = Math.ceil((Math.abs(r) - o2) / indicatorHeight.value);
const s = r < 0 ? -a2 : a2;
let current = Math.min(state.current + s, state.length - 1);
state.current = current = Math.max(current, 0);
scroller2.scrollTo(current * indicatorHeight.value);
}
}
}
return () => {
const defaultSlots = slots.default && slots.default();
state.length = flatVNode(defaultSlots).length;
const padding = `${maskSize.value}px 0`;
return vue.createVNode("uni-picker-view-column", {
ref: rootRef
}, [vue.createVNode("div", {
onWheel: handleWheel,
onClick: handleTap,
class: "uni-picker-view-group"
}, [vue.createVNode("div", vue.mergeProps(scopedAttrsState.attrs, {
class: ["uni-picker-view-mask", pickerViewProps.maskClass],
style: `background-size: 100% ${maskSize.value}px;${pickerViewProps.maskStyle}`
}), null, 16), vue.createVNode("div", vue.mergeProps(scopedAttrsState.attrs, {
class: ["uni-picker-view-indicator", pickerViewProps.indicatorClass],
style: pickerViewProps.indicatorStyle
}), [vue.createVNode(ResizeSensor, {
initial: true,
onResize: ({
height
}) => indicatorHeight.value = height
}, null, 8, ["initial", "onResize"])], 16), vue.createVNode("div", {
ref: contentRef,
class: ["uni-picker-view-content", className],
style: {
padding
}
}, [defaultSlots], 6)], 40, ["onWheel", "onClick"])], 512);
};
}
});
const VALUES = {
activeColor: "#007AFF",
backgroundColor: "#EBEBEB",
......@@ -5757,9 +5960,6 @@ const _sfc_main$3 = {
};
this.__handleTouchStart = function(event) {
if (event.touches.length === 1) {
disableScrollBounce({
disable: true
});
needStop = null;
touchStart = {
x: event.touches[0].pageX,
......@@ -5772,9 +5972,6 @@ const _sfc_main$3 = {
};
this.__handleTouchEnd = function(event) {
touchStart = null;
disableScrollBounce({
disable: false
});
if (self.refresherHeight >= self.refresherThreshold) {
self._setRefreshState("refreshing");
} else {
......@@ -5786,7 +5983,6 @@ const _sfc_main$3 = {
this.main.addEventListener("touchmove", this.__handleTouchMove, passiveOptions);
this.main.addEventListener("scroll", this.__handleScroll, passiveOptions);
this.main.addEventListener("touchend", this.__handleTouchEnd, passiveOptions);
initScrollBounce();
},
activated() {
this.scrollY && (this.main.scrollTop = this.lastScrollTop);
......@@ -6264,7 +6460,7 @@ function useSliderLoader(props2, sliderValue, sliderRef, sliderValueRef, trigger
const _onTrack = (e2) => {
if (!props2.disabled) {
return e2.detail.state === "move" ? (_onUserChangedValue({
x: e2.detail.x0
x: e2.detail.x
}), trigger("changing", e2, {
value: sliderValue.value
}), false) : e2.detail.state === "end" && trigger("change", e2, {
......@@ -6758,7 +6954,7 @@ var index$b = /* @__PURE__ */ vue.defineComponent({
} = useLayout(props2, state, swiperContexts, slideFrameRef, emit2, trigger);
return () => {
const defaultSlots = slots.default && slots.default();
swiperItems = defaultSlots || [];
swiperItems = flatVNode(defaultSlots);
return vue.createVNode("uni-swiper", {
ref: rootRef
}, [vue.createVNode("div", {
......@@ -6771,7 +6967,7 @@ var index$b = /* @__PURE__ */ vue.defineComponent({
ref: slideFrameRef,
class: "uni-swiper-slide-frame",
style: slideFrameStyle.value
}, [swiperItems], 4)], 4), props2.indicatorDots && vue.createVNode("div", {
}, [defaultSlots], 4)], 4), props2.indicatorDots && vue.createVNode("div", {
class: ["uni-swiper-dots", props2.vertical ? "uni-swiper-dots-vertical" : "uni-swiper-dots-horizontal"]
}, [swiperContexts.value.map((_, index2, array) => vue.createVNode("div", {
onClick: () => onSwiperDotClick(index2),
......@@ -6980,7 +7176,7 @@ var index$8 = /* @__PURE__ */ vue.defineComponent({
};
}
});
const props$7 = /* @__PURE__ */ Object.assign({}, props$i, {
const props$7 = /* @__PURE__ */ Object.assign({}, props$j, {
placeholderClass: {
type: String,
default: "input-placeholder"
......@@ -9866,24 +10062,26 @@ var index = /* @__PURE__ */ vue.defineComponent({
exports.AsyncErrorComponent = index$1;
exports.AsyncLoadingComponent = index;
exports.Audio = _sfc_main$7;
exports.Button = index$o;
exports.Button = index$q;
exports.Canvas = _sfc_main$6;
exports.Checkbox = index$l;
exports.CheckboxGroup = index$n;
exports.Checkbox = index$n;
exports.CheckboxGroup = index$p;
exports.CoverImage = _sfc_main$1;
exports.CoverView = _sfc_main$2;
exports.Editor = index$k;
exports.Form = index$p;
exports.Icon = index$j;
exports.Image = index$i;
exports.Editor = index$m;
exports.Form = index$r;
exports.Icon = index$l;
exports.Image = index$k;
exports.Input = Input;
exports.Label = index$m;
exports.Label = index$o;
exports.LayoutComponent = LayoutComponent;
exports.Map = index$3;
exports.MovableArea = index$h;
exports.MovableView = index$g;
exports.MovableArea = index$j;
exports.MovableView = index$i;
exports.Navigator = _sfc_main$5;
exports.PageComponent = index$2;
exports.PickerView = index$h;
exports.PickerViewColumn = index$g;
exports.Progress = index$f;
exports.Radio = index$d;
exports.RadioGroup = index$e;
......@@ -9910,7 +10108,7 @@ exports.getStorageInfo = getStorageInfo;
exports.getStorageInfoSync = getStorageInfoSync;
exports.getStorageSync = getStorageSync;
exports.getSystemInfoSync = getSystemInfoSync;
exports.plugin = index$q;
exports.plugin = index$s;
exports.removeStorage = removeStorage;
exports.removeStorageSync = removeStorageSync;
exports.request = request;
......
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册