UNPKG

shu-c-view

Version:

rollup 打包vue组件库框架

534 lines (531 loc) 16 kB
/** * @desc 下拉搜索 table 不分页组件 * https://juejin.cn/post/6844903710972182536 */ import _isEqual from 'lodash/isEqual'; import _map from 'lodash/map'; import _get from 'lodash/get'; import _isNil from 'lodash/isNil'; import _isFunction from 'lodash/isFunction'; import _includes from 'lodash/includes'; import _assign from 'lodash/assign'; import _forEach from 'lodash/forEach'; import _has from 'lodash/has'; import _set from 'lodash/set'; import _omit from 'lodash/omit'; import _debounce from 'lodash/debounce'; import _isEmpty from 'lodash/isEmpty'; import _isArray from 'lodash/isArray'; import _find from 'lodash/find'; import { BaseSelect } from '../select/index.js'; import { devConsole } from '../helper/util.js'; const BaseSelectInputTable = { name: 'BaseSelectInputTable', extends: _assign({}, BaseSelect, { watch: {} }), props: { props: { type: Object, default() { return {}; // defaultPageParams } }, width: { type: String }, // 一页分多少条 pageSize: { type: Number, default: 10 }, // 是否本地搜索 isLocalSearch: { type: Boolean, default: false }, // 第一次载入时是否自动刷新列表数据(第一页的数据) isReloadGrid: { type: Boolean, default: true }, // 输入内容改变后多少时间触发请求-毫秒 delay: { type: Number, default: 300 }, // 过滤返回数据(该函数带一个参数'data'用来指向源数据) loadFilter: { type: Function }, // 用于搜索参数的字段,默认代码中使用 displayField 配置的字段 searchField: { type: String }, // 如果是插槽slot那么需要返回的其它参数 extDataFields: { type: Array, default() { return []; } } }, computed: { elOptions() { const elOptions = []; /* if (this.vOptions) { this.vOptions = this.options; } */ if (_isNil(this.vOptions)) { return; } const h = this.$createElement; for (let i = 0; i < this.vOptions.length; i++) { const option = this.vOptions[i]; let optionNode = h('el-option', { props: { key: option[this.valueField], label: option[this.displayField], value: option[this.valueField], disabled: option.disabled } }); if (_has(this.$scopedSlots, 'optionSlot')) { optionNode = h( 'el-option', { props: { key: option[this.valueField], label: option[this.displayField], value: option[this.valueField], disabled: option.disabled } }, [ h( 'template', { slot: 'default' }, this.$scopedSlots.optionSlot(option) ) ] ); } elOptions.push(optionNode); } return elOptions; } }, watch: { value(value, oldValue) { if (!_isEqual(value, oldValue) && !_isEqual(this.vValue, value)) { this.vValue = value; this._changeEvent(this.vValue); this._selectChangeEvent(this.vValue); } } }, directives: { scroll: { bind(el, binding) { // 获取滚动页面DOM const SCROLL_DOM = el.querySelector( '.base-select-input-table-dropdown .el-select-dropdown__wrap' ); let scrollPosition = 0; SCROLL_DOM.addEventListener('scroll', function() { // 当前的滚动位置 减去 上一次的滚动位置 // 如果为true则代表向上滚动,false代表向下滚动 const flagToDirection = this.scrollTop - scrollPosition > 0; // 记录当前的滚动位置 scrollPosition = this.scrollTop; const LIMIT_BOTTOM = 100; // 记录滚动位置距离底部的位置 const scrollBottom = this.scrollHeight - (this.scrollTop + this.clientHeight) < LIMIT_BOTTOM; // 如果已达到指定位置则触发 if (scrollBottom) { // 将滚动行为告诉组件 binding.value(flagToDirection); } // 如果是向上滚动 并且距离顶部只有100px if (!flagToDirection && this.scrollTop < LIMIT_BOTTOM) { binding.value(flagToDirection); // console.log('如果是向上滚动 并且距离顶部只有100px'); } // console.log(flagToDirection ? '滚动方向:下' : '滚动方向:上'); }); } } }, data() { this.defaultPageParams = { pageNum: 'pageNum', pageSize: 'pageSize', results: 'data.results', totalPage: 'totalPage', totalRecord: 'totalRecord' }; // 默认的分页参数 this.pageParams = { pageNum: 1, // 当前第几页 pageSize: this.pageSize, results: [], totalPage: 1, totalRecord: 10 }; // 分页参数 this.vQueryParams = {}; this.totalPage = 0; // 总页数 this.current = 1; // 当前是第几页 this.query = ''; // 输入框中的搜索内容 this.selectedOption = null; // 选中的数据对象 return { vOptions: [], list: [], loading: false }; }, created() { if (this.isLocalSearch) { this.vOptions = this.options; // 本地搜索 } // 覆盖 分页 参数 _forEach(this.props, (value, key) => { if (_has(this.defaultPageParams, key)) { _set(this.defaultPageParams, key, value); } if (_has(this.pageParams, key)) { if (value !== key) { _set(this.pageParams, value, _get(this.pageParams, key)); delete this.pageParams[key]; } } }); this.debouncedLoadListData = _debounce(this.loadListData, this.delay); // 节流防止抖动 }, /* mounted() { if (this.isLocalSearch) { this.vOptions = this.options; // 本地搜索 console.log('this.vOptions: ', this.vOptions); } }, */ methods: { /** * @desc 获取所有数据 * @returns Array */ getList() { return this.list; }, /** * @desc 获取远程服务器数据的操作 * @param {Function} callBack - 回调函数 * @method */ loadListData(callBack) { if (_isEmpty(this.api) || _isNil(this.$api)) { return; } /* console.log( '...loadListData ', JSON.stringify(this.vQueryParams), JSON.stringify(this.pageParams), _assign({}, this.vQueryParams, this.pageParams) ); */ this.$api[this.api]({ params: _assign({}, this.vQueryParams, this.pageParams) }) .then(resData => { const currentPageNum = this.pageParams[this.props.pageNum]; const results = _get(resData, this.defaultPageParams.results, []); if (currentPageNum === 1 && _isEmpty(results)) { this.list = []; // 如果搜索第一页的数据为空则清空列表项 if (!_isNil(callBack) && _isFunction(callBack)) { callBack([]); } return; } if (!_isNil(this.loadFilter)) { resData = this.loadFilter(resData); if (!_has(resData, 'data')) { resData = { data: resData }; } } this.totalPage = _get( resData.data, this.defaultPageParams.totalPage, 0 ); // 总页数 this.current = parseInt( _get(resData.data, this.defaultPageParams.pageNum, 0) ); // 当前第几页 const list = _map(results, o => { const obj = { [this.valueField]: `${_get(o, this.valueField)}`, [this.displayField]: `${_get(o, this.displayField)}` }; for (let i = 0; i < this.extDataFields.length; i += 1) { const extDataField = this.extDataFields[i]; _set(obj, extDataField, o[extDataField]); } return obj; }); this.list.push(...list); if (!_isNil(callBack) && _isFunction(callBack)) { callBack(this.list); } return true; }) .catch(error => { console.error(error); if (!_isNil(callBack) && _isFunction(callBack)) { callBack([]); } }); }, /** * @desc 设置查询参数 * @param {Object} params - 查询对象参数 */ setQueryParams(params = {}) { this.vQueryParams = _assign({}, this.queryParams, params); }, /** * @desc 在输入值发生变化时调用,参数为当前输入值 * @param {String} query - 搜索的值 */ remoteMethod(query) { /* console.log( '在输入值发生变化时调用,参数为当前输入值', query, this.totalPage ); */ if (query !== '') { this.loading = true; if (!this.isLocalSearch) { this.list = []; _set(this.pageParams, this.defaultPageParams.pageNum, 1); // 输入值变化将当前页重置到第一页 this.$nextTick(() => { if (!_isNil(this.searchField)) { this.setQueryParams({ [this.searchField]: query }); } else { this.setQueryParams({ [this.displayField]: query }); } this.debouncedLoadListData(resData => { this.loading = false; this.vOptions = resData; }); }); // 远程搜索 } else { setTimeout(() => { this.loading = false; this.vOptions = this.options.filter(item => { /* console.log( query, _get(item, this.displayField), _includes(_get(item, this.displayField), query) ); */ return _includes(_get(item, this.displayField), query); }); }, this.delay); } } else { this.vOptions = []; } this.query = query; }, /** * @desc 设置上一页 */ setLastPage() { _set(this.pageParams, this.defaultPageParams.pageNum, this.current - 1); }, /** * @desc 设置下一页 */ setNextPage() { _set(this.pageParams, this.defaultPageParams.pageNum, this.current + 1); }, /** * @desc 处理滚动行为 * @param {Boolean} param - 滚动的方向 true代表向下滚动、false代表向上滚动 */ handleScroll(param) { /* console.log( '...处理滚动行为...', param, this.loading, param && !this.loading ); */ if (this.totalPage === this.current) { return; // 已经滚动到最后一页 } if (param && !this.loading) { this.loading = true; // 请求下一页的数据 this.setNextPage(); this.loadListData(resData => { this.loading = false; this.$nextTick(() => { this.vOptions = resData; }); }); } if (!param && !this.loading) { // 请求上一页的数据 console.log('请求上一页的数据'); } }, // 获取当前选中value-filed字段对应的值对象 getOption() { const apply = (scope, config) => { for (const i in config) { scope[i] = config[i]; } return scope; }; if (!_isNil(this.selectedOption)) { return apply({}, this.selectedOption); } }, /** * @desc 当 input 获得焦点时触发 * @event FastComboBox#_focusEvent * @param {*} event */ _focusEvent(event) { if (_isEmpty(this.vValue) && !_isEmpty(this.vOptions)) { this.vOptions = []; } if ( _isEqual(_isNil(this.listeners), false) && _has(this.listeners, 'focus') ) { this.listeners.focus(event); return; } this.$emit('focus', event); }, /** * @desc 多选模式下移除tag时触发 * @event FastComboBox#_removeTag * @param {*} value */ _removeTag(value) { if (_isEmpty(this.vValue)) { this.vOptions = []; // 如果全部选中的属性移除了,就清空下拉面板的搜索项 } if ( _isEqual(_isNil(this.listeners), false) && _has(this.listeners, 'remove-tag') ) { this.listeners['remove-tag'](value); return; } this.$emit('remove-tag', value); } }, render(h) { // v-if if (_isEqual(this.isRender, false)) { return h(); } const style = _assign( { width: this.width }, _get(this.$props, 'ctStyle', {}) ); // { ..._get(this.$props, 'ctStyle', {}) } if (this.width !== 'auto') { style.width = this.width; } // v-show if (_isEqual(this.isDisplay, false)) { _set(style, 'display', 'none'); } let popperClass = this.$attrs.popperClass; if (_has(this.$attrs, 'popper-class')) { popperClass = this.$attrs['popper-class']; } return h( 'el-select', { ref: `${this._uid}-el-select-input-table-ref`, class: _assign( { 'base-select-input-table': true }, _get(this.$props, 'ctCls', {}) ), style, attrs: { id: this.$attrs.id }, props: _assign( { filterable: true, remote: true, 'reserve-keyword': true, 'remote-method': this.remoteMethod, popperClass: _has(this.$attrs, 'popperClass') || _has(this.$attrs, 'popper-class') ? `base-select-input-table-dropdown ${popperClass}` : 'base-select-input-table-dropdown', loading: _isEmpty(this.vOptions) || this.isLocalSearch ? this.loading : false }, _omit(this.$attrs, ['id', 'popperClass', 'popper-class']), { value: this.vValue } ), // { ...this.$attrs, value: this.vValue }, on: { change: this._changeEvent, 'visible-change': this._visibleChangeEvent, 'remove-tag': this._removeTag, clear: this._clearEvent, blur: this._blurEvent, focus: this._focusEvent, input: val => { // v-model this.vValue = val; this._selectChangeEvent(this.vValue); this.selectedOption = null; if (!_isNil(val)) { this.selectedOption = _find( this.list, l => l[this.valueField] === val ); } } }, nativeOn: { click: () => { console.log('...click...', this.vValue, this.query); } }, directives: [ { name: 'scroll', value: this.isLocalSearch ? function() {} : this.handleScroll } ] }, [ this.elOptions, this.loading && !this.isLocalSearch ? h('i', { slot: 'prefix', class: { 'el-icon-loading': true } }, []) : h() // 加载中的 icon ] ); } }; BaseSelectInputTable.install = function(Vue, ElComponents) { // 用于按需加载的时候独立使用 devConsole('按需加载独立组件:' + BaseSelectInputTable.name); if (_isArray(ElComponents) && !_isEmpty(ElComponents)) { for (let i = 0; i < ElComponents.length; i++) { if (ElComponents[i].name !== BaseSelectInputTable.name) { Vue.use(ElComponents[i]); } } } Vue.component(BaseSelectInputTable.name, BaseSelectInputTable); }; export { BaseSelectInputTable };