vant2x picker源码阅读
Posted 绿叶清风
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vant2x picker源码阅读相关的知识,希望对你有一定的参考价值。
-
picker html结构
-
Picker index.js
// Utils import createNamespace from '../utils'; import preventDefault from '../utils/dom/event'; import BORDER_UNSET_TOP_BOTTOM from '../utils/constant'; import pickerProps, DEFAULT_ITEM_HEIGHT from './shared'; import unitToPx from '../utils/format/unit'; // Components import Loading from '../loading'; import PickerColumn from './PickerColumn'; const [createComponent, bem, t] = createNamespace('picker'); export default createComponent( props: ...pickerProps, defaultIndex: type: [Number, String], default: 0, , columns: type: Array, default: () => [], , toolbarPosition: type: String, default: 'top', , valueKey: type: String, default: 'text', , , data() return children: [], formattedColumns: [], ; , computed: itemPxHeight() return this.itemHeight ? unitToPx(this.itemHeight) : DEFAULT_ITEM_HEIGHT; , dataType() const columns = this; const firstColumn = columns[0] || ; if (firstColumn.children) return 'cascade'; if (firstColumn.values) return 'object'; return 'text'; , , watch: columns: handler: 'format', immediate: true, , , methods: format() const columns, dataType = this; if (dataType === 'text') this.formattedColumns = [ values: columns ]; else if (dataType === 'cascade') this.formatCascade(); else this.formattedColumns = columns; , formatCascade() const formatted = []; let cursor = children: this.columns ; while (cursor && cursor.children) const children = cursor; let defaultIndex = cursor.defaultIndex ?? +this.defaultIndex; while (children[defaultIndex] && children[defaultIndex].disabled) if (defaultIndex < children.length - 1) defaultIndex++; else defaultIndex = 0; break; formatted.push( values: cursor.children, className: cursor.className, defaultIndex, ); cursor = children[defaultIndex]; this.formattedColumns = formatted; , emit(event) if (this.dataType === 'text') this.$emit(event, this.getColumnValue(0), this.getColumnIndex(0)); else let values = this.getValues(); // compatible with old version of wrong parameters // should be removed in next major version // see: https://github.com/vant-ui/vant/issues/5905 if (this.dataType === 'cascade') values = values.map((item) => item[this.valueKey]); this.$emit(event, values, this.getIndexes()); , onCascadeChange(columnIndex) let cursor = children: this.columns ; const indexes = this.getIndexes(); for (let i = 0; i <= columnIndex; i++) cursor = cursor.children[indexes[i]]; while (cursor && cursor.children) columnIndex++; this.setColumnValues(columnIndex, cursor.children); cursor = cursor.children[cursor.defaultIndex || 0]; , onChange(columnIndex) if (this.dataType === 'cascade') this.onCascadeChange(columnIndex); if (this.dataType === 'text') this.$emit( 'change', this, this.getColumnValue(0), this.getColumnIndex(0) ); else let values = this.getValues(); // compatible with old version of wrong parameters // should be removed in next major version // see: https://github.com/vant-ui/vant/issues/5905 if (this.dataType === 'cascade') values = values.map((item) => item[this.valueKey]); this.$emit('change', this, values, columnIndex); , // get column instance by index getColumn(index) return this.children[index]; , // @exposed-api // get column value by index getColumnValue(index) const column = this.getColumn(index); return column && column.getValue(); , // @exposed-api // set column value by index setColumnValue(index, value) const column = this.getColumn(index); if (column) column.setValue(value); if (this.dataType === 'cascade') this.onCascadeChange(index); , // @exposed-api // get column option index by column index getColumnIndex(columnIndex) return (this.getColumn(columnIndex) || ).currentIndex; , // @exposed-api // set column option index by column index setColumnIndex(columnIndex, optionIndex) const column = this.getColumn(columnIndex); if (column) column.setIndex(optionIndex); if (this.dataType === 'cascade') this.onCascadeChange(columnIndex); , // @exposed-api // get options of column by index getColumnValues(index) return (this.children[index] || ).options; , // @exposed-api // set options of column by index setColumnValues(index, options) const column = this.children[index]; if (column) column.setOptions(options); , // @exposed-api // get values of all columns getValues() return this.children.map((child) => child.getValue()); , // @exposed-api // set values of all columns setValues(values) values.forEach((value, index) => this.setColumnValue(index, value); ); , // @exposed-api // get indexes of all columns getIndexes() return this.children.map((child) => child.currentIndex); , // @exposed-api // set indexes of all columns setIndexes(indexes) indexes.forEach((optionIndex, columnIndex) => this.setColumnIndex(columnIndex, optionIndex); ); , // @exposed-api confirm() this.children.forEach((child) => child.stopMomentum()); this.emit('confirm'); , cancel() this.emit('cancel'); , genTitle() const titleSlot = this.slots('title'); if (titleSlot) return titleSlot; if (this.title) return <div class=['van-ellipsis', bem('title')]>this.title</div>; , genCancel() return ( <button type="button" class=bem('cancel') onClick=this.cancel> this.slots('cancel') || this.cancelButtonText || t('cancel') </button> ); , genConfirm() return ( <button type="button" class=bem('confirm') onClick=this.confirm> this.slots('confirm') || this.confirmButtonText || t('confirm') </button> ); , genToolbar() if (this.showToolbar) return ( //class van-picker__toolbar <div class=bem('toolbar')> this.slots() || [ this.genCancel(), this.genTitle(), this.genConfirm(), ] </div> ); , genColumns() const itemPxHeight = this; //高度 const wrapHeight = itemPxHeight * this.visibleItemCount; const frameStyle = height: `$itemPxHeightpx` ; const columnsStyle = height: `$wrapHeightpx` ; const maskStyle = //宽度、高度 backgroundSize: `100% $(wrapHeight - itemPxHeight) / 2px`, ; return ( //阻止事件冒泡 <div class=bem('columns') style=columnsStyle // onTouchmove=preventDefault > this.genColumnItems() /*渐变背景*/ <div class=bem('mask') style=maskStyle /> /*中间选中背景*/ <div class=[BORDER_UNSET_TOP_BOTTOM, bem('frame')] style=frameStyle /> /* 1,后面两个div中的css样式设置了:pointer-events: none,会导致后面两个div z-index优先级虽然高,但是不能响应所有事件 2,所有touch、点击事件都会落在genColumnItems中的div上面 */ </div> ); , genColumnItems() //增加column return this.formattedColumns.map((item, columnIndex) => ( <PickerColumn readonly=this.readonly valueKey=this.valueKey allowHtml=this.allowHtml className=item.className itemHeight=this.itemPxHeight defaultIndex=item.defaultIndex ?? +this.defaultIndex swipeDuration=this.swipeDuration visibleItemCount=this.visibleItemCount initialOptions=item.values scopedSlots= option: this.$scopedSlots.option, onChange=() => this.onChange(columnIndex); /> )); , , render(h) return ( //clsss van-picker <div class=bem()> /*顶部工具栏*/ this.toolbarPosition === 'top' ? this.genToolbar() : h() /*Loading*/ this.loading ? <Loading class=bem('loading') /> : h() /**/ this.slots('columns-top') this.genColumns() this.slots('columns-bottom') this.toolbarPosition === 'bottom' ? this.genToolbar() : h() </div> ); , );
-
PickerColumn.js
import deepClone from '../utils/deep-clone'; import createNamespace, inBrowser, isObject from '../utils'; import range from '../utils/format/number'; import preventDefault, on, off from '../utils/dom/event'; import TouchMixin from '../mixins/touch'; const DEFAULT_DURATION = 200; // 惯性滑动思路: // 在手指离开屏幕时,如果和上一次 move 时的间隔小于 `MOMENTUM_LIMIT_TIME` 且 move // 距离大于 `MOMENTUM_LIMIT_DISTANCE` 时,执行惯性滑动 export const MOMENTUM_LIMIT_TIME = 300; export const MOMENTUM_LIMIT_DISTANCE = 15; const [createComponent, bem] = createNamespacevant2x picker源码阅读