├── docs ├── assets │ ├── README-aa6ca5f7.css │ ├── img1-df60c764.png │ ├── img2-407e7c99.png │ ├── logo-961f8a2e.jpg │ ├── lazy-error-ad8f0809.png │ ├── lazy-default-3fb51c0d.gif │ ├── test-d7202dcc.js │ ├── vue-9f3c8957.css │ ├── README-77590a54.js │ ├── README-69dae8d1.js │ └── vue-4a2b12f2.js ├── favicon.ico ├── image │ ├── img1.png │ └── img2.png ├── static │ ├── iconfont │ │ ├── iconfont.eot │ │ ├── iconfont.ttf │ │ ├── iconfont.woff │ │ ├── iconfont.woff2 │ │ └── iconfont.css │ └── mock │ │ └── testData.json └── index.html ├── src ├── packages │ ├── tag │ │ ├── index.ts │ │ ├── Tag.vue │ │ └── README.md │ ├── theme │ │ ├── _icon.scss │ │ ├── _lazy.scss │ │ ├── _autoForm.scss │ │ ├── _popover.scss │ │ ├── _backTop.scss │ │ ├── _textarea.scss │ │ ├── index.scss │ │ ├── _drawer.scss │ │ ├── _collapse.scss │ │ ├── _timePicker.scss │ │ ├── _select.scss │ │ ├── _tree.scss │ │ ├── _inputNumber.scss │ │ ├── _var.scss │ │ ├── _divider.scss │ │ ├── _radio.scss │ │ ├── _badge.scss │ │ ├── _checkbox.scss │ │ ├── _tag.scss │ │ ├── mixins.scss │ │ ├── _cascader.scss │ │ ├── _switch.scss │ │ ├── _formItem.scss │ │ ├── _page.scss │ │ ├── _dropdown.scss │ │ ├── _carousel.scss │ │ ├── _input.scss │ │ ├── _image.scss │ │ ├── _loading.scss │ │ ├── _colorPicker.scss │ │ ├── _tabs.scss │ │ ├── _progress.scss │ │ ├── _slider.scss │ │ ├── _datePicker.scss │ │ ├── _tooltip.scss │ │ ├── _button.scss │ │ └── _menu.scss │ ├── form │ │ ├── index.ts │ │ └── Form.vue │ ├── menu │ │ ├── index.ts │ │ ├── types.ts │ │ └── Menu.vue │ ├── tree │ │ ├── index.ts │ │ └── NodeContent.vue │ ├── dialog │ │ └── index.ts │ ├── icon │ │ ├── index.ts │ │ └── Icon.vue │ ├── image │ │ ├── index.ts │ │ └── README.md │ ├── input │ │ ├── index.ts │ │ └── README.md │ ├── slider │ │ └── index.ts │ ├── switch │ │ ├── index.ts │ │ └── Switch.vue │ ├── badge │ │ ├── index.ts │ │ ├── Badge.vue │ │ └── README.md │ ├── drawer │ │ ├── index.ts │ │ ├── README.md │ │ └── Drawer.vue │ ├── popover │ │ ├── index.ts │ │ ├── README.md │ │ └── Popover.vue │ ├── table │ │ ├── index.ts │ │ ├── HeaderSlot.vue │ │ ├── types.ts │ │ └── demoJs.json │ ├── tooltip │ │ └── index.ts │ ├── autoForm │ │ ├── index.ts │ │ └── test.vue │ ├── backTop │ │ ├── index.ts │ │ ├── README.md │ │ └── BackTop.vue │ ├── divider │ │ ├── index.ts │ │ ├── Divider.vue │ │ └── README.md │ ├── marquee │ │ └── index.ts │ ├── progress │ │ ├── index.ts │ │ ├── type.ts │ │ └── README.md │ ├── textarea │ │ ├── index.ts │ │ └── README.md │ ├── cascader │ │ ├── index.ts │ │ └── demo.json │ ├── colorPicker │ │ ├── index.ts │ │ ├── types.ts │ │ └── README.md │ ├── inputNumber │ │ ├── index.ts │ │ └── README.md │ ├── pagination │ │ ├── index.ts │ │ └── README.md │ ├── selectDown │ │ └── index.ts │ ├── timePicker │ │ ├── index.ts │ │ ├── types.ts │ │ └── README.md │ ├── breadcrumb │ │ ├── index.ts │ │ ├── type.ts │ │ ├── README.md │ │ └── Breadcrumb.vue │ ├── datePicker │ │ ├── index.ts │ │ ├── ControlHead.vue │ │ └── YearMonth.vue │ ├── timeSelect │ │ ├── index.ts │ │ └── README.md │ ├── transition │ │ ├── index.ts │ │ └── Transition.vue │ ├── lazy │ │ ├── img │ │ │ ├── lazy-error.png │ │ │ └── lazy-default.gif │ │ └── README.md │ ├── formItem │ │ ├── index.ts │ │ ├── Field.vue │ │ └── validate.ts │ ├── select │ │ ├── index.ts │ │ └── Option.vue │ ├── upload │ │ ├── index.ts │ │ ├── upload.php │ │ └── Comm.ts │ ├── button │ │ ├── index.ts │ │ ├── ButtonGroup.vue │ │ └── Button.vue │ ├── carousel │ │ ├── index.ts │ │ ├── Item.vue │ │ ├── ItemList.vue │ │ └── README.md │ ├── collapse │ │ ├── index.ts │ │ ├── Collapse.vue │ │ └── Panel.vue │ ├── dropdown │ │ ├── index.ts │ │ └── DropdownItem.vue │ ├── prefix.ts │ ├── tabs │ │ ├── index.ts │ │ ├── RenderSlot.ts │ │ └── TabPane.vue │ ├── radio │ │ ├── index.ts │ │ ├── RadioGroup.vue │ │ └── Radio.vue │ ├── checkbox │ │ ├── index.ts │ │ └── Checkbox.vue │ ├── util │ │ ├── form.ts │ │ ├── index.ts │ │ ├── request.ts │ │ └── dom.ts │ ├── README.md │ ├── index.ts │ ├── loading │ │ ├── index.ts │ │ ├── Loading.vue │ │ └── README.md │ └── message │ │ ├── README.md │ │ └── index.ts ├── assets │ ├── logo.jpg │ └── scss │ │ └── app.scss ├── main.ts ├── vite-env.d.ts ├── views │ └── test.vue └── App.vue ├── .env ├── public ├── favicon.ico ├── image │ ├── img1.png │ └── img2.png └── static │ ├── iconfont │ ├── iconfont.eot │ ├── iconfont.ttf │ ├── iconfont.woff │ ├── iconfont.woff2 │ └── iconfont.css │ └── mock │ └── testData.json ├── tsconfig.node.json ├── .gitignore ├── index.html ├── .prettierrc.js ├── tsconfig.json ├── package.json ├── vite.config.ts ├── README.md └── .eslintrc.cjs /docs/assets/README-aa6ca5f7.css: -------------------------------------------------------------------------------- 1 | .row{margin-bottom:10px} 2 | -------------------------------------------------------------------------------- /src/packages/tag/index.ts: -------------------------------------------------------------------------------- 1 | import Tag from './Tag.vue' 2 | export { Tag } 3 | -------------------------------------------------------------------------------- /src/packages/theme/_icon.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | @include ns(icon) {} 3 | -------------------------------------------------------------------------------- /src/packages/form/index.ts: -------------------------------------------------------------------------------- 1 | import Form from './Form.vue' 2 | export { Form } 3 | -------------------------------------------------------------------------------- /src/packages/menu/index.ts: -------------------------------------------------------------------------------- 1 | import Menu from './Menu.vue' 2 | export { Menu } 3 | -------------------------------------------------------------------------------- /src/packages/tree/index.ts: -------------------------------------------------------------------------------- 1 | import Tree from './Tree.vue' 2 | export { Tree } 3 | -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/337547038/ak-vue3/HEAD/docs/favicon.ico -------------------------------------------------------------------------------- /src/packages/dialog/index.ts: -------------------------------------------------------------------------------- 1 | import Dialog from './Dialog.vue' 2 | export { Dialog } 3 | -------------------------------------------------------------------------------- /src/packages/icon/index.ts: -------------------------------------------------------------------------------- 1 | import Icon from './Icon.vue' 2 | 3 | export { Icon } 4 | -------------------------------------------------------------------------------- /src/packages/image/index.ts: -------------------------------------------------------------------------------- 1 | import Image from './Image.vue' 2 | export { Image } 3 | -------------------------------------------------------------------------------- /src/packages/input/index.ts: -------------------------------------------------------------------------------- 1 | import Input from './Input.vue' 2 | export { Input } 3 | -------------------------------------------------------------------------------- /src/packages/slider/index.ts: -------------------------------------------------------------------------------- 1 | import Slider from './Slider.vue' 2 | export { Slider } 3 | -------------------------------------------------------------------------------- /src/packages/switch/index.ts: -------------------------------------------------------------------------------- 1 | import Switch from './Switch.vue' 2 | export { Switch } 3 | -------------------------------------------------------------------------------- /src/packages/theme/_lazy.scss: -------------------------------------------------------------------------------- 1 | @include ns(lazy-loading) {width: 50px;height: 50px;} 2 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | # 网站标题 2 | VITE_APP_TITLE = 'AK-Vue3' 3 | 4 | # 端口 5 | VITE_APP_PORT = 8890 6 | -------------------------------------------------------------------------------- /docs/image/img1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/337547038/ak-vue3/HEAD/docs/image/img1.png -------------------------------------------------------------------------------- /docs/image/img2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/337547038/ak-vue3/HEAD/docs/image/img2.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/337547038/ak-vue3/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/assets/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/337547038/ak-vue3/HEAD/src/assets/logo.jpg -------------------------------------------------------------------------------- /src/packages/badge/index.ts: -------------------------------------------------------------------------------- 1 | import Badge from './Badge.vue' 2 | 3 | export { Badge } 4 | -------------------------------------------------------------------------------- /src/packages/drawer/index.ts: -------------------------------------------------------------------------------- 1 | import Drawer from './Drawer.vue' 2 | 3 | export { Drawer } 4 | -------------------------------------------------------------------------------- /src/packages/popover/index.ts: -------------------------------------------------------------------------------- 1 | import Popover from './Popover.vue' 2 | export { Popover } 3 | -------------------------------------------------------------------------------- /src/packages/table/index.ts: -------------------------------------------------------------------------------- 1 | import Table from './Table.vue' 2 | 3 | export { Table } 4 | -------------------------------------------------------------------------------- /src/packages/tooltip/index.ts: -------------------------------------------------------------------------------- 1 | import Tooltip from './Tooltip.vue' 2 | export { Tooltip } 3 | -------------------------------------------------------------------------------- /public/image/img1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/337547038/ak-vue3/HEAD/public/image/img1.png -------------------------------------------------------------------------------- /public/image/img2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/337547038/ak-vue3/HEAD/public/image/img2.png -------------------------------------------------------------------------------- /src/packages/autoForm/index.ts: -------------------------------------------------------------------------------- 1 | import AutoForm from './AutoForm.vue' 2 | export { AutoForm } 3 | -------------------------------------------------------------------------------- /src/packages/backTop/index.ts: -------------------------------------------------------------------------------- 1 | import BackTop from './BackTop.vue' 2 | 3 | export { BackTop } 4 | -------------------------------------------------------------------------------- /src/packages/divider/index.ts: -------------------------------------------------------------------------------- 1 | import Divider from './Divider.vue' 2 | 3 | export { Divider } 4 | -------------------------------------------------------------------------------- /src/packages/marquee/index.ts: -------------------------------------------------------------------------------- 1 | import Marquee from './Marquee.vue' 2 | 3 | export { Marquee } 4 | -------------------------------------------------------------------------------- /src/packages/progress/index.ts: -------------------------------------------------------------------------------- 1 | import Progress from './Progress.vue' 2 | export { Progress } 3 | -------------------------------------------------------------------------------- /src/packages/textarea/index.ts: -------------------------------------------------------------------------------- 1 | import Textarea from './Textarea.vue' 2 | export { Textarea } 3 | -------------------------------------------------------------------------------- /src/packages/cascader/index.ts: -------------------------------------------------------------------------------- 1 | import Cascader from './Cascader.vue' 2 | 3 | export { Cascader } 4 | -------------------------------------------------------------------------------- /src/packages/colorPicker/index.ts: -------------------------------------------------------------------------------- 1 | import ColorPicker from './ColorPicker.vue' 2 | export { ColorPicker } 3 | -------------------------------------------------------------------------------- /src/packages/inputNumber/index.ts: -------------------------------------------------------------------------------- 1 | import InputNumber from './InputNumber.vue' 2 | export { InputNumber } 3 | -------------------------------------------------------------------------------- /src/packages/pagination/index.ts: -------------------------------------------------------------------------------- 1 | import Pagination from './Pagination.vue' 2 | export { Pagination } 3 | -------------------------------------------------------------------------------- /src/packages/selectDown/index.ts: -------------------------------------------------------------------------------- 1 | import SelectDown from './SelectDown.vue' 2 | export { SelectDown } 3 | -------------------------------------------------------------------------------- /src/packages/timePicker/index.ts: -------------------------------------------------------------------------------- 1 | import TimePicker from './TimePicker.vue' 2 | export { TimePicker } 3 | -------------------------------------------------------------------------------- /docs/assets/img1-df60c764.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/337547038/ak-vue3/HEAD/docs/assets/img1-df60c764.png -------------------------------------------------------------------------------- /docs/assets/img2-407e7c99.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/337547038/ak-vue3/HEAD/docs/assets/img2-407e7c99.png -------------------------------------------------------------------------------- /docs/assets/logo-961f8a2e.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/337547038/ak-vue3/HEAD/docs/assets/logo-961f8a2e.jpg -------------------------------------------------------------------------------- /src/packages/breadcrumb/index.ts: -------------------------------------------------------------------------------- 1 | import Breadcrumb from './Breadcrumb.vue' 2 | 3 | export { Breadcrumb } 4 | -------------------------------------------------------------------------------- /src/packages/datePicker/index.ts: -------------------------------------------------------------------------------- 1 | import DatePicker from './DatePicker.vue' 2 | 3 | export { DatePicker } 4 | -------------------------------------------------------------------------------- /src/packages/timeSelect/index.ts: -------------------------------------------------------------------------------- 1 | import TimeSelect from './TimeSelect.vue' 2 | 3 | export { TimeSelect } 4 | -------------------------------------------------------------------------------- /src/packages/transition/index.ts: -------------------------------------------------------------------------------- 1 | import Transition from './Transition.vue' 2 | 3 | export { Transition } 4 | -------------------------------------------------------------------------------- /src/packages/breadcrumb/type.ts: -------------------------------------------------------------------------------- 1 | export interface BreadcrumbItem { 2 | title: string 3 | href: string 4 | } 5 | -------------------------------------------------------------------------------- /docs/assets/lazy-error-ad8f0809.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/337547038/ak-vue3/HEAD/docs/assets/lazy-error-ad8f0809.png -------------------------------------------------------------------------------- /docs/static/iconfont/iconfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/337547038/ak-vue3/HEAD/docs/static/iconfont/iconfont.eot -------------------------------------------------------------------------------- /docs/static/iconfont/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/337547038/ak-vue3/HEAD/docs/static/iconfont/iconfont.ttf -------------------------------------------------------------------------------- /docs/static/iconfont/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/337547038/ak-vue3/HEAD/docs/static/iconfont/iconfont.woff -------------------------------------------------------------------------------- /docs/static/iconfont/iconfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/337547038/ak-vue3/HEAD/docs/static/iconfont/iconfont.woff2 -------------------------------------------------------------------------------- /public/static/iconfont/iconfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/337547038/ak-vue3/HEAD/public/static/iconfont/iconfont.eot -------------------------------------------------------------------------------- /public/static/iconfont/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/337547038/ak-vue3/HEAD/public/static/iconfont/iconfont.ttf -------------------------------------------------------------------------------- /src/packages/theme/_autoForm.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | @include ns(form) { 3 | .grid-row {display: flex} 4 | } 5 | 6 | -------------------------------------------------------------------------------- /docs/assets/lazy-default-3fb51c0d.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/337547038/ak-vue3/HEAD/docs/assets/lazy-default-3fb51c0d.gif -------------------------------------------------------------------------------- /public/static/iconfont/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/337547038/ak-vue3/HEAD/public/static/iconfont/iconfont.woff -------------------------------------------------------------------------------- /public/static/iconfont/iconfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/337547038/ak-vue3/HEAD/public/static/iconfont/iconfont.woff2 -------------------------------------------------------------------------------- /src/packages/lazy/img/lazy-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/337547038/ak-vue3/HEAD/src/packages/lazy/img/lazy-error.png -------------------------------------------------------------------------------- /src/packages/lazy/img/lazy-default.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/337547038/ak-vue3/HEAD/src/packages/lazy/img/lazy-default.gif -------------------------------------------------------------------------------- /src/packages/formItem/index.ts: -------------------------------------------------------------------------------- 1 | import FormItem from './FormItem.vue' 2 | import Field from './Field.vue' 3 | export { FormItem, Field } 4 | -------------------------------------------------------------------------------- /src/packages/select/index.ts: -------------------------------------------------------------------------------- 1 | import Select from './Select.vue' 2 | import Option from './Option.vue' 3 | 4 | export { Select, Option } 5 | -------------------------------------------------------------------------------- /src/packages/upload/index.ts: -------------------------------------------------------------------------------- 1 | import Upload from './Upload.vue' 2 | import ImgCrop from './ImgCrop.vue' 3 | 4 | export { Upload, ImgCrop } 5 | -------------------------------------------------------------------------------- /src/packages/colorPicker/types.ts: -------------------------------------------------------------------------------- 1 | export interface Color { 2 | [key: string]: number 3 | 4 | r: number 5 | g: number 6 | b: number 7 | } 8 | -------------------------------------------------------------------------------- /src/packages/theme/_popover.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | @include ns(popover) { 3 | .content{padding: 10px 0} 4 | .footer{text-align: right} 5 | } 6 | -------------------------------------------------------------------------------- /src/packages/button/index.ts: -------------------------------------------------------------------------------- 1 | import Button from './Button.vue' 2 | import ButtonGroup from './ButtonGroup.vue' 3 | 4 | export { Button, ButtonGroup } 5 | -------------------------------------------------------------------------------- /src/packages/carousel/index.ts: -------------------------------------------------------------------------------- 1 | import Carousel from './Carousel.vue' 2 | import CarouselItem from './Item.vue' 3 | 4 | export { Carousel, CarouselItem } 5 | -------------------------------------------------------------------------------- /src/packages/timePicker/types.ts: -------------------------------------------------------------------------------- 1 | export interface Time { 2 | h: number 3 | m: number 4 | s: number 5 | a?: number 6 | [key: string]: any 7 | } 8 | -------------------------------------------------------------------------------- /src/packages/collapse/index.ts: -------------------------------------------------------------------------------- 1 | import Collapse from './Collapse.vue' 2 | import CollapsePanel from './Panel.vue' 3 | 4 | export { Collapse, CollapsePanel } 5 | -------------------------------------------------------------------------------- /src/packages/dropdown/index.ts: -------------------------------------------------------------------------------- 1 | import Dropdown from './Dropdown.vue' 2 | import DropdownItem from './DropdownItem.vue' 3 | 4 | export { Dropdown, DropdownItem } 5 | -------------------------------------------------------------------------------- /src/packages/prefix.ts: -------------------------------------------------------------------------------- 1 | //import { ref } from 'vue' 2 | 3 | //const prefixCls = ref('ak') // 类名样式前缀和组件注册前缀名 4 | const prefixCls = 'ak' 5 | export default prefixCls 6 | -------------------------------------------------------------------------------- /src/packages/tabs/index.ts: -------------------------------------------------------------------------------- 1 | import Tabs from './Tabs.vue' 2 | import TabPane from './TabPane.vue' 3 | /* 4 | export default { Tabs, TabPane }*/ 5 | export { Tabs, TabPane } 6 | -------------------------------------------------------------------------------- /src/packages/radio/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 337547038 on 2018/9/7 0007. 3 | */ 4 | import Radio from './Radio.vue' 5 | import RadioGroup from './RadioGroup.vue' 6 | 7 | export { Radio, RadioGroup } 8 | -------------------------------------------------------------------------------- /src/packages/checkbox/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 337547038 on 2018/9/6 0006. 3 | */ 4 | import Checkbox from './Checkbox.vue' 5 | import CheckboxGroup from './Group.vue' 6 | 7 | export { Checkbox, CheckboxGroup } 8 | -------------------------------------------------------------------------------- /src/packages/menu/types.ts: -------------------------------------------------------------------------------- 1 | export interface Items { 2 | label?: string 3 | key: string 4 | icon?: string 5 | children?: Items[] 6 | disabled?: boolean 7 | className?: string 8 | childHeight?: number // 用于微调下拉高度,仅在mode为vertical时 9 | } 10 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /src/packages/theme/_backTop.scss: -------------------------------------------------------------------------------- 1 | @include ns(back-top){ 2 | position: fixed; z-index: 99;transition: all .5s; 3 | a{ display: block; padding: 10px; color: $textColor4; text-align: center; border-radius: 2px; background:$primaryColor; cursor: pointer; 4 | &:hover{ } 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/packages/progress/type.ts: -------------------------------------------------------------------------------- 1 | export interface circleStyleAttr { 2 | // [propName: string]: any 3 | width?: string 4 | height?: string 5 | borderWidth?: string 6 | borderColor?: string 7 | left?: string 8 | top?: string 9 | clip?: string 10 | transform?: string 11 | } 12 | -------------------------------------------------------------------------------- /src/packages/theme/_textarea.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | @include ns(textarea) {position: relative; 3 | textarea { 4 | font-size: 14px;font-family: "Microsoft YaHei UI";line-height: 22px;resize: none; 5 | @include scrollColor() 6 | } 7 | .input-count {position: absolute;right: 10px;bottom: 10px;font-size: 12px;color: #999} 8 | } 9 | -------------------------------------------------------------------------------- /src/packages/util/form.ts: -------------------------------------------------------------------------------- 1 | import { inject } from 'vue' 2 | import prefixCls from '../prefix' 3 | 4 | export const getFormDisabled = (bool: boolean) => { 5 | // 如果form里设置了,使用form的 6 | const formProps: any = inject(`${prefixCls}FormProps`, {}) 7 | if (formProps && formProps.disabled) { 8 | return true 9 | } else { 10 | return bool 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | ./dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import 'vite-plugin-doc-preview/style/style.css' 3 | import App from './App.vue' 4 | import router from './router' 5 | import AKUI from './packages' 6 | //import './packages/theme/index.scss' 7 | 8 | import './assets/scss/app.scss' 9 | const app = createApp(App) 10 | app.use(router) 11 | app.use(AKUI) 12 | 13 | app.mount('#app') 14 | -------------------------------------------------------------------------------- /src/packages/tabs/RenderSlot.ts: -------------------------------------------------------------------------------- 1 | import { defineComponent, h } from 'vue' 2 | 3 | export default defineComponent({ 4 | props: { 5 | slots: [Object, String] 6 | }, 7 | // @ts-ignore 8 | setup(props) { 9 | // console.log(props.slots[0]) 10 | // return () => [h('div', { props: props.slots?.props }, props.slots)] 11 | return () => [h('div', {}, props.slots)] 12 | } 13 | }) 14 | -------------------------------------------------------------------------------- /src/packages/theme/index.scss: -------------------------------------------------------------------------------- 1 | @import 'var',"mixins","selectDown", "button", "carousel", "collapse", 'cascader', 'backTop', 'badge', 'input', 'radio', 'select', 'checkbox', 'switch', 'textarea', 'inputNumber', 'formItem', 'datePicker', 'autoForm', 'table', 'page', 'tabs', 'colorPicker', 'progress', 'tooltip', 'dialog', 'loading', 'lazy', 'tree', 'tag', 'drawer', 'popover', 'upload','dropdown','divider','timePicker','menu','image','slider'; 2 | -------------------------------------------------------------------------------- /docs/static/mock/testData.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "label": "选项1", 5 | "value": "a1" 6 | }, 7 | { 8 | "label": "选项2", 9 | "value": "a2" 10 | }, 11 | { 12 | "label": "选项3", 13 | "value": "a3" 14 | }, 15 | { 16 | "label": "选项4", 17 | "value": "a4" 18 | }, 19 | { 20 | "label": "禁用", 21 | "value": "a5", 22 | "disabled": true 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /src/packages/theme/_drawer.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | @include ns(drawer) { 3 | position: fixed;top: 0;bottom: 0;right: 0;border-radius: 0; 4 | @include ns(dialog-header){} 5 | } 6 | @include ns(drawer-left) { 7 | right: auto;left: 0; 8 | } 9 | @include ns(drawer-bottom) { 10 | right: 0;left: 0;top:auto;bottom: 0;width: 100%!important; 11 | } 12 | @include ns(drawer-top) { 13 | right: 0;left: 0;top:0;bottom: auto;width: 100%!important; 14 | } 15 | -------------------------------------------------------------------------------- /public/static/mock/testData.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "label": "选项1", 5 | "value": "a1" 6 | }, 7 | { 8 | "label": "选项2", 9 | "value": "a2" 10 | }, 11 | { 12 | "label": "选项3", 13 | "value": "a3" 14 | }, 15 | { 16 | "label": "选项4", 17 | "value": "a4" 18 | }, 19 | { 20 | "label": "禁用", 21 | "value": "a5", 22 | "disabled": true 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /src/packages/upload/upload.php: -------------------------------------------------------------------------------- 1 | $names){ 12 | // move_uploaded_file($_FILES['file']['tmp_name'][$k],'upload/'.$name[$k]); 13 | // } 14 | //echo '批量上传成功' 15 | ?> -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | AK UI一套基于Vue3 + Typescript + Vite的组件库 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/packages/icon/Icon.vue: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 22 | -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | declare module '*.vue' { 4 | import type { DefineComponent } from 'vue' 5 | // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types 6 | const component: DefineComponent<{}, {}, any> 7 | export default component 8 | } 9 | 10 | declare module 'virtual:generated-pages' { 11 | const routesList: any[] 12 | export default routesList 13 | } 14 | declare module 'vue' 15 | declare module 'vue-router' 16 | declare module '*.md' 17 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | AK UI一套基于Vue3 + Typescript + Vite的组件库 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/packages/theme/_collapse.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | @include ns(collapse) { 3 | .collapse-panel {border-bottom: 1px solid $borderColor;overflow: hidden;} 4 | /*title*/ 5 | .collapse-title {height: 50px;line-height: 50px;cursor: pointer;user-select: none;display: flex;align-items: center; 6 | .arrow {font-size: 12px;margin-right: 5px;display: block;transform: rotate(-90deg) scale(.8);transition:all .3s; 7 | &.down {transform: rotate(0) scale(.8)} 8 | } 9 | } 10 | /*content*/ 11 | .collapse-content {padding: 10px;overflow: hidden;transition: all .3s; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/packages/autoForm/test.vue: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 23 | -------------------------------------------------------------------------------- /src/packages/tree/NodeContent.vue: -------------------------------------------------------------------------------- 1 | 20 | -------------------------------------------------------------------------------- /src/packages/carousel/Item.vue: -------------------------------------------------------------------------------- 1 | 24 | -------------------------------------------------------------------------------- /src/packages/dropdown/DropdownItem.vue: -------------------------------------------------------------------------------- 1 | 6 | 24 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | semi: false, //是否在语句末尾加分号 3 | singleQuote: true, // 是否使用单引号,建议使用单引号 4 | trailingComma: 'none', // 多行数组和对象的最后一项是否添加逗号 5 | printWidth: 80, // 一行的字符数,超出会自动换行,默认为 80。 6 | tabWidth: 2, // 一个 tab 的宽度,建议设置为 2 (默认为 2); 7 | bracketSpacing: true, //对象字面量的花括号之间是否添加空格,建议添加空格(即设置为 true); 8 | jsxSingleQuote: false, // 语法中属性是否使用单引号,默认为 false(即用双引号)。//jsx 语法中属性是否使用单引号,默认为 false(即用双引号)。 9 | jsxBracketSameLine: false, //jsx 中的 > 是否与前面的内容在同一行,建议分行(即设置为 false); 10 | arrowParens: 'avoid', //箭头函数的参数是否使用括号,建议不使用括号(即设置为 "avoid") 11 | vueIndentScriptAndStyle: true, 12 | endOfLine: 'auto' 13 | } 14 | -------------------------------------------------------------------------------- /src/packages/backTop/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # BackTop 返回顶部 4 | 5 | ### 用法 6 | 7 | ```vue demo 8 | 12 | ``` 13 | 14 | ## API 15 | 16 | ### BackTop Props 17 | 18 | | 参数 | 类型 | 说明 | 19 | |----------|--------------|--------| 20 | |height | Number/200 |页面滚动高度达到该值时才显示BackTop组件| 21 | |bottom | Number/30 |组件距离底部的距离| 22 | |right | Number/30 |组件距离右部的距离| 23 | |text | String |显示文本| 24 | 25 | ### BackTop Event 26 | 27 | | 参数 | 说明 | 28 | |------|------| 29 | |click |-| 30 | -------------------------------------------------------------------------------- /docs/assets/test-d7202dcc.js: -------------------------------------------------------------------------------- 1 | import{r as t,a as o,o as m,c as p,b as n,w as k,F as V,d as f}from"./index-dd3aacc0.js";const i={__name:"test",setup(g){const r=[{label:"广东",children:[{label:"广州",children:[{label:"天河区"},{label:"白云区"},{label:"越秀区"},{label:"海珠区"}]},{label:"深圳"},{label:"东莞"},{label:"佛山"}]},{label:"广西"},{label:"北京"}],s=u=>{},e=t(),l=t([]),c=()=>{console.log(e.value.getValue())};return(u,a)=>{const b=o("ak-tree"),_=o("ak-button");return m(),p(V,null,[n(b,{data:r,showCheckbox:!0,onChange:s,modelValue:l.value,"onUpdate:modelValue":a[0]||(a[0]=d=>l.value=d),ref_key:"treeEl",ref:e},null,8,["modelValue"]),n(_,{onClick:c},{default:k(()=>[f("getValue")]),_:1})],64)}}};export{i as default}; 2 | -------------------------------------------------------------------------------- /src/packages/carousel/ItemList.vue: -------------------------------------------------------------------------------- 1 | 27 | -------------------------------------------------------------------------------- /src/packages/table/HeaderSlot.vue: -------------------------------------------------------------------------------- 1 | 2 | 29 | -------------------------------------------------------------------------------- /src/packages/tabs/TabPane.vue: -------------------------------------------------------------------------------- 1 | 23 | -------------------------------------------------------------------------------- /src/assets/scss/app.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | //reset 3 | html, body, div, table, td, th, tr, input, button, h1, h2, h3, h4, pre, ul, li { 4 | margin: 0; 5 | padding: 0; 6 | } 7 | 8 | body { 9 | font-size: 14px; 10 | color: #333; 11 | } 12 | 13 | i { 14 | font-style: normal 15 | } 16 | 17 | ul, li { 18 | list-style: none 19 | } 20 | 21 | a { 22 | text-decoration: none; 23 | color: #333 24 | } 25 | 26 | .clearfix { 27 | &:after { 28 | content: ''; 29 | clear: both; 30 | height: 0; 31 | line-height: 0; 32 | visibility: hidden; 33 | display: inline-block 34 | } 35 | } 36 | 37 | * { 38 | box-sizing: border-box; 39 | } 40 | 41 | // demo style 42 | @import "demo"; 43 | // components 44 | 45 | -------------------------------------------------------------------------------- /src/packages/theme/_timePicker.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | @include ns(time-picker) { 3 | display: flex; 4 | .time-picker {display: flex;flex: 2} 5 | ul {flex: 2;height: 200px;overflow-y: auto;overflow-x: hidden;padding: 10px 1px; 6 | @include scrollColor() 7 | } 8 | li {height: 22px;line-height: 22px;padding: 0 10px;border-radius: $borderRadius;cursor: pointer; 9 | &.disabled {opacity: $disabledOpacity;cursor: not-allowed} 10 | &.active, &:hover {background: $backgroundColor2;color: $primaryColor} 11 | } 12 | &.is-range { 13 | .time-picker {margin: 10px;border: 1px solid $borderColor;border-radius: $borderRadius; 14 | &:first-child {margin-right: 5px} 15 | &:last-child {margin-left: 5px} 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/packages/theme/_select.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | @include ns(select) {background: $backgroundColor;box-sizing: border-box;width: 100%;z-index: 50;padding: 10px 0; 3 | li {list-style: none;height: 25px;line-height: 25px;padding: 0 10px;margin: 0;cursor: pointer;width: 100%;display: block;box-sizing: border-box;white-space: nowrap;text-overflow: ellipsis;overflow: hidden;user-select: none; 4 | &:hover {background: $backgroundColor2;} 5 | 6 | &.active {background: $backgroundColor2;color: $primaryColor; 7 | b{color: $backgroundColor}} 8 | 9 | &.disabled {cursor: not-allowed;opacity: $disabledOpacity} 10 | b{color: $primaryColor;font-weight: 400} 11 | } 12 | .select-empty-options{color: $textColor2;margin: 0;padding: 0 10px} 13 | } 14 | 15 | -------------------------------------------------------------------------------- /src/packages/theme/_tree.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | @include ns(tree) { 3 | ul {padding-left: 20px !important;} 4 | .tree-box {display: flex;align-items: center;padding: 2px 3px; 5 | &:hover {background: lighten($primaryColor, 45)} 6 | &.has-child {cursor: pointer; 7 | i {opacity: 1;visibility: visible} 8 | } 9 | &.selected {color: lighten($primaryColor, 0)} 10 | } 11 | .icon-down {font-size: 12px;transform: rotate(-90deg);transition: all .3s;cursor: pointer;width: 12px;opacity: 0;display: block;visibility: hidden} 12 | // 有子级时显示icon 13 | i.open-child {transform: rotate(0deg);} 14 | .lazy-loading {position: relative;width: 20px; 15 | .loading-svg {width: 15px;height: 15px;} 16 | } 17 | @include ns(checkbox) { 18 | margin-left: 3px; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/packages/table/types.ts: -------------------------------------------------------------------------------- 1 | export interface RowColSpan { 2 | row: number // 当前行号 3 | col: number // 当前列号 4 | rowSpan?: number // 行合并 5 | colSpan?: number // 列合并 6 | } 7 | 8 | export interface Columns { 9 | prop: string // 参数 10 | label: string // 显示的th名称 11 | width?: string 12 | className?: string 13 | align?: 'left' | 'center' | 'right' // 对齐方式,可选left/center/right 14 | type?: 'selection' | 'index' | 'extend' // 可选selection(多选)/index序号 15 | fixed?: 'left' | 'right' // 固定当前列,可选left/right 16 | sortBy?: boolean // 当前列显示排序按钮 17 | title?: boolean // 鼠标滑过单元格时是否显示title提示语 18 | drag?: boolean // 当前单元格允许拖动,仅在table设置drag=true时有效 19 | formatter?: (rowIndex: number, colIndex: number, row: any, col: any) => void 20 | tooltip?: boolean | object 21 | tag?: boolean | object 22 | } 23 | -------------------------------------------------------------------------------- /src/packages/theme/_inputNumber.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | @include ns(input-number) {display: inline-block;vertical-align: middle;position: relative; 3 | input {text-align: center;} 4 | .number-control { 5 | a {display: flex;position: absolute;top: 1px;width: 38px;bottom: 1px;background: #f5f7fa;left: 1px;border-right: 1px solid $borderColor;text-align: center;cursor: pointer;align-items: center;justify-content: center;font-size: 14px; 6 | 7 | &:last-child {left: auto;right: 1px;border-left: 1px solid $borderColor;border-right-color: transparent;} 8 | 9 | &.disabled {cursor: not-allowed;opacity: $disabledOpacity} 10 | } 11 | } 12 | &.disabled { 13 | .number-control {opacity: $disabledOpacity; 14 | a {background: #eee;cursor: not-allowed} 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/packages/util/index.ts: -------------------------------------------------------------------------------- 1 | export default {} 2 | // 防抖 3 | export function debounce(fn: any, delay = 500) { 4 | let timer: any 5 | return function (...args: any) { 6 | if (timer) { 7 | clearTimeout(timer) 8 | } 9 | timer = setTimeout(() => { 10 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 11 | // @ts-ignore 12 | fn.apply(this, args) 13 | }, delay) 14 | } 15 | } 16 | 17 | // 节流 18 | /* 19 | export function throttle(fn, delay = 500) { 20 | let canUse = true // 设置一个开关 21 | return function () { 22 | if (!canUse) { 23 | return false // 如果开关已经关掉了就不用往下了 24 | } 25 | canUse = false // 利用闭包刚进来的时候关闭开关 26 | setTimeout(() => { 27 | fn.apply(this, arguments) 28 | canUse = true // 执行完才打开开关 29 | }, delay) 30 | } 31 | }*/ 32 | -------------------------------------------------------------------------------- /src/packages/theme/_var.scss: -------------------------------------------------------------------------------- 1 | $colorBlue: #1989fa; 2 | $colorRed: #ee0a24; 3 | $colorOrange: #ff976a; 4 | $colorGreen: #07c160; 5 | $colorWhite: #fff; 6 | $colorBlack: #000; 7 | $colorGray: #f2f3f5; 8 | $colorGray2: #dcdee0; 9 | $colorGray3: #969799; 10 | $colorGray4: #323233; 11 | // 12 | $primaryColor: $colorBlue; 13 | $successColor: $colorGreen; 14 | $dangerColor: $colorRed; 15 | $warningColor: $colorOrange; 16 | // 17 | $textColor: $colorGray4; 18 | $textColor2: $colorGray3; 19 | $textColor3: $colorGray2; 20 | $textColor4: $colorGray; 21 | $textColor5: $colorWhite; 22 | $textLinkColor: $colorBlue; 23 | // 24 | $borderColor: $colorGray2; 25 | $borderLineColor: $colorGray; 26 | $borderRadius: 2px; 27 | $backgroundColor: $colorWhite; 28 | $backgroundColor2: $colorGray; 29 | // 30 | $disabledOpacity: 0.5; 31 | // 32 | $placeholder:$colorGray3 33 | -------------------------------------------------------------------------------- /src/packages/theme/_divider.scss: -------------------------------------------------------------------------------- 1 | @include ns(divider) { 2 | display: block; 3 | height: 1px; 4 | width: 100%; 5 | margin: 24px 0; 6 | position: relative; 7 | border-top: 1px $borderColor var(--divider-border-style, solid); 8 | .divider-text { 9 | position: absolute; 10 | background-color: #fff; 11 | padding: 0 20px; 12 | font-weight: 500; 13 | font-size: 14px; 14 | transform: translateY(-50%); 15 | &.center { 16 | transform: translate(-50%, -50%);left: 50%; 17 | } 18 | &.left {left: 20px;} 19 | &.right {right: 20px} 20 | } 21 | &.vertical{ 22 | display: inline-block; 23 | width: 1px; 24 | height: 1em; 25 | margin: 0 8px; 26 | vertical-align: middle; 27 | border-top: 0; 28 | border-left: 1px $borderColor var(--divider-border-style, solid); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/packages/select/Option.vue: -------------------------------------------------------------------------------- 1 | 28 | -------------------------------------------------------------------------------- /src/packages/breadcrumb/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Breadcrumb 面包屑 4 | 5 | ### 用法 6 | 7 | ```vue demo 8 | 11 | 21 | 22 | ``` 23 | 24 | ## API 25 | 26 | ### BackTop 27 | 28 | |参数|类型|说明| 29 | |----------|--------------|--------| 30 | |data | Array |数据| 31 | |separator | String |分隔字符| 32 | 33 | ### data 34 | 35 | |参数|类型|说明| 36 | |----------|--------------|--------| 37 | |title | String |显示的名称| 38 | |href | String |链接地址| 39 | -------------------------------------------------------------------------------- /src/packages/theme/_radio.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | @include ns(radio) {cursor: pointer;display: inline-block; 3 | > span {display: flex;align-items: center} 4 | .radio-inner {margin-right: 5px;width: 14px;height: 14px;border-radius: 50%;border: 1px solid $borderColor;display: flex;align-items: center;justify-content: center; 5 | &:after {display: block;width: 8px;height: 8px;border-radius: 50%;content: '';background: $borderColor;opacity: 0;transform: scale(0);transition: all .3s} 6 | } 7 | &.checked { 8 | // 选中状态 9 | .radio-inner {border-color: $primaryColor; 10 | &:after {opacity: 1;transform: scale(1);background: $primaryColor;} 11 | } 12 | } 13 | &.disabled {cursor: not-allowed;opacity: .5; 14 | .radio-inner {opacity: .5} 15 | } 16 | + .#{$namespace}radio {margin-left: 10px} 17 | } 18 | @include ns(radio-group) {display: inline-block} 19 | -------------------------------------------------------------------------------- /src/packages/util/request.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | // 全局设置 3 | /* axios.defaults.baseURL = window.APP_CONFIG.BASE_URL 4 | axios.defaults.headers.common['Authorization'] = getToken() */ 5 | 6 | const service = axios.create({ 7 | baseURL: import.meta.env.VITE_APP_URL, // api的base_url 8 | //baseURL: 'http://localhost:3001/api', // api的base_url 9 | timeout: 6000, // request timeout 10 | headers: {} 11 | }) 12 | 13 | service.interceptors.request.use( 14 | config => { 15 | return config 16 | }, 17 | error => { 18 | Promise.reject(error) 19 | } 20 | ) 21 | 22 | service.interceptors.response.use( 23 | response => { 24 | if (response.data.code === 0) { 25 | return Promise.reject(response) 26 | } else { 27 | return response 28 | } 29 | }, 30 | error => { 31 | return Promise.reject(error) 32 | } 33 | ) 34 | export default service 35 | -------------------------------------------------------------------------------- /src/packages/README.md: -------------------------------------------------------------------------------- 1 | 2 | # AK UI 3 | 4 | AK UI是一个vue3的组件库,基于 Vue3 + Typescript + Vite + pnpm。 5 | 6 | 常用基础组件,代码简洁,满足常见项目,组件类名可自定义,不依懒第三方库,全程无红线语法报错,便于二次开发,无缝衔接项目 7 | 8 | 主题可调,只需10分钟即可定义一套全新的组件样式 9 | 10 | 用于学习研究,欢迎交流,微信:337547038 11 | 12 | ## 全局引入(推荐) 13 | 14 | ```shell 15 | pnpm install ak-vue3 16 | ``` 17 | 18 | 19 | ```ts 20 | // main.ts 21 | import AKVUE from 'ak-vue3' 22 | import 'ak-vue3/style.css' // 引入组件样式 23 | import 'ak-vue3/iconfont.css' // 引入iconfont图标样式 24 | app.use(AKVUE) 25 | ``` 26 | 27 | 若不使用npm安装时,可将资源包复制到项目,如 src 目录下,然后在入口页面 main.ts 中如下配置: 28 | 29 | ```javascript 30 | import Component from "../packages/index"; 31 | // 全局注册基础组件 32 | Vue.use(Component); 33 | ``` 34 | 35 | ## 按需引用 36 | 37 | 在当前页面 import 所需组件 38 | 39 | ```javascript 40 | import Button from "../packages/button.vue"; 41 | ``` 42 | 43 | ## 可打包 44 | 45 | 可使用命令`npm run build:lib`将组件资源打包成一个js文件 46 | -------------------------------------------------------------------------------- /src/packages/breadcrumb/Breadcrumb.vue: -------------------------------------------------------------------------------- 1 | 2 | 22 | 35 | -------------------------------------------------------------------------------- /src/packages/button/ButtonGroup.vue: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 39 | -------------------------------------------------------------------------------- /src/packages/collapse/Collapse.vue: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 38 | -------------------------------------------------------------------------------- /src/packages/theme/_badge.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | @include ns(badge) { 3 | position: relative; 4 | vertical-align: middle; 5 | display: inline-block; 6 | sup { 7 | position: absolute; 8 | top: 0; 9 | right: 10px; 10 | transform: translateY(-50%) translateX(100%); 11 | display: inline-block; 12 | background-color: $primaryColor; 13 | border-radius: 10px; 14 | color: $textColor4; 15 | font-size: 12px; 16 | height: 18px; 17 | line-height: 18px; 18 | padding: 0 6px; 19 | text-align: center; 20 | white-space: nowrap; 21 | } 22 | &.dot { 23 | sup { 24 | height: 8px; 25 | width: 8px; 26 | padding: 0; 27 | right: 0; 28 | border-radius: 50%; 29 | font-size: 0; 30 | text-indent: -9999px; 31 | overflow: hidden; 32 | } 33 | } 34 | &.success sup{background-color: $successColor} 35 | &.warning sup{background-color: $warningColor} 36 | &.danger sup{background-color: $dangerColor} 37 | } 38 | -------------------------------------------------------------------------------- /src/views/test.vue: -------------------------------------------------------------------------------- 1 | 11 | 44 | -------------------------------------------------------------------------------- /docs/assets/vue-9f3c8957.css: -------------------------------------------------------------------------------- 1 | .doc-preview[data-v-43edb7f1]{border:1px solid #eee;margin-bottom:20px}.doc-preview .component[data-v-43edb7f1]{padding:10px}.doc-preview .control-tools[data-v-43edb7f1]{align-items:center;border-top:1px solid #eee;color:#333;display:flex;justify-content:flex-end;padding:5px 10px}.doc-preview .tools[data-v-43edb7f1]{display:flex}.doc-preview .control-tools .text[data-v-43edb7f1]{flex:2;text-align:center;visibility:hidden;opacity:0;transition:all .3s;transform:translate(100px);cursor:pointer}.doc-preview .control-tools:hover .text[data-v-43edb7f1]{visibility:visible;opacity:1;transform:translate(0)}.doc-preview .fixed-tools[data-v-43edb7f1]{position:relative;color:#999}.doc-preview .fixed-tools .tools[data-v-43edb7f1]{position:absolute;right:10px;top:10px}.doc-preview .item[data-v-43edb7f1]{cursor:pointer;margin-left:5px}.doc-preview .item[data-v-43edb7f1]:hover{opacity:.6}.doc-preview .code[data-v-43edb7f1]{border-top:1px solid #eee;padding:0}.doc-preview pre[data-v-43edb7f1]{border-radius:0;margin:0} 2 | -------------------------------------------------------------------------------- /src/packages/drawer/README.md: -------------------------------------------------------------------------------- 1 | # Drawer 抽屉对话框 2 | 3 | ### 基本用法 4 | 5 | 用法和所有参数同`Dialog`一样 6 | 7 | ```vue demo 8 | 19 | 29 | 30 | 31 | ``` 32 | 33 | ## API 34 | 35 | ### Drawer 36 | 37 | |参数|类型|说明| 38 | |----------|--------------|--------| 39 | |direction | string/right |显示方向,left/right/top/bottom| 40 | |- | - |其他所有参数同[dialog](/#/dialog)| 41 | -------------------------------------------------------------------------------- /src/packages/colorPicker/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # ColorPicker 颜色选择器 4 | 5 | ### 基础用法 6 | 7 | ```vue demo 8 | 11 | 15 | 16 | ``` 17 | 18 | ### RGB模式 19 | 20 | ```vue demo 21 | 24 | 28 | 29 | ``` 30 | 31 | ## API 32 | 33 | ### ColorPicker 34 | 35 | |参数|类型|说明| 36 | |----------|--------------|--------| 37 | |v-model | String |选择的颜色| 38 | |format | String/hex |格式化类型,hex和rgb两种| 39 | |change | Function |确认点击事件| 40 | |text | String |确认文本| 41 | 42 | ### ColorPicker Event 43 | 44 | |参数|说明| 45 | |----------|--------------| 46 | |change |确认点击事件| 47 | -------------------------------------------------------------------------------- /src/packages/badge/Badge.vue: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 43 | -------------------------------------------------------------------------------- /src/packages/theme/_checkbox.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | @include ns(checkbox) {cursor: pointer;display: inline-block; 3 | > span {display: flex;align-items: center} 4 | /*默认*/ 5 | .checkbox-text {margin-left: 5px} 6 | .checkbox-inner {border: 1px solid $borderColor;border-radius: 2px;box-sizing: border-box;width: 14px;height: 14px;display: flex;align-items: center;justify-content: center;transition: all .3s; 7 | 8 | &:hover {opacity: .8} 9 | 10 | &:before {font-size: 12px;display: block;opacity: 0;transform: scale(0);transition: opacity .3s, transform .3s;} 11 | 12 | &.checked { 13 | &.checkbox-inner{border-color: $primaryColor} 14 | &:before {opacity: 1;transform: scale(.9);color: $primaryColor;} 15 | } 16 | } 17 | &.disabled {cursor: not-allowed; 18 | 19 | .checkbox-inner {opacity: $disabledOpacity;background: #ddd} 20 | } 21 | + .#{$namespace}checkbox {margin-left: 10px} 22 | &.some-select { 23 | .checkbox-inner { 24 | &:before {opacity: 1;transform: scale(1);content: '';height: 3px;background: $primaryColor;width: 75%} 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/packages/popover/README.md: -------------------------------------------------------------------------------- 1 | # popover(Tooltip) 弹出框 2 | 3 | ### 基本用法 4 | 5 | 基于`tooltip`提示 6 | 7 | ```vue demo 8 | 25 | 30 | 31 | 32 | ``` 33 | 34 | ## API 35 | 36 | ### Popover Props 37 | 38 | | 参数 | 类型 | 说明 | 39 | |-----------|----------|--------------------------| 40 | | confirm | string | 确认按钮文案 | 41 | | cancel | string | 取消按钮文案 | 42 | | callback | function | 确认按钮事件 | 43 | | - | - | 其他同[Tooltip](/#/tooltip) | 44 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "module": "ESNext", 6 | "lib": [ 7 | "ES2020", 8 | "DOM", 9 | "DOM.Iterable" 10 | ], 11 | "skipLibCheck": true, 12 | /* Bundler mode */ 13 | "moduleResolution": "bundler", 14 | "allowImportingTsExtensions": true, 15 | "resolveJsonModule": true, 16 | "isolatedModules": true, 17 | "noEmit": true, 18 | "jsx": "preserve", 19 | "sourceMap": true, 20 | "types": [], 21 | /* Linting */ 22 | "strict": true, 23 | "noUnusedLocals": true, 24 | "noUnusedParameters": true, 25 | "noFallthroughCasesInSwitch": true, 26 | "paths": { 27 | "@/*": [ 28 | "./src/*" 29 | ] 30 | // 这里需要配置 31 | }, 32 | "esModuleInterop": true 33 | }, 34 | "include": [ 35 | "src/**/*.ts", 36 | "src/**/*.d.ts", 37 | "src/**/*.tsx", 38 | "src/**/*.vue" 39 | ], 40 | "references": [ 41 | { 42 | "path": "./tsconfig.node.json" 43 | } 44 | ], 45 | "exclude": [ 46 | "node_modules", 47 | "dist", 48 | "docs" 49 | ] 50 | } 51 | -------------------------------------------------------------------------------- /src/packages/theme/_tag.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | @mixin tagLighten($color,$num,$num2) { 3 | border: 1px solid lighten($color, $num); 4 | background-color: lighten($color, $num2); 5 | color: $color; 6 | } 7 | @include ns(tag) { 8 | @include tagLighten($primaryColor, 30, 42); 9 | display: inline-block; 10 | height: 28px; 11 | padding: 0 10px; 12 | line-height: 26px; 13 | font-size: 12px; 14 | border-radius: 4px; 15 | box-sizing: border-box; 16 | white-space: nowrap; 17 | + .#{$namespace}tag {margin-left: 10px} 18 | .icon-close {font-size: 12px; width: 16px;height: 16px;display: inline-block;margin-left: 10px;transform: scale(.8);vertical-align: middle;line-height: 16px;cursor: pointer; 19 | &:hover {opacity: .6} 20 | } 21 | &.tag-success{@include tagLighten($successColor, 30, 58);} 22 | &.tag-warning{@include tagLighten($warningColor, 10, 26);} 23 | &.tag-danger{@include tagLighten($dangerColor, 30, 46);} 24 | &.tag-large{ 25 | height: 32px; 26 | line-height: 30px; 27 | } 28 | &.tag-small{ 29 | height: 24px; 30 | line-height: 22px; 31 | padding: 0 8px; 32 | } 33 | &.tag-mini{ 34 | height: 20px; 35 | line-height: 18px; 36 | padding: 0 5px; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/packages/divider/Divider.vue: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 41 | -------------------------------------------------------------------------------- /src/packages/theme/mixins.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | $namespace: 'ak-'; 3 | @mixin ns($cls) { 4 | $NS: $namespace+$cls; 5 | //$NS: 'ak-'+$cls; 6 | .#{$NS} { 7 | @content; 8 | } 9 | } 10 | @mixin scrollColor(){ 11 | &::-webkit-scrollbar {width: 8px;height: 8px;position: relative;z-index: 100;background: $colorGray} 12 | &::-webkit-scrollbar-thumb {background-color: $colorGray2;background-clip: padding-box;min-height: 28px;-webkit-border-radius: 5px;-moz-border-radius: 5px;border-radius: 5px;} 13 | &::-webkit-scrollbar-corner {background: $colorGray2} 14 | /*&::-webkit-scrollbar:$colorGray2; //滚动条整体部分 15 | ::-webkit-scrollbar-button:''; //滚动条两端的按钮 16 | ::-webkit-scrollbar-track:''; //外层轨道 17 | ::-webkit-scrollbar-track-piece:''; //内层滚动槽 18 | ::-webkit-scrollbar-thumb:$colorGray3; //滚动的滑块 19 | ::-webkit-scrollbar-corner:''; //边角 20 | ::-webkit-resizer //定义右下角拖动块的样式*/ 21 | } 22 | 23 | /*$border: #dcdfe6; // 边框色 24 | $primary: #07c160;// 主色*/ 25 | // transparentize($primary, 0.2); 26 | /* 27 | lighten (颜色, 百分比) // 调亮 28 | darken (颜色, 百分比) // 调暗 29 | saturate (颜色, 百分比) // 调高饱和度 30 | desaturate (颜色, 百分比) // 降低饱和度 31 | transparentize (颜色, 0.0-1.0) // 透明度,注意这里接收的不是百分比,是 0.0-1.0 的小数值*/ 32 | -------------------------------------------------------------------------------- /src/packages/drawer/Drawer.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 50 | -------------------------------------------------------------------------------- /src/packages/theme/_cascader.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | @include ns(cascader) { 3 | @include ns(select-down-pane) { 4 | } 5 | } 6 | @include ns(cascader-down) { 7 | >div{display: flex;} 8 | ul {padding: 10px;min-width: 100px;border-left: 1px solid $borderColor; 9 | &:first-child {border: 0} 10 | li {padding: 3px 0;cursor: pointer;display: flex;align-items: center;justify-content: space-around; 11 | a {display: block;flex: 2;white-space: nowrap} 12 | i {display: block;font-size: 12px;} 13 | .icon-arrow {transform: rotate(-90deg) scale(.8)} 14 | .icon-hook {margin-right: 3px;transform: scale(.8);display: none} 15 | &.disabled { 16 | a, i {color: #999;cursor: not-allowed} 17 | } 18 | } 19 | } 20 | .empty-text {text-align: center;width: 100%} 21 | .checked {color: $primaryColor; 22 | a {color: $primaryColor} 23 | .icon-hook {display: block} 24 | } 25 | @include ns(loading) { 26 | @include ns(loading-spinner) {display: flex; align-items: center;justify-content: center; 27 | .loading-svg {width: 20px;height: 20px;} 28 | } 29 | &.loading {position: static; 30 | @include ns(loading-spinner) {position: static;transform: translate(0)} 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/packages/tag/Tag.vue: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 54 | -------------------------------------------------------------------------------- /src/packages/theme/_switch.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | @include ns(switch) { 3 | $height: 22px; 4 | display: inline-block; box-sizing: border-box; height: $height; min-width: 44px; vertical-align: middle; border-radius: 20px; background: #ccc; border: 1px solid $borderColor; cursor: pointer; transition: all 1s; user-select: none; position: relative; 5 | @include ns(switch-inner) {position: absolute; width: 18px; height: 18px; left: 1px; top: 1px; border-radius: 18px; background-color: $backgroundColor; cursor: pointer; transition: all .5s; display: block;} 6 | .switch-text {text-align: right;display: block;padding: 0 5px;font-size: 12px;line-height: 20px;color: #fff;transition: all .3s} 7 | &.switch-checked {background: $primaryColor; 8 | @include ns(switch-inner) {left: 23px;} 9 | .switch-text {text-align: left} 10 | } 11 | &.disabled {opacity: $disabledOpacity;cursor: not-allowed} 12 | &.large {height: 24px; 13 | @include ns(switch-inner) {top: 2px;} 14 | } 15 | &.small {height: 18px;min-width: 40px; 16 | @include ns(switch-inner) {height: 14px;width: 14px;} 17 | } 18 | &.mini {height: 16px;min-width: 32px; 19 | &.switch-checked { 20 | @include ns(switch-inner) {left: 16px;} 21 | } 22 | @include ns(switch-inner) {height: 12px;width: 12px;} 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ak-vue", 3 | "private": true, 4 | "version": "1.0.0", 5 | "repository": "git@github.com:337547038/ak-vue3.git", 6 | "author": "337547038 <337547038@qq.com>", 7 | "scripts": { 8 | "dev": "vite", 9 | "build": "vite build", 10 | "preview": "vite preview", 11 | "lint": "eslint --ext .js,.vue,.ts src --fix", 12 | "lint:fromat": "prettier -c --parser typescript \"{src,__tests__,e2e}/**/*.[jt]s?(x)\"", 13 | "build:lib": "pnpm --filter ./build build" 14 | }, 15 | "dependencies": { 16 | "axios": "^1.4.0", 17 | "vue": "^3.3.4", 18 | "vue-router": "^4.2.2" 19 | }, 20 | "devDependencies": { 21 | "@types/node": "^20.2.0", 22 | "@typescript-eslint/eslint-plugin": "^5.59.6", 23 | "@typescript-eslint/parser": "^5.59.6", 24 | "@vitejs/plugin-vue": "^4.2.3", 25 | "@vitejs/plugin-vue-jsx": "^3.0.1", 26 | "@vue/eslint-config-typescript": "^11.0.3", 27 | "eslint": "^8.40.0", 28 | "eslint-config-prettier": "^8.8.0", 29 | "eslint-plugin-prettier": "^4.2.1", 30 | "eslint-plugin-vue": "^9.13.0", 31 | "prettier": "^2.8.8", 32 | "sass": "^1.62.1", 33 | "typescript": "^5.0.4", 34 | "vite": "^4.3.9", 35 | "vite-plugin-doc-preview": "^0.2.1", 36 | "vite-plugin-pages": "^0.31.0", 37 | "vue-tsc": "^1.6.5" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import {defineConfig} from 'vite' 2 | import vitePluginVuedoc from 'vite-plugin-doc-preview' 3 | import vue from '@vitejs/plugin-vue' 4 | import Pages from 'vite-plugin-pages' 5 | import {resolve} from 'path' 6 | import vueJsx from '@vitejs/plugin-vue-jsx' 7 | // 表格使用formatter时需要添加vueJsx这个,要不会出错。页面同时需要添加 lang="jsx" 8 | // https://vitejs.dev/config/ 9 | export default defineConfig({ 10 | plugins: [ 11 | vueJsx({}), 12 | vitePluginVuedoc({ previewId: 'vue demo' }), 13 | vue({ 14 | include: [/\.vue$/, /\.md$/] // 2. Must include .md | .vd files 15 | }), 16 | Pages({ 17 | pagesDir: 'src/packages', 18 | extensions: ['md'] 19 | // exclude: ['**/components/*.vue'] 20 | }) 21 | ], 22 | base: './', 23 | build: { 24 | outDir: 'docs' 25 | // 去除console 26 | /*terserOptions: { 27 | compress: { 28 | drop_console: true, 29 | drop_debugger: true 30 | } 31 | }*/ 32 | }, 33 | resolve: { 34 | alias: [ 35 | { 36 | find: /@\//, 37 | replacement: resolve(__dirname, 'src') + '/' 38 | } 39 | ], 40 | 41 | // 使用路径别名时想要省略的后缀名,官方不建议将.vue文件省略后缀 42 | extensions: ['.js', '.ts'] 43 | }, 44 | server: { 45 | // 是否开启 https 46 | https: false, 47 | port: 3002, 48 | host: '0.0.0.0', 49 | open: false 50 | } 51 | }) 52 | -------------------------------------------------------------------------------- /src/packages/radio/RadioGroup.vue: -------------------------------------------------------------------------------- 1 | 2 | 16 | 46 | -------------------------------------------------------------------------------- /src/packages/theme/_formItem.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | @include ns(form-item) { 3 | margin-bottom: 10px;line-height: 40px;position: relative;display: flex; 4 | @include ns(form-label) { text-align: right;font-size: 14px;color: $textColor;padding: 0 10px 0 0;box-sizing: border-box;width: 90px;display: flex; align-items: center; 5 | &.required { 6 | &:before {content: '*';color: #f00;display: inline-block;vertical-align: middle;} 7 | } 8 | } 9 | @include ns(form-box) {position: relative;display: flex;align-items: center; 10 | } 11 | /*错误提示*/ 12 | @include ns(form-tips) {color: #f00;margin-left: 5px;display: flex; align-items: center; 13 | &.icon-success {color: $primaryColor} 14 | &.icon-tips {color: #999;} 15 | } 16 | &.form-item-mini{line-height: 28px; 17 | @include ns(input-control){height: 28px; line-height: 28px;} 18 | @include ns(btn){height: 28px; line-height: 28px;} 19 | } 20 | &.form-item-small{line-height: 32px; 21 | @include ns(input-control){height: 32px;line-height: 32px;} 22 | @include ns(btn){height: 32px;line-height: 32px;} 23 | } 24 | &.form-item-medium{line-height: 36px; 25 | @include ns(input-control){height: 36px; line-height: 36px;} 26 | @include ns(btn){height: 36px; line-height: 36px;} 27 | } 28 | } 29 | @include ns(form-item-error) { 30 | @include ns(input-control) { 31 | border-color: #f00; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/packages/theme/_page.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | @include ns(page) {display: flex;align-items: center;justify-content: center; 3 | > div {margin-right: 10px;} 4 | .page-list { 5 | ul {display: flex; 6 | li {padding: 0;display: block; height: 32px; min-width: 32px; line-height: 30px; margin: 0 4px 0 0;cursor: pointer; 7 | a {display: block;border: 1px solid $borderColor; border-radius: 4px; transition: all .5s;text-align: center; 8 | &:hover { border-color: $primaryColor; color: #2d8cf0; } 9 | &.active { border-color: $primaryColor; color: #fff; background: $primaryColor } 10 | &.disabled {opacity: 0.5; cursor: not-allowed } 11 | // 向前页 12 | &.jump-prev {font-size: 10px; 13 | &:before {content: '•••';} 14 | &:hover:before { content: '<<' } 15 | } 16 | // 向后 17 | &.jump-next {font-size: 10px; 18 | &:before {content: '•••';} 19 | &:hover { 20 | &:before { content: '>>' } 21 | } 22 | } 23 | } 24 | } 25 | } 26 | } 27 | @include ns(input-control) {text-align: center;width: 50px;height: 32px;line-height: 32px;box-sizing: border-box} 28 | @include ns(select) {min-width: inherit; 29 | ul {} 30 | @include ns(input-control) {width: 100px;} 31 | } 32 | .total {line-height: 32px; 33 | span {color: $primaryColor} 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/packages/theme/_dropdown.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | @include ns(dropdown){ 3 | position: relative; 4 | display: inline-block; 5 | } 6 | @include ns(dropdown-menu){ 7 | left:50%; 8 | position: absolute; 9 | margin: 5px 0 0 var(--ak-dropdown-left); 10 | z-index: 500; 11 | padding: 10px 0; 12 | background-color: #fff; 13 | border: 1px solid #ebeef5; 14 | border-radius: 4px; 15 | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .1); 16 | li{padding: 0 20px;line-height: 26px;cursor: pointer;white-space: nowrap; 17 | &:hover{background: $backgroundColor2} 18 | } 19 | .arrow{ 20 | display: block; 21 | width: 0; 22 | height: 0; 23 | border-bottom: 6px solid $borderColor; 24 | border-left: 6px solid transparent; 25 | border-right: 6px solid transparent; 26 | position: absolute;left: 45%;top: -6px; 27 | &:after{ 28 | display: block; 29 | content: ''; 30 | position: absolute; 31 | left: -6px; 32 | top: 1px; 33 | width: 0; 34 | height: 0; 35 | border-bottom: 6px solid #fff; 36 | border-left: 6px solid transparent; 37 | border-right: 6px solid transparent; 38 | } 39 | } 40 | &.top{ 41 | bottom: 40px; 42 | .arrow{ 43 | bottom: -6px; 44 | top: auto; 45 | transform: rotate(180deg); 46 | &:after{ 47 | left: -6px; 48 | top: auto; 49 | bottom: -6px; 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/packages/divider/README.md: -------------------------------------------------------------------------------- 1 | # Divider 分割线 2 | 3 | ### 基础用法 4 | 5 | 对段落间的文本进行分割 6 | 7 | ```vue demo 8 | 20 | ``` 21 | 22 | ### 设置文案提示 23 | 24 | 对段落间的文本进行分割 25 | 26 | ```vue demo 27 | 34 | ``` 35 | 36 | ### 垂直分隔线 37 | 38 | 对段落间的文本进行分割 39 | 40 | ```vue demo 41 | 50 | ``` 51 | 52 | ## API 53 | 54 | ### Divider 55 | 56 | | 参数 | 类型 | 说明 | 57 | | ---------------- | ------ | --------------------------------------------------- | 58 | | direction | string | 设置分割线方向,可选 horizontal / vertical | 59 | | border-style | string | 线条类型,可选`dashed`、`dotted`、`soild` | 60 | | content-position | string | 设置分割线文案的位置,可选`left`、`right`、`center` | 61 | | padding | string | 上下/左右边距 | 62 | -------------------------------------------------------------------------------- /src/packages/upload/Comm.ts: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | import axios from 'axios' 3 | 4 | export const getObjectURL = (file: File) => { 5 | let url = null 6 | if (window.URL !== undefined) { 7 | // mozilla(firefox)兼容火狐 8 | url = window.URL.createObjectURL(file) 9 | } else if (window.webkitURL !== undefined) { 10 | // webkit or chrome 11 | url = window.webkitURL.createObjectURL(file) 12 | } 13 | return url 14 | } 15 | export const axiosUpload = (file: any, data: any, callback: any) => { 16 | const param = new FormData() 17 | param.append(data.name, file, file.name) 18 | if (data.data) { 19 | for (const i in data.data) { 20 | param.append(i, data.data[i]) 21 | } 22 | } 23 | const source = axios.CancelToken.source() 24 | const cancelToken = source.token 25 | callback(source, 'source') // 用于取消 26 | const config = { 27 | cancelToken, 28 | headers: Object.assign( 29 | { 'Content-Type': 'multipart/form-data' }, 30 | data.headers 31 | ), 32 | timeout: data.timeout, // `timeout` 指定请求超时的毫秒数(0 表示无超时时间) 33 | onUploadProgress: (progressEvent: any) => { 34 | const complete = ((progressEvent.loaded / progressEvent.total) * 100) | 0 35 | // 上传进度 36 | console.log(complete) 37 | callback(complete, 'loaded') // 更新进度 38 | } 39 | } 40 | axios 41 | .post(data.action, param, config) 42 | .then((res: any) => { 43 | console.log(res) 44 | callback(res, 'success') 45 | }) 46 | .catch((res: any) => { 47 | console.log(res, 'catch') 48 | callback(res, 'catch') 49 | }) 50 | } 51 | -------------------------------------------------------------------------------- /src/packages/theme/_carousel.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | @include ns(carousel) {position: relative; 3 | .carousel-container { 4 | } 5 | .carousel-transform {} 6 | .carousel-slide {float: left;transition: all .3s;height: 100px;background: #ddd} 7 | .direction-nav { 8 | a {position: absolute;display: block;width: 30px;height: 30px;top: 50%;transform: translateY(-50%);left: 20px;z-index: 10;cursor: pointer;background: transparent; 9 | &:after {content: '';border-top: 1px solid $primaryColor;border-right: 1px solid $primaryColor;display: block;width: 100%;height: 100%;transform: rotate(-135deg);} 10 | &.carousel-next {right: 20px;left: auto; 11 | &:after {transform: rotate(45deg)} 12 | } 13 | &.disabled {cursor: not-allowed} 14 | } 15 | } 16 | .control-nav { 17 | position: absolute; left: 0; bottom: 0; width: 100%; text-align: center; z-index: 10; 18 | a { display: inline-block; vertical-align: middle; width: 6px; height: 6px; border-radius: 50%; background: #ccc; margin: 0 5px;font-size: 0; 19 | &.control-nav-active { background: $primaryColor } 20 | } 21 | } 22 | // 卡片式 23 | &.card { 24 | .carousel-slide {position: relative;height: 100px;transition: all 0s; 25 | div {left: 0;top: 0;width: 100%;height: 100px} 26 | } 27 | .carousel-transform {padding: 20px 0} 28 | .big-size {position: relative;z-index: 2} 29 | .big-size div { position: absolute;background: #F8F8F8; transition: all .3s;left: -20px;top: -20px;height: 140px;width: 440px; 30 | } 31 | .normal-size div {transition: all 0s} 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/packages/theme/_input.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | @include ns(form-input) { 3 | display: inline-block;position: relative; 4 | .suffix-icon, .prefix-icon {position: absolute;right: 5px;top: 50%;transform: translateY(-50%);display: flex;align-items: center;justify-content: flex-end; 5 | i {font-size: 20px;cursor: pointer;transition: all .3s;width: 25px;height: 25px;text-align: center;line-height: 25px;color: $textColor2} 6 | .icon-close{font-size: 14px} 7 | } 8 | .prefix-icon {left: 3px;right: auto;} 9 | .icon-close {display: none;} 10 | &:hover { 11 | .icon-close {display: block} 12 | } 13 | .has-prefix {padding-left: 30px} 14 | &.input-prepend, &.input-append {display: flex;justify-content: space-between;align-items: stretch; 15 | .prepend, .append {border: 1px solid $borderColor;display: flex;align-items: center;padding: 0 5px;} 16 | .prepend {border-radius: 3px 0 0 3px;border-right: none;margin-right: -1px} 17 | .append {border-radius: 0 3px 3px 0;border-left: none;margin-left: -1px} 18 | } 19 | } 20 | @include ns(input-control) { 21 | height: 36px; line-height: 36px;border: 1px solid $borderColor;border-radius: $borderRadius;background: none;outline: none;padding: 0 10px;font-size: 14px;overflow: hidden;box-sizing: border-box;width: 100%;transition: all .3s; 22 | &:hover {opacity: .7} 23 | &:focus, &.focus {border-color: $primaryColor} 24 | &::placeholder,&.placeholder {color: $placeholder} 25 | /*禁用状态*/ 26 | &.disabled {cursor: not-allowed; opacity: $disabledOpacity} 27 | &.large {height: 40px; line-height: 40px;} 28 | &.small {height: 32px;line-height: 32px;} 29 | &.mini {height: 28px; line-height: 28px;} 30 | } 31 | -------------------------------------------------------------------------------- /src/packages/theme/_image.scss: -------------------------------------------------------------------------------- 1 | @include ns(image) {display: inline-block;overflow: hidden; 2 | &.border{border: 1px solid $borderColor} 3 | .default-placeholder, .default-error {position: relative;width: 100%;height: 100%;display: flex;align-items: center;justify-content: center} 4 | .default-error {color: #999} 5 | img {max-width: 100%;width: 100%;height: 100%} 6 | } 7 | @include ns(image-preview) {position: fixed;left: 0;top: 0;right: 0;bottom: 0;background: rgba(0, 0, 0, .2);z-index: 100;display: flex; align-items: center;justify-content: center;transition: all .5s; 8 | [class*="icon-"] {cursor: pointer;z-index: 50;font-size: 22px} 9 | .icon-error {position: absolute;right: 10px;top: 10px;color: #606266;opacity: .8} 10 | .icon-arrow-r {position: absolute;top: 50%;transform: translateY(-50%);color: #606266;opacity: .8;font-size: 28px; 11 | &.disabled{opacity: .6;cursor: not-allowed} 12 | &.next {right: 10px} 13 | &.prev {left: 10px;transform: rotate(180deg)} 14 | } 15 | .control-tool {position: absolute;left: 50%; transform: translateX(-50%); bottom: 20px;background: rgba(96, 98, 102, 0.8);color: #fff;padding: 10px;border-radius: 20px;display: flex;align-items: center; 16 | i {font-size: 22px;display: block;margin: 0 5px} 17 | .rotate-left{transform: rotate(90deg)} 18 | } 19 | .img{max-width: 100%;max-height: 100%;transition: all .3s;width: auto;height: inherit} 20 | } 21 | .image-fade-enter-active{animation: image-fade-enter .3s both} 22 | .image-fade-leave-active{animation: image-fade-leave .3s both} 23 | @keyframes image-fade-enter{ 24 | 0%{opacity: 0;transform: translateY(-20px)} 25 | } 26 | @keyframes image-fade-leave{ 27 | 100%{opacity: 0;transform: translateY(-20px)} 28 | } 29 | -------------------------------------------------------------------------------- /src/packages/theme/_loading.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | @include ns(loading-parent-relative){ position: relative!important;} 3 | @include ns(loading){ 4 | position: absolute;z-index: 2000;background-color: rgba(0, 0, 0, .1);margin: 0;top: 0;right: 0;bottom: 0;left: 0;transition: opacity .3s; 5 | &.no-background{background: none!important;} 6 | @include ns(loading-spinner){top: 50%;left: 50%;width: 100%;text-align: center;position: absolute;transform: translate(-50%, -50%); 7 | .loading-svg{width: 45px;height: 45px;animation: loading-rotate 2s linear infinite} 8 | .svg-path{animation: loading-dash 1.5s ease-in-out infinite;stroke-dasharray: 90, 150;stroke-dashoffset: 0;stroke-width: 2px;stroke: $primaryColor;stroke-linecap: round} 9 | } 10 | @include ns(icon-rotate){animation: loading-rotate 2s linear infinite;display: inline-block;border: 2px solid #fff;border-top-color:transparent ;border-radius: 50%;width: 30px;height: 30px; 11 | } 12 | @include ns(loading-text){color: $primaryColor;margin: 3px 0;font-size: 14px;} 13 | &.#{$namespace}loading-full{position: fixed} 14 | } 15 | /*过渡动画*/ 16 | @include ns(loading-fade-enter-active){animation: loading-fade-enter .3s} 17 | @include ns(loading-fade-leave-active){animation: loading-fade-leave .3s} 18 | @keyframes loading-fade-enter{ 19 | 0%{opacity: 0} 20 | } 21 | @keyframes loading-fade-leave{ 22 | 100%{opacity: 0} 23 | } 24 | @keyframes loading-rotate{ 25 | 100%{ 26 | transform: rotate(360deg); 27 | } 28 | } 29 | 30 | @keyframes loading-dash { 31 | 0% { 32 | stroke-dasharray: 1,200; 33 | stroke-dashoffset: 0 34 | } 35 | 50% { 36 | stroke-dasharray: 90,150; 37 | stroke-dashoffset: -40px 38 | } 39 | to { 40 | stroke-dasharray: 90,150; 41 | stroke-dashoffset: -120px 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ak-vue 2 | 3 | 填坑 Vue3 + Typescript + Vite,用于学习研究,欢迎交流,微信:337547038 4 | 5 | **特点** 6 | 7 | - 不使用第三方插件或库,保证代码简洁、轻量、易上手 8 | - 提供了一系列丰富、可复用的UI组件 9 | - 提供丰富的插槽和事件接口,方便进行二次开发 10 | 11 | ## 演示地址 Demo 12 | 13 | https://337547038.github.io/ak-vue3/ 14 | 15 | ## 微信交流群 16 | 17 | 18 | 19 | ## 安装使用 20 | 21 | ```shell 22 | pnpm install ak-vue3 23 | ``` 24 | 25 | ```ts 26 | // main.ts 27 | import AKVUE from 'ak-vue3' 28 | import 'ak-vue3/style.css' // 引入组件栏目 29 | import 'ak-vue3/iconfont.css' // 引入iconfont图 30 | app.use(AKVUE) 31 | ``` 32 | 33 | 若不使用npm安装,可按下面操作按需复制相应组件到你项目: 34 | 35 | 1.将`/src/packages`复制到你的项目目录下,然后在`main.js`中引入并注册即可; 36 | 37 | 2.复制`/public/static/iconfont`到项目下,在`index.html`引入组件所需的字体图标; 38 | 39 | ```javascript 40 | import AKUI from './packages' 41 | app.use(AKUI) 42 | ``` 43 | 44 | ## vue2 版本 45 | 46 | vue2.x 版本的请点击这里进去 47 | 48 | https://github.com/337547038/Vue-UI-for-PC 49 | 50 | https://gitee.com/q337547038/ak-vue 51 | 52 | ## react 版本 53 | 54 | https://github.com/337547038/vite-react 55 | 56 | ## 组件 UI 库说明 57 | 58 | 组件库包含了 AutoForm 自动表单、BackTop 返回顶部、Breadcrumb 面包屑、 Button 按钮、Cascader 级联选择器、Checkbox 多选框、Collapse 折叠面板、ColorPicker 59 | 颜色选择器、DataPicker 时间选择器、Dialog 弹层对话框、Alert 弹框、Echarts 图形图表、Form 表单、Input 输入框、Lazy 图片延时加载、Loading 加载等待、Menu 菜单、Pagination 60 | 分页、Progress 进度条、Radio 单选框、Select 选择器、Steps 步骤条、Swiper 图片轮播、Switch 开关、Table 表格、Tabs 标签页、Textarea 文本框、Tooltip 提示、Transfer 61 | 穿梭框、Tree 树形、Upload 上传、Drawer 抽屉等常用组件 62 | 63 | ### 开发环境 64 | | 名称 | 版本 | 65 | |------|---------| 66 | | node | 16.15.x | 67 | | pnpm | 8.6.x | 68 | | vite | 4.3.x | 69 | | vue | 3.3.x | 70 | 71 | 72 | ```shell 73 | pnpm install 74 | pnpm dev 75 | ``` 76 | -------------------------------------------------------------------------------- /src/packages/inputNumber/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # InputNumber 计数器 4 | 5 | ### 基础用法 6 | 7 | ```vue demo 8 | 11 | 15 | 16 | ``` 17 | 18 | ### 禁用状态 19 | 20 | ```vue demo 21 | 24 | 29 | 30 | 31 | ``` 32 | 33 | ### 设置最大最小值 34 | 35 | `max="10" min="1"` 36 | 37 | ```vue demo 38 | 41 | 46 | 47 | 48 | ``` 49 | 50 | ### 设置步长 51 | 52 | `step="5"` 53 | 54 | ```vue demo 55 | 58 | 63 | 64 | ``` 65 | 66 | ## API 67 | 68 | ### InputNumber 69 | 70 | |参数|类型|说明| 71 | |----------|--------------|--------| 72 | |v-model | number |绑定值,默认0| 73 | |max | number |允许的最大值| 74 | |min | number |允许的最小值| 75 | |step | number |步长| 76 | |disabled | boolean/false|是否禁用| 77 | |placeholder | string |输入框点位符| 78 | |readOnly | boolean/true |允许手动输入| 79 | |size | string |添加的大小尺寸样式| 80 | 81 | ### InputNumber Events 82 | 83 | |参数|说明| 84 | |----------|--------------| 85 | |change | 绑定值被改变时触发| 86 | |blur | 在组件 Input 失去焦点时触发| 87 | |focus | 在组件 Input 获得焦点时触发| 88 | -------------------------------------------------------------------------------- /src/packages/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 337547038 on 2018/8/31 0031. 3 | */ 4 | // @ts-ignore 5 | import type { App, Component } from 'vue' 6 | // 所有需要全局注册的组件入口 7 | import './theme/index.scss' 8 | import prefixCls from './prefix' 9 | 10 | // @ts-ignore 11 | // @ts-ignore 12 | export default { 13 | // @ts-ignore 14 | install(app: App) { 15 | const moduleFilesTs = import.meta.globEager('./*/index.ts') 16 | console.log(moduleFilesTs) 17 | Object.keys(moduleFilesTs).forEach((key: string) => { 18 | // @ts-ignore 19 | const componentOptions: Record = moduleFilesTs[key] 20 | const exclude: string[] = ['./lazy', './loading', './message', './util'] 21 | const replaceKey = key.replace(/\/index.ts/, '') 22 | if (exclude.includes(replaceKey)) { 23 | switch (replaceKey) { 24 | case './lazy': 25 | app.use(componentOptions.default as () => void) 26 | break 27 | case './loading': 28 | app.config.globalProperties.$loading = componentOptions.loading 29 | app.provide('Loading', componentOptions) 30 | app.use(componentOptions.vLoading as () => void) 31 | break 32 | case './message': 33 | // console.log(componentOptions) 34 | app.provide('Message', componentOptions) 35 | // 支持this.$alert写法 36 | Object.keys(componentOptions).forEach((el: string) => { 37 | app.config.globalProperties[`$${el}`] = componentOptions[el] 38 | }) 39 | break 40 | } 41 | } else { 42 | if (componentOptions) { 43 | Object.keys(componentOptions).forEach((el: string) => { 44 | app.component(prefixCls + el, componentOptions[el]) 45 | }) 46 | } 47 | } 48 | }) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/packages/table/demoJs.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "date": "2016-05-03", 4 | "name": "张三", 5 | "province": "广东", 6 | "city": "白云区", 7 | "address": "广东省广州市白云区无名路888号", 8 | "zip": 200330, 9 | "sex": "男", 10 | "children": [ 11 | { 12 | "date": "2016-05-00", 13 | "name": "子级", 14 | "province": "子级广东", 15 | "city": "子级白云区", 16 | "address": "子级广东省广州市白云区无名路888号", 17 | "zip": 200330, 18 | "sex": 0 19 | } 20 | ] 21 | }, 22 | { 23 | "date": "2016-05-04", 24 | "name": "李四", 25 | "province": "广东", 26 | "city": "白云区", 27 | "address": "广东省广州市白云区无名路888号", 28 | "zip": 200330, 29 | "sex": "男" 30 | }, 31 | { 32 | "date": "2016-05-05", 33 | "name": "李四5", 34 | "province": "广东", 35 | "city": "白云区", 36 | "address": "广东省广州市白云区无名路888号", 37 | "zip": 200330, 38 | "sex": "女" 39 | }, 40 | { 41 | "date": "2016-05-06", 42 | "name": "李四6", 43 | "province": "广东", 44 | "city": "白云区", 45 | "address": "广东省广州市白云区无名路888号", 46 | "zip": 200330, 47 | "sex": "男" 48 | }, 49 | { 50 | "date": "2016-05-07", 51 | "name": "李四7", 52 | "province": "广东", 53 | "city": "白云区", 54 | "address": "广东省广州市白云区无名路888号", 55 | "zip": 200330, 56 | "sex": "女" 57 | }, 58 | { 59 | "date": "2016-05-08", 60 | "name": "李四8", 61 | "province": "广东", 62 | "city": "白云区", 63 | "address": "广东省广州市白云区无名路888号", 64 | "zip": 200330, 65 | "sex": "女" 66 | }, 67 | { 68 | "date": "2016-05-09", 69 | "name": "李四9", 70 | "province": "广东", 71 | "city": "白云区", 72 | "address": "广东省广州市白云区无名路888号", 73 | "zip": 200330, 74 | "sex": "女" 75 | }, 76 | { 77 | "date": "2016-05-10", 78 | "name": "李四10", 79 | "province": "广东", 80 | "city": "白云区", 81 | "address": "广东省广州市白云区无名路888号", 82 | "zip": 200330, 83 | "sex": "女" 84 | } 85 | ] 86 | -------------------------------------------------------------------------------- /src/packages/textarea/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Textarea 文本框 4 | 5 | ### 基本用法 6 | 7 | ```vue demo 8 | 13 | 18 | 19 | ``` 20 | 21 | ### 禁用 22 | 23 | ```vue demo 24 | 33 | 38 | 39 | ``` 40 | 41 | ### 自动高 42 | 43 | ```vue demo 44 | 47 | 52 | 53 | 54 | ``` 55 | 56 | ### 显示输入字数 57 | 在使用 `maxlength` 属性限制最大输入长度的同时,可通过设置 `show-word-limit` 属性来展示字数统计 58 | ```vue demo 59 | 69 | 74 | 75 | ``` 76 | 77 | ## API 78 | 79 | ### Textarea 80 | 81 | | 参数 | 类型 |说明| 82 | |---------------|---------------|-------------| 83 | | v-model | String | 绑定的值 | 84 | | autoHeight | boolean/true | 自动高 | 85 | | width | String | 要带单位px/% | 86 | | height | String | 要带单位px | 87 | | maxHeight | String | 最大高度 | 88 | | showWordLimit | boolena/false | 原生属性,最大输入长度 | 89 | | maxlength | number | 是否显示输入字数统计 | 90 | -------------------------------------------------------------------------------- /src/packages/theme/_colorPicker.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | @include ns(color-picker){ 3 | width: 300px; 4 | position: absolute; 5 | box-sizing: content-box; 6 | border: 1px solid $borderColor; 7 | box-shadow: 0 4px 15px rgba(0, 0, 0, .2); 8 | border-radius: 5px; 9 | z-index: 10; 10 | padding: 7px; 11 | background-color: $backgroundColor; 12 | user-select: none; 13 | .color-picker-content{position: relative;height: 180px;margin-bottom: 10px} 14 | .color-slider{position: absolute;width: 12px; 15 | height: 100%; 16 | z-index: 10; 17 | right: 0; 18 | top: 0; 19 | background: linear-gradient(180deg, #f00 0, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00);} 20 | .color-slier-thumb{ position: absolute; 21 | cursor: pointer; 22 | box-sizing: border-box; 23 | left: 0; 24 | top: 0; 25 | width: 12px; 26 | height: 4px; 27 | border-radius: 1px; 28 | background: #fff; 29 | border: 1px solid #f0f0f0; 30 | box-shadow: 0 0 2px rgba(0, 0, 0, .6);} 31 | .color-panel{ 32 | position: relative; 33 | width: 280px; 34 | height: 180px; 35 | cursor: pointer;} 36 | .color-white-panel{ 37 | position: absolute; 38 | left: 0; 39 | right: 0; 40 | top: 0; 41 | bottom: 0; 42 | background: linear-gradient(90deg, #fff, hsla(0, 0%, 100%, 0));} 43 | .color-block-panel{position: absolute; 44 | left: 0; 45 | right: 0; 46 | top: 0; 47 | bottom: 0; 48 | background: linear-gradient(0deg, #000, transparent); 49 | } 50 | .color-cursor{ 51 | position: absolute; 52 | width: 5px; 53 | height: 5px; 54 | box-shadow: 0 0 0 1.5px #fff, inset 0 0 1px 1px rgba(0, 0, 0, 0.3), 0 0 1px 2px rgba(0, 0, 0, 0.4); 55 | border-radius: 50%; 56 | transform: translate(-2px, -2px); 57 | cursor: pointer; 58 | z-index: 10;} 59 | .color-input{float: left;width: 60%; 60 | input{width: 100%} 61 | } 62 | .color-confirm{float: right;line-height: 38px;margin-right: 10px;cursor: pointer} 63 | } 64 | -------------------------------------------------------------------------------- /src/packages/popover/Popover.vue: -------------------------------------------------------------------------------- 1 | 2 | 21 | 22 | 74 | -------------------------------------------------------------------------------- /src/packages/theme/_tabs.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | @include ns(tabs) {display: flex;flex-wrap: wrap;flex-direction: column; 3 | .tabs-nav {position: relative;border-bottom: 1px solid $borderColor;height: 40px;display: flex;align-items: center;justify-content: space-between; 4 | .tabs-scroll {flex: 2;overflow: hidden;display: flex;align-items: center;} 5 | .tabs-tab {display: flex;transition: all .5s} 6 | .tabs-prev, .tabs-next {display: block;width: 30px;height: 30px;line-height: 30px;text-align: center;cursor: pointer;transition: all .3s; 7 | &.disabled {color: #999;cursor: not-allowed} 8 | } 9 | .tabs-prev {transform: rotate(90deg)} 10 | .tabs-next {transform: rotate(-90deg)} 11 | .tabs-item {padding: 0 20px;position: relative;line-height: 40px;cursor: pointer;z-index: 2;white-space: nowrap; 12 | &:after {content: '';display: block;margin: 0 auto;height: 2px;background: $primaryColor;opacity: 0;width: 0;transition: all .3s;position: relative;top: -1px;} 13 | /*选中*/ 14 | &.active { 15 | &:after {opacity: 1;width: 100%} 16 | } 17 | /*禁用*/ 18 | &.disabled {cursor: not-allowed;opacity: .5} 19 | .icon-close {font-size: 12px;position: relative;top: -3px;left: 3px} 20 | } 21 | } 22 | .tabs-content {padding: 20px;overflow: hidden;} 23 | &.bottom { 24 | .tabs-nav {order: 1} 25 | } 26 | &.left, &.right {flex-direction: row; 27 | .tabs-nav {width: 150px;display: block;text-align: center;height: auto} 28 | .tabs-scroll {display: block;overflow-x: hidden;overflow-y: auto;@include scrollColor()} 29 | .tabs-tab {display: block} 30 | .tabs-content {flex: 2} 31 | } 32 | &.right { 33 | .tabs-nav {order: 1} 34 | } 35 | } 36 | /*@include ns(tabs-transition-enter-active){ 37 | animation: tabs-transition-in .5s; 38 | } 39 | @include ns(tabs-transition-leave-active){ 40 | animation: tabs-transition-out .1s; 41 | } 42 | @keyframes tabs-transition-in { 43 | 0%{opacity: 0;} 44 | } 45 | @keyframes tabs-transition-out { 46 | 100%{opacity: 0;} 47 | }*/ 48 | -------------------------------------------------------------------------------- /src/packages/pagination/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Pagination 分页 4 | 5 | ### 基础用法 6 | 7 | ```vue demo 8 | 13 | 18 | 19 | ``` 20 | 21 | ### 其他选项参数 22 | 23 | ```vue demo 24 | 35 | 44 | 45 | ``` 46 | 47 | ### 事件 48 | 49 | ```vue demo 50 | 61 | 69 | 70 | ``` 71 | 72 | ## API 73 | 74 | ### Pagination 75 | 76 | |参数|类型|说明| 77 | |----------|--------------|--------| 78 | |current | number |当前页数,支持v-model| 79 | |total | number |总条目数| 80 | |pageSize | number |每页显示条数| 81 | |pagerCount | number/5 |页码按钮的数量,当总页数超过该值时会折叠| 82 | |showJumper | boolean/false |快速跳转| 83 | |pageSizes | number[] |每页显示个数选择器的选项设置| 84 | |showTotal | boolean/false |显示总记录条数| 85 | |hideSinglePage | boolean/false |当小于或只有一页时是否隐藏显示| 86 | |format | boolean/false |数值转千分制显示| 87 | 88 | ### Pagination Event 89 | 90 | |参数|说明| 91 | |----------|--------------| 92 | |changePageSizes |每页显示条数改变事件| 93 | |change |页码点击改变事件| 94 | -------------------------------------------------------------------------------- /docs/assets/README-77590a54.js: -------------------------------------------------------------------------------- 1 | import{C as l}from"./vue-4a2b12f2.js";import{_ as r,a as p,o as c,c as o,b as s,F as i,g as t,w as d,u as _,d as a,h as m}from"./index-dd3aacc0.js";/* empty css */const b={},k=t("div",{style:{height:"900px"}},"滚动页面试试",-1);function g(n,h){const e=p("ak-backTop");return c(),o(i,null,[k,s(e)],64)}const E=r(b,[["render",g]]),j={class:"marked-body"},u=t("h1",{id:"backtop-返回顶部"},"BackTop 返回顶部",-1),A=t("h3",{id:"用法"},"用法",-1),x=t("pre",{class:"language-xml"},[t("code",{class:"hljs"},[t("span",{class:"hljs-tag"},[a("<"),t("span",{class:"hljs-name"},"template"),a(">")]),a(` 2 | `),t("span",{class:"hljs-tag"},[a("<"),t("span",{class:"hljs-name"},"div"),a(),t("span",{class:"hljs-attr"},"style"),a("="),t("span",{class:"hljs-string"},'"height:900px"'),a(">")]),a("滚动页面试试"),t("span",{class:"hljs-tag"},[a("")]),a(` 3 | `),t("span",{class:"hljs-tag"},[a("<"),t("span",{class:"hljs-name"},"ak-backTop"),a(">")]),t("span",{class:"hljs-tag"},[a("")]),a(` 4 | `),t("span",{class:"hljs-tag"},[a("")])])],-1),T=m('

