提交 8a656509 编写于 作者: D DCloud_LXH

feat(nvue): wip label、button、movable-view、picker-view

上级 bfb4ea4a
import { showPage } from '../../../helpers/page.js'
import { showPage } from '@dcloudio/uni-core'
import {
defineAsyncApi,
API_SCAN_CODE,
......
......@@ -4,7 +4,7 @@ import {
defineAsyncApi,
ChooseLocationProtocol,
} from '@dcloudio/uni-api'
import { showPage } from '../../../helpers/page'
import { showPage } from '@dcloudio/uni-core'
import { getStatusBarStyle } from '../../../helpers/statusBar'
export const chooseLocation = <API_TYPE_CHOOSE_LOCATION>defineAsyncApi(
......
......@@ -5,7 +5,7 @@ import {
OpenLocationProtocol,
OpenLocationOptions,
} from '@dcloudio/uni-api'
import { showPage } from '../../../helpers/page.js'
import { showPage } from '@dcloudio/uni-core'
export const openLocation = <API_TYPE_OPEN_LOCATION>defineAsyncApi(
API_OPEN_LOCATION,
......
......@@ -6,7 +6,7 @@ import {
} from '@dcloudio/uni-components'
import { useI18n, initI18nPickerMsgsOnce } from '@dcloudio/uni-core'
import { UniFormCtx, uniFormKey } from '@dcloudio/uni-components'
import { showPage, Page } from '../../../helpers/page'
import { showPage, Page } from '@dcloudio/uni-core'
import { getNavigationBarHeight } from '../../../helpers/navigationBar'
type Mode = 'selector' | 'multiSelector' | 'time' | 'date'
......
import { provide } from 'vue'
import { PolySymbol } from '@dcloudio/uni-core'
export const props = {
for: {
type: String,
default: '',
},
}
export const uniLabelKey = PolySymbol(__DEV__ ? 'uniLabel' : 'ul')
export interface UniLabelCtx {
addHandler: (handler: UniLabelHandlerCtx) => void
removeHandler: (handler: UniLabelHandlerCtx) => void
}
export type UniLabelHandlerCtx = ($event: Event, b: boolean) => void
export function useProvideLabel() {
const handlers: UniLabelHandlerCtx[] = []
provide<UniLabelCtx>(uniLabelKey, {
addHandler(handler: UniLabelHandlerCtx) {
handlers.push(handler)
},
removeHandler(handler: UniLabelHandlerCtx) {
handlers.splice(handlers.indexOf(handler), 1)
},
})
return handlers
}
import { ExtractPropTypes } from 'vue'
export const props = {
scaleArea: {
type: Boolean,
default: false,
},
}
export type Props = ExtractPropTypes<typeof props>
import { ExtractPropTypes } from 'vue'
import { Decline, Friction, STD } from './utils'
export { Decline, Friction, STD }
export const props = {
direction: {
type: String,
default: 'none',
},
inertia: {
type: [Boolean, String],
default: false,
},
outOfBounds: {
type: [Boolean, String],
default: false,
},
x: {
type: [Number, String],
default: 0,
},
y: {
type: [Number, String],
default: 0,
},
damping: {
type: [Number, String],
default: 20,
},
friction: {
type: [Number, String],
default: 2,
},
disabled: {
type: [Boolean, String],
default: false,
},
scale: {
type: [Boolean, String],
default: false,
},
scaleMin: {
type: [Number, String],
default: 0.5,
},
scaleMax: {
type: [Number, String],
default: 10,
},
scaleValue: {
type: [Number, String],
default: 1,
},
animation: {
type: [Boolean, String],
default: true,
},
}
export type Props = ExtractPropTypes<typeof props>
export type FrictionCallback = (friction: Friction | STD) => void
export type Record = {
id: number
cancelled: boolean
}
export function v(a: number, b: number) {
return +((1000 * a - 1000 * b) / 1000).toFixed(1)
}
......@@ -18,7 +18,7 @@ export function Friction(e, t) {
this._v = 0
}
Friction.prototype.setV = function (x, y) {
var n = Math.pow(Math.pow(x, 2) + Math.pow(y, 2), 0.5)
const n = Math.pow(Math.pow(x, 2) + Math.pow(y, 2), 0.5)
this._x_v = x
this._y_v = y
this._x_a = (-this._f * this._x_v) / n
......@@ -39,8 +39,8 @@ Friction.prototype.s = function (t) {
t = this._t
this._lastDt = t
}
var x = this._x_v * t + 0.5 * this._x_a * Math.pow(t, 2) + this._x_s
var y = this._y_v * t + 0.5 * this._y_a * Math.pow(t, 2) + this._y_s
let x = this._x_v * t + 0.5 * this._x_a * Math.pow(t, 2) + this._x_s
let y = this._y_v * t + 0.5 * this._y_a * Math.pow(t, 2) + this._y_s
if (
(this._x_a > 0 && x < this._endPositionX) ||
(this._x_a < 0 && x > this._endPositionX)
......@@ -80,7 +80,7 @@ Friction.prototype.dt = function () {
return -this._x_v / this._x_a
}
Friction.prototype.done = function () {
var t =
const t =
e(this.s().x, this._endPositionX) ||
e(this.s().y, this._endPositionY) ||
this._lastDt === this._t
......@@ -105,10 +105,10 @@ export function Spring(m, k, c) {
this._startTime = 0
}
Spring.prototype._solve = function (e, t) {
var n = this._c
var i = this._m
var r = this._k
var o = n * n - 4 * i * r
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
......@@ -118,7 +118,7 @@ Spring.prototype._solve = function (e, t) {
return (s + l * e) * Math.pow(Math.E, a * e)
},
dx: function (e) {
var t = Math.pow(Math.E, a * e)
const t = Math.pow(Math.E, a * e)
return a * (s + l * e) * t + l * t
},
}
......@@ -130,8 +130,8 @@ Spring.prototype._solve = function (e, t) {
const h = e - d
return {
x: function (e) {
var t
var n
let t
let n
if (e === this._t) {
t = this._powER1T
n = this._powER2T
......@@ -146,8 +146,8 @@ Spring.prototype._solve = function (e, t) {
return h * t + d * n
},
dx: function (e) {
var t
var n
let t
let n
if (e === this._t) {
t = this._powER1T
n = this._powER2T
......@@ -163,10 +163,10 @@ Spring.prototype._solve = function (e, t) {
},
}
}
var p = Math.sqrt(4 * i * r - n * n) / (2 * i)
var f = (-n / 2) * i
var v = e
var g = (t - f * e) / p
const p = Math.sqrt(4 * i * r - n * n) / (2 * i)
const f = (-n / 2) * i
const v = e
const g = (t - f * e) / p
return {
x: function (e) {
return (
......@@ -174,9 +174,9 @@ Spring.prototype._solve = function (e, t) {
)
},
dx: function (e) {
var t = Math.pow(Math.E, f * e)
var n = Math.cos(p * e)
var i = Math.sin(p * e)
const t = Math.pow(Math.E, f * e)
const n = Math.cos(p * e)
const i = Math.sin(p * e)
return t * (g * p * n - v * p * i) + f * t * (g * i + v * n)
},
}
......@@ -199,7 +199,7 @@ Spring.prototype.setEnd = function (e, n, i) {
}
if (e !== this._endPosition || !t(n, 0.1)) {
n = n || 0
var r = this._endPosition
let r = this._endPosition
if (this._solution) {
if (t(n, 0.1)) {
n = this._solution.dx((i - this._startTime) / 1e3)
......@@ -286,14 +286,14 @@ export function STD(e, t, n) {
this._startTime = 0
}
STD.prototype.setEnd = function (e, t, n, i) {
var r = new Date().getTime()
const r = new Date().getTime()
this._springX.setEnd(e, i, r)
this._springY.setEnd(t, i, r)
this._springScale.setEnd(n, i, r)
this._startTime = r
}
STD.prototype.x = function () {
var e = (new Date().getTime() - this._startTime) / 1e3
const e = (new Date().getTime() - this._startTime) / 1e3
return {
x: this._springX.x(e),
y: this._springY.x(e),
......@@ -301,7 +301,7 @@ STD.prototype.x = function () {
}
}
STD.prototype.done = function () {
var e = new Date().getTime()
const e = new Date().getTime()
return (
this._springX.done(e) && this._springY.done(e) && this._springScale.done(e)
)
......
import {
PropType,
ExtractPropTypes,
ComponentInternalInstance,
WritableComputedRef,
} from 'vue'
export 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: '',
},
}
export type Props = ExtractPropTypes<typeof props>
export type GetPickerViewColumn = (
columnInstance: ComponentInternalInstance
) => WritableComputedRef<number>
import { inject, onBeforeUnmount, ref, defineComponent, Text } from 'vue'
import { uniLabelKey, UniLabelCtx } from '../label'
import { useListeners } from '../../helpers/useListeners'
import { useHoverClass } from '../utils'
import { buttonProps } from '../../components/button'
import { extend } from '@vue/shared'
const buttonStyle = [
{
ub: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
position: 'relative',
paddingLeft: '5',
paddingRight: '5',
overflow: 'hidden',
color: '#000000',
backgroundColor: '#f8f8f8',
borderRadius: '5',
borderStyle: 'solid',
borderWidth: '1',
borderColor: '#dbdbdb',
},
'ub-t': {
color: '#000000',
fontSize: '18',
textDecoration: 'none',
lineHeight: '46',
},
'ub-d': {
backgroundColor: '#f8f8f8',
},
'ub-p': {
backgroundColor: '#007aff',
borderColor: '#0062cc',
},
'ub-w': {
backgroundColor: '#e64340',
borderColor: '#b83633',
},
'ub-d-t': {
color: '#000000',
},
'ub-p-t': {
color: '#ffffff',
},
'ub-w-t': {
color: '#ffffff',
},
'ub-d-d': {
backgroundColor: '#f7f7f7',
},
'ub-p-d': {
backgroundColor: '#63acfc',
borderColor: '#4f8aca',
},
'ub-w-d': {
backgroundColor: '#ec8b89',
borderColor: '#bd6f6e',
},
'ub-d-t-d': {
color: '#cccccc',
},
'ub-p-t-d': {
color: 'rgba(255,255,255,0.6)',
},
'ub-w-t-d': {
color: 'rgba(255,255,255,0.6)',
},
'ub-d-plain': {
borderColor: '#353535',
backgroundColor: 'rgba(0,0,0,0)',
},
'ub-p-plain': {
borderColor: '#007aff',
backgroundColor: 'rgba(0,0,0,0)',
},
'ub-w-plain': {
borderColor: '#e64340',
backgroundColor: 'rgba(0,0,0,0)',
},
'ub-d-t-plain': {
color: '#353535',
},
'ub-p-t-plain': {
color: '#007aff',
},
'ub-w-t-plain': {
color: '#e64340',
},
'ub-d-d-plain': {
borderColor: '#c6c6c6',
backgroundColor: 'rgba(0,0,0,0)',
},
'ub-p-d-plain': {
borderColor: '#c6c6c6',
backgroundColor: 'rgba(0,0,0,0)',
},
'ub-w-d-plain': {
borderColor: '#c6c6c6',
backgroundColor: 'rgba(0,0,0,0)',
},
'ub-d-t-d-plain': {
color: 'rgba(0,0,0,0.2)',
},
'ub-p-t-d-plain': {
color: 'rgba(0,0,0,0.2)',
},
'ub-w-t-d-plain': {
color: 'rgba(0,0,0,0.2)',
},
'ub-mini': {
lineHeight: '30',
fontSize: '13',
paddingTop: 0,
paddingRight: '17.5',
paddingBottom: 0,
paddingLeft: '17.5',
},
'ub-loading': {
width: '18',
height: '18',
marginRight: '10',
},
'ub-d-loading': {
color: 'rgba(255,255,255,0.6)',
backgroundColor: 'rgba(0,0,0,0)',
},
'ub-p-loading': {
color: 'rgba(255,255,255,0.6)',
backgroundColor: 'rgba(0,0,0,0)',
},
'ub-w-loading': {
color: 'rgba(255,255,255,0.6)',
backgroundColor: 'rgba(0,0,0,0)',
},
'ub-d-loading-plain': {
color: '#353535',
},
'ub-p-loading-plain': {
color: '#007aff',
backgroundColor: '#0062cc',
},
'ub-w-loading-plain': {
color: '#e64340',
backgroundColor: 'rgba(0,0,0,0)',
},
'ub-d-hover': {
opacity: 0.8,
backgroundColor: '#dedede',
},
'ub-p-hover': {
opacity: 0.8,
backgroundColor: '#0062cc',
},
'ub-w-hover': {
opacity: 0.8,
backgroundColor: '#ce3c39',
},
'ub-d-t-hover': {
color: 'rgba(0,0,0,0.6)',
},
'ub-p-t-hover': {
color: 'rgba(255,255,255,0.6)',
},
'ub-w-t-hover': {
color: 'rgba(255,255,255,0.6)',
},
'ub-d-hover-plain': {
color: 'rgba(53,53,53,0.6)',
borderColor: 'rgba(53,53,53,0.6)',
backgroundColor: 'rgba(0,0,0,0)',
},
'ub-p-hover-plain': {
color: 'rgba(26,173,25,0.6)',
borderColor: 'rgba(0,122,255,0.6)',
backgroundColor: 'rgba(0,0,0,0)',
},
'ub-w-hover-plain': {
color: 'rgba(230,67,64,0.6)',
borderColor: 'rgba(230,67,64,0.6)',
backgroundColor: 'rgba(0,0,0,0)',
},
},
]
const TYPES = {
default: 'd',
primary: 'p',
warn: 'w',
}
export default defineComponent({
name: 'Button',
props: extend(buttonProps, {
type: {
type: String,
default: 'default',
},
size: {
type: String,
default: 'default',
},
}),
styles: buttonStyle,
setup(props, { slots, attrs }) {
const type = props.type as keyof typeof TYPES
const rootRef = ref<HTMLElement | null>(null)
const onClick = (e: Event, isLabelClick?: boolean) => {
if (props.disabled) {
return
}
if (isLabelClick) {
rootRef.value!.click()
}
/* const formType = props.formType
if (formType) {
if (!uniForm) {
return
}
if (formType === 'submit') {
uniForm.submit(e)
} else if (formType === 'reset') {
uniForm.reset(e)
}
} */
}
const _getClass = (t: string) => {
let cl = 'ub-' + TYPES[type] + t
props.disabled && (cl += '-d')
props.plain && (cl += '-plain')
props.size === 'mini' && t === '-t' && (cl += ' ub-mini')
return cl
}
const _getHoverClass = (t: string) => {
if (props.disabled) {
return ''
}
let cl = 'ub-' + TYPES[type] + t + '-hover'
props.plain && (cl += '-plain')
return cl
}
const uniLabel = inject<UniLabelCtx>(
uniLabelKey,
false as unknown as UniLabelCtx
)
if (uniLabel) {
uniLabel.addHandler(onClick)
onBeforeUnmount(() => {
uniLabel.removeHandler(onClick)
})
}
useListeners(props, { 'label-click': onClick })
const wrapSlots = () => {
if (!slots.default) return []
const _slots = slots.default()
return _slots.map((slot) => {
if (slot.type === Text) {
return <text>{slot}</text>
}
return slot
})
}
return () => {
return (
<div
ref={rootRef}
class="ub"
// @ts-expect-error
class={_getClass('')}
{...extend({}, useHoverClass(props), {
hoverClass: _getHoverClass(''),
})}
onClick={onClick}
>
{props.loading ? (
<loading-indicator
class="ub-loading"
// @ts-expect-error
class={`ub-${TYPES[type]}-loading`}
{...{ arrow: 'false', animating: 'true' }}
></loading-indicator>
) : null}
{...wrapSlots()}
</div>
)
}
},
})
import Navigator from './navigator'
import Label from './label'
import Button from './button'
import MovableArea from './movable-area'
import MovableView from './movable-view'
export default {
Navigator,
/* Label,
Button,
MovableArea,
MovableView */
}
export function cached(fn: Function) {
const cache = Object.create(null)
return function cachedFn(str: string) {
const hit = cache[str]
return hit || (cache[str] = fn(str))
}
}
export const parseStyleText = cached(function (cssText: string) {
const res: Record<string, any> = {}
const listDelimiter = /;(?![^(]*\))/g
const propertyDelimiter = /:(.+)/
cssText.split(listDelimiter).forEach(function (item) {
if (item) {
const tmp = item.split(propertyDelimiter)
tmp.length > 1 && (res[tmp[0].trim()] = tmp[1].trim())
}
})
return res
})
export const firstLetterToLowerCase = cached((str: string) => {
return str.charAt(0).toLowerCase() + str.slice(1)
})
export function isDef(v: any) {
return typeof v !== 'undefined'
}
export function isFn(fn: any) {
return typeof fn === 'function'
}
export type Size = { width: number; height: number; top: number; left: number }
export const getComponentSize = (el: HTMLElement) => {
const dom = weex.requireModule('dom')
return new Promise<Size>((resolve) => {
dom.getComponentRect(el, ({ size }: { size: Size }) => {
resolve(size)
})
})
}
export * from './common'
export * from './dom'
import { defineComponent } from 'vue'
import { useCurrentPageId } from '@dcloudio/uni-core'
import { props, useProvideLabel } from '../../components/label'
export { UniLabelCtx, uniLabelKey } from '../../components/label'
type LabelTarget = HTMLElement & {
attr: { dataUncType: string }
}
export default defineComponent({
name: 'Label',
props,
styles: [],
setup(props, { slots }) {
const pageId = useCurrentPageId()
const handlers = useProvideLabel()
const _onClick = ($event: Event) => {
const EventTarget = $event.target as LabelTarget
const dataType = EventTarget.attr.dataUncType || ''
let stopPropagation = /^uni-(checkbox|radio|switch)-/.test(dataType)
if (!stopPropagation) {
stopPropagation = /^uni-(checkbox|radio|switch|button)$/i.test(dataType)
}
if (stopPropagation) {
return
}
if (props.for) {
UniViewJSBridge.emit(
`uni-label-click-${pageId}-${props.for}`,
$event,
true
)
} else {
handlers.length && handlers[0]($event, true)
}
}
return () => (
<div onClick={_onClick}>{slots.default && slots.default()}</div>
)
},
})
import { defineComponent, Ref, ref, onMounted, provide } from 'vue'
import { props } from '../../components/movable-area'
import { flatVNode } from '../../helpers/flatVNode'
import { TouchtrackEvent } from '../movable-view/useTouchtrack'
import { getComponentSize } from '../helpers'
export interface MovableViewContext {
setParent: Function
}
export type AddMovableViewContext = (context: MovableViewContext) => void
export type RemoveMovableViewContext = (context: MovableViewContext) => void
interface TouchMovableViewContext {
touchstart: (e: TouchtrackEvent) => void
touchmove: (e: TouchtrackEvent) => void
touchend: (e: TouchtrackEvent) => void
}
export type SetTouchMovableViewContext = (
context: TouchMovableViewContext | null
) => void
type RootRef = Ref<HTMLElement | null>
export interface parentSize {
width: Ref<number>
height: Ref<number>
top: Ref<number>
left: Ref<number>
}
export default defineComponent({
name: 'MovableArea',
props,
styles: [
{
'uni-movable-area': {
width: '10px',
height: '10px',
},
},
],
setup(props, { slots }) {
const width = ref(0)
const height = ref(0)
const top = ref(0)
const left = ref(0)
const _isMounted = ref(false)
const rootRef: RootRef = ref(null)
const originMovableViewContexts: MovableViewContext[] = []
let touchMovableView: null | TouchMovableViewContext = null
const setTouchMovableViewContext: SetTouchMovableViewContext = (
movableview
) => {
touchMovableView = movableview
}
const _getWH = () => {
return getComponentSize(rootRef.value!).then(
({ width: _width, height: _height, top: _top, left: _left }) => {
width.value = _width
height.value = _height
top.value = _top
left.value = _left
}
)
}
const _resize = () => {
_getWH().then(() => {
originMovableViewContexts.forEach(function (item) {
item.setParent()
})
})
}
onMounted(() => {
// 由于weex在mounted后渲染是异步的不能确保元素渲染完成,需要延迟执行
setTimeout(() => {
_isMounted.value = true
_resize()
}, 200)
})
const listeners = {
onPanstart(e: TouchtrackEvent) {
touchMovableView && touchMovableView.touchstart(e)
},
onPanmove(e: TouchtrackEvent) {
e.stopPropagation()
touchMovableView && touchMovableView.touchmove(e)
},
onPanend(e: TouchtrackEvent) {
touchMovableView && touchMovableView.touchend(e)
},
}
const addMovableViewContext: AddMovableViewContext = (
movableViewContext
) => {
originMovableViewContexts.push(movableViewContext)
}
const removeMovableViewContext: RemoveMovableViewContext = (
movableViewContext
) => {
const index = originMovableViewContexts.indexOf(movableViewContext)
if (index >= 0) {
originMovableViewContexts.splice(index, 1)
}
}
provide('_isMounted', _isMounted)
provide('parentSize', {
width: width,
height: height,
top: top,
left: left,
})
provide('addMovableViewContext', addMovableViewContext)
provide('removeMovableViewContext', removeMovableViewContext)
provide('setTouchMovableViewContext', setTouchMovableViewContext)
return () => {
const defaultSlots = slots.default && slots.default()
const movableViewItems = flatVNode(defaultSlots)
return (
<div class="uni-movable-area" {...listeners}>
{movableViewItems}
</div>
)
}
},
})
import {
defineComponent,
onMounted,
onUnmounted,
ref,
Ref,
computed,
inject,
watch,
} from 'vue'
import {
useTouchtrack,
touchstart,
touchmove,
touchend,
TouchtrackEvent,
} from './useTouchtrack'
import {
CustomEventTrigger,
EmitEvent,
useCustomEvent,
} from '../../helpers/useNvueEvent'
import {
MovableViewContext,
AddMovableViewContext,
RemoveMovableViewContext,
SetTouchMovableViewContext,
parentSize,
} from '../movable-area'
import {
Decline,
Friction,
STD,
props,
Props,
FrictionCallback,
Record,
v,
} from '../../components/movable-view'
import { getComponentSize } from '../helpers'
function g(
friction: Friction | STD,
execute: FrictionCallback,
endCallback: FrictionCallback
) {
let record: Record = {
id: 0,
cancelled: false,
}
let cancel = function (record: Record) {
if (record && record.id) {
cancelAnimationFrame(record.id)
}
if (record) {
record.cancelled = true
}
}
function fn(
record: Record,
friction: Friction | STD,
execute: FrictionCallback,
endCallback: FrictionCallback
) {
if (!record || !record.cancelled) {
execute(friction)
let isDone = friction.done()
if (!isDone) {
if (!record.cancelled) {
record.id = requestAnimationFrame(
fn.bind(null, record, friction, execute, endCallback)
)
}
}
if (isDone && endCallback) {
endCallback(friction)
}
}
}
fn(record, friction, execute, endCallback)
return {
cancel: cancel.bind(null, record),
model: friction,
}
}
let requesting = false
function _requestAnimationFrame(e: Function) {
if (!requesting) {
requesting = true
requestAnimationFrame(function () {
e()
requesting = false
})
}
}
function requestAnimationFrame(callback: Function) {
return setTimeout(callback, 16)
}
function cancelAnimationFrame(id: number) {
clearTimeout(id)
}
type ReturnType_g = ReturnType<typeof g> | null
type ScaleOffset = {
x: number
y: number
}
type MoveDirection = 'htouchmove' | 'vtouchmove'
type Size = { width: number; height: number; top: number; left: number }
type RootRef = Ref<HTMLElement | null>
const animation = weex.requireModule('animation')
export default defineComponent({
name: 'MovableView',
props,
emits: ['change', 'scale'],
styles: [
{
'uni-movable-view': {
position: 'absolute',
top: '0px',
left: '0px',
width: '10px',
height: '10px',
},
},
],
setup(props, { emit, slots }) {
const rootRef: RootRef = ref(null)
const trigger = useCustomEvent<EmitEvent<typeof emit>>(rootRef, emit)
const setTouchMovableViewContext: SetTouchMovableViewContext = inject(
'setTouchMovableViewContext',
() => {}
)
useMovableViewState(props, trigger, rootRef)
const touchStart = () => {
setTouchMovableViewContext({
touchstart,
touchmove,
touchend,
})
}
return () => {
const attrs = {
preventGesture: true,
}
return (
<div
ref={rootRef}
onTouchstart={touchStart}
class="uni-movable-view"
style="transform-origin: center;"
{...attrs}
>
{slots.default && slots.default()}
</div>
)
}
},
})
function useMovableViewState(
props: Props,
trigger: CustomEventTrigger,
rootRef: RootRef
) {
const _isMounted: Ref<boolean> = inject('_isMounted', ref(false))
const parentSize: parentSize = inject('parentSize', {
width: ref(0),
height: ref(0),
top: ref(0),
left: ref(0),
})
const addMovableViewContext: AddMovableViewContext = inject(
'addMovableViewContext',
() => {}
)
const removeMovableViewContext: RemoveMovableViewContext = inject(
'removeMovableViewContext',
() => {}
)
function _getPx(val: string | number) {
// if (/\d+[ur]px$/i.test(val)) {
// return uni.upx2px(parseFloat(val))
// }
return Number(val) || 0
}
function _getScaleNumber(val: number) {
val = Number(val)
return isNaN(val) ? 1 : val
}
const xSync = ref(_getPx(props.x))
const ySync = ref(_getPx(props.y))
const scaleValueSync = ref(_getScaleNumber(Number(props.scaleValue)))
const width = ref(0)
const height = ref(0)
const minX = ref(0)
const minY = ref(0)
const maxX = ref(0)
const maxY = ref(0)
let _SFA: ReturnType_g = null
let _FA: ReturnType_g = null
const _offset: ScaleOffset = {
x: 0,
y: 0,
}
const _scaleOffset: ScaleOffset = {
x: 0,
y: 0,
}
let _scale = 1
let _oldScale = 1
let _translateX = 0
let _translateY = 0
let _isScaling = false
let _isTouching = false
let __baseX: number
let __baseY: number
let _checkCanMove: boolean | null = null
let _firstMoveDirection: MoveDirection | null = null
let _rect: Size = {
top: 0,
left: 0,
width: 0,
height: 0,
}
const _declineX = new Decline()
const _declineY = new Decline()
const __touchInfo = {
historyX: [0, 0],
historyY: [0, 0],
historyT: [0, 0],
}
const dampingNumber = computed(() => {
let val = Number(props.damping)
return isNaN(val) ? 20 : val
})
const frictionNumber = computed(() => {
let val = Number(props.friction)
return isNaN(val) || val <= 0 ? 2 : val
})
const scaleMinNumber = computed(() => {
let val = Number(props.scaleMin)
return isNaN(val) ? 0.5 : val
})
const scaleMaxNumber = computed(() => {
let val = Number(props.scaleMax)
return isNaN(val) ? 10 : val
})
const xMove = computed(
() => props.direction === 'all' || props.direction === 'horizontal'
)
const yMove = computed(
() => props.direction === 'all' || props.direction === 'vertical'
)
const _STD = new STD(
1,
(9 * Math.pow(dampingNumber.value, 2)) / 40,
dampingNumber.value
)
const _friction = new Friction(1, frictionNumber.value)
watch(
() => props.x,
(val) => {
xSync.value = _getPx(val)
}
)
watch(
() => props.y,
(val) => {
ySync.value = _getPx(val)
}
)
watch(
() => props.scaleValue,
(val) => {
scaleValueSync.value = _getScaleNumber(Number(val))
}
)
watch(xSync, _setX)
watch(ySync, _setY)
watch(scaleValueSync, _setScaleValue)
watch(scaleMinNumber, _setScaleMinOrMax)
watch(scaleMaxNumber, _setScaleMinOrMax)
function FAandSFACancel() {
if (_FA) {
_FA.cancel()
}
if (_SFA) {
_SFA.cancel()
}
}
function _setX(val: number) {
if (xMove.value) {
if (val + _scaleOffset.x === _translateX) {
return _translateX
} else {
if (_SFA) {
_SFA.cancel()
}
_animationTo(val + _scaleOffset.x, ySync.value + _scaleOffset.y, _scale)
}
}
return val
}
function _setY(val: number) {
if (yMove.value) {
if (val + _scaleOffset.y === _translateY) {
return _translateY
} else {
if (_SFA) {
_SFA.cancel()
}
_animationTo(xSync.value + _scaleOffset.x, val + _scaleOffset.y, _scale)
}
}
return val
}
function _setScaleMinOrMax() {
if (!props.scale) {
return false
}
_updateScale(_scale, true)
_updateOldScale(_scale)
}
function _setScaleValue(scale: number) {
if (!props.scale) {
return false
}
scale = _adjustScale(scale)
_updateScale(scale, true)
_updateOldScale(scale)
return scale
}
function __handleTouchStart() {
if (!_isScaling) {
if (!props.disabled) {
FAandSFACancel()
__touchInfo.historyX = [0, 0]
__touchInfo.historyY = [0, 0]
__touchInfo.historyT = [0, 0]
if (xMove.value) {
__baseX = _translateX
}
if (yMove.value) {
__baseY = _translateY
}
_checkCanMove = null
_firstMoveDirection = null
_isTouching = true
}
}
}
function __handleTouchMove(event: TouchtrackEvent) {
if (!_isScaling && !props.disabled && _isTouching) {
let x = _translateX
let y = _translateY
if (_firstMoveDirection === null) {
_firstMoveDirection =
Math.abs(event.detail.dx / event.detail.dy) > 1
? 'htouchmove'
: 'vtouchmove'
}
if (xMove.value) {
x = event.detail.dx + __baseX
__touchInfo.historyX.shift()
__touchInfo.historyX.push(x)
if (!yMove.value && _checkCanMove === null) {
_checkCanMove = Math.abs(event.detail.dx / event.detail.dy) < 1
}
}
if (yMove.value) {
y = event.detail.dy + __baseY
__touchInfo.historyY.shift()
__touchInfo.historyY.push(y)
if (!xMove.value && _checkCanMove === null) {
_checkCanMove = Math.abs(event.detail.dy / event.detail.dx) < 1
}
}
__touchInfo.historyT.shift()
__touchInfo.historyT.push(event.detail.timeStamp)
if (!_checkCanMove) {
// event.preventDefault()
let source = 'touch'
if (x < minX.value) {
if (props.outOfBounds) {
source = 'touch-out-of-bounds'
x = minX.value - _declineX.x(minX.value - x)
} else {
x = minX.value
}
} else if (x > maxX.value) {
if (props.outOfBounds) {
source = 'touch-out-of-bounds'
x = maxX.value + _declineX.x(x - maxX.value)
} else {
x = maxX.value
}
}
if (y < minY.value) {
if (props.outOfBounds) {
source = 'touch-out-of-bounds'
y = minY.value - _declineY.x(minY.value - y)
} else {
y = minY.value
}
} else {
if (y > maxY.value) {
if (props.outOfBounds) {
source = 'touch-out-of-bounds'
y = maxY.value + _declineY.x(y - maxY.value)
} else {
y = maxY.value
}
}
}
_requestAnimationFrame(function () {
_setTransform(x, y, _scale, source)
})
}
}
}
function __handleTouchEnd() {
if (!_isScaling && !props.disabled && _isTouching) {
_isTouching = false
if (!_checkCanMove && !_revise('out-of-bounds') && props.inertia) {
const xv =
(1000 * (__touchInfo.historyX[1] - __touchInfo.historyX[0])) /
(__touchInfo.historyT[1] - __touchInfo.historyT[0])
const yv =
(1000 * (__touchInfo.historyY[1] - __touchInfo.historyY[0])) /
(__touchInfo.historyT[1] - __touchInfo.historyT[0])
_friction.setV(xv, yv)
_friction.setS(_translateX, _translateY)
const x0 = _friction.delta().x
const y0 = _friction.delta().y
let x = x0 + _translateX
let y = y0 + _translateY
if (x < minX.value) {
x = minX.value
y = _translateY + ((minX.value - _translateX) * y0) / x0
} else {
if (x > maxX.value) {
x = maxX.value
y = _translateY + ((maxX.value - _translateX) * y0) / x0
}
}
if (y < minY.value) {
y = minY.value
x = _translateX + ((minY.value - _translateY) * x0) / y0
} else {
if (y > maxY.value) {
y = maxY.value
x = _translateX + ((maxY.value - _translateY) * x0) / y0
}
}
_friction.setEnd(x, y)
_FA = g(
_friction,
function () {
let t = _friction.s()
let x = t.x
let y = t.y
_setTransform(x, y, _scale, 'friction')
},
function () {
_FA!.cancel()
}
)
}
}
}
function _getLimitXY(x: number, y: number) {
let outOfBounds = false
if (x > maxX.value) {
x = maxX.value
outOfBounds = true
} else {
if (x < minX.value) {
x = minX.value
outOfBounds = true
}
}
if (y > maxY.value) {
y = maxY.value
outOfBounds = true
} else {
if (y < minY.value) {
y = minY.value
outOfBounds = true
}
}
return {
x,
y,
outOfBounds,
}
}
function _updateOffset() {
_offset.x = _rect.left - parentSize.left.value
_offset.y = _rect.top - parentSize.top.value
}
function _updateWH(scale: number) {
scale = scale || _scale
scale = _adjustScale(scale)
height.value = _rect.height / _scale
width.value = _rect.width / _scale
let _height = height.value * scale
let _width = width.value * scale
_scaleOffset.x = (_width - width.value) / 2
_scaleOffset.y = (_height - height.value) / 2
}
function _updateBoundary() {
let x = 0 - _offset.x + _scaleOffset.x
let _width =
parentSize.width.value - width.value - _offset.x - _scaleOffset.x
minX.value = Math.min(x, _width)
maxX.value = Math.max(x, _width)
let y = 0 - _offset.y + _scaleOffset.y
let _height =
parentSize.height.value - height.value - _offset.y - _scaleOffset.y
minY.value = Math.min(y, _height)
maxY.value = Math.max(y, _height)
}
function _beginScale() {
_isScaling = true
}
function _updateScale(scale: number, animat?: boolean) {
if (props.scale) {
scale = _adjustScale(scale)
_updateWH(scale)
_updateBoundary()
const limitXY = _getLimitXY(_translateX, _translateY)
const x = limitXY.x
const y = limitXY.y
if (animat) {
_animationTo(x, y, scale, '', true, true)
} else {
_requestAnimationFrame(function () {
_setTransform(x, y, scale, '', true, true)
})
}
}
}
function _updateOldScale(scale: number) {
_oldScale = scale
}
function _adjustScale(scale: number) {
scale = Math.max(0.5, scaleMinNumber.value, scale)
scale = Math.min(10, scaleMaxNumber.value, scale)
return scale
}
function _animationTo(
x: number,
y: number,
scale: number,
source?: number | string,
r?: boolean,
o?: boolean
) {
FAandSFACancel()
if (!xMove.value) {
x = _translateX
}
if (!yMove.value) {
y = _translateY
}
if (!props.scale) {
scale = _scale
}
let limitXY = _getLimitXY(x, y)
x = limitXY.x
y = limitXY.y
if (!props.animation) {
_setTransform(x, y, scale, source, r, o)
return
}
_STD._springX._solution = null
_STD._springY._solution = null
_STD._springScale._solution = null
_STD._springX._endPosition = _translateX
_STD._springY._endPosition = _translateY
_STD._springScale._endPosition = _scale
_STD.setEnd(x, y, scale, 1)
_SFA = g(
_STD,
function () {
let data = _STD.x()
let x = data.x
let y = data.y
let scale = data.scale
_setTransform(x, y, scale, source, r, o)
},
function () {
_SFA!.cancel()
}
)
}
function _revise(source: number | string) {
let limitXY = _getLimitXY(_translateX, _translateY)
let x = limitXY.x
let y = limitXY.y
let outOfBounds = limitXY.outOfBounds
if (outOfBounds) {
_animationTo(x, y, _scale, source)
}
return outOfBounds
}
function _setTransform(
x: number,
y: number,
scale: number,
source: string | number = '',
r?: boolean,
o?: boolean
) {
if (!(x !== null && x.toString() !== 'NaN' && typeof x === 'number')) {
x = _translateX || 0
}
if (!(y !== null && y.toString() !== 'NaN' && typeof y === 'number')) {
y = _translateY || 0
}
x = Number(x.toFixed(1))
y = Number(y.toFixed(1))
scale = Number(scale.toFixed(1))
if (!(_translateX === x && _translateY === y)) {
if (!r) {
trigger('change', {
x: v(x, _scaleOffset.x),
y: v(y, _scaleOffset.y),
source: source,
})
}
}
if (!props.scale) {
scale = _scale
}
scale = _adjustScale(scale)
scale = +scale.toFixed(3)
if (o && scale !== _scale) {
trigger('scale', {
x: x,
y: y,
scale: scale,
})
}
const transform = `translate(${x}px, ${y}px) scale(${scale})`
animation.transition(rootRef.value, {
styles: {
transform,
},
duration: 0,
delay: 0,
})
_translateX = x
_translateY = y
_scale = scale
}
function _updateRect() {
return getComponentSize(rootRef.value!).then((rect: Size) => {
_rect = rect
})
}
function setParent() {
if (!_isMounted.value) {
return
}
FAandSFACancel()
let scale = props.scale ? scaleValueSync.value : 1
_updateOffset()
_updateWH(scale)
_updateBoundary()
_translateX = xSync.value + _scaleOffset.x
_translateY = ySync.value + _scaleOffset.y
let limitXY = _getLimitXY(_translateX, _translateY)
let x = limitXY.x
let y = limitXY.y
_setTransform(x, y, scale, '', true)
_updateOldScale(scale)
}
onMounted(() => {
useTouchtrack((event) => {
switch (event.detail.state) {
case 'start':
__handleTouchStart()
break
case 'move':
__handleTouchMove(event)
break
case 'end':
__handleTouchEnd()
}
})
setTimeout(() => {
_updateRect().then(() => {
setParent()
})
}, 100)
_friction.reconfigure(1, frictionNumber.value)
_STD.reconfigure(
1,
(9 * Math.pow(dampingNumber.value, 2)) / 40,
dampingNumber.value
)
const context: MovableViewContext = {
setParent,
}
addMovableViewContext(context)
onUnmounted(() => {
removeMovableViewContext(context)
})
})
onUnmounted(() => {
FAandSFACancel()
})
}
type State = 'start' | 'move' | 'end' | 'cancel'
type TouchOrMouseEvent = TouchEvent | MouseEvent
type Detail = {
state: State
x: number
y: number
dx: number
dy: number
ddx: number
ddy: number
timeStamp: Event['timeStamp']
}
type CallbackType = 'touchstart' | 'touchmove' | 'touchend'
export interface TouchtrackEvent {
target: Event['target']
currentTarget: Event['currentTarget']
preventDefault?: Event['preventDefault']
stopPropagation: Event['stopPropagation']
touches: TouchEvent['touches']
changedTouches: TouchEvent['changedTouches']
detail: Detail
}
const __event: Record<string, Function> = {}
function callback(type: CallbackType, $event: TouchtrackEvent) {
if (__event[type]) {
__event[type]($event)
}
}
function addListener(type: CallbackType, callback: Function) {
__event[type] = function ($event: TouchtrackEvent) {
if (typeof callback === 'function') {
$event.touches = $event.changedTouches
if (callback($event) === false) {
$event.stopPropagation()
}
}
}
}
export function touchstart($event: TouchtrackEvent) {
callback('touchstart', $event)
}
export function touchmove($event: TouchtrackEvent) {
callback('touchmove', $event)
}
export function touchend($event: TouchtrackEvent) {
callback('touchend', $event)
}
export function useTouchtrack(
method: (event: TouchtrackEvent) => boolean | void
) {
let x0 = 0
let y0 = 0
let x1 = 0
let y1 = 0
const fn = function (
$event: TouchOrMouseEvent,
state: State,
x: number,
y: number
) {
if (
method({
target: $event.target,
currentTarget: $event.currentTarget,
stopPropagation: $event.stopPropagation.bind($event),
touches: ($event as TouchEvent).touches,
changedTouches: ($event as TouchEvent).changedTouches,
detail: {
state,
x,
y,
dx: x - x0,
dy: y - y0,
ddx: x - x1,
ddy: y - y1,
timeStamp: $event.timeStamp || Date.now(),
},
}) === false
) {
return false
}
}
let $eventOld: TouchOrMouseEvent | null = null
addListener('touchstart', function ($event: TouchEvent) {
if (!$eventOld) {
$eventOld = $event
x0 = x1 = $event.touches[0].pageX
y0 = y1 = $event.touches[0].pageY
return fn($event, 'start', x0, y0)
}
})
addListener('touchmove', function ($event: TouchEvent) {
if ($eventOld) {
const res = fn(
$event,
'move',
$event.touches[0].pageX,
$event.touches[0].pageY
)
x1 = $event.touches[0].pageX
y1 = $event.touches[0].pageY
return res
}
})
addListener('touchend', function ($event: TouchEvent) {
if ($eventOld) {
$eventOld = null
return fn(
$event,
'end',
$event.changedTouches[0].pageX,
$event.changedTouches[0].pageY
)
}
})
}
import {
defineComponent,
inject,
ref,
Ref,
watch,
VNode,
computed,
getCurrentInstance,
onMounted,
} from 'vue'
import { extend } from '@vue/shared'
import { Props, GetPickerViewColumn } from '../picker-view'
import { parseStyleText, getComponentSize } from '../helpers'
type ScrollOptions = {
showScrollbar: boolean
scrollToBegin: boolean
decelerationRate: number
scrollY: boolean
scrollTop?: number
}
const dom = weex.requireModule('dom')
const isAndroid = weex.config.env.platform.toLowerCase() === 'android'
function getStyle(val: string) {
return extend({}, typeof val === 'string' ? parseStyleText(val) : val)
}
export default defineComponent({
name: 'PickerViewColumn',
props: {
length: {
type: [Number, String],
default: 0,
},
},
data: () => ({
_isMounted: false,
}),
setup(props, { slots }) {
const instance = getCurrentInstance()!
const rootRef: Ref<HTMLElement | null> = ref(null)
const contentRef: Ref<HTMLElement | null> = ref(null)
const scrollViewItemRef: Ref<HTMLElement | null> = ref(null)
const indicatorRef: Ref<HTMLElement | null> = ref(null)
const pickerViewProps = inject<Props>('pickerViewProps')!
const getPickerViewColumn = inject<GetPickerViewColumn>(
'getPickerViewColumn',
() => computed({ set: () => {}, get: () => 0 })
)
const current = getPickerViewColumn(instance)
const indicatorStyle = computed(() =>
getStyle(pickerViewProps.indicatorStyle)
)
const maskStyle = computed(() => getStyle(pickerViewProps.maskStyle))
let indicatorHeight = getHeight(indicatorStyle)
let pickerViewHeight = parseFloat(pickerViewProps.height as string)
watch(
() => props.length,
() => {
setTimeout(() => {
setCurrent(current.value, true, true)
}, 150)
}
)
let scrollToElementTime: number
const setCurrent = (_current: number, animated = true, force: Boolean) => {
if (current.value === _current && !force) {
return
}
dom.scrollToElement(contentRef.value, {
offset: _current * indicatorHeight,
animated,
})
current.value = _current
if (animated) {
scrollToElementTime = Date.now()
}
}
const onScrollend = (event: { detail: Record<string, any> }) => {
if (Date.now() - scrollToElementTime < 340) {
return
}
const y = event.detail.contentOffset.y
const _current = Math.round(y / indicatorHeight)
if (y % indicatorHeight) {
setCurrent(_current, true, true)
} else {
current.value = _current
}
}
const checkMounted = () => {
let height_: number
let indicatorHeight_: number
setTimeout(() => {
Promise.all([
getComponentSize(rootRef.value!).then(({ height }) => {
height_ = pickerViewHeight = height
}),
isAndroid && props.length
? getComponentSize(scrollViewItemRef.value!).then(({ height }) => {
indicatorHeight_ = indicatorHeight =
height / parseFloat(props.length as string)
})
: getComponentSize(indicatorRef.value!).then(({ height }) => {
indicatorHeight_ = indicatorHeight = height
}),
]).then(() => {
if (height_ && indicatorHeight_) {
// 初始化时iOS直接滚动经常出错
setTimeout(() => {
setCurrent(current.value, false, true)
instance.data._isMounted = true
}, 50)
} else {
checkMounted()
}
})
}, 50)
}
onMounted(checkMounted)
const createScrollViewChild = (item?: VNode[]) => {
if (!item) return null
return isAndroid ? (
<div ref={scrollViewItemRef} style="flex-direction:column;">
{item}
</div>
) : (
item
)
}
return () => {
const children = slots.default && slots.default()
let padding = (pickerViewHeight - indicatorHeight) / 2
const maskPosition = `${pickerViewHeight - padding}px`
const scrollOptions: ScrollOptions = {
showScrollbar: false,
scrollToBegin: false,
decelerationRate: 0.3,
scrollY: true,
}
if (!isAndroid) {
scrollOptions.scrollTop = current.value * indicatorHeight
}
return (
<div ref={rootRef} class="uni-picker-view-column">
<scroll-view
class="uni-picker-view-group"
style="flex-direction:column;"
onScrollend={onScrollend}
{...scrollOptions}
>
<div
ref={contentRef}
class="uni-picker-view-content"
style={{
flexDirection: 'column',
paddingTop: `${padding}px`,
paddingBottom: `${padding}px`,
}}
>
{createScrollViewChild(children)}
</div>
</scroll-view>
<u-scalable class="uni-picker-view-mask" style={maskStyle}>
<u-scalable
class="uni-picker-view-mask uni-picker-view-mask-top"
style={{
bottom: maskPosition,
}}
></u-scalable>
<u-scalable
class="uni-picker-view-mask uni-picker-view-mask-bottom"
style={{
top: maskPosition,
}}
></u-scalable>
</u-scalable>
<u-scalable
ref={indicatorRef}
class="uni-picker-view-indicator"
style={extend({}, indicatorStyle.value, {
top: `${padding}px`,
})}
></u-scalable>
</div>
)
}
},
styles: [
{
'uni-picker-view-column': {
flex: 1,
position: 'relative',
alignItems: 'stretch',
overflow: 'hidden',
},
'uni-picker-view-mask': {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
pointerEvents: 'none',
},
'uni-picker-view-mask-top': {
bottom: 0,
backgroundImage:
'linear-gradient(to bottom,rgba(255, 255, 255, 0.95),rgba(255, 255, 255, 0.6))',
},
'uni-picker-view-mask-bottom': {
top: 0,
backgroundImage:
'linear-gradient(to top,rgba(255, 255, 255, 0.95),rgba(255, 255, 255, 0.6))',
},
'uni-picker-view-group': {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
},
'uni-picker-view-content': {
paddingTop: 0,
paddingRight: 0,
paddingBottom: 0,
paddingLeft: 0,
},
'uni-picker-view-indicator': {
position: 'absolute',
left: 0,
right: 0,
top: 0,
height: '34px',
pointerEvents: 'none',
borderColor: '#e5e5e5',
borderTopWidth: '1px',
borderBottomWidth: '1px',
},
},
],
})
function getHeight(style: Record<string, any>) {
const height = style.height || style.lineHeight || ''
const res = height.match(/(-?[\d\.]+)px/)
let value = 0
if (res) {
value = parseFloat(res[1])
}
return value
}
import {
defineComponent,
computed,
watch,
ref,
Ref,
reactive,
VNode,
provide,
ExtractPropTypes,
} from 'vue'
import { extend } from '@vue/shared'
import { props, GetPickerViewColumn } from '../../components/picker-view'
import { flatVNode } from '../../helpers/flatVNode'
import { useCustomEvent, EmitEvent } from '../../helpers/useNvueEvent'
export { Props, GetPickerViewColumn }
const pickerViewProps = extend({}, props, {
height: {
type: [Number, String],
default: 0,
},
})
type Props = ExtractPropTypes<typeof pickerViewProps>
export default defineComponent({
name: 'PickerView',
props: pickerViewProps,
emits: ['change', 'update:value'],
setup(props, { slots, emit }) {
const rootRef: Ref<HTMLElement | null> = ref(null)
const state = useState(props)
const trigger = useCustomEvent<EmitEvent<typeof emit>>(rootRef, emit)
let columnVNodes: VNode[] = []
const getItemIndex = (vnode: VNode) =>
Array.prototype.indexOf.call(columnVNodes, vnode.el)
const getPickerViewColumn: GetPickerViewColumn = (columnInstance) => {
return computed({
get() {
const index = getItemIndex(columnInstance.vnode)
return state.value[index] || 0
},
set(current: number) {
if (!columnInstance.data._isMounted) return
const index = getItemIndex(columnInstance.vnode)
if (index < 0) {
return
}
const oldCurrent = state.value[index]
if (oldCurrent !== current) {
state.value[index] = current
// 避免外部直接对此值进行修改
const value = state.value.map((val) => val)
emit('update:value', value)
trigger('change', {
value,
})
}
},
})
}
provide('getPickerViewColumn', getPickerViewColumn)
provide('pickerViewProps', props)
return () => {
const defaultSlots = slots.default && slots.default()
columnVNodes = flatVNode(defaultSlots)
return (
<div
ref={rootRef}
class="uni-picker-view"
{...{
preventGesture: true,
}}
>
<div class="uni-picker-view-wrapper">{defaultSlots}</div>
</div>
)
}
},
styles: [
{
'uni-picker-view': {
position: 'relative',
},
'uni-picker-view-wrapper': {
display: 'flex',
flexDirection: 'row',
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
overflow: 'hidden',
},
},
],
})
function useState(props: Props) {
const value: number[] = reactive([...props.value])
const state = reactive({
value,
})
watch(
() => props.value,
(val) => {
state.value.length = val.length
val.forEach((val, index) => {
if (val !== state.value[index]) {
state.value.splice(index, 1, val)
}
})
}
)
return state
}
import { provide, computed } from 'vue'
import { PolySymbol, useCurrentPageId } from '@dcloudio/uni-core'
import { computed } from 'vue'
import { useCurrentPageId } from '@dcloudio/uni-core'
import { withWebEvent } from '../../helpers/useEvent'
import { defineBuiltInComponent } from '../../helpers/component'
export const uniLabelKey = PolySymbol(__DEV__ ? 'uniLabel' : 'ul')
const props = {
for: {
type: String,
default: '',
},
}
import { props, useProvideLabel } from '../../components/label'
export { UniLabelCtx, uniLabelKey } from '../../components/label'
export default /*#__PURE__*/ defineBuiltInComponent({
name: 'Label',
......@@ -55,24 +51,3 @@ export default /*#__PURE__*/ defineBuiltInComponent({
)
},
})
export interface UniLabelCtx {
addHandler: (handler: UniLabelHandlerCtx) => void
removeHandler: (handler: UniLabelHandlerCtx) => void
}
type UniLabelHandlerCtx = ($event: Event, b: boolean) => void
function useProvideLabel() {
const handlers: UniLabelHandlerCtx[] = []
provide<UniLabelCtx>(uniLabelKey, {
addHandler(handler: UniLabelHandlerCtx) {
handlers.push(handler)
},
removeHandler(handler: UniLabelHandlerCtx) {
handlers.splice(handlers.indexOf(handler), 1)
},
})
return handlers
}
import {
ref,
ExtractPropTypes,
reactive,
Ref,
onMounted,
VNode,
markRaw,
provide,
} from 'vue'
import { ref, reactive, Ref, onMounted, VNode, markRaw, provide } from 'vue'
import { defineBuiltInComponent } from '../../helpers/component'
import { withWebEvent } from '../../helpers/useEvent'
import { useAttrs } from '../../helpers/useAttrs'
......@@ -15,15 +6,8 @@ import { initScrollBounce, disableScrollBounce } from '../../helpers/scroll'
import ResizeSensor from '../resize-sensor/index'
import { flatVNode } from '../../helpers/flatVNode'
import { useRebuild } from '../../helpers/useRebuild'
import { props, Props } from '../../components/movable-area'
const props = {
scaleArea: {
type: Boolean,
default: false,
},
}
type Props = ExtractPropTypes<typeof props>
type _TouchEvent = '_onTouchstart' | '_onTouchmove' | '_onTouchend'
export interface MovableViewContext {
rootRef: Ref<HTMLElement | null>
......
import {
ref,
ExtractPropTypes,
Ref,
onMounted,
inject,
computed,
watch,
onUnmounted,
} from 'vue'
import { ref, Ref, onMounted, inject, computed, watch, onUnmounted } from 'vue'
import { defineBuiltInComponent } from '../../helpers/component'
import { initScrollBounce, disableScrollBounce } from '../../helpers/scroll'
import { useTouchtrack, TouchtrackEvent } from '../../helpers/useTouchtrack'
......@@ -22,64 +13,17 @@ import type {
AddMovableViewContext,
RemoveMovableViewContext,
} from '../movable-area/index'
import { Decline, Friction, STD } from './utils'
const props = {
direction: {
type: String,
default: 'none',
},
inertia: {
type: [Boolean, String],
default: false,
},
outOfBounds: {
type: [Boolean, String],
default: false,
},
x: {
type: [Number, String],
default: 0,
},
y: {
type: [Number, String],
default: 0,
},
damping: {
type: [Number, String],
default: 20,
},
friction: {
type: [Number, String],
default: 2,
},
disabled: {
type: [Boolean, String],
default: false,
},
scale: {
type: [Boolean, String],
default: false,
},
scaleMin: {
type: [Number, String],
default: 0.5,
},
scaleMax: {
type: [Number, String],
default: 10,
},
scaleValue: {
type: [Number, String],
default: 1,
},
animation: {
type: [Boolean, String],
default: true,
},
}
import {
Decline,
Friction,
STD,
props,
Props,
FrictionCallback,
Record,
v,
} from '../../components/movable-view'
type Props = ExtractPropTypes<typeof props>
type RootRef = Ref<HTMLElement | null>
export default /*#__PURE__*/ defineBuiltInComponent({
......@@ -127,14 +71,6 @@ function f(t: HTMLElement, n: HTMLElement): number {
let i = t.offsetTop
return t.offsetParent ? (i += f(t.offsetParent as HTMLElement, n)) : 0
}
function v(a: number, b: number) {
return +((1000 * a - 1000 * b) / 1000).toFixed(1)
}
type FrictionCallback = (friction: Friction | STD) => void
type Record = {
id: number
cancelled: boolean
}
function g(
friction: Friction | STD,
execute: FrictionCallback,
......
......@@ -8,8 +8,6 @@ import {
reactive,
VNode,
SetupContext,
PropType,
ComponentInternalInstance,
onMounted,
ComponentPublicInstance,
nextTick,
......@@ -20,39 +18,9 @@ import { flatVNode } from '../../helpers/flatVNode'
import { useRebuild } from '../../helpers/useRebuild'
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: '',
},
}
export type Props = Record<keyof typeof props, any>
import { props } from '../../components/picker-view'
import type { Props, GetPickerViewColumn } from '../../components/picker-view'
export { Props, GetPickerViewColumn }
export interface State {
value: number[]
height: number
......@@ -84,10 +52,6 @@ function useState(props: Props): State {
return state
}
export type GetPickerViewColumn = (
columnInstance: ComponentInternalInstance
) => WritableComputedRef<number>
export default /*#__PURE__*/ defineBuiltInComponent({
name: 'PickerView',
props,
......
......@@ -11,6 +11,7 @@ export default defineConfig({
root: __dirname,
define: {
global: 'window',
__DEV__: `(process.env.NODE_ENV !== 'production')`,
},
resolve: {
alias: [
......@@ -25,12 +26,21 @@ export default defineConfig({
lib: {
name: 'components',
entry: path.resolve(__dirname, 'src/nvue/components.ts'),
formats: ['es'],
formats: ['iife'],
},
rollupOptions: {
external: ['uni', 'vue', 'weex', '@vue/shared', '@dcloudio/uni-shared'],
external: ['uni', 'vue', 'weex', '@vue/shared'],
output: {
banner:
'export function initComponents({uni,Vue,weex,plus,BroadcastChannel,UniViewJSBridge,VueShared}) {',
footer: 'return components\n}',
entryFileNames: 'components.js',
globals: {
uni: 'uni',
vue: 'Vue',
weex: 'weex',
'@vue/shared': 'VueShared',
},
},
},
},
......
......@@ -6,3 +6,4 @@ export * from './hook'
export * from './scroll'
export * from './route'
export * from './callbacks'
export * from './showPage'
......@@ -3664,7 +3664,6 @@ packages:
/at-least-node/1.0.0:
resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==}
engines: {node: '>= 4.0.0'}
dev: true
/atob/2.1.2:
resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==}
......@@ -5539,9 +5538,10 @@ packages:
engines: {node: '>= 0.6'}
/fs-extra/10.0.0:
resolution: {integrity: sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==}
engines: {node: '>=12'}
resolution: {integrity: sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==, tarball: fs-extra/-/fs-extra-10.0.0.tgz}
engines: {node: '>=10'}
dependencies:
at-least-node: 1.0.0
graceful-fs: 4.2.8
jsonfile: 6.1.0
universalify: 2.0.0
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册