diff --git a/devui/rate/index.ts b/devui/rate/index.ts index 7955ec32f3b63ef8f66001af625f645ecdff1d12..ec34c35859ff969cbfde374d05e068b4043f26f5 100644 --- a/devui/rate/index.ts +++ b/devui/rate/index.ts @@ -10,6 +10,7 @@ export { Rate } export default { title: 'Rate 评分', category: '数据录入', + status: '已完成', install(app: App): void { app.use(Rate as any); }, diff --git a/devui/rate/src/rate.tsx b/devui/rate/src/rate.tsx index 7b8eeeb0d2f81ec745b41d8472bfeb2147206a79..d9ccd7595dfe8b3090474c5d089bd3435c11e670 100644 --- a/devui/rate/src/rate.tsx +++ b/devui/rate/src/rate.tsx @@ -41,7 +41,7 @@ export default defineComponent({ initRating() }) - const hoverToggle = (_, index: number, reset = false) => { + const hoverToggle = (e, index: number, reset = false) => { if (props.read) { return } @@ -54,17 +54,31 @@ export default defineComponent({ } } else { setChange(0, index + 1, '100%') + // 判断是否是半选模式并且判断鼠标所在图标区域 + if (props.allowHalf && (e.offsetX * 2 <= e.target.clientWidth)) { + setChange(index, index + 1, '50%') + } else { + setChange(index, index + 1, '100%') + } setChange(index + 1, props.count, '0') } } - const selectValue = (index: number) => { + const selectValue = (e, index: number) => { if (props.read) { return } - setChange(0, index + 1, '100%') + setChange(0, index, '100%') + // 判断是否是半选模式 + if (props.allowHalf && (e.offsetX * 2 <= e.target.clientWidth)) { + setChange(index, index + 1, '50%') + chooseValue.value = index - 0.5 + } else { + setChange(index, index + 1, '100%') + chooseValue.value = index + } setChange(index + 1, props.count, '0') - chooseValue.value = index + index = chooseValue.value props.onChange && props.onChange(index + 1) props.onTouched && props.onTouched() ctx.emit('update:modelValue', index + 1) @@ -86,7 +100,7 @@ export default defineComponent({ type, color, hoverToggle, - selectValue, + selectValue } = this return (
{totalLevelArray.map((item, index) => (
hoverToggle(e, index)} - onClick={() => selectValue(index)} + onClick={(e) => selectValue(e, index)} > {icon && !character && ( diff --git a/devui/rate/src/use-rate.ts b/devui/rate/src/use-rate.ts index c62c7a1ca6f58dc2bfba1d554827b1e23065c035..d5ced884beff9551ea942b7760666c1d1ae27a0c 100644 --- a/devui/rate/src/use-rate.ts +++ b/devui/rate/src/use-rate.ts @@ -29,6 +29,10 @@ export const rateProps = { type: String, default: '', }, + allowHalf: { + type: Boolean, + default: false, + }, onChange: { type: Function as PropType<(value: number) => void>, default: undefined, diff --git a/devui/tag-input/src/tag-input.tsx b/devui/tag-input/src/tag-input.tsx index 8ed491cbe549f9e6518decf9d53e49d6fa5abcd4..70d35d826f05d9fbfc73d9b00b3645d1053c3077 100644 --- a/devui/tag-input/src/tag-input.tsx +++ b/devui/tag-input/src/tag-input.tsx @@ -20,13 +20,21 @@ const tagInputProps = { type: String, default: '' }, + minLength: { + type: Number, + default: 3 + }, + maxLength: { + type: Number, + default: Number.MAX_SAFE_INTEGER + }, maxTags: { type: Number, default: Number.MAX_SAFE_INTEGER }, maxTagsText: { type: String, - default: '' + default: '已达到最大个数:' }, spellcheck: { type: Boolean, @@ -40,6 +48,10 @@ const tagInputProps = { type: Boolean, default: false }, + isAddBySpace: { + type: Boolean, + default: true + }, disabledText: { type: String, default: '' @@ -125,6 +137,8 @@ export default defineComponent({ }; const handleEnter = () => { let res = { [props.displayProperty]: tagInputVal.value }; + // 判断输入框和输入建议是否为空 + if (tagInputVal.value === '' && mergedSuggestions.value.length === 0) return false if (mergedSuggestions.value.length) { const target = mergedSuggestions.value[selectIndex.value]; res = target; @@ -215,7 +229,8 @@ export default defineComponent({ isShowSuggestion, noData, mergedSuggestions, - selectIndex + selectIndex, + maxTags } = this; const inputBoxCls = { @@ -268,10 +283,10 @@ export default defineComponent({ onFocus={onInputFocus} onBlur={onInputBlur} onInput={($event: any) => onInput($event)} - placeholder={placeholder} + placeholder={isTagsLimit ? `${maxTagsText} ${maxTags}` : placeholder} spellcheck={spellcheck} disabled={isTagsLimit} - title={isTagsLimit ? maxTagsText : ''} /> + />
{ !isShowSuggestion ? '' : ( diff --git a/docs/.vitepress/devui-theme/components/Page.vue b/docs/.vitepress/devui-theme/components/Page.vue deleted file mode 100644 index 7a1d422bc5f308dce065b5a95b762aaf2bc57357..0000000000000000000000000000000000000000 --- a/docs/.vitepress/devui-theme/components/Page.vue +++ /dev/null @@ -1,53 +0,0 @@ - - - - - diff --git a/docs/.vitepress/devui-theme/composables/useToc.ts b/docs/.vitepress/devui-theme/composables/useToc.ts new file mode 100644 index 0000000000000000000000000000000000000000..ffb2689db24acecd70f1ef5e872f25561e128d11 --- /dev/null +++ b/docs/.vitepress/devui-theme/composables/useToc.ts @@ -0,0 +1,57 @@ +import { computed } from 'vue' +import { useData } from 'vitepress' +import { joinUrl } from '../utils' + +import type { PageData } from 'vitepress' + +type EnhanceArrayElement = T extends Array ? (U & P)[] : never + +type Headers = EnhanceArrayElement< + PageData['headers'], + { + children?: Headers + } +> + +export const useToc = () => { + const { page } = useData() + + return computed(() => resolveHeaders(page.value.headers)) +} + +export const resolveLink = (base: string, path: string) => { + if (path === undefined) { + return path + } + // keep relative hash to the same page + if (path.startsWith('#')) { + return path + } + return joinUrl(base, path) +} + +export const resolveHeaders = (headers: PageData['headers']) => { + return mapHeaders(groupHeaders(headers)) +} + +export function groupHeaders(headers: PageData['headers']) { + headers = headers.map((h) => Object.assign({}, h)) + let lastH2 + + headers.forEach((h) => { + if (h.level === 3) { + lastH2 = h + } else if (lastH2) { + ;(lastH2.children || (lastH2.children = [])).push(h) + } + }) + return headers.filter((h) => h.level === 3) +} + +export function mapHeaders(headers: Headers) { + return headers.map((header) => ({ + text: header.title, + link: `#${header.slug}`, + children: header.children ? mapHeaders(header.children) : undefined, + })) +} diff --git a/docs/components/rate/index.md b/docs/components/rate/index.md index ab3f6ff327c98decec3c700d2f4852d2a0b4a74c..16540d0b9249a2b750bf1b5bfe13ed7d4b2b1e86 100644 --- a/docs/components/rate/index.md +++ b/docs/components/rate/index.md @@ -74,6 +74,33 @@ export default { } ``` +::: + +### 半选模式 + +:::demo + +```vue + + +``` ::: @@ -137,3 +164,10 @@ d-rate 参数 | color | `string` | -- | 可选,星星颜色 | [动态模式-自定义](#动态模式-自定义) | | icon | `string` | -- | 可选,评分图标的样式,只支持 devUI 图标库中所有图标 | [动态模式](#动态模式) | | character | `string` | -- | 可选,评分图标的样式,icon 与 character 只能设置其中一个 | [动态模式-自定义](#动态模式-自定义) | +| allowHalf | `boolean` | false | 可选,动态模式下是否允许半选 | [半选模式](#半选模式) | + +d-rate 事件 + +| 参数 | 类型 | 说明 | 回调参数 | 跳转 Demo | +| --------------- | -------------------- | ----------------------------- | ----------------------------- | --------------------- | +| change | `EventEmitter` | 分值改变时触发 | 改变后的分值 | [半选模式](#半选模式) | diff --git a/docs/components/tag-input/index.md b/docs/components/tag-input/index.md index 80bd047cb149732bdff969239b4df514a74174a6..82dc0ab4c8b2fc3613548817b4ec7f442359a0cc 100644 --- a/docs/components/tag-input/index.md +++ b/docs/components/tag-input/index.md @@ -9,20 +9,23 @@ ### 基本用法 +v-model:tags="state.tags" +v-model:suggestionList="state.suggestionList" +display-property="name" +no-data="暂无数据" +:maxTags="4" +placeholder="请输入名字" + +> ```html ``` @@ -37,8 +40,30 @@ export default defineComponent({ }) return { - state, + state } } }) - \ No newline at end of file + + +### d-tag-input 参数 + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | 全局配置项 | +| :-------------: | :-------: | :---------------------: | :----------------------------------: | :-------------------- | ---------- | +| tags | `Array` | [] | 必选,记录输入的标签和选择的标签列表 | [基本用法](#基本用法) | +| suggestionList | `Array` | [] | 可选,下拉选项,默认可选择的标签列表 | [基本用法](#基本用法) | +| displayProperty | `string` | 'name' | 可选,列表项使用的属性名 | [基本用法](#基本用法) | +| placeholder | `boolean` | '' | 可选,输入框的 placeholder | [基本用法](#基本用法) | +| noData | `boolean` | '' | 可选,无数据提示 | [基本用法](#基本用法) | +| maxTags | `number` | Number.MAX_SAFE_INTEGER | 可选,可输入标签的最大个数 | [基本用法](#基本用法) | +| caseSensitivity | `boolean` | false | 可选,大小写敏感,默认忽略大小写 | | | +| spellcheck | `boolean` | true | 可选,input 输入框是否开启拼写检查的 | | | +| isAddBySpace | `boolean` | true | 可选,是否支持空格键输入标签 | | | +| disabled | `boolean` | false | 可选,disabled 灰化状态 | | +| showAnimation | `boolean` | true | 可选,是否开启动画 | | ✔ | + +### d-tags-input 事件 + +| 事件 | 类型 | 说明 | 跳转 Demo | +| :---------: | :-----------------: | :------------------------------------------------------- | --------------------- | +| valueChange | `EventEmitter` | 当选中某个选项项后,将会调用此函数,参数为当前选择项的值 | [基本用法](#基本用法) | diff --git a/docs/index.md b/docs/index.md index bc713836d6560a8cccaa2a18322dd0775414b1d6..f6f46f1cc13da44436fff756e6f2be11f7a4b2c5 100644 --- a/docs/index.md +++ b/docs/index.md @@ -32,12 +32,47 @@ yarn add vue-devui main.ts ```js +// 全局引入 import DevUI from 'vue-devui' import 'vue-devui/style.css' createApp(App).use(DevUI).mount('#app') ``` +```js +// 按需引入 +// main.ts文件 +import { createApp } from 'vue' +import App from './App.vue' + +// Step 1: 引入单个组件 +import { Button } from 'vue-devui' +// or import Button from 'vue-devui/button' +// Step 2: 引入组件样式 +// 方式一:手动引入组件样式 +import 'vue-devui/button/style.css' + +// 方式二:自动按需引入组件 +// vite.config.ts文件 +// import styleImport from 'vite-plugin-style-import' +// plugins: [ +// vue(), +// styleImport({ +// libs: [ +// { +// libraryName: 'vue-devui', +// esModule: true, +// resolveStyle: (name) => `vue-devui/${name}/style`, +// }, +// ], +// }) +// ] + +createApp(App) +.use(Button) // Step 3: 使用组件 +.mount('#app') +``` + ### 4. 启动开发调试 ```shell