API

BackTop Props

参数类型说明
heightNumber/200页面滚动高度达到该值时才显示BackTop组件
bottomNumber/30组件距离底部的距离
rightNumber/30组件距离右部的距离
textString显示文本

BackTop Event

参数说明
click-
',5),C={__name:"README",setup(n){return(h,e)=>(c(),o("div",j,[u,A,s(_(l),{code:"%3Ctemplate%3E%0A%20%20%20%3Cdiv%20style%3D%22height%3A900px%22%3E%E6%BB%9A%E5%8A%A8%E9%A1%B5%E9%9D%A2%E8%AF%95%E8%AF%95%3C%2Fdiv%3E%0A%20%20%20%3Cak-backTop%3E%3C%2Fak-backTop%3E%0A%3C%2Ftemplate%3E"},{code:d(()=>[x]),default:d(()=>[s(E)]),_:1}),T]))}};export{C as default}; 5 | -------------------------------------------------------------------------------- /src/packages/theme/_progress.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | @include ns(progress) {display: inline-block; 3 | &.success { 4 | .progress-bar {background: $successColor} 5 | .circle-circle { 6 | .circle-left, .circle-right {border-color: $successColor} 7 | } 8 | } 9 | &.warning { 10 | .progress-bar {background: $warningColor} 11 | .circle-circle { 12 | .circle-left, .circle-right {border-color: $successColor} 13 | } 14 | } 15 | &.danger { 16 | .progress-bar {background: $dangerColor} 17 | .circle-circle { 18 | .circle-left, .circle-right {border-color: $successColor} 19 | } 20 | } 21 | } 22 | @include ns(progress-circle) { 23 | position: relative; border-radius: 50%; box-sizing: border-box;border-color: $borderColor;border-style: solid; 24 | /*progress用作底背景色,*/ 25 | .circle-circle { display: block; border-radius: 50%; box-sizing: border-box; position: absolute; overflow: hidden; 26 | /*显示右半边,进度大小50%显示全部-*/ 27 | /*circle-left左半环,裁切显示左半边*/ 28 | .circle-left { position: absolute; display: block; box-sizing: border-box; border-radius: 50%; top: 0; left: 0; border-style: solid;border-color: $primaryColor} 29 | /*circle-right右半环,裁切显示右半边,只有进度大于50%才显示*/ 30 | .circle-right { position: absolute; right: 0; top: 0; display: block; box-sizing: border-box; border-radius: 50%; border-style: solid;border-color: $primaryColor} 31 | } 32 | /*进度文字*/ 33 | .progress-text { text-align: center; left: 50%; top: 50%; transform: translate(-50%, -50%); display: block; position: absolute; font-size: 20px;} 34 | /*自定义文字*/ 35 | .custom-content {position: absolute; text-align: center; top: 15px; width: 60%; left: 20%;line-height: 18px;} 36 | } 37 | /*直线进度*/ 38 | @include ns(progress-line) { position: relative; border-radius: 5px;background: $borderColor;min-height: 15px;width: 400px; 39 | .progress-bar { position: absolute; width: 0; left: 0; top: 0; border-radius: 5px;background: $primaryColor;height: 15px;line-height: 15px;text-align: right;font-size: 12px;color: $textColor5 } 40 | .progress-fixed-text {position: absolute;right: -40px;top: -3px} 41 | } 42 | -------------------------------------------------------------------------------- /docs/assets/README-69dae8d1.js: -------------------------------------------------------------------------------- 1 | /* empty css */import{o as s,c as a,h as n}from"./index-dd3aacc0.js";const p={class:"marked-body"},l=n(`

