仿 iOS UIPickerView 的滚动选择器
npm install woby-wheeler
pnpm dev
`
安装
$3
`sh
npm install woby-wheeler --save
`
$3
`html
`
使用
`ts
import { Wheeler } from "woby-wheeler"
import { $, $$, Observable, render, useMemo, useEffect, ObservableMaybe, isObservable, type JSX } from "woby"
import data from './data.json'
import { Data } from "src/Wheel"
import './dist/output.css'
import { DateWheeler } from "./src/DateWheeler"
const v1 = () => {
const stv = [$('草莓')]
useEffect(() => console.log('Single changed', stv[0]()))
const fruits = ["西瓜,柠檬,草莓,荔枝,橘子,菠萝,香蕉,柚子,苹果,龙眼".split(",")]
const sshown = $(false)
return <>
stv.map(v => v() + '')} onClick={() => sshown(true)} >
title={< h1 > 单列选择器 < button onClick={e => stv0} > 香蕉}
data={fruits}
value={stv as any}
rows={6}
hideOnBackdrop
open={sshown}
toolbar
/>
>
}
const v2 = () => {
const fruits = "西瓜,柠檬,草莓,荔枝,橘子,菠萝,香蕉,柚子,苹果,龙眼".split(",")
const frutisEn = "watermelon,lemon,strawberry,litchi,orange,pineapple,banana,grapefruit,apple,longan".split(",")
const frutiData = $(fruits.map((name, idx) => ({
text: name,
value: frutisEn[idx]
})))
const mshown = $(false)
const vegetables = "香菜,青菜,芦笋,萝卜,水芹,黄瓜,冬瓜,番茄,茄子,土豆".split(",")
const vegetablesEn = "parsley,celery,asparagus,carrot,celery,cucumber,melon,tomato,eggplant,potato".split(",")
const vegetableData = $(vegetables.map((name, idx) => ({
text: name,
value: vegetablesEn[idx]
})))
const mtv = [$('lemon'), $('carrot')]
useEffect(() => console.log('Multiple changed', mtv[0](), mtv[1]()))
const valuer = [r => r.value, r => r.value]
return <>
mtv.map((v, i) => $$(v))} onClick={() => mshown(true)} >
data={[frutiData, vegetableData]}
value={mtv}
renderer={[r => r.text, r => r.text]}
valuer={[r => r.value, r => r.value]}
open={mshown}
toolbar
/>>
}
const v3 = () => {
let defaultProv = Object.keys(data)[0]
const keys = Object.keys(data)
const cshown = $(false)
Object.keys(data).forEach(k => {
keys[k] = Object.keys(data[k])
Object.keys(data[k]).forEach(kk => {
keys[k][kk] = data[k][kk]
})
})
const dt = [
$(Object.keys(data)), //state
$(keys[defaultProv]), //Object.keys(data[defaultProv]), //city
$(keys[defaultProv][keys[defaultProv][0]])//data[defaultProv][Object.keys(data[defaultProv])[0]] //district
] as const
const value = [$(), $(), $()]
const empty = []
// useEffect(() => { console.log('dv', dv[0](), dv[1](), dv[2]()) })
useEffect(() => {
let l1 = keys[value[0]() + ''] ?? empty
if (!(value[1]()?.valueOf()))
value1
let l2 = l1[value[1]() + ''] ?? empty
const d = dt
if (d[1]() !== l1 || d[2]() !== l2)
if (d[1]() !== l1 || d[2]() !== l2) {
d1
if (d[2] !== l2)
d2
const i1 = d[1]().indexOf(value[1]() + '') === -1
const i2 = d[2]().indexOf(value[2]() + '') === -1
if (i1 || i2) {
// dv0)
if (i1)
/ dv1[0]) //)
if (i2)
/ dv2[0]) //)
}
}
})
return <>
value.map(v => v() + '')} onClick={() => cshown(true)} >
data={dt as any}
value={value}
resetSelectedOnDataChanged
hideOnBackdrop
onShow={() => {
console.log("onShow")
}}
onCancel={() => {
console.log("onCancel")
}}
open={cshown}
toolbar
/>>
}
const CloseCircle = (props: JSX.SVGAttributes) =>
const CheckChip = () => {
const selectAll = $(false)
const fruits = [$([
// { text: '', value: '西瓜', checked: selectAll, readonly: $(false), valueOf: () => '', toString: () => '*' },
{ text: '西瓜...', value: '西瓜', checked: $(false), readonly: $(true) },
{ text: '柠檬', value: '柠檬', checked: $(false), readonly: $(true) },
{ text: '...草莓', value: '草莓', checked: $(false), readonly: $(false) },
{ text: '荔枝', value: '荔枝', checked: $(false), readonly: $(false) },
{ text: '橘子..', value: '橘子', checked: $(false), readonly: $(false) },
{ text: '菠萝', value: '菠萝', checked: $(false), readonly: $(false) },
{ text: '....香蕉', value: '香蕉', checked: $(false), readonly: $(false) },
{ text: '柚子', value: '柚子', checked: $(false), readonly: $(false) },
{ text: '苹果', value: '苹果', checked: $(false), readonly: $(false) },
{ text: '龙眼....', value: '龙眼', checked: $(false), readonly: $(false) }
])]
const stv = [$(fruits[0][2])]
let suspense = false
useEffect(() => {
if (!suspense)
$$(fruits[0]).forEach((r: Data) => r.checked($$(selectAll)))
})
useEffect(() => {
if ($$(fruits[0]).some((r: Data) => !$$(r.checked) || r.text === '*')) {
suspense = true
selectAll(false)
}
})
const sshown = $(false)
return <>
sshown(true)}>
{() => $$(fruits[0]).map(f => $$(f.checked) ? bg-[#0096fb] inline-flex items-center text-[13px] leading-[19px] text-white whitespace-nowrap mr-[5px] px-2.5 py-1 rounded-[11px],]}>{f.text}
{() => !$$(f.readonly) ? class="icon_cancel closeIcon h-[13px] w-[13px] float-right cursor-pointer ml-[5px] fill-[white]"
onClick={e => { e.cancelBubble = true; f.checked(false) }}
/> : null}
: null)}
data={fruits}
value={stv as any}
renderer={[r => r.text]}
valuer={[r => r.value]}
checkboxer={[r => r.checked]}
rows={6}
hideOnBackdrop
open={sshown}
checkbox={[$(true)]}
noMask
/>
>
}
const cshown = $(false)
const date = $(new Date())
const format = (value: Observable[]) => value.slice(0, 3).map(v => $$(v) + '').join(' ') + ' ' + value.slice(3).map(v => ($$(v) + '').padStart(2, '0')).join(':')
const cshownDateOnly = $(false)
const yearOnly = $(new Date())
const cshownYear = $(false)
const monthOnly = $(new Date())
const cshownMonth = $(false)
const yearMonth = $(new Date())
const cshownYearMonth = $(false)
const timeOnly = $(new Date()) //$([$(0), $(1), $(1)])
const cshownTime = $(false)
const hasSecond = $(true)
const TimeIcon = (props: JSX.SVGAttributes) =>
render(
WheelPicker
仿 iOS UIPickerView 的滚动选择器
单列
{v1}
{v2}
{v3}
{CheckChip}
cshown(true)} >{() => $$(date).toString()}
title={{() => $$(date).toDateString() + ' ' + $$(date).getHours() + ':' + $$(date).getMinutes() + ':' + $$(date).getSeconds()}
hasSecond(!$$(hasSecond))}>With Time
}
value={date}
format={format}
shown={cshown}
hasSecond={hasSecond}
/>
Date only
cshownDateOnly(true)} >{() => $$(date).toString()}
// hasSecond
value={date}
format={format}
shown={cshownDateOnly}
/>
Year Only
cshownYear(true)} >{() => Array.isArray($$(yearOnly)) ? ($$(yearOnly) as any as Observable[]).map(r => $$(r) + '').join(' ') : $$(yearOnly).toString()}
value={yearOnly}
format={format}
shown={cshownYear}
hasMonth={false}
hasDay={false}
/>
Month Only
cshownMonth(true)} >{() => Array.isArray($$(monthOnly)) ? ($$(monthOnly) as any as Observable[]).map(r => $$(r) + '').join(' ') : $$(monthOnly).toString()}
value={monthOnly}
format={format}
shown={cshownMonth}
hasYear={false}
hasDay={false}
/>
Year & Month
cshownYearMonth(true)} >{() => Array.isArray($$(yearMonth)) ? ($$(yearMonth) as any as Observable[]).map(r => $$(r) + '').join(' ') : $$(yearMonth).toString()}
value={yearMonth}
format={format}
shown={cshownYearMonth}
// hasYear={false}
hasDay={false}
/>
Time Only
cshownTime(true)} >{() => Array.isArray($$(timeOnly)) ? ($$(timeOnly) as any as Observable[]).map(r => $$(r) + '').join(' ') : $$(timeOnly).toString()}
value={timeOnly}
format={format}
shown={cshownTime}
hasYear={false}
hasMonth={false}
hasDay={false}
hasSecond
headers={['Hour', 'Minute', 'Second']}
/>
, document.getElementById('woby'))
``