From 38624a41abc320da41a2a2e800dd0950fb8a1f0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E8=8B=A5=E6=9E=AB?= <768047505@qq.com> Date: Mon, 24 Jan 2022 00:15:28 +0800 Subject: [PATCH] feat: init v3 --- demo/demo.vue | 123 +++++++ demo/main.js | 11 + docs/v2.md | 372 ++++++++++++++++++++++ package.json | 8 +- packages/components/LabelExtension.vue | 21 ++ packages/components/VueFilterBoxItem.vue | 134 ++++++++ packages/components/VueFilterBoxLabel.vue | 97 ++++++ packages/constants.js | 10 + packages/index.js | 9 + packages/index.vue | 158 +++++++++ packages/utils/get.js | 87 +++++ packages/utils/is.js | 30 ++ public/index.html | 17 + src/App.vue | 145 --------- src/CustomComponent.vue | 77 ----- src/components/VueFilterBox/index.vue | 142 --------- src/components/index.js | 9 - src/main.js | 11 - vue.config.js | 11 +- yarn.lock | 30 +- 20 files changed, 1097 insertions(+), 405 deletions(-) create mode 100644 demo/demo.vue create mode 100644 demo/main.js create mode 100644 docs/v2.md create mode 100644 packages/components/LabelExtension.vue create mode 100644 packages/components/VueFilterBoxItem.vue create mode 100644 packages/components/VueFilterBoxLabel.vue create mode 100644 packages/constants.js create mode 100644 packages/index.js create mode 100644 packages/index.vue create mode 100644 packages/utils/get.js create mode 100644 packages/utils/is.js create mode 100644 public/index.html delete mode 100644 src/App.vue delete mode 100644 src/CustomComponent.vue delete mode 100644 src/components/VueFilterBox/index.vue delete mode 100644 src/components/index.js delete mode 100644 src/main.js diff --git a/demo/demo.vue b/demo/demo.vue new file mode 100644 index 0000000..d6d940e --- /dev/null +++ b/demo/demo.vue @@ -0,0 +1,123 @@ + + + + is vertical + + + + + 提交 + 重置 + 提交 + + + + + Select Value: + {{ value }} + + + + + + + diff --git a/demo/main.js b/demo/main.js new file mode 100644 index 0000000..4574381 --- /dev/null +++ b/demo/main.js @@ -0,0 +1,11 @@ +import Vue from 'vue'; +import Demo from './demo.vue'; +import viewDesign, { Select } from 'view-design'; +import 'view-design/dist/styles/iview.css'; + +Vue.config.productionTip = false; +Vue.use(viewDesign); + +new Vue({ + render: h => h(Demo), +}).$mount('#app'); diff --git a/docs/v2.md b/docs/v2.md new file mode 100644 index 0000000..0aba373 --- /dev/null +++ b/docs/v2.md @@ -0,0 +1,372 @@ +# vue-filter-box + +> 项目依赖于**vue**和**view-design**, 请提前安装 + +## 介绍 + +vue-filter-box是一款根据JSON对象自动构建的vue筛选框组件, 基于[view-design](), 支持多种常见筛选组件: 输入框, 下拉框, 时间选择器, 级联选择器等多种组件, 以及根据特定规则编写的自定义组件 + +## 项目引入要求 + +1. 安装`vue` +2. 项目[全局引入](https://www.iviewui.com/docs/guide/start#YR_ViewUI)`view-design`, 或是[按需引入](https://www.iviewui.com/docs/guide/start#AXYY)所需组件 + +## 安装 + +``` +# use npm +npm i vue-filter-box +# or yarn +yarn add vue-filter-box +``` + +## 使用 + +### 全局注册: + +```javascript +import Vue from 'vue' +import VueFilterBox from 'vue-filter-box' +Vue.use(VueFilterBox) +``` + +### 单独引入组件: + +```vue + + + +``` + +```html + +``` + +## 示例 + + + +```html + + + + 搜索 + + {{filterValue}} + + +``` + +```html + +``` + +## 使用文档 + +### Props + +| 属性 | 说明 | 类型 | 默认值 | +| ----------- | ------------------------------------------------------------ | ------- | ------- | +| model | 筛选项构建模型, 详细结构查看[Model](#model) | Object | {} | +| value | 绑定的值, 可使用v-model双向绑定, value的**key**为**model**中的`` | Object | {} | +| size | 组件大小, 可选值为small, default, large | String | default | +| loading | 加载状态 | Boolean | false | +| button-hide | 是否隐藏默认按钮 | Boolean | false | + +### Events + +| 事件名 | 说明 | 返回值 | +| --------- | ------------------ | ------ | +| on-search | 点击搜索按钮时触发 | value | + +### slots + +| 名称 | 说明 | +| ------ | ---------------------------------------------- | +| footer | 筛选项底部, 跟在最后一个筛选项或是搜索按钮后面 | + +### Model + +**props中的model结构设计**, **model**的格式为`{: }`, **key**表示该筛选组件对应**value**中的键值 + +以下是**modelItem**的设计: + +| 属性 | 说明 | 类型 | 示例 | +| --------- | ------------------------------------------------------------ | ---------------- | --------------------------- | +| component | 筛选项组件, 支持Input, Select等, 具体查看[Components](#components) | String/Component | 'Input' | +| title | 筛选项标题 | String | '这是一个标题' | +| width | 筛选项宽度, 支持px和百分比 | String | '200px' 或者 '20%' | +| required | 是否必填 | Boolean | false | +| options | 下拉选项, 仅当component为Select时有效, 具体格式请查看[Options](#options) | Array | [{label: '文本', value: 1}] | +| props | 筛选项组件props, 具体请查看[view-design]()中组件对应的props | Object | {type: 'textarea'} | +| on | 筛选项组件的methods, 具体请查看[view-design](https://www.iviewui.com/)中组件支持的methods | Object | {'on-change': () => {}} | + +### Options + +**model props中的options结构设计** + +| 属性 | 说明 | 类型 | +| ----- | ---------------- | ------------- | +| label | 选项显示文本内容 | String | +| value | 选项值 | String/Number | + +### Components + +**vue-filter-box支持的组件列表** + +| 组件名称 | 说明 | +| ----------- | ----------------------- | +| Input | 输入框 | +| InputNumber | 数字输入框 | +| Select | 下拉框, 配合options使用 | +| DatePicker | 日期选择器 | +| TimePicker | 时间选择器 | +| i-switch | 开关 | +| Slider | 可拖动的滑块 | +| Cascader | 级联选择器 | + +### 自定义组件 + +除了[Components](#components)中指定的组件, 还可使用**自定义组件**, 只要组件内部支持v-model进行数据绑定即可, 以下是**自定义组件**的例子: + +```html +// CustomComponent.vue + + + + {{option.label}} + + + +``` + +```html + + + +``` + +在vue-filter-box中引入: + +```html +// App.vue + + + + + + +``` + +```html + +``` + +**展示**: + + \ No newline at end of file diff --git a/package.json b/package.json index 9f0be7b..ccf2910 100644 --- a/package.json +++ b/package.json @@ -32,8 +32,7 @@ "attributes": "vetur/attributes.json" }, "peerDependencies": { - "vue": "^2.6.11", - "view-design": "^4.1.3" + "vue": "^2.6.11" }, "devDependencies": { "@vue/cli-plugin-babel": "^4.3.0", @@ -44,8 +43,9 @@ "chai": "^4.1.2", "less": "^3.0.4", "less-loader": "^5.0.0", - "view-design": "^4.1.3", + "view-design": "^4.7.0", "vue": "^2.6.11", "vue-template-compiler": "^2.6.11" - } + }, + "dependencies": {} } diff --git a/packages/components/LabelExtension.vue b/packages/components/LabelExtension.vue new file mode 100644 index 0000000..7cab2d5 --- /dev/null +++ b/packages/components/LabelExtension.vue @@ -0,0 +1,21 @@ + + + + + diff --git a/packages/components/VueFilterBoxItem.vue b/packages/components/VueFilterBoxItem.vue new file mode 100644 index 0000000..a891b25 --- /dev/null +++ b/packages/components/VueFilterBoxItem.vue @@ -0,0 +1,134 @@ + + + + + + + + + + {{ option.label }} + + + + + {{ option.label }} + + + + + + + + + diff --git a/packages/components/VueFilterBoxLabel.vue b/packages/components/VueFilterBoxLabel.vue new file mode 100644 index 0000000..99b2388 --- /dev/null +++ b/packages/components/VueFilterBoxLabel.vue @@ -0,0 +1,97 @@ + + + + + {{ modelItem.label }} + + + + + + + + diff --git a/packages/constants.js b/packages/constants.js new file mode 100644 index 0000000..cf63993 --- /dev/null +++ b/packages/constants.js @@ -0,0 +1,10 @@ +export const DEFAULT_LABEL = ''; + +export const DEFAULT_HIDDEN_COLON = false; + +export const DEFAULT_COMPONENT_VALUE = ''; + +export const DEFAULT_PROPS = { + LABEL_MAX_WIDTH: 120, + MAX_WIDTH: 300, +}; diff --git a/packages/index.js b/packages/index.js new file mode 100644 index 0000000..be65cdb --- /dev/null +++ b/packages/index.js @@ -0,0 +1,9 @@ +import FilterBox from './index.vue'; + +export const VueFilterBox = FilterBox; + +export default { + install(Vue) { + Vue.component(FilterBox.name, FilterBox); + }, +} diff --git a/packages/index.vue b/packages/index.vue new file mode 100644 index 0000000..2c80f82 --- /dev/null +++ b/packages/index.vue @@ -0,0 +1,158 @@ + + + + + + + + + + + + + + + diff --git a/packages/utils/get.js b/packages/utils/get.js new file mode 100644 index 0000000..bc4f949 --- /dev/null +++ b/packages/utils/get.js @@ -0,0 +1,87 @@ +import Vue from 'vue'; +import { DEFAULT_COMPONENT_VALUE } from '../constants'; +import { isSimilarNum, isStr, isArr, isFunc } from './is'; + +export function getEmptyArray() { + return []; +} + +export function getEmptyObject() { + return {}; +} + +export function getValidator(arr = []) { + return function(val) { + return arr.includes(val); + }; +} + +export function getSizePx(size) { + const sizeIsNum = isSimilarNum(size); + if (sizeIsNum || isStr(size)) { + return sizeIsNum ? `${size}px` : size; + } + return size; +} + +export function getCamelCase(str) { + const splitArr = str.split('-'); + if (str.length <= 1) { + return str; + } + const pascalCaseArr = []; + const camelCaseArr = splitArr.map((splitItem, index) => { + const result = splitItem.slice(0, 1).toUpperCase() + splitItem.slice(1); + pascalCaseArr.push(index === 0 ? splitItem : result); + return result; + }); + return { + camelCase: camelCaseArr.join(''), + pascalCase: pascalCaseArr.join(''), + }; +} + +export function getParamCase(str) { + return str.replace(/([A-Z])/g, (all, letter, index) => { + if (index === 0) { + return letter; + } + return `-${letter}`; + }).toLowerCase(); +} + +export function getDefaultValueByComponentType(component) { + if (isStr(component)) { + const components = Vue?.options?.components; + if (components[component]) { + return getDefaultValueByComponentType(components[component]?.options); + } + // 需要进行组件名转换 + if (component.indexOf('-') !== -1) { + const { camelCase, pascalCase } = getCamelCase(component); + if (components[camelCase]) { + return getDefaultValueByComponentType(components[camelCase]?.options); + } + if (components[pascalCase]) { + return getDefaultValueByComponentType(components[pascalCase]?.options); + } + } else { + const paramCase = getParamCase(component); + if (components[paramCase]) { + return getDefaultValueByComponentType(components[paramCase]?.options); + } + } + } else { + const props = component?.props; + if (isArr(props)) { + return DEFAULT_COMPONENT_VALUE; + } else { + const value = props?.value; + if (isFunc(value)) { + return valueProp(); + } + return isFunc(value?.type) ? value.type() : ''; + } + } + return DEFAULT_COMPONENT_VALUE; +} diff --git a/packages/utils/is.js b/packages/utils/is.js new file mode 100644 index 0000000..22b0818 --- /dev/null +++ b/packages/utils/is.js @@ -0,0 +1,30 @@ +export function isSimilarNum(val) { + const _val = val - ''; + return !isNaN(_val) && typeof (val - '') === 'number'; +} + +export function isStr(val) { + return typeof val === 'string'; +} + +export function isArr(val) { + return Array.isArray(val); +} + +export function isFunc(val) { + return typeof val === 'function'; +} + +function isEqualComponentType(type, componentTypes) { + return componentTypes.includes(type) || componentTypes.includes(type?.name); +} + +export function isSelect(type) { + const componentTypes = ['iSelect', 'i-select']; + return isEqualComponentType(type, componentTypes); +} + +export function isCheckbox(type) { + const componentTypes = ['CheckboxGroup', 'checkbox-group']; + return isEqualComponentType(type, componentTypes); +} diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..daf04fd --- /dev/null +++ b/public/index.html @@ -0,0 +1,17 @@ + + + + + + + + <%= htmlWebpackPlugin.options.title %> + + + + We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue. + + + + + \ No newline at end of file diff --git a/src/App.vue b/src/App.vue deleted file mode 100644 index 2c254a8..0000000 --- a/src/App.vue +++ /dev/null @@ -1,145 +0,0 @@ - - - - 筛选框: - - - 搜索 - - - - - 筛选框绑定值: - {{_filterValue}} - - - - - - - \ No newline at end of file diff --git a/src/CustomComponent.vue b/src/CustomComponent.vue deleted file mode 100644 index a1e8c38..0000000 --- a/src/CustomComponent.vue +++ /dev/null @@ -1,77 +0,0 @@ - - - - {{option.label}} - - - - - - - diff --git a/src/components/VueFilterBox/index.vue b/src/components/VueFilterBox/index.vue deleted file mode 100644 index e9d4f25..0000000 --- a/src/components/VueFilterBox/index.vue +++ /dev/null @@ -1,142 +0,0 @@ - - - - - - - {{option.label}} - - - - - - 筛选 - - - - - - - - - - - \ No newline at end of file diff --git a/src/components/index.js b/src/components/index.js deleted file mode 100644 index 4567509..0000000 --- a/src/components/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import FilterBox from './VueFilterBox' - -export const VueFilterBox = FilterBox - -export default { - install(Vue) { - Vue.component(FilterBox.name, FilterBox) - } -} diff --git a/src/main.js b/src/main.js deleted file mode 100644 index eff46c9..0000000 --- a/src/main.js +++ /dev/null @@ -1,11 +0,0 @@ -import Vue from 'vue' -import App from './App.vue' -import viewDesign from 'view-design' -import 'view-design/dist/styles/iview.css' - -Vue.config.productionTip = false -Vue.use(viewDesign) - -new Vue({ - render: h => h(App), -}).$mount('#app') diff --git a/vue.config.js b/vue.config.js index 19257f2..3c7a843 100644 --- a/vue.config.js +++ b/vue.config.js @@ -1,5 +1,12 @@ module.exports = { + pages: { + index: { + entry: 'demo/main.js', + template: 'public/index.html', + filename: 'index.html', + }, + }, css: { extract: false - } -} \ No newline at end of file + }, +}; diff --git a/yarn.lock b/yarn.lock index 8051ec5..17459e2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1589,10 +1589,10 @@ async-limiter@~1.0.0: resolved "https://registry.npm.taobao.org/async-limiter/download/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" integrity sha1-3TeelPDbgxCwgpH51kwyCXZmF/0= -async-validator@^1.10.0: - version "1.12.2" - resolved "https://registry.yarnpkg.com/async-validator/-/async-validator-1.12.2.tgz#beae671e7174d2938b7b4b69d2fb7e722b7fd72c" - integrity sha512-57EETfCPFiB7M4QscvQzWSGNsmtkjjzZv318SK1CBlstk+hycV72ocjriMOOM48HjvmoAoJGpJNjC7Z76RlnZA== +async-validator@^3.3.0: + version "3.5.2" + resolved "https://registry.yarnpkg.com/async-validator/-/async-validator-3.5.2.tgz#68e866a96824e8b2694ff7a831c1a25c44d5e500" + integrity sha512-8eLCg00W9pIRZSB781UUX/H6Oskmm8xloZfr09lz5bikRpBVDlJ3hRVuxxP1SxcwsEYfJ4IU8Q19Y8/893r3rQ== async@^2.6.2: version "2.6.3" @@ -3136,9 +3136,9 @@ electron-to-chromium@^1.3.390: integrity sha1-22QMLmewjVkKUEwgtWkEU3qiuvo= element-resize-detector@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/element-resize-detector/-/element-resize-detector-1.2.1.tgz#b0305194447a4863155e58f13323a0aef30851d1" - integrity sha512-BdFsPepnQr9fznNPF9nF4vQ457U/ZJXQDSNF1zBe7yaga8v9AdZf3/NElYxFdUh7SitSGt040QygiTo6dtatIw== + version "1.2.4" + resolved "https://registry.yarnpkg.com/element-resize-detector/-/element-resize-detector-1.2.4.tgz#3e6c5982dd77508b5fa7e6d5c02170e26325c9b1" + integrity sha512-Fl5Ftk6WwXE0wqCgNoseKWndjzZlDCwuPTcoVZfCP9R3EHQF8qUtr3YUPNETegRBOKqQKPW3n4kiIWngGi8tKg== dependencies: batch-processor "1.0.0" @@ -7753,9 +7753,9 @@ timsort@^0.3.0: integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= tinycolor2@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.1.tgz#f4fad333447bc0b07d4dc8e9209d8f39a8ac77e8" - integrity sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g= + version "1.4.2" + resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.2.tgz#3f6a4d1071ad07676d7fa472e1fac40a719d8803" + integrity sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA== to-arraybuffer@^1.0.0: version "1.0.1" @@ -8124,12 +8124,12 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" -view-design@^4.1.3: - version "4.1.3" - resolved "https://registry.yarnpkg.com/view-design/-/view-design-4.1.3.tgz#f617e75e6dc98313fcde28ec1ad6740538584f5e" - integrity sha512-umnlnickwC8SnRm94hn+z+g6P/eqjBgScM8ga8e+4QptJ/SmOub/QSMtwoxQaQFPNI+MMHEkWWt4iJJQpfyIQg== +view-design@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/view-design/-/view-design-4.7.0.tgz#98c4ec18ed70d1b58157007f8107a77158334846" + integrity sha512-WRvVRfsZciN0aJYlz+6b1zxs5G8tLFb4OUKOu+PiN0QyIGmdgWVziEyEmioYtJahQpueWiQpRYGzyxrpz3UkWQ== dependencies: - async-validator "^1.10.0" + async-validator "^3.3.0" deepmerge "^2.2.1" element-resize-detector "^1.2.0" js-calendar "^1.2.3"
Select Value:
{{ value }}
{{filterValue}}
{{_filterValue}}