AK UI

AK UI是一个vue3的组件库,基于 Vue3 + Typescript + Vite + pnpm。

常用基础组件,代码简洁,满足常见项目,组件类名可自定义,不依懒第三方库,全程无红线语法报错,便于二次开发,无缝衔接项目

主题可调,只需10分钟即可定义一套全新的组件样式

用于学习研究,欢迎交流,微信:337547038

全局引入(推荐)

pnpm install ak-vue3
// main.ts
2 | import AKVUE from 'ak-vue3'
3 | import 'ak-vue3/style.css'  // 引入组件样式
4 | import 'ak-vue3/iconfont.css' // 引入iconfont图标样式
5 | app.use(AKVUE)

若不使用npm安装时,可将资源包复制到项目,如 src 目录下,然后在入口页面 main.ts 中如下配置:

import Component from "../packages/index";
6 | // 全局注册基础组件
7 | Vue.use(Component);

按需引用

在当前页面 import 所需组件

import Button from "../packages/button.vue";

可打包

可使用命令npm run build:lib将组件资源打包成一个js文件

`,15),c=[l],h={__name:"README",setup(e){return(t,o)=>(s(),a("div",p,c))}};export{h as default}; 8 | -------------------------------------------------------------------------------- /src/packages/loading/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 337547038 on 2018/9/5 0005. 3 | */ 4 | /** 5 | * 方法一 6 | *
容器区域
7 | * 8 | * 方法二 9 | * this.$loading({}) 10 | * **/ 11 | import akLoading from './Loading.vue' 12 | import prefixCls from '../prefix' 13 | //import { App } from 'vue' 14 | import { createApp } from 'vue' 15 | 16 | const appendChild = (opt: any) => { 17 | const app = createApp(akLoading, opt) 18 | if (opt.el === document.body || !opt.el) { 19 | const container = document.createElement('div') 20 | document.body.appendChild(container) 21 | return app.mount(container) 22 | } else { 23 | // 插入到当前标签 24 | return app.mount(opt.el) 25 | } 26 | } 27 | const loading = (opt?: any) => { 28 | const component: any = appendChild(opt || {}) 29 | component && component.open() 30 | return component 31 | } 32 | const vLoading = (app: any) => { 33 | app.directive('loading', { 34 | mounted(el: any, binding: any) { 35 | el.style.position = 'relative' 36 | const text = el.getAttribute(`${prefixCls}-loading-text`) || '' 37 | const spinner = el.getAttribute(`${prefixCls}-loading-spinner`) || '' 38 | const background = 39 | el.getAttribute(`${prefixCls}-loading-background`) || '' 40 | const zIndex = el.getAttribute(`${prefixCls}-loading-zIndex`) || '' 41 | let bodyEl 42 | if (binding.modifiers.el) { 43 | // 插入到body 44 | bodyEl = document.body 45 | } 46 | const component: any = appendChild({ 47 | text: text, 48 | spinner: spinner, 49 | background: background, 50 | lock: binding.modifiers.lock, 51 | zIndex: parseInt(zIndex), 52 | el: bodyEl || el 53 | }) 54 | console.log('component') 55 | console.log(component) 56 | if (binding.value) { 57 | component && component.open() 58 | } 59 | el.component = component // 保存当前组件和样式,更新时调用 60 | }, 61 | updated(el: any, binding: any) { 62 | if (binding.value) { 63 | el.component.open() 64 | } else { 65 | el.component.close() 66 | } 67 | } 68 | }) 69 | } 70 | export { loading, vLoading } 71 | -------------------------------------------------------------------------------- /src/packages/radio/Radio.vue: -------------------------------------------------------------------------------- 1 | 2 | 20 | 76 | -------------------------------------------------------------------------------- /src/packages/collapse/Panel.vue: -------------------------------------------------------------------------------- 1 | 2 | 23 | 68 | -------------------------------------------------------------------------------- /src/packages/backTop/BackTop.vue: -------------------------------------------------------------------------------- 1 | 2 | 17 | 78 | -------------------------------------------------------------------------------- /src/packages/message/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Message 信息弹窗 4 | 5 | 为方便使用,定义了`Dialog`,`Alert`,`Confirm`,`Msg`三种以适应不同场景,如果需要弹出较为复杂的内容,请使用 `Dialog`。可使用`inject`,`getCurrentInstance`和`Vue2`选项卡的方式,使用`this.$msg()`方式调用。同时定义了`clear`用于移除所有`message`提示 6 | 7 | ### Alert 8 | 9 | 使用`inject`注入方式调用 10 | 11 | ```vue demo 12 | 25 | 33 | 34 | ``` 35 | 36 | ### Confirm 37 | 38 | 使用`getCurrentInstance`方式打开 39 | 40 | ```vue demo 41 | 46 | 60 | 61 | 62 | ``` 63 | 64 | ### Msg 65 | 66 | `Vue2`选项卡的方式,使用`this.$msg()`打开 67 | 68 | ```vue demo 69 | 77 | 91 | 92 | 93 | ``` 94 | 95 | ## API 96 | 97 | 所有参数详见[Dialog](/#/dialog) 98 | -------------------------------------------------------------------------------- /docs/assets/vue-4a2b12f2.js: -------------------------------------------------------------------------------- 1 | import{e as h,r as v,o as p,c as _,g as o,v as c,s as d,x as l,t as w,y as u,z as k,_ as g}from"./index-dd3aacc0.js";/* empty css */const i=e=>(u("data-v-43edb7f1"),e=e(),k(),e),m={class:"doc-preview"},C={class:"component"},f={class:"fixed-tools"},x=i(()=>o("svg",{fill:"none",height:"20",stroke:"currentColor","stroke-width":"2",viewBox:"0 0 24 24",width:"20",xmlns:"http://www.w3.org/2000/svg"},[o("path",{d:"M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2m-6 9 2 2 4-4","stroke-linecap":"round","stroke-linejoin":"round"})],-1)),M=[x],B=i(()=>o("svg",{height:"20",viewBox:"0 0 512 512",width:"20",xmlns:"http://www.w3.org/2000/svg"},[o("path",{d:"M160 368L32 256l128-112M352 368l128-112-128-112M304 96l-96 320",fill:"none",stroke:"currentColor","stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"46"})],-1)),S=[B],I={class:"code"},b={class:"control-tools"},j=i(()=>o("svg",{fill:"none",height:"20",stroke:"currentColor","stroke-width":"2",viewBox:"0 0 24 24",width:"20",xmlns:"http://www.w3.org/2000/svg"},[o("path",{d:"M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2m-6 9 2 2 4-4","stroke-linecap":"round","stroke-linejoin":"round"})],-1)),y=[j],V=i(()=>o("svg",{height:"20",viewBox:"0 0 512 512",width:"20",xmlns:"http://www.w3.org/2000/svg"},[o("path",{d:"M160 368L32 256l128-112M352 368l128-112-128-112M304 96l-96 320",fill:"none",stroke:"currentColor","stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"46"})],-1)),D=[V],H=h({__name:"vue",props:{code:{}},setup(e){const r=e,s=v(!1),a=()=>{try{navigator.clipboard.writeText(decodeURIComponent(r.code))}catch(t){console.log(t)}},n=()=>{s.value=!s.value};return(t,L)=>(p(),_("div",m,[o("div",C,[c(t.$slots,"default",{},void 0,!0)]),d(o("div",f,[o("div",{class:"tools"},[o("div",{class:"item",onClick:a},M),o("div",{class:"item",onClick:n},S)])],512),[[l,s.value]]),d(o("div",I,[c(t.$slots,"code",{},void 0,!0)],512),[[l,s.value]]),o("div",b,[o("div",{class:"text",onClick:n},w(s.value?"隐藏代码":"展开代码"),1),o("div",{class:"tools"},[o("div",{class:"item",onClick:a},y),o("div",{class:"item",onClick:n},D)])])]))}}),E=g(H,[["__scopeId","data-v-43edb7f1"]]);export{E as C}; 2 | -------------------------------------------------------------------------------- /src/packages/message/index.ts: -------------------------------------------------------------------------------- 1 | import { Dialog } from '../dialog' 2 | import { createApp } from 'vue' 3 | import prefixCls from '../prefix' 4 | 5 | const dialogCom = (opt: any) => { 6 | const mountNode = document.createElement('div') 7 | document.body.appendChild(mountNode) 8 | Object.assign(opt, { 9 | isAlert: true, 10 | closeModal: false, 11 | // modelValue: true, 12 | remove: () => { 13 | app.unmount() 14 | document.body.removeChild(mountNode) 15 | } 16 | }) 17 | const app = createApp(Dialog, opt) 18 | const component: any = app.mount(mountNode) 19 | component.open() // 使用open方式打开 20 | return component 21 | } 22 | const dialog = (opt: any) => { 23 | return dialogCom(opt || {}) 24 | } 25 | const confirm = (content: string, opt?: any) => { 26 | if (!opt) { 27 | opt = {} 28 | } 29 | return dialogCom( 30 | Object.assign( 31 | {}, 32 | { 33 | title: opt.title || '信息', 34 | content: content, 35 | confirm: opt.confirm || '确定', 36 | cancel: '取消', 37 | className: 'dialog-confirm' 38 | }, 39 | opt 40 | ) 41 | ) 42 | } 43 | const alert = (content: string, opt?: any) => { 44 | if (!opt) { 45 | opt = {} 46 | } 47 | return dialogCom( 48 | Object.assign( 49 | {}, 50 | { 51 | title: opt.title || '信息', 52 | content: content, 53 | confirm: opt.confirm || '确定', 54 | className: 'dialog-alert' 55 | }, 56 | opt 57 | ) 58 | ) 59 | } 60 | const msg = (content: string, opt?: any) => { 61 | if (!opt) { 62 | opt = {} 63 | } 64 | return dialogCom( 65 | Object.assign( 66 | {}, 67 | { 68 | content: content, 69 | className: 'dialog-msg', 70 | showClose: false, 71 | autoClose: opt.autoClose || 3, 72 | modal: (opt && opt.modal) || false 73 | }, 74 | opt 75 | ) 76 | ) 77 | } 78 | const clear = () => { 79 | // 添加一个简单粗暴的方法,用于清除所有alert弹窗 80 | const dialog = document.querySelectorAll(`.${prefixCls}-dialog-isAlert`) 81 | if (dialog && dialog.length > 0) { 82 | dialog.forEach(item => { 83 | document.body.removeChild(item) 84 | // 锁定body解锁 85 | document.body.style.overflow = '' 86 | document.body.style.paddingRight = '' // 滚动条的宽,防抖动 87 | }) 88 | } 89 | } 90 | export { dialog, confirm, alert, msg, clear } 91 | -------------------------------------------------------------------------------- /src/packages/badge/README.md: -------------------------------------------------------------------------------- 1 | # Badge 标记 2 | 3 | ### 基础用法 4 | 5 | ```vue demo 6 | 16 | ``` 17 | 18 | ### 最大值 19 | 20 | 可自定义最大值,当 value 为 Number 时 21 | 22 | ```vue demo 23 | 31 | ``` 32 | 33 | ### 小圆点 34 | 35 | 以红点的形式标注需要关注的内容 36 | 37 | ```vue demo 38 | 46 | ``` 47 | 48 | ### 自定义内容 49 | 50 | 自定义显示内容 51 | 52 | ```vue demo 53 | 61 | ``` 62 | 63 | ### 显示不同主题 64 | 65 | 支持 `default`、`primary`、`success`、`warning`、`danger`、五种类型,默认为 `danger`。 66 | 67 | ```vue demo 68 | 84 | ``` 85 | 86 | ## API 87 | 88 | ### Badge 89 | 90 | | 参数 | 类型 | 说明 | 91 | | ----- | ------------- |-----------------------------------------------------------------------| 92 | | value | String/Number | 显示值 | 93 | | max | Number | 最大值,value 为 Number 有效,默认99 | 94 | | dot | boolean/false | 显示小圆点 | 95 | | type | String | 支持 `default`、`primary`、`success`、`warning`、`danger`、五种类型,默认为 `danger` | 96 | -------------------------------------------------------------------------------- /src/packages/timeSelect/README.md: -------------------------------------------------------------------------------- 1 | # TimeSelect 时间选择 2 | 3 | 4 | ### 基础用法 5 | 6 | ```vue demo 7 | 10 | 14 | 15 | 16 | ``` 17 | ### 选择开始和结束时间 18 | 19 | ```vue demo 20 | 28 | 32 | 33 | 34 | ``` 35 | ### 固定时间范围 36 | 37 | ```vue demo 38 | 46 | 50 | 51 | 52 | ``` 53 | 54 | ## API 55 | 56 | ### TimeSelect Props 57 | 58 | | 参数 | 类型 | 说明 | 59 | |--------------|---------------|---------------------------| 60 | | v-model | string | 显示的值 | 61 | | start | string | 开始时间 09:00 | 62 | | end | string | 结束时间 18:00 | 63 | | step | string | 间隔时间 00:30 | 64 | | min-time | string | 最早时间点,早于该时间的时间段将被禁用| 65 | | max-time | string | 最晚时间点,晚于该时间的时间段将被禁用 | 66 | | disabled | boolean/false | 禁用状态 | 67 | | width | string | 组件宽 | 68 | | clear | boolean/false | 是否可清空 | 69 | | size | string | 大小 | 70 | | placeholder | string | 占位符 | 71 | | direction | number | 下拉的方向动画,0默认 1向下 2向上| 72 | | downClass | string | 下拉面板类 | 73 | | downStyle | object | 下拉面板样式 | 74 | | appendToBody | boolean/false | 下拉插入到body | 75 | | downHeight | number | 下拉的面板的高 | 76 | | icon | string | icon图标 | 77 | 78 | ### TimeSelect Event 79 | 80 | | 参数 | 说明 | 81 | |-------------|----------------| 82 | | change | modelValue改变事件 | 83 | | toggleClick | 点击展开收起事件 | 84 | | clear | 清空事件 | 85 | -------------------------------------------------------------------------------- /src/packages/formItem/Field.vue: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 84 | -------------------------------------------------------------------------------- /src/packages/loading/Loading.vue: -------------------------------------------------------------------------------- 1 | 2 | 23 | 24 | 84 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 28 | 94 | -------------------------------------------------------------------------------- /src/packages/loading/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Loading 加载等待 4 | 5 | 自定义指令`v-loading`,只需要绑定`Boolean`即可。默认状况下,`Loading`会插入到绑定元素的子节点 6 | 7 | ### 基本用法 8 | 9 | ```vue demo 10 | 19 | 24 | 25 | 26 | ``` 27 | 28 | ### 自定义 29 | 30 | 可自定义加载文案、图标和背景色。通过`ak-loading-text`设置提示文字,`ak-loading-spinner`设置图标类名,`ak-loading-background`设置背景色 31 | 32 | ```vue demo 33 | 45 | 50 | 51 | 52 | ``` 53 | 54 | ### 其他加载方式 55 | 56 | 支持`inject('Loading')`,`this.$msg()`,`getCurrentInstance().proxy.$loading()`方式引用 57 | 58 | ```vue demo 59 | 70 | 88 | ``` 89 | 90 | ## API 91 | 92 | ### Loading 93 | 94 | |参数|类型|说明| 95 | |----------|--------------|--------| 96 | |text | String |显示在加载图标下方的加载文案| 97 | |background | String |遮罩背景色| 98 | |spinner | String |自定义加载图标类名| 99 | |lock | Boolean/false |锁定滚动| 100 | |zIndex | Number |层级| 101 | |el | 标签对象 |将内容插入到指定标签,默认为当前标签| 102 | -------------------------------------------------------------------------------- /docs/static/iconfont/iconfont.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "iconfont"; /* Project id 1935909 */ 3 | src: url('iconfont.woff2?t=1657508699542') format('woff2'), 4 | url('iconfont.woff?t=1657508699542') format('woff'), 5 | url('iconfont.ttf?t=1657508699542') format('truetype'); 6 | } 7 | 8 | .iconfont,[class*="icon-"] { 9 | font-family: "iconfont" !important; 10 | font-size: 16px; 11 | font-style: normal; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | } 15 | 16 | .icon-rotateLeft:before { 17 | content: "\e65a"; 18 | } 19 | 20 | .icon-rotateRight:before { 21 | content: "\e65c"; 22 | } 23 | 24 | .icon-default:before { 25 | content: "\e912"; 26 | } 27 | 28 | .icon-arrow-r:before { 29 | content: "\e788"; 30 | } 31 | 32 | .icon-zoom-out:before { 33 | content: "\ec13"; 34 | } 35 | 36 | .icon-zoom-in:before { 37 | content: "\ec14"; 38 | } 39 | 40 | .icon-loading:before { 41 | content: "\e62b"; 42 | } 43 | 44 | .icon-down:before { 45 | content: "\e610"; 46 | } 47 | 48 | .icon-check:before { 49 | content: "\e6c1"; 50 | } 51 | 52 | .icon-arrow:before { 53 | content: "\e61a"; 54 | } 55 | 56 | .icon-hook:before { 57 | content: "\e88c"; 58 | } 59 | 60 | .icon-lock:before { 61 | content: "\e88f"; 62 | } 63 | 64 | .icon-user:before { 65 | content: "\e898"; 66 | } 67 | 68 | .icon-correct:before { 69 | content: "\e60e"; 70 | } 71 | 72 | .icon-eye-close:before { 73 | content: "\e61c"; 74 | } 75 | 76 | .icon-error:before { 77 | content: "\e640"; 78 | } 79 | 80 | .icon-del:before { 81 | content: "\e608"; 82 | } 83 | 84 | .icon-top:before { 85 | content: "\e90c"; 86 | } 87 | 88 | .icon-upload:before { 89 | content: "\e915"; 90 | } 91 | 92 | .icon-search:before { 93 | content: "\e60b"; 94 | } 95 | 96 | .icon-eye:before { 97 | content: "\eab4"; 98 | } 99 | 100 | .icon-minus:before { 101 | content: "\e7af"; 102 | } 103 | 104 | .icon-warn:before { 105 | content: "\e638"; 106 | } 107 | 108 | .icon-close:before { 109 | content: "\e650"; 110 | } 111 | 112 | .icon-plus:before { 113 | content: "\e625"; 114 | } 115 | 116 | .icon-date:before { 117 | content: "\e6c7"; 118 | } 119 | 120 | .icon-refresh:before { 121 | content: "\e615"; 122 | } 123 | 124 | .icon-failure:before { 125 | content: "\e90b"; 126 | } 127 | 128 | .icon-tips:before { 129 | content: "\e90d"; 130 | } 131 | 132 | .icon-success:before { 133 | content: "\e90e"; 134 | } 135 | 136 | -------------------------------------------------------------------------------- /public/static/iconfont/iconfont.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "iconfont"; /* Project id 1935909 */ 3 | src: url('iconfont.woff2?t=1657508699542') format('woff2'), 4 | url('iconfont.woff?t=1657508699542') format('woff'), 5 | url('iconfont.ttf?t=1657508699542') format('truetype'); 6 | } 7 | 8 | .iconfont,[class*="icon-"] { 9 | font-family: "iconfont" !important; 10 | font-size: 16px; 11 | font-style: normal; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | } 15 | 16 | .icon-rotateLeft:before { 17 | content: "\e65a"; 18 | } 19 | 20 | .icon-rotateRight:before { 21 | content: "\e65c"; 22 | } 23 | 24 | .icon-default:before { 25 | content: "\e912"; 26 | } 27 | 28 | .icon-arrow-r:before { 29 | content: "\e788"; 30 | } 31 | 32 | .icon-zoom-out:before { 33 | content: "\ec13"; 34 | } 35 | 36 | .icon-zoom-in:before { 37 | content: "\ec14"; 38 | } 39 | 40 | .icon-loading:before { 41 | content: "\e62b"; 42 | } 43 | 44 | .icon-down:before { 45 | content: "\e610"; 46 | } 47 | 48 | .icon-check:before { 49 | content: "\e6c1"; 50 | } 51 | 52 | .icon-arrow:before { 53 | content: "\e61a"; 54 | } 55 | 56 | .icon-hook:before { 57 | content: "\e88c"; 58 | } 59 | 60 | .icon-lock:before { 61 | content: "\e88f"; 62 | } 63 | 64 | .icon-user:before { 65 | content: "\e898"; 66 | } 67 | 68 | .icon-correct:before { 69 | content: "\e60e"; 70 | } 71 | 72 | .icon-eye-close:before { 73 | content: "\e61c"; 74 | } 75 | 76 | .icon-error:before { 77 | content: "\e640"; 78 | } 79 | 80 | .icon-del:before { 81 | content: "\e608"; 82 | } 83 | 84 | .icon-top:before { 85 | content: "\e90c"; 86 | } 87 | 88 | .icon-upload:before { 89 | content: "\e915"; 90 | } 91 | 92 | .icon-search:before { 93 | content: "\e60b"; 94 | } 95 | 96 | .icon-eye:before { 97 | content: "\eab4"; 98 | } 99 | 100 | .icon-minus:before { 101 | content: "\e7af"; 102 | } 103 | 104 | .icon-warn:before { 105 | content: "\e638"; 106 | } 107 | 108 | .icon-close:before { 109 | content: "\e650"; 110 | } 111 | 112 | .icon-plus:before { 113 | content: "\e625"; 114 | } 115 | 116 | .icon-date:before { 117 | content: "\e6c7"; 118 | } 119 | 120 | .icon-refresh:before { 121 | content: "\e615"; 122 | } 123 | 124 | .icon-failure:before { 125 | content: "\e90b"; 126 | } 127 | 128 | .icon-tips:before { 129 | content: "\e90d"; 130 | } 131 | 132 | .icon-success:before { 133 | content: "\e90e"; 134 | } 135 | 136 | -------------------------------------------------------------------------------- /src/packages/carousel/README.md: -------------------------------------------------------------------------------- 1 | # Carousel 走马灯 2 | 3 | ### 基本使用 4 | 5 | ```vue demo 6 | 13 | 14 | ``` 15 | 16 | ### 循环轮播 17 | 18 | 循环轮播`loop=true` 19 | 20 | ```vue demo 21 | 28 | 29 | ``` 30 | 31 | ### 方向 32 | 33 | 默认情况下,`direction` 为 `horizontal`。通过设置 `direction` 为 `vertical` 来让走马灯在垂直方向上显示。需设置高度`itemHeight` 34 | 35 | ```vue demo 36 | 43 | 44 | ``` 45 | 46 | ### 卡片 47 | 48 | 通过设置每屏可视数量,配合自定义样式展示卡片化切换。每屏展示的可视数一般为3/5/7个,每次移动单位为1个 49 | 50 | ```vue demo 51 | 58 | 59 | ``` 60 | 61 | ### 一次显示多个slides 62 | 63 | 同时可使用`move`指定每次移动的个数 64 | 65 | ```vue demo 66 | 73 | 74 | ``` 75 | 76 | ## API 77 | 78 | ### Carousel Props 79 | 80 | |参数|类型|说明| 81 | |----------|--------------|--------| 82 | |controlNav | Boolean/true |显示控制导航| 83 | |directionNav | Boolean/true |显示前后控制导航| 84 | |direction | string/h |走马灯展示的方向,horizontal/vertical两种,简写h/v| 85 | |showNumber | Number/1 |可视个数| 86 | |loop | Boolean/true |是否循环| 87 | |move | Number/1 |每次移动单位个数| 88 | |itemWidth | Number |单位移动宽度| 89 | |active | Number/0 |初始显示第几个,从1开始| 90 | |duration | Number/500 |切换过渡时间| 91 | |showTime | Number/3000 |自动播放时停留的时间| 92 | |autoPlay | Boolean/false |是否用动播放| 93 | |pauseOnHover | Boolean/true |鼠标滑动过暂停播放| 94 | |type | string |卡片类型,可选card| 95 | 96 | ### Carousel Event 97 | 98 | |参数|说明| 99 | |----------|-------| 100 | |slideBefore | -| 101 | |slideAfter | -| 102 | -------------------------------------------------------------------------------- /src/packages/theme/_slider.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | @include ns(slider){ 3 | height: 38px; 4 | @include ns(slider-runway){ 5 | width: 100%; 6 | height: 6px; 7 | margin: 16px 0; 8 | background-color: #e4e7ed; 9 | border-radius: 3px; 10 | position: relative; 11 | cursor: pointer; 12 | vertical-align: middle; 13 | } 14 | .slider-bar{ 15 | height: 6px; 16 | background-color: $primaryColor; 17 | border-radius: 3px; 18 | position: absolute;} 19 | .slider-control{ 20 | display: block; 21 | height: 36px; 22 | width: 36px; 23 | position: absolute; 24 | z-index: 81; 25 | top: -15px; 26 | transform: translateX(-50%); 27 | background-color: transparent; 28 | user-select: none; 29 | line-height: normal; 30 | &:after{ 31 | display: block; 32 | content: ''; 33 | width: 16px; 34 | height: 16px; 35 | border: 2px solid $primaryColor; 36 | background-color: #fff; 37 | border-radius: 50%; 38 | transition: .2s; 39 | user-select: none; 40 | margin: 8px auto; 41 | } 42 | &:hover{ 43 | &:after{ 44 | transform: scale(1.2); 45 | } 46 | .slider-tooltip{opacity: 1} 47 | } 48 | } 49 | .slider-tooltip{position: absolute;white-space: nowrap;padding: 5px 10px;background: #000;color: #fff;border-radius: 10px;transform: translate(-50%, -100%);left: 50%;box-shadow: 0 0 2px #999;opacity: 0; transition: all .3s; 50 | &:after{ 51 | content: ''; 52 | display: block; 53 | width: 0; 54 | height: 0; 55 | border: 5px solid transparent; 56 | border-top-color: black; 57 | position: absolute; 58 | left: 50%; 59 | bottom: -10px; 60 | transform: translateX(-50%); 61 | } 62 | } 63 | .slider-stop{ 64 | position: absolute; 65 | height: 6px; 66 | width: 6px; 67 | border-radius: 100%; 68 | background-color: #fff; 69 | transform: translateX(-50%); 70 | } 71 | .slider-marks{ 72 | position: absolute; 73 | height: 6px; 74 | width: 6px; 75 | border-radius: 100%; 76 | background-color: #fff; 77 | transform: translateX(-50%); 78 | .slider-marks-text{display: block;white-space: nowrap;position: absolute;transform: translateX(-50%);left: 50%;bottom: -25px;color: #999} 79 | } 80 | &.disabled{ 81 | .slider-bar{background: #c0c4cc} 82 | .slider-control{ 83 | &:after{border-color: #c0c4cc} 84 | &:hover{ 85 | &:after{cursor: not-allowed;transform: scale(1)} 86 | } 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/packages/tag/README.md: -------------------------------------------------------------------------------- 1 | # Tag 标签 2 | 3 | ### 基本使用 4 | 5 | 由`type`属性来选择`tag`的类型,支持 `default`、`success`、`warning`、`danger`类型,默认为 `default`。 6 | 7 | ```vue demo 8 | 17 | ``` 18 | 19 | ### 不同尺寸 20 | 21 | `Tag` 组件提供除了默认值以外的三种尺寸,可以在不同场景下选择合适的按钮尺寸。 22 | 23 | ```vue demo 24 | 32 | ``` 33 | 34 | ### 可移除标签 35 | 36 | 设置`closable`属性可以定义一个标签是否可移除 37 | 38 | ```vue demo 39 | 47 | ``` 48 | 49 | ### 动态编辑标签 50 | 51 | ```vue demo 52 | 64 | 78 | 79 | ``` 80 | 81 | ## API 82 | 83 | ### Tag Props 84 | 85 | | 参数 | 类型 | 说明 | 86 | | ----------- | ------------- | ------------------------------------ | 87 | | type | string | 类型,success/default/warning/danger | 88 | | closable | boolean/false | 是否可关闭 | 89 | | color | string | 字体颜色 | 90 | | bgColor | string | 背景色 | 91 | | borderColor | string | 边框颜色 | 92 | | size | string | 尺寸,large / default/small / mini | 93 | -------------------------------------------------------------------------------- /src/packages/formItem/validate.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 337547038 on 2018/8/15 0015. 3 | */ 4 | // 验证通过时返回true,否则返回错误提示 5 | const regular: { [index: string]: any } = { 6 | digits: /^[0-9]*[1-9][0-9]*$/, // 正整数 7 | number: /^\d+(\.\d+)?$/, // 带小数 8 | mobile: /^1[3|4|5|7|8]\d{9}$/, // 手机 9 | mail: /^[a-z0-9A-Z._%-]+@([a-z0-9A-Z-]+\.)+[a-zA-Z]{2,4}$/, 10 | tel: /^0\d{2,3}-\d{7,8}$/, // 电话020-00000 11 | fax: /^(\d{3,4})?[-]?\d{7,8}$/ 12 | } 13 | 14 | function newEval(fn: any) { 15 | const Fn = Function // 一个变量指向Function,防止有些前端编译工具报错 16 | return new Fn('return ' + fn)() 17 | } 18 | 19 | const isEmpty = function (value: string) { 20 | return /^\s*$/g.test(value) 21 | } 22 | const isRules = function (value: any, rule: any, type?: any) { 23 | if (type === 'rule') { 24 | // return eval(rule).test(value) 25 | return newEval(rule).test(value) 26 | } else { 27 | if (regular[rule] === undefined) { 28 | return 'undefined' 29 | } 30 | return newEval(regular[rule]).test(value) 31 | } 32 | } 33 | const Validate = function (value: any, rules: any) { 34 | for (let i = 0, len = rules.length; i < len; i++) { 35 | const rule = rules[i] 36 | switch (rule.type) { 37 | case 'required': 38 | // false也当作空处理 39 | if (isEmpty(value) || value === false) { 40 | return rule.msg 41 | } 42 | break 43 | case 'digits': 44 | case 'number': 45 | case 'mobile': 46 | case 'mail': 47 | case 'tel': 48 | case 'fax': 49 | if (!isEmpty(value) && !isRules(value, rule.type)) { 50 | return rule.msg 51 | } 52 | break 53 | case 'phone': 54 | if ( 55 | !isEmpty(value) && 56 | !(isRules(value, 'mobile') || isRules(value, 'tel')) 57 | ) { 58 | return rule.msg 59 | } 60 | break 61 | case 'maxLength': 62 | if (!isEmpty(value) && parseInt(value.length) > parseInt(rule.len)) { 63 | return rule.msg 64 | } 65 | break 66 | case 'minLength': 67 | if (!isEmpty(value) && parseInt(value.length) < parseInt(rule.len)) { 68 | return rule.msg 69 | } 70 | break 71 | case 'rule': 72 | if (!isEmpty(value) && !isRules(value, rule.rule, 'rule')) { 73 | return rule.msg 74 | } 75 | break 76 | case 'fn': 77 | if (!rule.validator(value)) { 78 | return rule.msg 79 | } 80 | break 81 | default: 82 | break 83 | } 84 | } 85 | return true 86 | } 87 | export default Validate 88 | -------------------------------------------------------------------------------- /src/packages/theme/_datePicker.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | @include ns(date-picker) {background: #fff;padding: 5px; overflow: hidden;box-sizing: border-box;min-width: 100%;display: flex; 3 | .calendar {display: block; user-select: none;width: 250px; 4 | &:nth-child(2) {border-left: 1px solid $borderColor } 5 | } 6 | .calendar-head {height: 34px;line-height: 34px;display: flex;align-items: center;justify-content: space-between;padding: 0 10px; 7 | span {flex: 2;text-align: center; 8 | a {margin: 0} 9 | } 10 | a { cursor: pointer;font-size: 14px;margin: 0 5px } 11 | } 12 | .calendar-body { text-align: center; position: relative; 13 | .calendar-week, .calendar-list {display: flex} 14 | .calendar-list {flex-wrap: wrap} 15 | .calendar-days { 16 | a { width: 14.28%; height: 25px;line-height: 25px; display: block; font-size: 12px; color: #333; box-sizing: border-box; cursor: pointer; position: relative; 17 | &:hover { color: $primaryColor; } 18 | span {display: block;width: 25px;height: 100%;border-radius: 50%;margin: 0 auto;position: relative} 19 | i {position: absolute;right: -4px;top: -5px;transform: scale(.8);color: $primaryColor} 20 | } 21 | /*非当前月*/ 22 | .calendar-date-out { color: #999; } 23 | .calendar-date-disabled { color: #ccc; cursor: not-allowed !important; 24 | &:hover { background: none } 25 | } 26 | /*当前选中*/ 27 | .calendar-date-select { 28 | span {background: $primaryColor;color: #fff} 29 | } 30 | } 31 | /*今天的*/ 32 | .calendar-date-today { 33 | color: red; 34 | span {color: red} 35 | } 36 | .calendar-week { 37 | a { cursor: default; 38 | &:hover { background: none; } 39 | } 40 | } 41 | .calendar-months, .calendar-year {background: #fff; overflow: hidden;z-index: 10;display: flex;flex-wrap: wrap; 42 | a {width: 33.33%; height: 44px;line-height: 44px; display: block; cursor: pointer; 43 | &:hover { background: #eaf8fe; } 44 | &.calendar-date-select { background: $primaryColor; color: #fff; font-weight: 700; } 45 | &.calendar-date-disabled { background: #ccc; cursor: not-allowed;color: #999 } 46 | } 47 | } 48 | .calendar-time {height: 22px;line-height: 22px; position: relative;display: flex;align-items: center;justify-content: space-between;padding-left: 10px; 49 | .calendar-time-input { border: 1px solid $borderColor; width: 80px;} 50 | input { width: 20px; text-align: center; border: 0; font-size: 12px;outline: none } 51 | .btn-time { right: 10px; top: 0; position: absolute; cursor: pointer; } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/packages/menu/Menu.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 88 | -------------------------------------------------------------------------------- /src/packages/util/dom.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 337547038 on 2018/9/5 0005. 3 | */ 4 | 5 | /* 节点操作的一些方法 */ 6 | interface Offset { 7 | width: number 8 | height: number 9 | left: number 10 | top: number 11 | } 12 | 13 | const scrollTop = () => { 14 | // 滚动条的位置 15 | return document.documentElement.scrollTop || document.body.scrollTop 16 | } 17 | const getOffset = (el: HTMLElement): Offset => { 18 | // console.log(el) 19 | // 返回元素偏移位置 20 | /*if (!el) { 21 | return 22 | }*/ 23 | const componentRect: DOMRect = el.getBoundingClientRect() 24 | const top = 25 | componentRect.top + 26 | (window.pageYOffset || document.documentElement.scrollTop) - 27 | (document.documentElement.clientTop || 0) 28 | const left = 29 | componentRect.left + 30 | (window.pageXOffset || document.documentElement.scrollLeft) - 31 | (document.documentElement.clientLeft || 0) 32 | const width = el.offsetWidth 33 | const height = el.offsetHeight 34 | return { left: left, top: top, width: width, height: height } 35 | } 36 | const getWindow = () => { 37 | // 返回窗口宽高 38 | const width = 39 | document.documentElement.clientWidth || document.body.clientWidth 40 | const height = 41 | document.documentElement.clientHeight || document.body.clientHeight 42 | return { width: width, height: height } 43 | } 44 | const getScrollbarWidth = (bool?: boolean) => { 45 | // 取滚动条的宽 46 | const hasScroll = 47 | document.body.scrollHeight > 48 | (window.innerHeight || document.documentElement.clientHeight) 49 | const scrollDiv: HTMLDivElement = document.createElement('div') 50 | scrollDiv.style.cssText = 51 | 'width: 99px; height: 99px; overflow: scroll; position: absolute; top: -9999px;' 52 | document.body.appendChild(scrollDiv) 53 | const scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth 54 | document.body.removeChild(scrollDiv) 55 | if (bool) { 56 | return { hasScroll: hasScroll, width: scrollbarWidth } 57 | } else { 58 | return scrollbarWidth 59 | } 60 | } 61 | const hasClass = (elements: Element, cName = '') => { 62 | return !!elements.className.match(new RegExp('(\\s|^)' + cName + '(\\s|$)')) 63 | } 64 | const addClass = (elements: Element, cName = '') => { 65 | if (!hasClass(elements, cName)) { 66 | if (elements.className) { 67 | elements.className += ' ' + cName 68 | } else { 69 | elements.className += cName 70 | } 71 | } 72 | } 73 | const removeClass = (elements: Element, cName = '') => { 74 | if (hasClass(elements, cName)) { 75 | elements.className = elements.className.replace( 76 | new RegExp('(\\s|^)' + cName + '(\\s|$)'), 77 | '' 78 | ) 79 | } 80 | } 81 | 82 | export { 83 | scrollTop, 84 | getOffset, 85 | getWindow, 86 | getScrollbarWidth, 87 | hasClass, 88 | addClass, 89 | removeClass 90 | } 91 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | "env": { 4 | "browser": true, 5 | "es2021": true, 6 | "node": true 7 | }, 8 | extends: [ 9 | 'plugin:vue/vue3-essential', 10 | 'eslint:recommended', 11 | '@vue/typescript/recommended', 12 | 'prettier', 13 | 'plugin:prettier/recommended' 14 | ], 15 | "parser": "vue-eslint-parser", 16 | "parserOptions": { 17 | "ecmaVersion": "latest", 18 | "sourceType": "module", 19 | "parser": "@typescript-eslint/parser" 20 | }, 21 | "plugins": [ 22 | "prettier", 23 | "vue", 24 | "@typescript-eslint" 25 | ], 26 | overrides: [ 27 | { 28 | files: ['*.vue'], 29 | rules: { 30 | indent: 'off', 31 | }, 32 | }, 33 | ], 34 | globals: { 35 | ace: true, 36 | tinymce: true, 37 | AMap: true, 38 | echarts: true 39 | }, 40 | rules: { 41 | "prettier/prettier": ["error", { 42 | vueIndentScriptAndStyle: true 43 | }], 44 | "vue/script-setup-uses-vars": "error", 45 | "@typescript-eslint/ban-ts-ignore": "off", 46 | "@typescript-eslint/explicit-function-return-type": "off", 47 | "@typescript-eslint/no-explicit-any": "off", 48 | "@typescript-eslint/no-var-requires": "off", 49 | "@typescript-eslint/no-empty-function": "off", 50 | "vue/custom-event-name-casing": "off", 51 | "no-use-before-define": "off", 52 | "@typescript-eslint/no-use-before-define": "off", 53 | "@typescript-eslint/ban-ts-comment": "off", 54 | "@typescript-eslint/ban-types": "off", 55 | "@typescript-eslint/no-non-null-assertion": "off", 56 | "@typescript-eslint/explicit-module-boundary-types": "off", 57 | "@typescript-eslint/no-unused-vars": [ 58 | "error", 59 | { 60 | argsIgnorePattern: "^_", 61 | varsIgnorePattern: "^_", 62 | }, 63 | ], 64 | "no-unused-vars": [ 65 | "error", 66 | { 67 | argsIgnorePattern: "^_", 68 | varsIgnorePattern: "^_", 69 | }, 70 | ], 71 | "space-before-function-paren": "off", 72 | 73 | "vue/attributes-order": "off", 74 | "vue/one-component-per-file": "off", 75 | "vue/html-closing-bracket-newline": "off", 76 | "vue/max-attributes-per-line": "off", 77 | "vue/multiline-html-element-content-newline": "off", 78 | "vue/singleline-html-element-content-newline": "off", 79 | "vue/attribute-hyphenation": "off", 80 | "vue/require-default-prop": "off", 81 | "vue/require-explicit-emits": "off", 82 | "vue/html-self-closing": [ 83 | "error", 84 | { 85 | html: { 86 | void: "always", 87 | normal: "never", 88 | component: "always", 89 | }, 90 | svg: "always", 91 | math: "always", 92 | }, 93 | ], 94 | "vue/multi-word-component-names": "off", 95 | "vue/no-v-html": "off" 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/packages/theme/_tooltip.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | @include ns(tooltip-box) {display: inline-block;position: relative} 3 | @include ns(tooltip) { 4 | // $background: lighten($primaryColor,0); 5 | $background: $borderColor; 6 | position: absolute; z-index: 100; background: $backgroundColor; color: $textColor; padding: 8px 12px; line-height: 20px; border-radius: 5px;box-sizing: border-box;border: 1px solid $borderColor;box-shadow: 0 0 12px rgba(0, 0, 0, .12);text-align: left; 7 | .arrow {position: absolute;display: block;width: 0;height: 0;border-color: transparent;border-style: solid;border-width: 5px;filter: drop-shadow(0 2px 12px rgba(0, 0, 0, .03)); border-top-width: 0;border-bottom-color: $borderColor; 8 | &:before {content: '';position: absolute;display: block;width: 0;height: 0;border-color: transparent;border-style: solid;border-width: 5px;border-top-width: 0;border-bottom-color: $backgroundColor;top: 1px;left: -5px} 9 | } 10 | /*&:before { content: ''; display: inline-block; border: 5px solid transparent; position: absolute; }*/ 11 | /*处理下箭头方向*/ 12 | &.top-left { 13 | .arrow { left: 15px; bottom: -6px;transform: rotate(180deg)} 14 | } 15 | &.top { 16 | .arrow { left: 50%; bottom: -6px; margin-left: -5px;transform: rotate(180deg) } 17 | } 18 | &.top-right { 19 | .arrow { right: 15px; bottom: -6px; transform: rotate(180deg)} 20 | } 21 | &.left { 22 | .arrow { right: -8px; top: 50%;margin-top: -3px;transform: rotate(90deg) } 23 | } 24 | &.right { 25 | .arrow { left: -8px; top: 50%; transform: rotate(-90deg); margin-top: -3px; } 26 | } 27 | &.bottom-left { 28 | .arrow { left: 15px; top: -6px; } 29 | } 30 | &.bottom { 31 | .arrow { left: 50%; top: -6px; margin-left: -3px; } 32 | } 33 | &.bottom-right { 34 | .arrow { right: 15px; top: -6px;} 35 | } 36 | } 37 | .tooltip-fade-enter-active { 38 | animation: tooltip-fade-in .3s; 39 | &.top,&.bottom{ 40 | //translateX 41 | animation: tooltip-fade-inX .3s; 42 | } 43 | &.left,&.right{ 44 | //translateY 45 | animation: tooltip-fade-inY .3s; 46 | } 47 | } 48 | .tooltip-fade-leave-active { 49 | animation: tooltip-fade-out 0.3s; 50 | } 51 | @keyframes tooltip-fade-in { 52 | 0% { 53 | transform: scale(.8); 54 | opacity: 0; 55 | } 56 | } 57 | @keyframes tooltip-fade-out { 58 | 100% { 59 | opacity: 0; 60 | transform: scale(.8); 61 | } 62 | } 63 | @keyframes tooltip-fade-inX { 64 | 0% { 65 | transform: translateX(-50%) scale(.8); 66 | opacity: 0; 67 | } 68 | } 69 | /*@keyframes tooltip-fade-outX { 70 | 100% { 71 | opacity: 0; 72 | transform: translateX(-50%) scale(.8); 73 | } 74 | }*/ 75 | @keyframes tooltip-fade-inY { 76 | 0% { 77 | transform: translateY(-50%) scale(.8); 78 | opacity: 0; 79 | } 80 | } 81 | /*@keyframes tooltip-fade-outY { 82 | 100% { 83 | opacity: 0; 84 | transform: translateY(-50%) scale(.8); 85 | } 86 | }*/ 87 | -------------------------------------------------------------------------------- /src/packages/cascader/demo.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "value": "广东", 4 | "label": "广东", 5 | "children": [ 6 | { 7 | "value": "广州", 8 | "label": "广州", 9 | "children": [ 10 | { 11 | "value": "天河", 12 | "label": "天河" 13 | }, 14 | { 15 | "value": "白云", 16 | "label": "白云" 17 | }, 18 | { 19 | "value": "越秀", 20 | "label": "越秀" 21 | }, 22 | { 23 | "value": "海珠", 24 | "label": "海珠" 25 | } 26 | ] 27 | }, 28 | { 29 | "value": "深圳", 30 | "label": "深圳", 31 | "children": [ 32 | { 33 | "value": "罗湖区", 34 | "label": "罗湖区" 35 | }, 36 | { 37 | "value": "宝安区", 38 | "label": "宝安区" 39 | }, 40 | { 41 | "value": "南山区", 42 | "label": "南山区" 43 | }, 44 | { 45 | "value": "龙岗区", 46 | "label": "龙岗区" 47 | }, 48 | { 49 | "value": "盐田区", 50 | "label": "盐田区" 51 | } 52 | ] 53 | }, 54 | { 55 | "value": "东莞", 56 | "label": "东莞", 57 | "children": [ 58 | { 59 | "value": "长安", 60 | "label": "长安" 61 | }, 62 | { 63 | "value": "虎门", 64 | "label": "虎门" 65 | }, 66 | { 67 | "value": "茶山", 68 | "label": "茶山" 69 | } 70 | ] 71 | }, 72 | { 73 | "label": "禁用测试", 74 | "disabled": true, 75 | "value": "1", 76 | "children": [ 77 | { 78 | "label": "禁用测试2", 79 | "value": "2" 80 | } 81 | ] 82 | } 83 | ] 84 | }, 85 | { 86 | "value": "北京", 87 | "label": "北京", 88 | "children": [ 89 | { 90 | "value": "西城区", 91 | "label": "西城区" 92 | }, 93 | { 94 | "value": "崇文区", 95 | "label": "崇文区" 96 | }, 97 | { 98 | "value": "宣武区", 99 | "label": "宣武区" 100 | }, 101 | { 102 | "value": "朝阳区", 103 | "label": "朝阳区" 104 | }, 105 | { 106 | "value": "丰台区", 107 | "label": "丰台区" 108 | }, 109 | { 110 | "value": "海淀区", 111 | "label": "海淀区" 112 | } 113 | ] 114 | }, 115 | { 116 | "value": "上海", 117 | "label": "上海", 118 | "children": [ 119 | { 120 | "value": "黄浦区", 121 | "label": "黄浦区" 122 | }, 123 | { 124 | "value": "卢湾区", 125 | "label": "卢湾区" 126 | }, 127 | { 128 | "value": "徐汇区", 129 | "label": "徐汇区" 130 | } 131 | ] 132 | } 133 | ] 134 | -------------------------------------------------------------------------------- /src/packages/datePicker/ControlHead.vue: -------------------------------------------------------------------------------- 1 | 2 | 33 | 34 | 100 | -------------------------------------------------------------------------------- /src/packages/progress/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Progress 进度条 4 | 5 | ### 基础用法 6 | 7 | ```vue demo 8 | 30 | 34 | 35 | ``` 36 | 37 | ### 其他用法 38 | 39 | ```vue demo 40 | 41 | 57 | ``` 58 | 59 | ### 环形进度条 60 | 61 | ```vue demo 62 | 97 | 98 | ``` 99 | 100 | ## API 101 | 102 | ### Progress 103 | 104 | | 参数 |类型|说明| 105 | |-------------|--------------|--------| 106 | | v-model | Number |进度值| 107 | | type | String |进度条类型,支持两种line直线、circle圆环| 108 | | radius | Number |圆环半径,单位px。line时为宽| 109 | | border | Number |进度条宽,单位px。line时为高| 110 | | color | String |背景颜色| 111 | | borderColor | String |进度颜色| 112 | | duration | Number/1000 |持续时间,单位毫秒| 113 | | showText | Boolean/true |显示进度文字| 114 | | followText | Boolean/true |进度文字跟随进度的位置,type=line时有效| 115 | | className | String |样式类名| 116 | | status | String |支持 `primary`、`success`、`warning`、`danger` 类型,默认为 `primary`。| 117 | 118 | -------------------------------------------------------------------------------- /src/packages/lazy/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Lazy 图片懒加载(指令) 4 | 5 | ### 基本用法 6 | 7 | 图片的`src`可通过`v-lazy='src'`或`data-src='src'`两种方式传入 8 | 9 | ```vue demo 10 | 23 | 27 | 28 | 29 | ``` 30 | 31 | ### 自定默认和错误时的图片 32 | 33 | `data-src`图片真实地址,`data-error`加载错误显示的图片地址,`src`默认初始显示图片地址 34 | 35 | ```vue demo 36 | 47 | 50 | 51 | ``` 52 | 53 | ### 在指定容器中滚动 54 | 55 | 指令后面指定容器`id` `v-lazy:container='src''` 56 | 57 | ```vue demo 58 | 65 | 78 | 79 | ``` 80 | 81 | ## API 82 | 83 | ### 全局设置 84 | 85 | ```javascript 86 | Vue.use(Lazy, { 87 | loading: '/static/img/lazy-default.gif', // 初始默认显示的图片 88 | error: '/static/img/lazy-error.png', // 加载错误时显示的图片 89 | fadeIn: true, // 加载完成时图片淡入 90 | threshold: 0 // 图片离可视区域的距离。负值表示提前进入,正值表示延迟进入 91 | }) 92 | ``` 93 | 94 | ### Lazy Props 95 | 96 | |参数|类型|说明| 97 | |----------|--------------|--------| 98 | |v-lazy | String |图片真实地址,也可使用`data-src`| 99 | |src | String |初始默认显示的图片,一般不需要单独设置| 100 | |data-error | String |加载错误时显示的图片,一般不需要单独设置| 101 | |data-src | String |图片真实地址| 102 | -------------------------------------------------------------------------------- /src/packages/image/README.md: -------------------------------------------------------------------------------- 1 | # Image 图片 2 | 3 | ### 基本使用 4 | 5 | 通过`fit`确定图片如何适应到容器框 6 | 7 | ```vue demo 8 | 23 | 28 | 29 | ``` 30 | 31 | ### 设置边框圆角 32 | 33 | ```vue demo 34 | 40 | 41 | ``` 42 | 43 | ### 占位符,加载状态,加载异常 44 | 45 | ```vue demo 46 | 62 | 63 | ``` 64 | 65 | ### 预览 66 | 67 | ```vue demo 68 | 78 | 83 | 84 | ``` 85 | 86 | ## API 87 | 88 | ### Image Props 89 | 90 | | 参数 | 类型 | 说明 | 91 | |------------------|----------|--------------------| 92 | | src | string | 图片源地址,同原生属性一致 | 93 | | fit | string | 图片如何适应容器框,同原生 object-fit,可选`'fill'|'contain'|'cover'|'none'|'scale-down'` | 94 | | alt | string | 原生alt属性 | 95 | | preview-src-list | string[] | 开启图片预览功能 | 96 | | z-index | number | 设置图片预览的 z-index | 97 | | previewCls | string | 图片预览窗口类名 | 98 | | border | boolean | 显示边框 | 99 | | radius | string | 圆角 | 100 | 101 | ### Image Slots 102 | 103 | |参数|说明| 104 | |----------|--------| 105 | |error |加载失败内容| 106 | |placeholder |自定义占位内容| 107 | -------------------------------------------------------------------------------- /src/packages/input/README.md: -------------------------------------------------------------------------------- 1 | # Input 输入框 2 | 3 | ### 基本使用 4 | 5 | ```vue demo 6 | 12 | 16 | 17 | ``` 18 | 19 | ### 显示清空按钮 20 | 21 | 设置`clear="true"`,在输入框不为空时显示清空按钮 22 | 23 | ```vue demo 24 | 31 | 35 | 36 | ``` 37 | 38 | ### 可显示密码明文 39 | 40 | `type="password`时设置`showEye="true"`可显示密码明文 41 | 42 | ```vue demo 43 | 51 | 55 | 56 | ``` 57 | 58 | ### 添加前后缀Icon 59 | 60 | 可以通过 `prefix-icon` 和 `suffix-icon` 属性在 input 组件首部和尾部增加显示图标,也可以通过 slot `prefix` 和 `suffix` 来放置图标。 61 | 62 | ```vue demo 63 | 71 | 72 | ``` 73 | 74 | ### 复合型输入框 75 | 76 | 可前置或后置元素,一般为标签或按钮 77 | 78 | ```vue demo 79 | 91 | 92 | ``` 93 | 94 | ### 设置大小 95 | 96 | 支持 `large`、`normal`、`small`、`mini` 四种尺寸,默认为 normal 97 | 98 | ```vue demo 99 | 105 | 106 | ``` 107 | 108 | ## API 109 | 110 | ### Input Props 111 | 112 | |参数|类型|说明| 113 | |----------|--------------|--------| 114 | |v-model | any |输入框的值| 115 | |clear | boolean/false |显示清空按钮| 116 | |showEye | boolean/false |密码框显示明文切换| 117 | |width | string |设置宽度属性| 118 | |size | string |支持 `large`、`normal`、`small`、`mini` 四种尺寸,默认为 `normal`| 119 | |prefixIcon | string |前缀icon图标| 120 | |suffixIcon | string |后缀icon图标| 121 | |- | |其它原生所有属性| 122 | 123 | ### Input Slots 124 | 125 | |参数|说明| 126 | |----------|--------| 127 | |prepend |输入框前置内容| 128 | |append |输入框后置内容| 129 | |prefix |前缀icon图标| 130 | |suffix |后缀icon图标| 131 | -------------------------------------------------------------------------------- /src/packages/transition/Transition.vue: -------------------------------------------------------------------------------- 1 | 2 | 7 | 93 | -------------------------------------------------------------------------------- /src/packages/theme/_button.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | @mixin BBT($border,$background,$color) { 3 | border-color: $border; 4 | background-color: $background; 5 | color: $color; 6 | } 7 | @mixin BBTLighten($color,$num,$num2) { 8 | border-color: lighten($color, $num); 9 | background-color: lighten($color, $num2); 10 | color: $color; 11 | } 12 | @include ns(btn) { 13 | @include BBT($borderColor, $backgroundColor, $textColor); 14 | display: inline-block;white-space: nowrap;cursor: pointer;border: 1px solid $borderColor; text-align: center; box-sizing: border-box;outline: none;padding: 0 20px;border-radius: $borderRadius;font-size: 14px;transition: .2s;user-select: none;height: 36px;line-height: 36px; 15 | @include ns(icon) {margin-right: 5px;display: inline-block;vertical-align: middle} 16 | &:hover { 17 | opacity: .8; 18 | } 19 | &.disabled {cursor: not-allowed;opacity: $disabledOpacity} 20 | &.is-round {border-radius: 18px; 21 | &.large {border-radius: 20px} 22 | &.small {border-radius: 16px} 23 | &.mini {border-radius: 14px} 24 | } 25 | &.is-circle {border-radius: 50%;height: 36px;padding: 0;width: 36px; 26 | &.large {width: 40px;height: 40px} 27 | &.small {width: 32px;height: 32px} 28 | &.mini {width: 28px;height: 28px} 29 | } 30 | /*以上为默认*/ 31 | /*要对每种type定义不同的状态,如type=primary*/ 32 | &.#{$namespace}btn-primary { 33 | @include BBT($primaryColor, $primaryColor, $textColor5); 34 | &.is-plain { 35 | @include BBTLighten($primaryColor, 30, 42); 36 | &:hover { 37 | @include BBT($primaryColor, $primaryColor, $textColor5); 38 | } 39 | } 40 | } 41 | &.#{$namespace}btn-success { 42 | @include BBT($successColor, $successColor, $textColor5); 43 | &.is-plain { 44 | @include BBTLighten($successColor, 30, 58); 45 | &:hover { 46 | @include BBT($successColor, $successColor, $textColor5); 47 | } 48 | } 49 | } 50 | &.#{$namespace}btn-warning { 51 | @include BBT($warningColor, $warningColor, $textColor5); 52 | &.is-plain { 53 | @include BBTLighten($warningColor, 10, 26); 54 | &:hover { 55 | @include BBT($warningColor, $warningColor, $textColor5); 56 | } 57 | } 58 | } 59 | &.#{$namespace}btn-danger { 60 | @include BBT($dangerColor, $dangerColor, $textColor5); 61 | &.is-plain { 62 | @include BBTLighten($dangerColor, 30, 46); 63 | &:hover { 64 | @include BBT($dangerColor, $dangerColor, $textColor5); 65 | } 66 | } 67 | } 68 | &.#{$namespace}btn-text { 69 | //文字链接按钮 70 | border: 0;padding: 0;height: auto;line-height: normal; 71 | } 72 | // 尺寸大小 73 | &.large {padding: 0 20px;border-radius: 4px;font-size: 14px;height: 40px;line-height: 40px} 74 | &.small {padding: 0 15px;border-radius: 3px;font-size: 12px;height: 32px;line-height: 32px} 75 | &.mini {padding: 0 15px;border-radius: 4px;font-size: 12px;height: 28px;line-height: 28px} 76 | /*+ .-btn{margin-left: 10px}*/ 77 | + .#{$namespace}btn {margin-left: 10px} 78 | // loading动画 79 | .icon-loading {margin: 0 2px 0 0;position: relative;top: -2px; 80 | &:before {animation: iconLoading 2s linear infinite;display: block} 81 | } 82 | } 83 | @include ns(btn-group) {} 84 | @keyframes iconLoading { 85 | 0% {transform: rotate(0)} 86 | 100% {transform: rotate(360deg)} 87 | } 88 | -------------------------------------------------------------------------------- /src/packages/timePicker/README.md: -------------------------------------------------------------------------------- 1 | # TimePicker 时间选择 2 | 3 | ### 基础用法 4 | 5 | ```vue demo 6 | 9 | 15 | 16 | ``` 17 | 18 | ### 可输入 19 | 20 | ```vue demo 21 | 24 | 30 | 31 | ``` 32 | 33 | ### 限制时间范围 34 | 35 | 使用`disabled-time`限制时间选择范围 36 | 37 | 示例限制时间范围上午 9-12,下午 14-18 点 38 | 39 | 选择 9 点时,9:30 可选,选择 18 点时,18:30 之前可选 40 | 41 | ```vue demo 42 | 45 | 70 | 71 | ``` 72 | 73 | ### 区间选择 74 | ```vue demo 75 | 78 | 82 | 83 | ``` 84 | 85 | ## API 86 | 87 | ### TimeSelect Props 88 | 89 | | 参数 | 类型 | 说明 | 90 | | ------------ | ------------- | ---------------------------------------- | 91 | | v-model | string | 显示的值 | 92 | | disabled | boolean/false | 禁用状态 | 93 | | width | string | 组件宽 | 94 | | clear | boolean/false | 是否可清空 | 95 | | filterable | boolean/false | 可输入 | 96 | | size | string | 大小 | 97 | | placeholder | string | 占位符 | 98 | | direction | number | 下拉的方向动画,0 默认  1 向下  2 向上 | 99 | | downClass | string | 下拉面板类 | 100 | | downStyle | object | 下拉面板样式 | 101 | | appendToBody | boolean/false | 下拉插入到 body | 102 | | downHeight | number | 下拉的面板的高 | 103 | | icon | string | icon 图标 | 104 | 105 | ### TimeSelect Event 106 | 107 | | 参数 | 说明 | 108 | |-------------|---------| 109 | | toggleClick | 点击展开收起事件 | 110 | | clear | 清空事件 | 111 | | blur | 失焦事件 | 112 | -------------------------------------------------------------------------------- /src/packages/datePicker/YearMonth.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 109 | -------------------------------------------------------------------------------- /src/packages/theme/_menu.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | @include ns(menu) { 3 | ul { 4 | li { 5 | /*ul {display: none;}*/ 6 | } 7 | } 8 | .icon-arrow {font-size: 14px;transform: scale(.8);margin-left: 5px;display: block;cursor: pointer;transition: all .3s} 9 | li { 10 | &.disabled {opacity: $disabledOpacity;cursor: not-allowed; 11 | .menu-title {cursor: not-allowed} 12 | } 13 | // 展开状态 14 | &.is-down { 15 | > .menu-title {color: $primaryColor; 16 | .icon-arrow {transform: rotate(180deg) scale(.8)} 17 | } 18 | } 19 | // 选中状态 20 | &.selected { 21 | > .menu-title {background: $backgroundColor2;color: $primaryColor} 22 | } 23 | } 24 | .menu-title {display: flex; align-items: center;font-size: 14px; text-overflow: ellipsis;white-space: nowrap;width: 100%;cursor: pointer;padding: 0 20px;transition: all .3s;justify-content: space-around; 25 | .name {flex: 2} 26 | .icon {display: block;margin-right: 3px;font-size: 16px;} 27 | } 28 | &.horizontal { 29 | > ul {display: flex;line-height: 40px;border-bottom: 1px solid $borderColor;} 30 | li {position: relative; 31 | ul {background: #fff;position: absolute;box-shadow: 0 0 12px rgba(0, 0, 0, .12);z-index: 10;left: 101%;top: 0; 32 | &.layer-1 {left: 0;top: inherit} 33 | li { 34 | &:after {display: none} 35 | } 36 | } 37 | &:after {content: '';position: absolute;left: 0;bottom: 0;width: 100%;height: 1px;background: $primaryColor;opacity: 0;transition: all .3s} 38 | &:hover { 39 | > .menu-title {color: $primaryColor;} 40 | &:after {opacity: 1} 41 | } 42 | } 43 | } 44 | &.vertical { 45 | li {line-height: 40px; 46 | &:hover { 47 | > .menu-title {background: $backgroundColor2;} 48 | } 49 | } 50 | // 缩进 51 | .layer-1 { 52 | .menu-title {padding-left: 40px} 53 | } 54 | .layer-2 { 55 | .menu-title {padding-left: 60px} 56 | } 57 | .layer-3 { 58 | .menu-title {padding-left: 80px} 59 | } 60 | } 61 | &.collapse {width: 60px; 62 | // 第一级只显示一个icon 63 | .layer-0 { 64 | > li > .menu-title { 65 | .icon-arrow, .name {display: none} 66 | &:hover {background: $backgroundColor2} 67 | } 68 | } 69 | li { 70 | position: relative; 71 | ul {position: absolute;left: 100%;top: 0;box-shadow: 0 0 12px rgba(0, 0, 0, .12);z-index: 10;} 72 | } 73 | .menu-title {padding: 0 20px !important;} 74 | } 75 | // 不同主题 76 | &.dark {background: rgb(68 75 80);color: #fff; 77 | &.horizontal { 78 | ul {background: rgb(68 75 80);} 79 | } 80 | &.vertical { 81 | ul{background: rgb(68 75 80);} 82 | li { 83 | &:hover { 84 | > .menu-title {background: $primaryColor;color: #fff} 85 | } 86 | &.is-down { 87 | > .menu-title {color: #fff; 88 | } 89 | } 90 | } 91 | } 92 | } 93 | // 动画 94 | .menu-enter-active {animation: menu-enter .3s forwards} 95 | .menu-leave-active {animation: menu-exit .3s forwards} 96 | } 97 | @keyframes menu-enter { 98 | 0% { opacity: 0;height: 0} 99 | 100% {opacity: 1;} 100 | } 101 | @keyframes menu-exit { 102 | 0% { opacity: 1;} 103 | 100% {opacity: 0;height: 0;} 104 | } 105 | -------------------------------------------------------------------------------- /src/packages/form/Form.vue: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 114 | -------------------------------------------------------------------------------- /src/packages/switch/Switch.vue: -------------------------------------------------------------------------------- 1 | 2 | 20 | 113 | -------------------------------------------------------------------------------- /src/packages/button/Button.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 113 | -------------------------------------------------------------------------------- /src/packages/checkbox/Checkbox.vue: -------------------------------------------------------------------------------- 1 | 2 | 21 | 113 | --------------------------------------------------------------------------------