mirror of
https://gitee.com/wot-design-uni/wot-design-uni.git
synced 2025-12-06 17:18:40 +08:00
chore: 🚀 init
This commit is contained in:
parent
9f925396c8
commit
69a4ef5540
2
.eslintignore
Normal file
2
.eslintignore
Normal file
@ -0,0 +1,2 @@
|
||||
babel.config.js
|
||||
src/uni_modules/mp-html/*
|
||||
42
.eslintrc.js
Normal file
42
.eslintrc.js
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2023-03-14 16:06:21
|
||||
* @LastEditTime: 2023-03-28 16:52:32
|
||||
* @LastEditors: weisheng
|
||||
* @Description:
|
||||
* @FilePath: \fant-mini-plus\.eslintrc.js
|
||||
* 记得注释
|
||||
*/
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
es2021: true
|
||||
},
|
||||
extends: ['eslint:recommended', 'plugin:vue/vue3-essential', 'plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'],
|
||||
overrides: [],
|
||||
parser: 'vue-eslint-parser',
|
||||
parserOptions: {
|
||||
parser: '@typescript-eslint/parser',
|
||||
ecmaVersion: 2020
|
||||
},
|
||||
plugins: ['vue', '@typescript-eslint'],
|
||||
rules: {
|
||||
'linebreak-style': ['error', 'unix'],
|
||||
quotes: ['error', 'single'],
|
||||
semi: ['error', 'never'],
|
||||
'no-console': 'off',
|
||||
'no-debugger': 'off',
|
||||
'no-undef': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/no-use-before-define': 'off',
|
||||
'@typescript-eslint/no-inferrable-types': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||
'@typescript-eslint/no-var-requires': 'off',
|
||||
'@typescript-eslint/no-namespace': 'off',
|
||||
'no-inner-declarations': 'off',
|
||||
'@typescript-eslint/no-this-alias': 'off',
|
||||
'@typescript-eslint/no-empty-function': 'off',
|
||||
'vue/multi-word-component-names': 'off'
|
||||
}
|
||||
}
|
||||
70
.git-cz.json
Normal file
70
.git-cz.json
Normal file
@ -0,0 +1,70 @@
|
||||
{
|
||||
"disableEmoji": false,
|
||||
"list": ["test", "feat", "fix", "chore", "docs", "refactor", "style", "ci", "perf", "release", "revert", "build"],
|
||||
"maxMessageLength": 64,
|
||||
"minMessageLength": 3,
|
||||
"questions": ["type", "scope", "subject", "body", "breaking", "issues", "lerna"],
|
||||
"scopes": [],
|
||||
"types": {
|
||||
"chore": {
|
||||
"description": "Chore | 构建/工程依赖/工具",
|
||||
"emoji": "🚀",
|
||||
"value": "chore"
|
||||
},
|
||||
"ci": {
|
||||
"description": "Continuous Integration | CI 配置",
|
||||
"emoji": "👷",
|
||||
"value": "ci"
|
||||
},
|
||||
"docs": {
|
||||
"description": "Documentation | 文档",
|
||||
"emoji": "✏️ ",
|
||||
"value": "docs"
|
||||
},
|
||||
"feat": {
|
||||
"description": "Features | 新功能",
|
||||
"emoji": "✨",
|
||||
"value": "feat"
|
||||
},
|
||||
"fix": {
|
||||
"description": "Bug Fixes | Bug 修复",
|
||||
"emoji": "🐛",
|
||||
"value": "fix"
|
||||
},
|
||||
"perf": {
|
||||
"description": "Performance Improvements | 性能优化",
|
||||
"emoji": "⚡",
|
||||
"value": "perf"
|
||||
},
|
||||
"refactor": {
|
||||
"description": "Code Refactoring | 代码重构",
|
||||
"emoji": "♻️ ",
|
||||
"value": "refactor"
|
||||
},
|
||||
"release": {
|
||||
"description": "Create a release commit | 发版提交",
|
||||
"emoji": "🏹",
|
||||
"value": "release"
|
||||
},
|
||||
"style": {
|
||||
"description": "Styles | 风格",
|
||||
"emoji": "💄",
|
||||
"value": "style"
|
||||
},
|
||||
"revert": {
|
||||
"description": "Revert | 回退",
|
||||
"emoji": "⏪",
|
||||
"value": "revert"
|
||||
},
|
||||
"build": {
|
||||
"description": "Build System | 打包构建",
|
||||
"emoji": "📦",
|
||||
"value": "build"
|
||||
},
|
||||
"test": {
|
||||
"description": "Tests | 测试",
|
||||
"emoji": "✅",
|
||||
"value": "test"
|
||||
}
|
||||
}
|
||||
}
|
||||
42
.gitignore
vendored
42
.gitignore
vendored
@ -1,18 +1,30 @@
|
||||
# Build and Release Folders
|
||||
bin-debug/
|
||||
bin-release/
|
||||
[Oo]bj/
|
||||
[Bb]in/
|
||||
.DS_Store
|
||||
node_modules/
|
||||
unpackage/
|
||||
dist/
|
||||
lib/
|
||||
website/
|
||||
/docs
|
||||
.temp
|
||||
.cache
|
||||
# src/uni_modules/fant-mini-plus/components/hd-*/API.md
|
||||
docs/components/hd-*
|
||||
docs/.vuepress/public/*.zip
|
||||
|
||||
# Other files and folders
|
||||
.settings/
|
||||
# local env files
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Executables
|
||||
*.swf
|
||||
*.air
|
||||
*.ipa
|
||||
*.apk
|
||||
# Log files
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Project files, i.e. `.project`, `.actionScriptProperties` and `.flexProperties`
|
||||
# should NOT be excluded as they contain compiler settings and other important
|
||||
# information for Eclipse / Flash Builder.
|
||||
# Editor directories and files
|
||||
.project
|
||||
.idea
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw*
|
||||
|
||||
4
.husky/commit-msg
Normal file
4
.husky/commit-msg
Normal file
@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
npx commitlint --edit $1
|
||||
4
.husky/pre-commit
Normal file
4
.husky/pre-commit
Normal file
@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
npx lint-staged --allow-empty $1
|
||||
11
.prettierrc
Normal file
11
.prettierrc
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"printWidth": 150,
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"bracketSpacing": true,
|
||||
"requirePragma": false,
|
||||
"proseWrap": "preserve",
|
||||
"arrowParens": "always",
|
||||
"htmlWhitespaceSensitivity": "ignore"
|
||||
}
|
||||
39
.vscode/settings.json
vendored
Normal file
39
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
{
|
||||
"workbench.settings.useSplitJSON": true,
|
||||
// vscode默认启用了根据文件类型自动设置tabsize的选项
|
||||
"editor.detectIndentation": false,
|
||||
// 重新设定tabsize
|
||||
"editor.tabSize": 2,
|
||||
// #每次保存的时候自动格式化
|
||||
// "editor.formatOnSave": true,
|
||||
// #每次保存的时候将代码按eslint格式进行修复
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": true
|
||||
},
|
||||
// 添加 vue 支持
|
||||
"eslint.validate": [
|
||||
"javascript",
|
||||
"javascriptreact",
|
||||
"typescript",
|
||||
"vue"
|
||||
],
|
||||
// #去掉代码结尾的分号
|
||||
"prettier.semi": true,
|
||||
// #使用单引号替代双引号
|
||||
"prettier.singleQuote": true,
|
||||
// #让函数(名)和后面的括号之间加个空格
|
||||
"javascript.format.insertSpaceBeforeFunctionParenthesis": true,
|
||||
// #这个按用户自身习惯选择
|
||||
"vetur.format.defaultFormatter.html": "js-beautify-html",
|
||||
// #让vue中的js按编辑器自带的ts格式进行格式化
|
||||
"vetur.format.defaultFormatter.js": "vscode-typescript",
|
||||
"vetur.format.options.tabSize": 2,
|
||||
"vetur.format.defaultFormatterOptions": {
|
||||
"js-beautify-html": {
|
||||
"wrap_line_length": 150,
|
||||
"wrap_attributes": true,
|
||||
"end_with_newline": true
|
||||
// #vue组件中html代码格式化样式
|
||||
}
|
||||
}
|
||||
}
|
||||
112
CHANGELOG.md
Normal file
112
CHANGELOG.md
Normal file
@ -0,0 +1,112 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||
|
||||
### [0.0.12](https://gitlab.hd123.com/vue/fant-mini-plus/compare/v0.0.11...v0.0.12) (2023-05-16)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* ✨ Transition组件在APP、微信、H5、支付宝、QQ平台使用wxs优化动画表现 ([14806e0](https://gitlab.hd123.com/vue/fant-mini-plus/commit/14806e0d77ef5e0bf0e93d723861ef306c8c8b3e))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 🐛 修复Popup组件从中心弹出时宽度异常的问题 ([4fd41d4](https://gitlab.hd123.com/vue/fant-mini-plus/commit/4fd41d4b42c37cce1c939c57e6001d5b3afeafaf))
|
||||
|
||||
### [0.0.11](https://gitlab.hd123.com/vue/fant-mini-plus/compare/v0.0.10...v0.0.11) (2023-05-15)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* ✨ Button组件自定义节点设置为虚拟节点去掉微信小程序自定义组件多出的最外层标签 ([a877049](https://gitlab.hd123.com/vue/fant-mini-plus/commit/a87704996224269a9077ee380be72268c936cf82))
|
||||
|
||||
### [0.0.10](https://gitlab.hd123.com/vue/fant-mini-plus/compare/v0.0.9...v0.0.10) (2023-05-15)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* ✨ 新增 Image 和 WaterMark 组件 ([90a097e](https://gitlab.hd123.com/vue/fant-mini-plus/commit/90a097e83a7f612f9b76425e07de5f602ff39d3c))
|
||||
* ✨ 新增WaterMark水印组件 ([37a3979](https://gitlab.hd123.com/vue/fant-mini-plus/commit/37a39798f555d55394d33830256398452d5e7d35))
|
||||
|
||||
### [0.0.9](https://gitlab.hd123.com/vue/fant-mini-plus/compare/v0.0.8...v0.0.9) (2023-04-25)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* ✨ Table组件优化支持data-source响应式更新 ([4f4b451](https://gitlab.hd123.com/vue/fant-mini-plus/commit/4f4b4510f395f02f554e45958c40a10cde07ff93))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 🐛 修复Calendar组件在某些版本uni-app的H5端第一次打开无数据渲染的问题 ([2d2dd33](https://gitlab.hd123.com/vue/fant-mini-plus/commit/2d2dd337c2e29b774c8dedfa01917758b1283917))
|
||||
|
||||
### [0.0.8](https://gitlab.hd123.com/vue/fant-mini-plus/compare/v0.0.7...v0.0.8) (2023-04-23)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* ✨ 新增WaterMark水印组件 ([3d9ba3f](https://gitlab.hd123.com/vue/fant-mini-plus/commit/3d9ba3f658c2ce8de8eaec2a5c8bf64963e4f871))
|
||||
* ✨ Table表格组件支持自定义列模板并增加row-height行高属性 ([23866e2](https://gitlab.hd123.com/vue/fant-mini-plus/commit/23866e2f6ef8ef9a080824f3ebe720dd9755dca6))
|
||||
|
||||
### [0.0.7](https://gitlab.hd123.com/vue/fant-mini-plus/compare/v0.0.6...v0.0.7) (2023-04-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 🐛 修复README中缺少演示小程序二维码的问题 ([298a21d](https://gitlab.hd123.com/vue/fant-mini-plus/commit/298a21d647bc82d705d4458aa4694ecff35f3f56))
|
||||
|
||||
### [0.0.6](https://gitlab.hd123.com/vue/fant-mini-plus/compare/v0.0.5...v0.0.6) (2023-04-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 🐛 修复DatePicker组件动画效果生硬的问题 ([1b821e0](https://gitlab.hd123.com/vue/fant-mini-plus/commit/1b821e04e56025e9cee82859e8278dfabfc90d23))
|
||||
|
||||
### [0.0.5](https://gitlab.hd123.com/vue/fant-mini-plus/compare/v0.0.4...v0.0.5) (2023-04-05)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 🐛 修复支付宝小程序Calendar组件不显示二级标题月份的问题 ([b7c541d](https://gitlab.hd123.com/vue/fant-mini-plus/commit/b7c541d4b6fbbe10c746f7a56dbc36c5eb1e0831))
|
||||
* 🐛 修复Area组件有默认值时打开未滚动到默认选项的问题 ([b3df205](https://gitlab.hd123.com/vue/fant-mini-plus/commit/b3df20514b7ef22ef7cb46907229dc9d981a374f))
|
||||
* 🐛 修复Transition组件动画抖动的问题 ([e5fa79b](https://gitlab.hd123.com/vue/fant-mini-plus/commit/e5fa79b8ee599cc14392abb89cbf988e07104e92))
|
||||
|
||||
### [0.0.4](https://gitlab.hd123.com/vue/fant-mini-plus/compare/v0.0.3...v0.0.4) (2023-04-04)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* ✨ Popup和Transition组件新增destory属性用于控制是否销毁插槽中的内容 ([bb26d31](https://gitlab.hd123.com/vue/fant-mini-plus/commit/bb26d318af7af1cffe6d3d9eca9018c1c1ce8f40))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 🐛 修复Modal组件弹出异常的问题 ([38b88b6](https://gitlab.hd123.com/vue/fant-mini-plus/commit/38b88b6f5fc8e596411ab43df59a1f41db430528))
|
||||
* 🐛 修复Popup连续多次弹出有概率无法再弹出的问题 ([23e51d2](https://gitlab.hd123.com/vue/fant-mini-plus/commit/23e51d2e04bf6931bd8c3cd5b4dcf7dce15f3850))
|
||||
|
||||
### [0.0.3](https://gitlab.hd123.com/vue/fant-mini-plus/compare/v0.0.2...v0.0.3) (2023-04-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 🐛 修复DatePicker组件在支付宝平台显示异常的问题 ([604277c](https://gitlab.hd123.com/vue/fant-mini-plus/commit/604277c16a284b05829353a93a6a213f42269dc4))
|
||||
|
||||
### [0.0.2](https://gitlab.hd123.com/vue/fant-mini-plus/compare/v0.0.1...v0.0.2) (2023-04-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 🐛 改善transition动画延迟的问题 ([38b4d74](https://gitlab.hd123.com/vue/fant-mini-plus/commit/38b4d74bf27166d81f799661b058762caf6c145c))
|
||||
|
||||
### 0.0.1 (2023-03-29)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* ✨ v0.0.1版本完成,移植所有fant-mini组件到vue3 ([e0a7e75](https://gitlab.hd123.com/vue/fant-mini-plus/commit/e0a7e75ffbcc89928be1868d1130cf0a74727882))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 🐛 修复动画组件在微信小程序上卡顿的问题 ([4c66ced](https://gitlab.hd123.com/vue/fant-mini-plus/commit/4c66cedcb67515a1c1301bba65a9c7e653885df7))
|
||||
22
build/changelog.js
Normal file
22
build/changelog.js
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2022-02-24 15:37:04
|
||||
* @LastEditTime: 2023-03-21 20:57:36
|
||||
* @LastEditors: weisheng
|
||||
* @Description: 讲生成的changelog移动到文档和组件中
|
||||
* @FilePath: \fant-mini-plus-plus\build\changelog.js
|
||||
* 记得注释
|
||||
*/
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const fromPath = path.resolve(__dirname, '../CHANGELOG.md')
|
||||
const toPath = path.resolve(__dirname, '../src/uni_modules/fant-mini-plus')
|
||||
const docPath = path.resolve(__dirname, '../fant-doc/docs/components')
|
||||
|
||||
try {
|
||||
const file = fs.readFileSync(fromPath, 'utf-8')
|
||||
fs.writeFileSync(`${toPath}/changelog.md`, file)
|
||||
fs.writeFileSync(`${docPath}/changelog.md`, file)
|
||||
} catch (error) {
|
||||
console.log('CHANGELOG 获取失败')
|
||||
}
|
||||
27
build/ci_keys/private.wxa3fab3dcde4667f0.key
Normal file
27
build/ci_keys/private.wxa3fab3dcde4667f0.key
Normal file
@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEogIBAAKCAQEAqtvdTeEPKGwStj1fVg6UWlMN5uxMv7TQDVs/6vlHSf307ObC
|
||||
6acjvH+Id2ci5OepN6NgKoGh3P3xwLAXQsOQsCvfnlwiRFaTZ/kD6BWTPSxLHmpf
|
||||
oS4LYEqUxTrRKnypOarGvqOIvkLNyzpw5En8Vnf1/K67eoFY0UFF87fn4763zlUW
|
||||
wOuzvVYu56i7FLdU2v0m3UdguJ6pZ3VGpTVfOpkA/nnTjRvPVjFK0BgQBLnHzXUx
|
||||
1kcA3ZRuCOEFGnyxgaIGwxmD2k5rcwFmvgXkOTaZeERdlRj3As8N7scGsSaIm2RJ
|
||||
y43lQg2l4gEY2F9HZniGC3H5Qiqa8YttVFGX2wIDAQABAoIBAFUk2eTceeRH7w84
|
||||
CFFnVJCqgOwJ57lFDsUJKxIahWcfEjYYTRuI+isOVuBB2ka+FzqtxNeJ4DKzrgy6
|
||||
8+yGbo0MYBSXj1AE4NJYapT2Y3iBoTGYCu3Ud0DWCcs7o06L7vzY2M/ZyOQfgFR9
|
||||
XBK3t/MTNtdj7/N9j9g/se9hP0LjUEqBBzsE27CGNIu2YzbXxQ5Se72WkM665v5K
|
||||
Ivkb7Pgh+duN0Bt4hR2BsMUWK/SGOoGoXpM1TgDwzNyRQEgjPOpX/Ipt0AO3jVhL
|
||||
xS3mFQD6NQckm6l8QTma8su7lFod+K3nvC24QTwbtAfxWdrioLfDyxcGZzUk82Gb
|
||||
XYXnkIECgYEA1tGQFk1H4bU+ARDrwolPQJI/WPdLs9sscheEeiu2nM6kdbAmwnzm
|
||||
sY2NtOynksrLMXeEyGCnXtKm7qEH+tUBVB/lsgEXw9Te1gHGZSBk/aPNcA5jXTOA
|
||||
8684zZBJ6JZVsGmAVbAjti6yUsMhSZk8MjGJnhNKlPqWoURl1q3TmcECgYEAy5zu
|
||||
wIkd7pmoWHczv9aoMRUUu8xtTNUTq1pfbCb6sc2v4Nocw3+Wtbf3xwe7gwd7QhBn
|
||||
clwMF/reNslFxyuQQRB1UIOP3igJ6r4sTCPAl8Qsj8xdmN9DMa1WVSLPjCEdj+6Z
|
||||
0tAnOiYPYCqxG+Hsvbmm5vGk3Kj+nW97lZ8TgJsCgYB95rC2AXEhneHLKimjCGrE
|
||||
g3JRKA7cSJZR/+qK19fdK1dECouM7Tsf0MC+yvyjketpAI14Cv3NG1TvAr30iqaO
|
||||
sWsj2nQdOEOp1bx7RHMsHLao+CXQWAE50PZPtEM85+8sx4iJsAQeIFwvGWIHCqI3
|
||||
IMVxOgk6K2vg9H9jRNmBgQKBgGTpzYbNLnGP5FicE6DToZ5Z5WHCSrWWsV3ut3Zh
|
||||
x0QSPkYBs9nMxYQgvoP9OBkTvyoZ+Ts7lZ7Y7gNXM+cnlyI4JvyVh9tCGtAmGsxN
|
||||
t+lACBno3saieKoJT814KEc6Lm2kgsZx9c8jB+HQpuC701qgxbCWOPBILZEXrLeW
|
||||
FNNbAoGAfxFWLGPXl6oB8qAXX/41v8RhhsziBAuOfoRy7CzkGm1L2BWjTXF/gR/0
|
||||
xVrNTm/sRIX82zLt/AwWZZja9TutEa3PIGo+E6VaTDIMMyT/vPFol1SWabcRaQgk
|
||||
KivcysDoP2DLtwYjVznD3WLmxNVN0boNjnZWto3hYzxAqlkVcg4=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
46
build/compiler.js
Normal file
46
build/compiler.js
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2023-03-21 20:58:19
|
||||
* @LastEditTime: 2023-03-21 20:58:31
|
||||
* @LastEditors: weisheng
|
||||
* @Description:
|
||||
* @FilePath: \fant-mini-plus-plus\build\compiler.js
|
||||
* 记得注释
|
||||
*/
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
const src = path.resolve(__dirname, '../src/uni_modules/fant-mini-plus')
|
||||
const libDir = path.resolve(__dirname, '../lib')
|
||||
|
||||
const copyFile = function (srcPath, tarPath, filter = []) {
|
||||
fs.mkdir(tarPath, (err) => {})
|
||||
fs.readdir(srcPath, function (err, files) {
|
||||
if (err === null) {
|
||||
files.forEach(function (filename) {
|
||||
const filedir = path.join(srcPath, filename)
|
||||
const filterFlag = filter.some((item) => {
|
||||
return path.extname(filename).toLowerCase() === item && filename !== 'changelog.md'
|
||||
})
|
||||
if (!filterFlag) {
|
||||
fs.stat(filedir, function (errs, stats) {
|
||||
const isFile = stats.isFile()
|
||||
if (isFile) {
|
||||
// 复制文件
|
||||
const destPath = path.join(tarPath, filename)
|
||||
fs.copyFile(filedir, destPath, (err) => {})
|
||||
} else {
|
||||
// 创建文件夹
|
||||
const tarFiledir = path.join(tarPath, filename)
|
||||
copyFile(filedir, tarFiledir, filter) // 递归
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
if (err) console.error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
copyFile(src, libDir, ['.md'])
|
||||
72
build/deploy.js
Normal file
72
build/deploy.js
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2022-01-28 14:23:02
|
||||
* @LastEditTime: 2023-03-21 20:59:16
|
||||
* @LastEditors: weisheng
|
||||
* @Description:
|
||||
* @FilePath: \fant-mini-plus\build\deploy.js
|
||||
* 记得注释
|
||||
*/
|
||||
|
||||
const OSS = require('ali-oss')
|
||||
const fs = require('fs')
|
||||
|
||||
const client = new OSS({
|
||||
region: 'oss-cn-hongkong',
|
||||
accessKeyId: 'LTAI5tJ6okg3xgdy4VfCjmzs',
|
||||
accessKeySecret: '8Hk0Af1CQufErdjrnTI2o5BQmbhY41',
|
||||
bucket: 'historysoa'
|
||||
})
|
||||
|
||||
async function putOss(ossPath, filePath) {
|
||||
try {
|
||||
const result = await client.multipartUpload(ossPath, filePath)
|
||||
console.log(`上传远程oss文件:${filePath}成功!`)
|
||||
} catch (e) {
|
||||
console.log(`上传异常:${e}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传前删除所有的文件
|
||||
*/
|
||||
async function deleteAll(object) {
|
||||
const result = await client.list({
|
||||
prefix: `${object}`
|
||||
})
|
||||
result.objects.forEach((item) => {
|
||||
client.delete(item.name)
|
||||
console.log(`删除远程oss文件:${item.name}成功!`)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定文件夹下的文件
|
||||
* @param {string} local 文件夹路径
|
||||
*/
|
||||
async function addFile(local, objectName, srcName) {
|
||||
const localFiles = fs.readdirSync(local)
|
||||
localFiles.forEach(async (localFile) => {
|
||||
// 拼接文件夹子项的路径
|
||||
const filePath = `${local}/${localFile}`
|
||||
// 获取子项文件信息
|
||||
const stat = fs.statSync(filePath)
|
||||
if (stat.isFile()) {
|
||||
console.log(srcName, 'srcName')
|
||||
const ossPath = filePath.split(`${srcName ? srcName : local}`).join(`${objectName}`)
|
||||
// 上传到oss
|
||||
await putOss(ossPath, filePath)
|
||||
} else {
|
||||
addFile(filePath, objectName, srcName ? srcName : local)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function upload() {
|
||||
await deleteAll('fant-mini-plus')
|
||||
await addFile('fant-doc/dist', 'fant-mini-plus')
|
||||
await deleteAll('fant-demo')
|
||||
await addFile('dist/build/h5', 'fant-demo')
|
||||
}
|
||||
|
||||
upload()
|
||||
54
build/docs.js
Normal file
54
build/docs.js
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2022-02-11 15:19:37
|
||||
* @LastEditTime: 2023-03-28 16:40:46
|
||||
* @LastEditors: weisheng
|
||||
* @Description:
|
||||
* @FilePath: \fant-mini-plus\build\docs.js
|
||||
* 记得注释
|
||||
*/
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
/**
|
||||
* 获取指定文件夹下的文件
|
||||
* @param {string} local 文件夹路径
|
||||
*/
|
||||
function getFile(local) {
|
||||
const localFiles = fs.readdirSync(local).filter((file) => {
|
||||
return path.extname(file).toLowerCase() === '' || path.extname(file).toLowerCase() === '.md'
|
||||
})
|
||||
const docfile = {
|
||||
introduction: '', // 简介
|
||||
instructions: '', // 使用说明
|
||||
api: ''
|
||||
} // 文档文件内容
|
||||
localFiles.forEach((localFile) => {
|
||||
// 拼接文件夹子项的路径
|
||||
const filePath = `${local}/${localFile}`
|
||||
// 获取子项文件信息
|
||||
const stat = fs.statSync(filePath)
|
||||
if (stat.isFile()) {
|
||||
if (localFile === 'API.md') {
|
||||
// 读取markdown
|
||||
const file = fs.readFileSync(filePath, 'utf-8')
|
||||
docfile.api = file.replace(new RegExp(file.split('\n\n', 2)[0], 'g'), '').replace(new RegExp(file.split('\n\n', 2)[1], 'g'), '')
|
||||
// fs.writeFileSync(`docs/components/${filePath.split('/').reverse()[1]}.md`, file)
|
||||
} else if (localFile === 'README.md') {
|
||||
// 读取markdown为数组
|
||||
docfile.introduction = fs.readFileSync(filePath, 'utf-8')
|
||||
} else if (localFile === 'INDEX.md') {
|
||||
// 读取markdown为数组
|
||||
docfile.instructions = fs.readFileSync(filePath, 'utf-8')
|
||||
}
|
||||
} else {
|
||||
getFile(filePath)
|
||||
}
|
||||
})
|
||||
if (docfile.api || docfile.instructions || docfile.introduction) {
|
||||
fs.writeFileSync(`fant-doc/docs/components/${local.split('/').reverse()[0]}.md`, docfile.introduction + docfile.instructions + docfile.api)
|
||||
}
|
||||
}
|
||||
|
||||
// 合并文档
|
||||
getFile('src/uni_modules/fant-mini-plus/components')
|
||||
283
build/generate.js
Normal file
283
build/generate.js
Normal file
@ -0,0 +1,283 @@
|
||||
/*
|
||||
* @Author: 庞昭昭
|
||||
* @Date: 2022-02-21 10:23:46
|
||||
* @LastEditTime: 2023-03-21 20:59:58
|
||||
* @LastEditors: weisheng
|
||||
* @Description: 创建文件夹并初始化
|
||||
* @FilePath: \fant-mini-plus\build\generate.js
|
||||
* 记得注释
|
||||
*/
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const inquirer = require('inquirer')
|
||||
const { execSync } = require('child_process')
|
||||
|
||||
inquirer
|
||||
.prompt([
|
||||
{
|
||||
type: 'list',
|
||||
name: 'operation',
|
||||
message: '请选择操作类型(默认值:✨ create)',
|
||||
choices: ['✨ create 创建', '🐛 modify 编辑', '🚀 remove 移除'],
|
||||
default: '✨ create 创建'
|
||||
},
|
||||
{
|
||||
type: 'list',
|
||||
name: 'type',
|
||||
message: '请选择组件类型(默认值:✨ basic 基础组件)',
|
||||
choices: ['✨ basic 基础组件', '🐛 form 表单组件', '🚀 action 反馈组件', '🔬 display 展示组件', '🧭 navigation 导航组件'],
|
||||
default: '✨ basic 基础组件'
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'oldname',
|
||||
message: '请输入原组件名',
|
||||
default: '',
|
||||
when: function (answers) {
|
||||
// 当操作不是创建
|
||||
return answers['operation'] !== '✨ create 创建'
|
||||
},
|
||||
validate: function (val) {
|
||||
if (!val || !val.trim()) {
|
||||
return '请输入原组件名'
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'name',
|
||||
message: '请输入组件名',
|
||||
default: '',
|
||||
validate: function (val) {
|
||||
if (!val || !val.trim()) {
|
||||
return '请输入组件名'
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'list',
|
||||
name: 'confirm',
|
||||
message: '确认操作吗?',
|
||||
choices: ['Y', 'N'],
|
||||
default: 'Y'
|
||||
}
|
||||
])
|
||||
.then((answers) => {
|
||||
if (!answers['confirm'] || answers['confirm'].toLowerCase() != 'y') {
|
||||
console.log('🚨 操作取消')
|
||||
return
|
||||
}
|
||||
|
||||
let name = ''
|
||||
if (answers['name']) {
|
||||
name = answers['name']
|
||||
}
|
||||
|
||||
let oldname = ''
|
||||
if (answers['oldname']) {
|
||||
oldname = answers['oldname']
|
||||
}
|
||||
|
||||
let type = ''
|
||||
if (answers['type']) {
|
||||
type = answers['type'].split(' ')[1]
|
||||
}
|
||||
|
||||
// 文件夹父目录
|
||||
const parentPath = 'src/uni_modules/fant-mini-plus/components'
|
||||
// 文件夹目录
|
||||
const folderPath = `${parentPath}/${name}`
|
||||
|
||||
// 操作
|
||||
switch (answers['operation']) {
|
||||
case '✨ create 创建':
|
||||
create(folderPath, type, name) // 新建
|
||||
break
|
||||
case '🐛 modify 编辑':
|
||||
modify(folderPath, type, name, oldname) // 编辑名称
|
||||
break
|
||||
case '🚀 remove 移除':
|
||||
remove(folderPath, type, name, oldname) // 删除
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.isTtyError) {
|
||||
// Prompt couldn't be rendered in the current environment
|
||||
} else {
|
||||
// Something else went wrong
|
||||
}
|
||||
})
|
||||
|
||||
// 创建
|
||||
function create(url, type, name) {
|
||||
// 检查创建路径是否存在
|
||||
if (!fs.existsSync(url)) {
|
||||
// 不存在,创建文件夹
|
||||
fs.mkdirSync(url)
|
||||
// vue模板代码
|
||||
const vueTemplate = `<template>
|
||||
<view class="${name}"></view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: '${name}',
|
||||
props: {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.${name} {}
|
||||
</style>`
|
||||
// 创建vue组件
|
||||
fs.writeFile(`${url}/${name}.vue`, vueTemplate, (err) => {
|
||||
if (err) throw err
|
||||
})
|
||||
// 创建代码演示文档
|
||||
fs.writeFile(`${url}/INDEX.md`, '## 代码演示', (err) => {
|
||||
if (err) throw err
|
||||
})
|
||||
// 创建组件说明文档
|
||||
fs.writeFile(`${url}/README.md`, '', (err) => {
|
||||
if (err) throw err
|
||||
})
|
||||
// 更新doc文档
|
||||
updateDoc('create', type, name)
|
||||
} else {
|
||||
console.error('warning:文件夹已存在', url)
|
||||
}
|
||||
}
|
||||
|
||||
// 编辑
|
||||
function modify(url, type, name, oldname) {
|
||||
const oldName = oldname
|
||||
const newName = name
|
||||
// 判断给定的路径是否存在
|
||||
if (fs.existsSync(url)) {
|
||||
if (!newName) {
|
||||
console.log('error:请传入新名称')
|
||||
return
|
||||
}
|
||||
/**
|
||||
* 返回文件和子目录的数组
|
||||
*/
|
||||
files = fs.readdirSync(url)
|
||||
files.forEach((file, index) => {
|
||||
// 规范化生成文件路径。
|
||||
const curPath = path.join(url, file)
|
||||
/**
|
||||
* fs.statSync同步读取文件夹文件,如果是文件夹,在重复触发函数
|
||||
*/
|
||||
if (fs.statSync(curPath).isDirectory()) {
|
||||
// recurse
|
||||
modify(curPath.replace(/\\/g, '/'))
|
||||
} else {
|
||||
// 获取文件内容
|
||||
const cur = fs.readFileSync(curPath, 'utf-8')
|
||||
// 替换文件名称
|
||||
fs.writeFileSync(curPath, cur.replace(new RegExp(oldName, 'g'), newName), (err) => {
|
||||
if (err) throw err
|
||||
})
|
||||
if (file.includes(oldName)) {
|
||||
// 修改文件名称
|
||||
fs.renameSync(`${url}/${file}`, `${url}/${file.replace(new RegExp(oldName, 'g'), newName)}`)
|
||||
}
|
||||
}
|
||||
})
|
||||
/**
|
||||
* 修改文件夹名称
|
||||
*/
|
||||
const newUrlArr = url.split('/')
|
||||
newUrlArr.splice(newUrlArr.length - 1, 1, newName)
|
||||
const newUrl = newUrlArr.join('/')
|
||||
fs.renameSync(url, newUrl, (err) => {
|
||||
if (err) throw err
|
||||
})
|
||||
// 更新doc文档配置
|
||||
updateDoc(type, name)
|
||||
} else {
|
||||
console.error('error:给定的路径不存在,请给出正确的路径', folderPath)
|
||||
}
|
||||
}
|
||||
|
||||
// 删除
|
||||
function remove(url, type, name, oldname) {
|
||||
// 判断给定的路径是否存在
|
||||
if (fs.existsSync(url)) {
|
||||
/**
|
||||
* 返回文件和子目录的数组
|
||||
*/
|
||||
files = fs.readdirSync(url)
|
||||
files.forEach((file, index) => {
|
||||
// 规范化生成文件路径。
|
||||
const curPath = path.join(url, file)
|
||||
/**
|
||||
* fs.statSync同步读取文件夹文件,如果是文件夹,在重复触发函数
|
||||
*/
|
||||
if (fs.statSync(curPath).isDirectory()) {
|
||||
// recurse
|
||||
remove(curPath)
|
||||
} else {
|
||||
// 函数删除文件
|
||||
fs.unlinkSync(curPath)
|
||||
}
|
||||
})
|
||||
/**
|
||||
* 清除文件夹
|
||||
*/
|
||||
fs.rmdirSync(url)
|
||||
// 更新doc文档配置
|
||||
updateDoc(type, name, oldname)
|
||||
} else {
|
||||
console.error('error:给定的路径不存在,请给出正确的路径', folderPath)
|
||||
}
|
||||
}
|
||||
|
||||
// 更新doc文档新config
|
||||
function updateDoc(operation, type, name, oldname) {
|
||||
// 更新config配置
|
||||
// 获取组件list集合
|
||||
const cmpList = require(`../fant-doc/docs/.vuepress/cmp/${type}.js`)
|
||||
|
||||
// 操作
|
||||
if (operation == 'create') {
|
||||
// 将新建文档插入到数组末尾
|
||||
if (!cmpList.children.includes(`/components/${name}`)) {
|
||||
// 检查是否已存在文档路径配置,避免重复加入
|
||||
cmpList.children.push(`/components/${name}`)
|
||||
// 重写cmpList文件
|
||||
fs.writeFileSync(`fant-doc/docs/.vuepress/cmp/${type}.js`, `module.exports = ${JSON.stringify(cmpList)}`, (err) => {
|
||||
if (err) throw err
|
||||
})
|
||||
}
|
||||
} else if (operation == 'modify') {
|
||||
const oldName = oldname
|
||||
const newName = name
|
||||
// 替换文档路径名称
|
||||
cmpList.children.splice(cmpList.children.indexOf(`/components/${oldName}`), 1, `/components/${newName}`)
|
||||
// 重写cmpList文件
|
||||
fs.writeFileSync(`fant-doc/docs/.vuepress/cmp/${type}.js`, `module.exports = ${JSON.stringify(cmpList)}`, (err) => {
|
||||
if (err) throw err
|
||||
})
|
||||
} else if (operation == 'remove') {
|
||||
// 获取删除文档路径配置下标
|
||||
const index = cmpList.children.indexOf(`/components/${name}`)
|
||||
if (index > -1) {
|
||||
// 检查是否已存在文档路径配置,存在时删除
|
||||
cmpList.children.splice(index, 1)
|
||||
// 重写cmpList文件
|
||||
fs.writeFileSync(`fant-doc/docs/.vuepress/cmp/${type}.js`, `module.exports = ${JSON.stringify(cmpList)}`, (err) => {
|
||||
if (err) throw err
|
||||
})
|
||||
}
|
||||
} else {
|
||||
console.log('无操作,未更新文档')
|
||||
}
|
||||
}
|
||||
87
build/release.js
Normal file
87
build/release.js
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2022-11-01 17:12:57
|
||||
* @LastEditTime: 2023-03-28 16:40:56
|
||||
* @LastEditors: weisheng
|
||||
* @Description: 组件发版问答
|
||||
* @FilePath: \fant-mini-plus\build\release.js
|
||||
* 记得注释
|
||||
*/
|
||||
const inquirer = require('inquirer')
|
||||
// Node 核心模块
|
||||
const { execSync } = require('child_process')
|
||||
const { writeFileSync, readFileSync } = require('fs')
|
||||
const path = require('path')
|
||||
const src = path.resolve(__dirname, '../src/uni_modules/fant-mini-plus')
|
||||
const oldVersion = require('../package.json').version
|
||||
inquirer
|
||||
.prompt([
|
||||
{
|
||||
type: 'list',
|
||||
name: 'version',
|
||||
message: '请选择发版类型(默认值:✨ minor)',
|
||||
choices: ['🐛 patch 小版本', '✨ minor 中版本', '🚀 major 大版本'],
|
||||
default: '✨ minor 中版本'
|
||||
},
|
||||
{
|
||||
type: 'list',
|
||||
name: 'release',
|
||||
message: '确认发布?',
|
||||
choices: ['Y', 'N'],
|
||||
default: 'Y'
|
||||
}
|
||||
])
|
||||
.then((answers) => {
|
||||
if (!answers['release'] || answers['release'].toLowerCase() != 'y') {
|
||||
console.log('🚨 操作取消')
|
||||
return
|
||||
}
|
||||
// 项目版本更新
|
||||
switch (answers['version']) {
|
||||
case '🐛 patch 小版本':
|
||||
execSync('yarn release-patch')
|
||||
break
|
||||
case '✨ minor 中版本':
|
||||
execSync('yarn release-minor')
|
||||
break
|
||||
case '🚀 major 大版本':
|
||||
execSync('yarn release-major')
|
||||
break
|
||||
default:
|
||||
execSync('yarn release-minor')
|
||||
break
|
||||
}
|
||||
// 生成日志
|
||||
execSync('yarn changelog')
|
||||
// 更新版本
|
||||
const file = readFileSync(path.resolve(__dirname, '../package.json'))
|
||||
const packageJson = JSON.parse(file.toString())
|
||||
const version = packageJson.version
|
||||
console.log(`√ bumping version in package.json from ${oldVersion} to ${version}`)
|
||||
const package = require('../src/uni_modules/fant-mini-plus/package.json')
|
||||
package.version = version
|
||||
writeFileSync(path.resolve(src, 'package.json'), JSON.stringify(package))
|
||||
// 生成声明文件
|
||||
execSync('yarn build:types')
|
||||
console.log('√ build:types complete')
|
||||
// 生成制品
|
||||
execSync('yarn compiler')
|
||||
console.log('√ compiler complete')
|
||||
execSync(`node build/updateDownloadVersion.js ${oldVersion} ${version}`)
|
||||
execSync('yarn lint')
|
||||
execSync('git add -A ')
|
||||
execSync(`git commit -am "build: compile ${version}"`)
|
||||
execSync(`git tag -a v${version} -am "chore(release): ${version}"`)
|
||||
console.log('√ committing changes')
|
||||
const branch = execSync('git branch --show-current').toString().replace(/\*/g, '').replace(/ /g, '')
|
||||
console.log('🎉 版本发布成功')
|
||||
const tip = 'Run `git push --follow-tags origin ' + branch + '` ' + 'to publish'
|
||||
console.log(tip.replace(/\n/g, ''))
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.isTtyError) {
|
||||
// Prompt couldn't be rendered in the current environment
|
||||
} else {
|
||||
// Something else went wrong
|
||||
}
|
||||
})
|
||||
44
build/test.js
Normal file
44
build/test.js
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2023-06-10 23:33:04
|
||||
* @LastEditTime: 2023-06-10 23:42:45
|
||||
* @LastEditors: weisheng
|
||||
* @Description:
|
||||
* @FilePath: \wot-design-uni\build\test.js
|
||||
* 记得注释
|
||||
*/
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
// 文件夹父目录
|
||||
|
||||
const src = path.resolve(__dirname, '../src/uni_modules/wot-design-uni/components')
|
||||
|
||||
const make = (local) => {
|
||||
fs.readdir(local, function (err, files) {
|
||||
if (err === null) {
|
||||
files.forEach(function (filename) {
|
||||
const url = path.resolve(local, filename + '/' + filename + '.vue')
|
||||
// 检查创建路径是否存在
|
||||
if (!fs.existsSync(url)) {
|
||||
// vue模板代码
|
||||
const vueTemplate = `<template>
|
||||
</template>
|
||||
<script>
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
</style>`
|
||||
// 创建vue组件
|
||||
fs.writeFile(`${url}`, vueTemplate, (err) => {
|
||||
if (err) throw err
|
||||
})
|
||||
} else {
|
||||
console.error('warning:文件夹已存在', url)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
if (err) console.error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
make(src)
|
||||
27
build/updateDownloadVersion.js
Normal file
27
build/updateDownloadVersion.js
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2023-03-14 17:35:30
|
||||
* @LastEditTime: 2023-03-28 16:41:20
|
||||
* @LastEditors: weisheng
|
||||
* @Description:
|
||||
* @FilePath: \fant-mini-plus\build\updateDownloadVersion.js
|
||||
* 记得注释
|
||||
*/
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const docPath = path.resolve(__dirname, '../fant-doc/docs/components')
|
||||
// 传入参数
|
||||
const args = process.argv.splice(2)
|
||||
const oldVersion = args[0]
|
||||
const newVersion = args[1]
|
||||
console.log(oldVersion, 'oldVersion')
|
||||
console.log(newVersion, 'newVersion')
|
||||
|
||||
if (oldVersion && newVersion) {
|
||||
let installation = fs.readFileSync(`${docPath}/installation.md`, 'utf-8')
|
||||
installation = installation.replace(new RegExp(`<span >fant-mini-plus@${oldVersion}</span>`, 'g'), `<span >fant-mini-plus@${newVersion}</span>`)
|
||||
installation = installation.replace(new RegExp('<span >fant-mini-plus</span>', 'g'), `<span >fant-mini-plus@${newVersion}</span>`)
|
||||
fs.writeFileSync(`${docPath}/installation.md`, installation)
|
||||
} else {
|
||||
console.log('组件库压缩包本本更新失败...')
|
||||
}
|
||||
12
commitlint.config.js
Normal file
12
commitlint.config.js
Normal file
@ -0,0 +1,12 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2021-11-24 13:10:52
|
||||
* @LastEditTime: 2023-03-25 18:12:52
|
||||
* @LastEditors: weisheng
|
||||
* @Description:
|
||||
* @FilePath: \fant-mini-plus\commitlint.config.js
|
||||
* 记得注释
|
||||
*/
|
||||
module.exports = {
|
||||
extends: ['@commitlint/config-conventional']
|
||||
}
|
||||
30
index.html
Normal file
30
index.html
Normal file
@ -0,0 +1,30 @@
|
||||
<!--
|
||||
* @Author: weisheng
|
||||
* @Date: 2023-03-21 22:49:24
|
||||
* @LastEditTime: 2023-04-26 12:43:27
|
||||
* @LastEditors: weisheng
|
||||
* @Description:
|
||||
* @FilePath: \fant-mini-plus\index.html
|
||||
* 记得注释
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<script>
|
||||
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
|
||||
CSS.supports('top: constant(a)'))
|
||||
document.write(
|
||||
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
|
||||
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
|
||||
</script>
|
||||
<script src="https://fant-mini-plus.top/touch-emulator.js"></script>
|
||||
<title></title>
|
||||
<!--preload-links-->
|
||||
<!--app-context-->
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"><!--app-html--></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
145
package.json
Normal file
145
package.json
Normal file
@ -0,0 +1,145 @@
|
||||
{
|
||||
"name": "wot-design-uni",
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"dev:app": "uni -p app",
|
||||
"dev:app-android": "uni -p app-android",
|
||||
"dev:app-ios": "uni -p app-ios",
|
||||
"dev:custom": "uni -p",
|
||||
"dev:h5": "uni",
|
||||
"dev:h5:ssr": "uni --ssr",
|
||||
"dev:mp-alipay": "uni -p mp-alipay",
|
||||
"dev:mp-baidu": "uni -p mp-baidu",
|
||||
"dev:mp-kuaishou": "uni -p mp-kuaishou",
|
||||
"dev:mp-lark": "uni -p mp-lark",
|
||||
"dev:mp-qq": "uni -p mp-qq",
|
||||
"dev:mp-toutiao": "uni -p mp-toutiao",
|
||||
"dev:mp-weixin": "uni -p mp-weixin",
|
||||
"dev:quickapp-webview": "uni -p quickapp-webview",
|
||||
"dev:quickapp-webview-huawei": "uni -p quickapp-webview-huawei",
|
||||
"dev:quickapp-webview-union": "uni -p quickapp-webview-union",
|
||||
"build:app": "uni build -p app",
|
||||
"build:app-android": "uni build -p app-android",
|
||||
"build:app-ios": "uni build -p app-ios",
|
||||
"build:custom": "uni build -p",
|
||||
"build:h5": "uni build",
|
||||
"build:h5:ssr": "uni build --ssr",
|
||||
"build:mp-alipay": "uni build -p mp-alipay",
|
||||
"build:mp-baidu": "uni build -p mp-baidu",
|
||||
"build:mp-kuaishou": "uni build -p mp-kuaishou",
|
||||
"build:mp-lark": "uni build -p mp-lark",
|
||||
"build:mp-qq": "uni build -p mp-qq",
|
||||
"build:mp-toutiao": "uni build -p mp-toutiao",
|
||||
"build:mp-weixin": "uni build -p mp-weixin",
|
||||
"build:quickapp-webview": "uni build -p quickapp-webview",
|
||||
"build:quickapp-webview-huawei": "uni build -p quickapp-webview-huawei",
|
||||
"build:quickapp-webview-union": "uni build -p quickapp-webview-union",
|
||||
"type-check": "vue-tsc --noEmit",
|
||||
"prepare": "husky install",
|
||||
"lint": "eslint --fix --ext .js,.vue,.ts src",
|
||||
"commit": "git-cz",
|
||||
"release-major": "standard-version --release-as major",
|
||||
"release-minor": "standard-version --release-as minor",
|
||||
"release-patch": "standard-version --release-as patch",
|
||||
"clean:lib": "rimraf lib",
|
||||
"release-lib": "node build/release.js",
|
||||
"build:types": "tsc -b ./tsconfig.types.json && node ./typesCopy.js",
|
||||
"compiler": "npm run clean:lib && node build/compiler.js",
|
||||
"publish-lib": "cd lib && npm publish",
|
||||
"install:fant-doc": "cd fant-doc && yarn",
|
||||
"docs:generate": "yarn compiler && node build/docs.js",
|
||||
"docs:dev": "yarn docs:generate && cd fant-doc && yarn serve",
|
||||
"docs:build": "yarn docs:generate && cd fant-doc && yarn build",
|
||||
"deploy": "yarn docs:build && node build/deploy.js",
|
||||
"component:generate": "node build/generate.js",
|
||||
"changelog": "node build/changelog.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dcloudio/uni-app": "3.0.0-alpha-3080220230511001",
|
||||
"@dcloudio/uni-app-plus": "3.0.0-alpha-3080220230511001",
|
||||
"@dcloudio/uni-components": "3.0.0-alpha-3080220230511001",
|
||||
"@dcloudio/uni-h5": "3.0.0-alpha-3080220230511001",
|
||||
"@dcloudio/uni-mp-alipay": "3.0.0-alpha-3080220230511001",
|
||||
"@dcloudio/uni-mp-baidu": "3.0.0-alpha-3080220230511001",
|
||||
"@dcloudio/uni-mp-jd": "3.0.0-alpha-3080220230511001",
|
||||
"@dcloudio/uni-mp-kuaishou": "3.0.0-alpha-3080220230511001",
|
||||
"@dcloudio/uni-mp-lark": "3.0.0-alpha-3080220230511001",
|
||||
"@dcloudio/uni-mp-qq": "3.0.0-alpha-3080220230511001",
|
||||
"@dcloudio/uni-mp-toutiao": "3.0.0-alpha-3080220230511001",
|
||||
"@dcloudio/uni-mp-weixin": "3.0.0-alpha-3080220230511001",
|
||||
"@dcloudio/uni-quickapp-webview": "3.0.0-alpha-3080220230511001",
|
||||
"vue": "^3.2.45",
|
||||
"vue-i18n": "^9.1.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^17.4.4",
|
||||
"@commitlint/config-conventional": "^17.4.4",
|
||||
"@dcloudio/types": "^3.3.2",
|
||||
"@dcloudio/uni-automator": "3.0.0-alpha-3080220230511001",
|
||||
"@dcloudio/uni-cli-shared": "3.0.0-alpha-3080220230511001",
|
||||
"@dcloudio/uni-stacktracey": "3.0.0-alpha-3080220230511001",
|
||||
"@dcloudio/vite-plugin-uni": "3.0.0-alpha-3080220230511001",
|
||||
"@types/node": "^18.14.6",
|
||||
"@typescript-eslint/eslint-plugin": "^5.55.0",
|
||||
"@typescript-eslint/parser": "^5.55.0",
|
||||
"@vant/area-data": "^1.4.1",
|
||||
"@vue/tsconfig": "^0.1.3",
|
||||
"eslint": "^8.36.0",
|
||||
"eslint-config-prettier": "^8.7.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-vue": "^9.9.0",
|
||||
"git-cz": "^4.9.0",
|
||||
"husky": "^8.0.3",
|
||||
"inquirer": "8.0.0",
|
||||
"lint-staged": "^13.2.0",
|
||||
"mini-types": "^0.1.7",
|
||||
"miniprogram-api-typings": "^3.9.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^2.8.4",
|
||||
"query-string": "^8.1.0",
|
||||
"rimraf": "^4.4.0",
|
||||
"rollup-plugin-visualizer": "^5.9.0",
|
||||
"sass": "^1.59.3",
|
||||
"standard-version": "^9.5.0",
|
||||
"typescript": "^4.9.4",
|
||||
"uni-mini-router": "^0.0.12",
|
||||
"uni-read-pages-vite": "^0.0.6",
|
||||
"vite": "4.0.3",
|
||||
"vitest": "^0.30.1",
|
||||
"vue-eslint-parser": "^9.1.0",
|
||||
"vue-tsc": "^1.0.24"
|
||||
},
|
||||
"config": {
|
||||
"commitizen": {
|
||||
"path": "git-cz"
|
||||
}
|
||||
},
|
||||
"standard-version": {
|
||||
"skip": {
|
||||
"tag": true
|
||||
}
|
||||
},
|
||||
"browserslist": [
|
||||
"Android >= 4.4",
|
||||
"ios >= 9"
|
||||
],
|
||||
"lint-staged": {
|
||||
"*.{js,ts,vue}": "eslint --fix --ext .js,.vue,.ts src"
|
||||
},
|
||||
"uni-app": {
|
||||
"scripts": {
|
||||
"mp-dingtalk": {
|
||||
"title": "钉钉小程序",
|
||||
"env": {
|
||||
"UNI_PLATFORM": "mp-alipay"
|
||||
},
|
||||
"define": {
|
||||
"MP-DINGTALK": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
]
|
||||
}
|
||||
22
src/App.vue
Normal file
22
src/App.vue
Normal file
@ -0,0 +1,22 @@
|
||||
<!--
|
||||
* @Author: weisheng
|
||||
* @Date: 2023-03-09 19:23:03
|
||||
* @LastEditTime: 2023-06-11 13:23:52
|
||||
* @LastEditors: weisheng
|
||||
* @Description:
|
||||
* @FilePath: \wot-design-uni\src\App.vue
|
||||
* 记得注释
|
||||
-->
|
||||
<script setup lang="ts">
|
||||
import { onLaunch, onShow, onHide } from '@dcloudio/uni-app'
|
||||
onLaunch((ctx) => {
|
||||
console.log('App Launch')
|
||||
})
|
||||
onShow(() => {
|
||||
console.log('App Show')
|
||||
})
|
||||
onHide(() => {
|
||||
console.log('App Hide')
|
||||
})
|
||||
</script>
|
||||
<style lang="scss"></style>
|
||||
52
src/components/demo-block/demo-block.vue
Normal file
52
src/components/demo-block/demo-block.vue
Normal file
@ -0,0 +1,52 @@
|
||||
<template>
|
||||
<view :class="['demo-block', transparent ? '' : 'is-white', 'custom-class']">
|
||||
<view class="demo-title">{{ title }}</view>
|
||||
<view class="demo-container" :style="transparent ? '' : style">
|
||||
<slot />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch } from 'vue'
|
||||
|
||||
interface Props {
|
||||
title: string
|
||||
ver: number
|
||||
hor: number
|
||||
transparent: boolean
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
ver: 10,
|
||||
hor: 15
|
||||
})
|
||||
|
||||
const style = ref<string>('')
|
||||
|
||||
watch(
|
||||
[() => props.ver, () => props.hor],
|
||||
() => {
|
||||
setStyle()
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
)
|
||||
|
||||
function setStyle() {
|
||||
style.value = `margin: ${props.ver}px ${props.hor}px`
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.demo-block {
|
||||
margin: 15px 0;
|
||||
color: #666;
|
||||
overflow: hidden;
|
||||
}
|
||||
.is-white {
|
||||
background: #fff;
|
||||
}
|
||||
.demo-title {
|
||||
padding: 0 15px;
|
||||
margin: 10px 0;
|
||||
font-size: 13px;
|
||||
}
|
||||
</style>
|
||||
17
src/env.d.ts
vendored
Normal file
17
src/env.d.ts
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2023-03-21 21:06:55
|
||||
* @LastEditTime: 2023-03-21 21:07:02
|
||||
* @LastEditors: weisheng
|
||||
* @Description:
|
||||
* @FilePath: \fant-mini-plus\src\env.d.ts
|
||||
* 记得注释
|
||||
*/
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
declare module '*.vue' {
|
||||
import { DefineComponent } from 'vue'
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
||||
20
src/main.ts
Normal file
20
src/main.ts
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2023-03-09 19:23:03
|
||||
* @LastEditTime: 2023-06-10 23:01:56
|
||||
* @LastEditors: weisheng
|
||||
* @Description:
|
||||
* @FilePath: \wot-design-uni\src\main.ts
|
||||
* 记得注释
|
||||
*/
|
||||
import { createSSRApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
export function createApp() {
|
||||
const app = createSSRApp(App)
|
||||
app.config.warnHandler = () => null
|
||||
app.use(router)
|
||||
return {
|
||||
app
|
||||
}
|
||||
}
|
||||
72
src/manifest.json
Normal file
72
src/manifest.json
Normal file
@ -0,0 +1,72 @@
|
||||
{
|
||||
"name" : "",
|
||||
"appid" : "",
|
||||
"description" : "",
|
||||
"versionName" : "1.0.0",
|
||||
"versionCode" : "100",
|
||||
"transformPx" : false,
|
||||
/* 5+App特有相关 */
|
||||
"app-plus" : {
|
||||
"usingComponents" : true,
|
||||
"nvueStyleCompiler" : "uni-app",
|
||||
"compilerVersion" : 3,
|
||||
"splashscreen" : {
|
||||
"alwaysShowBeforeRender" : true,
|
||||
"waiting" : true,
|
||||
"autoclose" : true,
|
||||
"delay" : 0
|
||||
},
|
||||
/* 模块配置 */
|
||||
"modules" : {},
|
||||
/* 应用发布信息 */
|
||||
"distribute" : {
|
||||
/* android打包配置 */
|
||||
"android" : {
|
||||
"permissions" : [
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
|
||||
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
|
||||
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
|
||||
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
|
||||
"<uses-feature android:name=\"android.hardware.camera\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
|
||||
]
|
||||
},
|
||||
/* ios打包配置 */
|
||||
"ios" : {},
|
||||
/* SDK配置 */
|
||||
"sdkConfigs" : {}
|
||||
}
|
||||
},
|
||||
/* 快应用特有相关 */
|
||||
"quickapp" : {},
|
||||
/* 小程序特有相关 */
|
||||
"mp-weixin" : {
|
||||
"appid" : "wxa3fab3dcde4667f0",
|
||||
"setting" : {
|
||||
"urlCheck" : false
|
||||
},
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-alipay" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-baidu" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-toutiao" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"uniStatistics": {
|
||||
"enable": false
|
||||
},
|
||||
"vueVersion" : "3"
|
||||
}
|
||||
13
src/model/KV.ts
Normal file
13
src/model/KV.ts
Normal file
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2021-12-28 15:57:08
|
||||
* @LastEditTime: 2021-12-28 15:58:09
|
||||
* @LastEditors: weisheng
|
||||
* @Description:
|
||||
* @FilePath: \fant-mini\src\model\KV.ts
|
||||
* 记得注释
|
||||
*/
|
||||
export default class KV<T> {
|
||||
label: string = '' // 操作标题
|
||||
value!: T // 操作项数组
|
||||
}
|
||||
16
src/model/OperationOption.ts
Normal file
16
src/model/OperationOption.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import KV from './KV'
|
||||
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2021-12-28 15:13:43
|
||||
* @LastEditTime: 2023-03-21 22:34:12
|
||||
* @LastEditors: weisheng
|
||||
* @Description: 模板操作选项
|
||||
* @FilePath: \fant-mini-plus\src\model\OperationOption.ts
|
||||
* 记得注释
|
||||
*/
|
||||
export default class OperationOption {
|
||||
label: string = '' // 操作的标题(用于展示)
|
||||
name: string | string[] = '' // 操作真实值用于代码传参
|
||||
value: KV<any>[] = [] // 操作项数组
|
||||
}
|
||||
47
src/pages.json
Normal file
47
src/pages.json
Normal file
@ -0,0 +1,47 @@
|
||||
{
|
||||
"pages": [
|
||||
{
|
||||
"path": "pages/button/Button",
|
||||
"name": "button",
|
||||
"style": {
|
||||
"mp-alipay": {
|
||||
"allowsBounceVertical": "NO"
|
||||
},
|
||||
|
||||
"navigationBarTitleText": "Button 按钮"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/icon/Icon",
|
||||
"name": "icon",
|
||||
"style": {
|
||||
"mp-alipay": {
|
||||
"allowsBounceVertical": "NO"
|
||||
},
|
||||
|
||||
"navigationBarTitleText": "Icon 图标"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/badge/Badge",
|
||||
"name": "badge",
|
||||
"style": {
|
||||
"mp-alipay": {
|
||||
"allowsBounceVertical": "NO"
|
||||
},
|
||||
"navigationBarTitleText": "Badge 徽标"
|
||||
}
|
||||
}
|
||||
],
|
||||
"tabBar": {
|
||||
"color": "#7a7e83",
|
||||
"selectedColor": "#1C64FD",
|
||||
"backgroundColor": "#ffffff",
|
||||
"list": [ ]
|
||||
},
|
||||
"globalStyle": {
|
||||
"navigationBarTextStyle": "black",
|
||||
"navigationBarBackgroundColor": "#FFF",
|
||||
"backgroundColor": "#F8F8F8"
|
||||
}
|
||||
}
|
||||
54
src/pages/badge/Badge.vue
Normal file
54
src/pages/badge/Badge.vue
Normal file
@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<demo-block title="展示消息数量">
|
||||
<wd-badge custom-class="badge" :modelValue="12">
|
||||
<wd-button :round="false" type="info" size="small">评论</wd-button>
|
||||
</wd-badge>
|
||||
<wd-badge custom-class="badge" :modelValue="3" bg-color="pink">
|
||||
<wd-button :round="false" type="info" size="small">回复</wd-button>
|
||||
</wd-badge>
|
||||
<wd-badge custom-class="badge" :modelValue="1" type="primary">
|
||||
<wd-button :round="false" type="info" size="small">评论</wd-button>
|
||||
</wd-badge>
|
||||
<wd-badge custom-class="badge" :modelValue="2" type="warning">
|
||||
<wd-button :round="false" type="info" size="small">回复</wd-button>
|
||||
</wd-badge>
|
||||
<wd-badge custom-class="badge" :modelValue="1" type="success">
|
||||
<wd-button :round="false" type="info" size="small">评论</wd-button>
|
||||
</wd-badge>
|
||||
<wd-badge custom-class="badge" :modelValue="2" type="info">
|
||||
<wd-button :round="false" type="info" size="small">回复</wd-button>
|
||||
</wd-badge>
|
||||
</demo-block>
|
||||
|
||||
<demo-block title="可定义消息最大值">
|
||||
<wd-badge custom-class="badge" :modelValue="200" max="99">
|
||||
<wd-button :round="false" type="info" size="small">评论</wd-button>
|
||||
</wd-badge>
|
||||
<wd-badge custom-class="badge" :modelValue="200" max="10">
|
||||
<wd-button :round="false" type="info" size="small">回复</wd-button>
|
||||
</wd-badge>
|
||||
</demo-block>
|
||||
|
||||
<demo-block title="自定义内容">
|
||||
<wd-badge custom-class="badge" model:modelValue="new">
|
||||
<wd-button :round="false" type="info" size="small">评论</wd-button>
|
||||
</wd-badge>
|
||||
<wd-badge custom-class="badge" model:modelValue="hot">
|
||||
<wd-button :round="false" type="info" size="small">回复</wd-button>
|
||||
</wd-badge>
|
||||
</demo-block>
|
||||
|
||||
<demo-block title="点状类型">
|
||||
<wd-badge custom-class="badge" is-dot>数据查询</wd-badge>
|
||||
<wd-badge custom-class="badge" is-dot>
|
||||
<wd-button :round="false" type="info" size="small">回复</wd-button>
|
||||
</wd-badge>
|
||||
</demo-block>
|
||||
</template>
|
||||
<script setup lang="ts"></script>
|
||||
<style lang="scss" scoped>
|
||||
.badge {
|
||||
margin: 0 30px 20px 0;
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
1
src/pages/badge/index.js
Normal file
1
src/pages/badge/index.js
Normal file
@ -0,0 +1 @@
|
||||
Page({})
|
||||
8
src/pages/badge/index.json
Normal file
8
src/pages/badge/index.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"navigationBarTitleText": "Badge 角标",
|
||||
"usingComponents": {
|
||||
"demo-block": "../../components/demo-block/index",
|
||||
"wd-badge": "../../wot-design/badge/index",
|
||||
"wd-button": "../../wot-design/button/index"
|
||||
}
|
||||
}
|
||||
132
src/pages/badge/index.jxml
Normal file
132
src/pages/badge/index.jxml
Normal file
@ -0,0 +1,132 @@
|
||||
<demo-block title="展示消息数量">
|
||||
<wd-badge
|
||||
custom-class="badge"
|
||||
value="12"
|
||||
>
|
||||
<wd-button
|
||||
round="{{false}}"
|
||||
type="info"
|
||||
size="small"
|
||||
>评论</wd-button>
|
||||
</wd-badge>
|
||||
<wd-badge
|
||||
custom-class="badge"
|
||||
value="3"
|
||||
bg-color="pink"
|
||||
>
|
||||
<wd-button
|
||||
round="{{false}}"
|
||||
type="info"
|
||||
size="small"
|
||||
>回复</wd-button>
|
||||
</wd-badge>
|
||||
<wd-badge
|
||||
custom-class="badge"
|
||||
value="1"
|
||||
type="primary"
|
||||
>
|
||||
<wd-button
|
||||
round="{{false}}"
|
||||
type="info"
|
||||
size="small"
|
||||
>评论</wd-button>
|
||||
</wd-badge>
|
||||
<wd-badge
|
||||
custom-class="badge"
|
||||
value="2"
|
||||
type="warning"
|
||||
>
|
||||
<wd-button
|
||||
round="{{false}}"
|
||||
type="info"
|
||||
size="small"
|
||||
>回复</wd-button>
|
||||
</wd-badge>
|
||||
<wd-badge
|
||||
custom-class="badge"
|
||||
value="1"
|
||||
type="success"
|
||||
>
|
||||
<wd-button
|
||||
round="{{false}}"
|
||||
type="info"
|
||||
size="small"
|
||||
>评论</wd-button>
|
||||
</wd-badge>
|
||||
<wd-badge
|
||||
custom-class="badge"
|
||||
value="2"
|
||||
type="info"
|
||||
>
|
||||
<wd-button
|
||||
round="{{false}}"
|
||||
type="info"
|
||||
size="small"
|
||||
>回复</wd-button>
|
||||
</wd-badge>
|
||||
</demo-block>
|
||||
|
||||
<demo-block title="可定义消息最大值">
|
||||
<wd-badge
|
||||
custom-class="badge"
|
||||
value="200"
|
||||
max="99"
|
||||
>
|
||||
<wd-button
|
||||
round="{{false}}"
|
||||
type="info"
|
||||
size="small"
|
||||
>评论</wd-button>
|
||||
</wd-badge>
|
||||
<wd-badge
|
||||
custom-class="badge"
|
||||
value="200"
|
||||
max="10"
|
||||
>
|
||||
<wd-button
|
||||
round="{{false}}"
|
||||
type="info"
|
||||
size="small"
|
||||
>回复</wd-button>
|
||||
</wd-badge>
|
||||
</demo-block>
|
||||
|
||||
<demo-block title="自定义内容">
|
||||
<wd-badge
|
||||
custom-class="badge"
|
||||
value="new"
|
||||
>
|
||||
<wd-button
|
||||
round="{{false}}"
|
||||
type="info"
|
||||
size="small"
|
||||
>评论</wd-button>
|
||||
</wd-badge>
|
||||
<wd-badge
|
||||
custom-class="badge"
|
||||
value="hot"
|
||||
>
|
||||
<wd-button
|
||||
round="{{false}}"
|
||||
type="info"
|
||||
size="small"
|
||||
>回复</wd-button>
|
||||
</wd-badge>
|
||||
</demo-block>
|
||||
|
||||
<demo-block title="点状类型">
|
||||
<wd-badge
|
||||
custom-class="badge"
|
||||
is-dot
|
||||
>数据查询</wd-badge>
|
||||
<wd-badge
|
||||
custom-class="badge"
|
||||
is-dot
|
||||
>
|
||||
<wd-button
|
||||
round="{{false}}"
|
||||
type="info"
|
||||
size="small"
|
||||
>回复</wd-button>
|
||||
</wd-badge>
|
||||
</demo-block>
|
||||
4
src/pages/badge/index.jxss
Normal file
4
src/pages/badge/index.jxss
Normal file
@ -0,0 +1,4 @@
|
||||
.badge {
|
||||
margin: 0 30px 20px 0;
|
||||
display: inline-block;
|
||||
}
|
||||
118
src/pages/button/Button.vue
Normal file
118
src/pages/button/Button.vue
Normal file
@ -0,0 +1,118 @@
|
||||
<template>
|
||||
<view>
|
||||
<demo-block title="基本用法">
|
||||
<wd-button open-type="getUserInfo" @getuserinfo="handleGetuserinfo">主要按钮</wd-button>
|
||||
<wd-button type="success">成功按钮</wd-button>
|
||||
<wd-button type="info">信息按钮</wd-button>
|
||||
<wd-button type="warning">警告按钮</wd-button>
|
||||
<wd-button type="error">危险按钮</wd-button>
|
||||
</demo-block>
|
||||
<demo-block title="禁用按钮">
|
||||
<wd-button disabled>主要按钮</wd-button>
|
||||
<wd-button type="success" disabled>成功按钮</wd-button>
|
||||
<wd-button type="info" disabled>信息按钮</wd-button>
|
||||
<wd-button type="warning" disabled>警告按钮</wd-button>
|
||||
<wd-button type="error" disabled>危险按钮</wd-button>
|
||||
</demo-block>
|
||||
<demo-block title="幽灵按钮">
|
||||
<wd-button plain>主要按钮</wd-button>
|
||||
<wd-button type="success" plain>成功按钮</wd-button>
|
||||
<wd-button type="info" plain>信息按钮</wd-button>
|
||||
<wd-button type="warning" plain>警告按钮</wd-button>
|
||||
<wd-button type="error" plain>危险按钮</wd-button>
|
||||
</demo-block>
|
||||
<demo-block title="幽灵按钮禁用状态">
|
||||
<wd-button plain disabled>主要按钮</wd-button>
|
||||
<wd-button type="success" plain disabled>成功按钮</wd-button>
|
||||
<wd-button type="info" plain disabled>信息按钮</wd-button>
|
||||
<wd-button type="warning" plain disabled>警告按钮</wd-button>
|
||||
<wd-button type="error" plain disabled>危险按钮</wd-button>
|
||||
</demo-block>
|
||||
<demo-block title="按钮大小">
|
||||
<wd-button size="small">小型按钮</wd-button>
|
||||
<wd-button size="medium">普通按钮</wd-button>
|
||||
<wd-button size="large">大型按钮</wd-button>
|
||||
</demo-block>
|
||||
<demo-block title="加载中">
|
||||
<wd-button loading>加载中</wd-button>
|
||||
<wd-button type="success" loading>加载中</wd-button>
|
||||
<wd-button type="warning" loading>加载中</wd-button>
|
||||
<wd-button type="error" loading>加载中</wd-button>
|
||||
<wd-button type="info" loading>加载中</wd-button>
|
||||
</demo-block>
|
||||
<demo-block title="文字按钮">
|
||||
<wd-button type="text">按钮</wd-button>
|
||||
<wd-button type="text" disabled>按钮</wd-button>
|
||||
</demo-block>
|
||||
<demo-block title="图标按钮">
|
||||
<wd-button type="icon" icon="delete-thin"></wd-button>
|
||||
<wd-button type="icon" icon="delete-thin" disabled></wd-button>
|
||||
</demo-block>
|
||||
<demo-block title="带图标的基本按钮">
|
||||
<wd-button icon="download">下载</wd-button>
|
||||
<wd-button icon="setting">设置</wd-button>
|
||||
</demo-block>
|
||||
<demo-block title="块状按钮,宽度100%">
|
||||
<wd-button block size="large">主要按钮</wd-button>
|
||||
<wd-button type="success" block size="large">成功按钮</wd-button>
|
||||
<wd-button type="info" block size="large">信息按钮</wd-button>
|
||||
<wd-button type="warning" block size="large">警告按钮</wd-button>
|
||||
<wd-button type="error" block size="large">危险按钮</wd-button>
|
||||
</demo-block>
|
||||
<demo-block title="常用按钮:块状+圆角">
|
||||
<wd-button block size="large" disabled>主要按钮</wd-button>
|
||||
<wd-button block size="large">主要按钮</wd-button>
|
||||
<wd-button block size="large" loading>主要按钮</wd-button>
|
||||
<wd-button type="info" block size="large" disabled>信息按钮</wd-button>
|
||||
<wd-button type="info" block size="large">信息按钮</wd-button>
|
||||
</demo-block>
|
||||
<demo-block title="常用按钮:圆角或圆角+幽灵">
|
||||
<view>
|
||||
<wd-button disabled>主操作</wd-button>
|
||||
<wd-button size="small" disabled>主操作</wd-button>
|
||||
</view>
|
||||
<view>
|
||||
<wd-button>主操作</wd-button>
|
||||
<wd-button size="small">主操作</wd-button>
|
||||
</view>
|
||||
<view>
|
||||
<wd-button type="info" disabled>次操作</wd-button>
|
||||
<wd-button type="info" size="small" disabled>次操作</wd-button>
|
||||
</view>
|
||||
<view>
|
||||
<wd-button type="info">次操作</wd-button>
|
||||
<wd-button type="info" size="small">次操作</wd-button>
|
||||
</view>
|
||||
<view>
|
||||
<wd-button plain disabled>幽灵按钮</wd-button>
|
||||
<wd-button size="small" plain disabled>幽灵按钮</wd-button>
|
||||
</view>
|
||||
<view>
|
||||
<wd-button plain>幽灵按钮</wd-button>
|
||||
<wd-button size="small" plain>幽灵按钮</wd-button>
|
||||
</view>
|
||||
<view>
|
||||
<wd-button type="info" plain disabled>次操作</wd-button>
|
||||
<wd-button type="info" size="small" plain disabled>次操作</wd-button>
|
||||
</view>
|
||||
<view>
|
||||
<wd-button type="info" plain>次操作</wd-button>
|
||||
<wd-button type="info" size="small" plain>次操作</wd-button>
|
||||
</view>
|
||||
</demo-block>
|
||||
</view>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
function handleGetuserinfo(event) {
|
||||
// TODO
|
||||
console.log(event)
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
button {
|
||||
margin: 0 10px 10px 0;
|
||||
}
|
||||
.button-block {
|
||||
margin-right: 0;
|
||||
}
|
||||
</style>
|
||||
93
src/pages/icon/Icon.vue
Normal file
93
src/pages/icon/Icon.vue
Normal file
@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<view class="icon-list">
|
||||
<view v-for="(icon, index) in icons" :key="index" class="icon-item">
|
||||
<view><wd-icon :name="icon" size="22px" /></view>
|
||||
<view class="icon-item-name">{{ icon }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
|
||||
const icons = ref([
|
||||
'keyboard-collapse',
|
||||
'keyboard-delete',
|
||||
'arrow-thin-up',
|
||||
'arrow-thin-down',
|
||||
'rotate',
|
||||
'setting',
|
||||
'arrow-right',
|
||||
'arrow-down',
|
||||
'arrow-up',
|
||||
'arrow-left',
|
||||
'fill-camera',
|
||||
'star-on',
|
||||
'check-bold',
|
||||
'error-fill',
|
||||
'warn-bold',
|
||||
'close-outline',
|
||||
'close-bold',
|
||||
'check-outline',
|
||||
'wifi-error',
|
||||
'subscribe',
|
||||
'detection',
|
||||
'read',
|
||||
'fill-arrow-down',
|
||||
'dong',
|
||||
'edit-outline',
|
||||
'add-circle',
|
||||
'copy',
|
||||
'bags',
|
||||
'decrease',
|
||||
'jdm',
|
||||
'spool',
|
||||
'download',
|
||||
'phone-compute',
|
||||
'computer',
|
||||
'clock',
|
||||
'view',
|
||||
'eye-close',
|
||||
'picture',
|
||||
'evaluation',
|
||||
'goods',
|
||||
'lenovo',
|
||||
'list',
|
||||
'note',
|
||||
'video',
|
||||
'warning',
|
||||
'camera',
|
||||
'transfer',
|
||||
'keywords',
|
||||
'chat',
|
||||
'delete-thin',
|
||||
'add',
|
||||
'scan',
|
||||
'translate-bold',
|
||||
'close',
|
||||
'search',
|
||||
'delete',
|
||||
'more',
|
||||
'thin-arrow-left',
|
||||
'filter',
|
||||
'phone',
|
||||
'refresh',
|
||||
'check'
|
||||
])
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.icon-list {
|
||||
display: flex;
|
||||
margin: 15px;
|
||||
flex-wrap: wrap;
|
||||
background: #fff;
|
||||
}
|
||||
.icon-item {
|
||||
width: 25%;
|
||||
padding: 15px 0;
|
||||
text-align: center;
|
||||
}
|
||||
.icon-item-name {
|
||||
margin: 10px 0;
|
||||
color: #999;
|
||||
}
|
||||
</style>
|
||||
27
src/router/index.ts
Normal file
27
src/router/index.ts
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2021-10-13 11:15:00
|
||||
* @LastEditTime: 2023-04-06 20:10:46
|
||||
* @LastEditors: weisheng
|
||||
* @Description:
|
||||
* @FilePath: \fant-mini-plus\src\router\index.ts
|
||||
* 记得注释
|
||||
*/
|
||||
import { createRouter } from 'uni-mini-router'
|
||||
|
||||
const router = createRouter({
|
||||
routes: [...ROUTES]
|
||||
})
|
||||
router.beforeEach((to, from, next) => {
|
||||
console.log(to, 'to')
|
||||
console.log(from, 'from')
|
||||
console.log('进入路由之前调用')
|
||||
next()
|
||||
})
|
||||
router.afterEach((to, from) => {
|
||||
console.log(to, 'to')
|
||||
console.log(from, 'from')
|
||||
console.log('进入路由之后调用')
|
||||
})
|
||||
|
||||
export default router
|
||||
15
src/shime-uni.d.ts
vendored
Normal file
15
src/shime-uni.d.ts
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
/* eslint-disable @typescript-eslint/no-empty-interface */
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2023-03-09 19:23:03
|
||||
* @LastEditTime: 2023-03-21 21:30:30
|
||||
* @LastEditors: weisheng
|
||||
* @Description:
|
||||
* @FilePath: \fant-mini-plus\src\shime-uni.d.ts
|
||||
* 记得注释
|
||||
*/
|
||||
export {}
|
||||
declare module 'vue' {
|
||||
type Hooks = App.AppInstance & Page.PageInstance
|
||||
interface ComponentCustomOptions extends Hooks {}
|
||||
}
|
||||
11
src/types.d.ts
vendored
Normal file
11
src/types.d.ts
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2023-03-09 21:36:22
|
||||
* @LastEditTime: 2023-03-21 21:32:12
|
||||
* @LastEditors: weisheng
|
||||
* @Description:
|
||||
* @FilePath: \fant-mini-plus\src\types.d.ts
|
||||
* 记得注释
|
||||
*/
|
||||
//type.d.ts
|
||||
declare const ROUTES: []
|
||||
1
src/uni.scss
Normal file
1
src/uni.scss
Normal file
@ -0,0 +1 @@
|
||||
|
||||
0
src/uni_modules/wot-design-uni/changelog.md
Normal file
0
src/uni_modules/wot-design-uni/changelog.md
Normal file
@ -0,0 +1,7 @@
|
||||
/**
|
||||
* SCSS 配置项:命名空间以及BEM
|
||||
*/
|
||||
$namespace: 'wd';
|
||||
$elementSeparator: '__';
|
||||
$modifierSeparator: '--';
|
||||
$state-prefix: 'is-';
|
||||
@ -0,0 +1,80 @@
|
||||
/**
|
||||
* 辅助函数
|
||||
*/
|
||||
@import 'config';
|
||||
$default-theme: #4d80f0 !default; // 正常色
|
||||
|
||||
/* 转换成字符串 */
|
||||
@function selectorToString($selector) {
|
||||
$selector: inspect($selector);
|
||||
$selector: str-slice($selector, 2, -2);
|
||||
|
||||
@return $selector;
|
||||
}
|
||||
|
||||
/* 判断是否存在 Modifier */
|
||||
@function containsModifier($selector) {
|
||||
$selector: selectorToString($selector);
|
||||
|
||||
@if str-index($selector, $modifierSeparator) {
|
||||
@return true;
|
||||
} @else {
|
||||
@return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* 判断是否存在伪类 */
|
||||
@function containsPseudo($selector) {
|
||||
$selector: selectorToString($selector);
|
||||
|
||||
@if str-index($selector, ':') {
|
||||
@return true;
|
||||
} @else {
|
||||
@return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 主题色切换
|
||||
* @params $theme-color 主题色
|
||||
* @params $type 变暗’dark‘ 变亮 'light'
|
||||
* @params $mix-color 自己设置的混色
|
||||
*/
|
||||
@function themeColor($theme-color, $type: "", $mix-color: "") {
|
||||
@if $default-theme != #4d80f0 {
|
||||
@if $type == "dark" {
|
||||
@return darken($theme-color, 10%);
|
||||
} @else if $type == "light" {
|
||||
@return lighten($theme-color, 10%);
|
||||
} @else {
|
||||
@return $theme-color;
|
||||
}
|
||||
} @else {
|
||||
@return $mix-color;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 颜色结果切换, 如果开启线性渐变色 使用渐变色,如果没有开启,那么使用主题色
|
||||
* @params $open-linear 是否开启线性渐变色
|
||||
* @params $deg 渐变色角度
|
||||
* @params $theme-color 当前配色
|
||||
* @params [Array] $set 主题色明暗设置,与 $color-list 数量对应
|
||||
* @params [Array] $color-list 渐变色顺序, $color-list 和 $per-list 数量相同
|
||||
* @params [Array] $per-list 渐变色比例
|
||||
*/
|
||||
@function resultColor($open-linear, $deg, $theme-color, $set, $color-list, $per-list) {
|
||||
// 开启渐变
|
||||
@if $open-linear {
|
||||
$len: length($color-list);
|
||||
$arg: $deg;
|
||||
@for $i from 1 through $len {
|
||||
$arg: $arg + "," + themeColor($theme-color, nth($set, $i), nth($color-list, $i)) + " " + nth($per-list, $i);
|
||||
}
|
||||
@return linear-gradient(unquote($arg));
|
||||
} @else {
|
||||
// 不开启渐变 直接使用色值
|
||||
@return $theme-color;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,265 @@
|
||||
/**
|
||||
* 混合宏
|
||||
*/
|
||||
@import "config";
|
||||
@import "function";
|
||||
|
||||
/**
|
||||
* BEM,定义块(b)
|
||||
*/
|
||||
@mixin b($block) {
|
||||
$B: $namespace + "-" + $block !global;
|
||||
|
||||
.#{$B} {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
/* 定义元素(e),对于伪类,会自动将 e 嵌套在 伪类 底下 */
|
||||
@mixin e($element...) {
|
||||
$selector: &;
|
||||
$selectors: "";
|
||||
|
||||
@if containsPseudo($selector) {
|
||||
@each $item in $element {
|
||||
$selectors: #{$selectors + "." + $B + $elementSeparator + $item + ","};
|
||||
}
|
||||
@at-root {
|
||||
#{$selector} {
|
||||
#{$selectors} {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
}
|
||||
} @else {
|
||||
@each $item in $element {
|
||||
$selectors: #{$selectors + $selector + $elementSeparator + $item + ","};
|
||||
}
|
||||
@at-root {
|
||||
#{$selectors} {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* 定义状态(m) */
|
||||
@mixin m($modifier...) {
|
||||
$selectors: "";
|
||||
@each $item in $modifier {
|
||||
$selectors: #{$selectors + & + $modifierSeparator + $item + ","};
|
||||
}
|
||||
|
||||
@at-root {
|
||||
#{$selectors} {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* 对于需要需要嵌套在 m 底下的 e,调用这个混合宏,一般在切换整个组件的状态,如切换颜色的时候 */
|
||||
@mixin me($element...) {
|
||||
$selector: &;
|
||||
$selectors: "";
|
||||
|
||||
@if containsModifier($selector) {
|
||||
@each $item in $element {
|
||||
$selectors: #{$selectors + "." + $B + $elementSeparator + $item + ","};
|
||||
}
|
||||
@at-root {
|
||||
#{$selector} {
|
||||
#{$selectors} {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
}
|
||||
} @else {
|
||||
@each $item in $element {
|
||||
$selectors: #{$selectors + $selector + $elementSeparator + $item + ","};
|
||||
}
|
||||
@at-root {
|
||||
#{$selectors} {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 状态,生成 is-$state 类名 */
|
||||
@mixin when($state) {
|
||||
@at-root {
|
||||
&.#{$state-prefix + $state} {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 常用混合宏
|
||||
*/
|
||||
|
||||
/* 单行超出隐藏 */
|
||||
@mixin lineEllipsis {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* 多行超出隐藏 */
|
||||
@mixin multiEllipsis($lineNumber: 3) {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: $lineNumber;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 清除浮动 */
|
||||
@mixin clearFloat {
|
||||
&::after {
|
||||
display: block;
|
||||
content: "";
|
||||
height: 0;
|
||||
clear: both;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
/* 0.5px 边框 */
|
||||
@mixin halfPixelBorder($direction: "bottom", $left: 0, $color: $-color-border-light) {
|
||||
&::after {
|
||||
position: absolute;
|
||||
display: block;
|
||||
content: "";
|
||||
@if ($left == 0) {
|
||||
width: 100%;
|
||||
} @else {
|
||||
width: calc(100% - #{$left});
|
||||
}
|
||||
height: 1px;
|
||||
left: $left;
|
||||
@if ($direction == "bottom") {
|
||||
bottom: 0;
|
||||
} @else {
|
||||
top: 0;
|
||||
}
|
||||
transform: scaleY(0.5);
|
||||
background: $color;
|
||||
}
|
||||
}
|
||||
@mixin buttonClear {
|
||||
outline: none;
|
||||
-webkit-appearance: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/**
|
||||
* 三角形实现尖角样式,适用于背景透明情况
|
||||
* @param $size 三角形高,底边为 $size * 2
|
||||
* @param $bg 三角形背景颜色
|
||||
*/
|
||||
@mixin triangleArrow($size, $bg) {
|
||||
@include e(arrow) {
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
@include e(arrow-down) {
|
||||
border-left: $size solid transparent;
|
||||
border-right: $size solid transparent;
|
||||
border-top: $size solid $bg;
|
||||
transform: translateX(-50%);
|
||||
bottom: -$size;
|
||||
}
|
||||
@include e(arrow-up) {
|
||||
border-left: $size solid transparent;
|
||||
border-right: $size solid transparent;
|
||||
border-bottom: $size solid $bg;
|
||||
transform: translateX(-50%);
|
||||
top: -$size;
|
||||
}
|
||||
@include e(arrow-left) {
|
||||
border-top: $size solid transparent;
|
||||
border-bottom: $size solid transparent;
|
||||
border-right: $size solid $bg;
|
||||
transform: translateY(-50%);
|
||||
left: -$size;
|
||||
}
|
||||
@include e(arrow-right) {
|
||||
border-top: $size solid transparent;
|
||||
border-bottom: $size solid transparent;
|
||||
border-left: $size solid $bg;
|
||||
transform: translateY(-50%);
|
||||
right: -$size;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 正方形实现尖角样式,适用于背景不透明情况
|
||||
* @param $size 正方形边长
|
||||
* @param $bg 正方形背景颜色
|
||||
* @param $z-index z-index属性值,不得大于外部包裹器
|
||||
* @param $box-shadow 阴影
|
||||
*/
|
||||
@mixin squareArrow($size, $bg, $z-index, $box-shadow) {
|
||||
@include e(arrow) {
|
||||
position: absolute;
|
||||
width: $size;
|
||||
height: $size;
|
||||
z-index: $z-index;
|
||||
}
|
||||
|
||||
@include e(arrow-down) {
|
||||
transform: translateX(-50%);
|
||||
bottom: 0;
|
||||
|
||||
&:after {
|
||||
content: "";
|
||||
width: $size;
|
||||
height: $size;
|
||||
background-color: $bg;
|
||||
position: absolute;
|
||||
bottom: -$size/2;
|
||||
transform: rotateZ(45deg);
|
||||
box-shadow: $box-shadow;
|
||||
}
|
||||
}
|
||||
@include e(arrow-up) {
|
||||
transform: translateX(-50%);
|
||||
&:after {
|
||||
content: "";
|
||||
width: $size;
|
||||
height: $size;
|
||||
background-color: $bg;
|
||||
position: absolute;
|
||||
top: -$size/2;
|
||||
transform: rotateZ(45deg);
|
||||
box-shadow: $box-shadow;
|
||||
}
|
||||
}
|
||||
@include e(arrow-left) {
|
||||
transform: translateY(-50%);
|
||||
&:after {
|
||||
content: "";
|
||||
width: $size;
|
||||
height: $size;
|
||||
background-color: $bg;
|
||||
position: absolute;
|
||||
left: -$size/2;
|
||||
transform: rotateZ(45deg);
|
||||
box-shadow: $box-shadow;
|
||||
}
|
||||
}
|
||||
@include e(arrow-right) {
|
||||
transform: translateY(-50%);
|
||||
&:after {
|
||||
content: "";
|
||||
width: $size;
|
||||
height: $size;
|
||||
background-color: $bg;
|
||||
position: absolute;
|
||||
right: -$size/2;
|
||||
transform: rotateZ(45deg);
|
||||
box-shadow: $box-shadow;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,829 @@
|
||||
@import './function';
|
||||
$open-linear: true !default;
|
||||
|
||||
/**
|
||||
* UI规范基础变量
|
||||
*/
|
||||
/*----------------------------------------- Theme color. start ----------------------------------------*/
|
||||
/* 主题颜色 */
|
||||
$-color-theme: $default-theme !default; // 品牌色
|
||||
$-color-white: #ffffff !default; // 用于mix的白色
|
||||
$-color-black: #000000 !default; // 用于mix的黑色
|
||||
|
||||
/* 辅助色 */
|
||||
$-color-success: #34d19d !default; // 成功色
|
||||
$-color-warning: #f0883a !default; // 警告色
|
||||
$-color-danger: #fa4350 !default; // 危险出错色
|
||||
$-color-purple: #8268de !default; // 紫色
|
||||
$-color-yellow: #f0cd1d !default; // 黄色
|
||||
$-color-blue: #2bb3ed !default; // 蓝色
|
||||
|
||||
// TODO 全部替换后如果不用此处就删除
|
||||
$-color-info: #909399 !default;
|
||||
$-color-theme-light: mix($-color-white, $-color-theme, 42%) !default; // 弱化色
|
||||
$-color-theme-emph: mix($-color-black, $-color-theme, 18%) !default; // 强调色
|
||||
|
||||
/* 文字颜色(默认浅色背景下 */
|
||||
$-color-title: $-color-black !default; // 模块标题/重要正文 000
|
||||
$-color-content: mix($-color-black, $-color-white, 85%) !default; // 普通正文 262626
|
||||
$-color-secondary: mix($-color-black, $-color-white, 65%) !default; // 次要信息,注释/补充/正文 595959
|
||||
$-color-aid: mix($-color-black, $-color-white, 45%) !default; // 辅助文字字号,弱化信息,引导性/不可点文字 8c8c8c
|
||||
$-color-tip: mix($-color-black, $-color-white, 25%) !default; // 失效、默认提示文字 bfbfbf
|
||||
$-color-border: mix($-color-black, $-color-white, 15%) !default; // 控件边框线 d9d9d9
|
||||
$-color-border-light: mix($-color-black, $-color-white, 9%) !default; // 分割线颜色 e8e8e8
|
||||
$-color-bg: mix($-color-black, $-color-white, 4%) !default; // 背景色、禁用填充色 f5f5f5
|
||||
$-color-table-bg: mix($-color-black, $-color-white, 2%) !default; // 表头填充 fafafa
|
||||
|
||||
/* 文字颜色-深背景 */
|
||||
$-color-title-indark: $-color-white !default; // 模块标题/重要正文 fff
|
||||
$-color-text-indark: mix($-color-white, $-color-black, 85%) !default; // 普通正文 d9d9d9
|
||||
$-color-secondary-indark: mix($-color-white, $-color-black, 65%) !default; // 次要信息,注释/补充/正文 a6a6a6
|
||||
$-color-aid-indark: mix($-color-white, $-color-black, 45%) !default; // 次级按钮边框线 737373
|
||||
$-color-tip-indark: mix($-color-white, $-color-black, 25%) !default; // 失效、默认提示文字 404040
|
||||
$-color-border-indark: mix($-color-white, $-color-black, 15%) !default; // 控件边框线 262626
|
||||
$-color-border-light-indark: mix($-color-white, $-color-black, 9%) !default; // 分割线颜色 171717
|
||||
$-color-bg-indark: mix($-color-white, $-color-black, 4%) !default; // 背景色、禁用填充色 0a0a0a
|
||||
$-color-table-bg-indark: mix($-color-white, $-color-black, 2%) !default; // 表头填充 fafafa
|
||||
|
||||
// TODO 待替换
|
||||
/* 透明度 */
|
||||
$-color-inlight-title-mask: mix($-color-black, $-color-white, 100%) !default; // 模块标题/重要正文 000
|
||||
/* 图形颜色 */
|
||||
$-color-icon: mix($-color-black, $-color-white, 15%) !default; // icon颜色
|
||||
$-color-icon-active: #eee !default; // icon颜色hover
|
||||
$-color-icon-disabled: #a7a7a7 !default; // icon颜色disabled
|
||||
/* modal */
|
||||
$-modal-bg: rgba($-color-black, 0.65) !default;
|
||||
|
||||
/*----------------------------------------- Theme color. end -------------------------------------------*/
|
||||
|
||||
/*-------------------------------- Theme color application size. start --------------------------------*/
|
||||
|
||||
/* 文字字号 */
|
||||
$-fs-big: 24px !default; // 大型标题
|
||||
$-fs-important: 19px !default; // 重要数据
|
||||
$-fs-title: 16px !default; // 标题字号/重要正文字号
|
||||
$-fs-content: 14px !default; // 普通正文
|
||||
$-fs-secondary: 12px !default; // 次要信息,注释/补充/正文
|
||||
$-fs-aid: 10px !default; // 辅助文字字号,弱化信息,引导性/不可点文字
|
||||
|
||||
/* 文字字重 */
|
||||
$-fw-medium: 500 !default; // PingFangSC-Medium
|
||||
$-fw-semibold: 600 !default; // PingFangSC-Semibold
|
||||
|
||||
/* 尺寸 */
|
||||
$-size-side-padding: 15px !default; // 屏幕两边留白
|
||||
|
||||
/*-------------------------------- Theme color application size. end --------------------------------*/
|
||||
|
||||
/* action-sheet */
|
||||
$-action-sheet-weight: 500 !default; // 面板字重
|
||||
$-action-sheet-radius: 16px !default; // 面板圆角大小
|
||||
$-action-sheet-action-height: 48px !default; // 单条菜单高度
|
||||
$-action-sheet-color: rgba($-color-black, 0.85) !default; // 选项名称颜色
|
||||
$-action-sheet-fs: $-fs-title !default; // 选项名称字号
|
||||
$-action-sheet-active-color: $-color-bg !default; // 点击高亮颜色
|
||||
$-action-sheet-subname-fs: $-fs-secondary !default; // 描述信息字号
|
||||
$-action-sheet-subname-color: rgba($-color-black, 0.45) !default; // 描述信息颜色
|
||||
$-action-sheet-disabled-color: rgba($-color-black, 0.25) !default; // 禁用颜色
|
||||
$-action-sheet-bg: $-color-white !default; // 菜单容器颜色(取消按钮上方的颜色)
|
||||
$-action-sheet-title-height: 64px !default; // 标题高度
|
||||
$-action-sheet-title-fs: $-fs-title !default; // 标题字号
|
||||
$-action-sheet-close-fs: $-fs-title !default; // 关闭按钮大小
|
||||
$-action-sheet-close-color: rgba($-color-black, 0.65) !default; // 关闭按钮颜色
|
||||
$-action-sheet-close-top: 25px !default; // 关闭按钮距离标题顶部距离
|
||||
$-action-sheet-close-right: 15px !default; // 关闭按钮距离标题右侧距离
|
||||
$-action-sheet-cancel-color: #131415 !default; // 取消按钮颜色
|
||||
$-action-sheet-cancel-height: 44px !default; // 取消按钮高度
|
||||
$-action-sheet-cancel-bg: rgba(240,240,240,1) !default; // 取消按钮背景色
|
||||
$-action-sheet-cancel-radius: 22px !default; // 取消按钮圆角大小
|
||||
$-action-sheet-panel-padding: 12px 0 11px !default; // 自定义面板内边距大小
|
||||
$-action-sheet-panel-img-fs: 40px !default; // 自定义面板图片大小
|
||||
$-action-sheet-panel-img-radius: 4px !default; // 自定义面板图片圆角大小
|
||||
|
||||
/* badge */
|
||||
$-badge-bg: $-color-danger !default; // 背景填充颜色
|
||||
$-badge-color: #fff !default; // 文字颜色
|
||||
$-badge-fs: 12px !default; // 文字字号
|
||||
$-badge-padding: 0 5px !default; // padding
|
||||
$-badge-height: 16px !default; // 高度
|
||||
$-badge-primary: $-color-theme !default;
|
||||
$-badge-success: $-color-success !default;
|
||||
$-badge-warning: $-color-warning !default;
|
||||
$-badge-danger: $-color-danger !default;
|
||||
$-badge-info: $-color-info !default;
|
||||
$-badge-dot-size: 6px !default; // dot 类型大小
|
||||
$-badge-border: 2px solid $-badge-color; // 边框样式
|
||||
|
||||
/* button */
|
||||
$-button-small-height: 28px !default; // 小型按钮高度
|
||||
$-button-small-padding: 0 11px !default; // 小型按钮padding
|
||||
$-button-small-fs: $-fs-secondary !default; // 小型按钮字号
|
||||
$-button-small-radius: 2px !default; // 小型按钮圆角大小
|
||||
$-button-small-loading: 14px !default; // 小型按钮loading图标大小
|
||||
|
||||
$-button-medium-height: 36px !default; // 中型按钮高度
|
||||
$-button-medium-padding: 0 15px !default; // 中型按钮padding
|
||||
$-button-medium-fs: $-fs-content !default; // 中型按钮字号
|
||||
$-button-medium-radius: 4px !default; // 中型按钮圆角大小
|
||||
$-button-medium-loading: 18px !default; // 中型按钮loading图标大小
|
||||
$-button-medium-box-shadow-size: 0px 2px 4px 0px !default; // 中尺寸阴影尺寸
|
||||
|
||||
$-button-large-height: 44px !default; // 大型按钮高度
|
||||
$-button-large-padding: 0 36px !default; // 大型按钮padding
|
||||
$-button-large-fs: $-fs-title !default; // 大型按钮字号
|
||||
$-button-large-radius: 8px !default; // 大型按钮圆角大小
|
||||
$-button-large-loading: 24px !default; // 大小按钮loading图标大小
|
||||
$-button-large-box-shadow-size: 0px 4px 8px 0px !default; // 大尺寸阴影尺寸
|
||||
|
||||
$-button-icon-fs: 18px !default; // 带图标的按钮的图标大小
|
||||
$-button-icon-size: 40px !default; // icon 类型按钮尺寸
|
||||
$-button-icon-color: rgba($-color-black, 0.65) !default; // icon 类型按钮颜色
|
||||
$-button-icon-active-color: $-color-icon-active !default; // icon 类型按钮点击态颜色
|
||||
$-button-icon-disabled-color: $-color-icon-disabled !default; // icon 类型按钮禁用颜色
|
||||
|
||||
$-button-normal-bg: $-color-white !default; // 默认按钮禁用背景色
|
||||
$-button-normal-color: $-color-title !default; // 文字颜色
|
||||
$-button-normal-active-color: $-color-black !default; // 文字点击态颜色
|
||||
$-button-normal-active-bg: $-color-bg !default; // 默认按钮点击态背景色
|
||||
$-button-normal-border-active-color: rgba($-color-black, 0.45) !default; // 默认按钮点击态边框色
|
||||
$-button-normal-disabled-color: rgba($-color-black, 0.25) !default; // 默认按钮禁用文字色
|
||||
$-button-normal-disabled-bg: $-color-white !default; // 默认按钮禁用背景色
|
||||
$-button-normal-border-disabled-color: $-color-bg !default; // 默认按钮禁用边框色
|
||||
$-button-border-color: mix($-color-black, $-color-white, 65%) !default; // 默认按钮边框色
|
||||
|
||||
$-button-primary-color: $-color-theme !default; // 主要按钮颜色
|
||||
$-button-primary-bg-color: resultColor(
|
||||
$open-linear,
|
||||
315deg,
|
||||
$-color-theme,
|
||||
"dark" "light",
|
||||
#4f7cf8 #668df8,
|
||||
0% 100%
|
||||
) !default; // 主要按钮背景颜色
|
||||
$-button-primary-active-color: resultColor(
|
||||
$open-linear,
|
||||
315deg,
|
||||
darken($-color-theme, 7%),
|
||||
"dark" "light",
|
||||
#416bdf #4e79ee,
|
||||
0% 100%
|
||||
) !default; // 主要按钮点击态颜色
|
||||
$-button-primary-plain-active-bg-color: #eff4fe !default; // 主要按钮点击态颜色
|
||||
$-button-primary-disabled-color: resultColor(
|
||||
$open-linear,
|
||||
315deg,
|
||||
rgba($-color-theme, 0.6),
|
||||
"dark" "light",
|
||||
#8FADFF #9FB8FE,
|
||||
0% 100%
|
||||
) !default; // 主要按钮禁用颜色
|
||||
$-button-primary-plain-disabled-color: themeColor($-color-theme, "light", #9DB9F6) !default; // 主要按钮点击态文字颜色
|
||||
$-button-primary-box-shadow-color: rgba($-color-theme, 0.25) !default; // 主要按钮阴影颜色
|
||||
|
||||
$-button-success-color: $-color-success !default; // 成功按钮颜色
|
||||
$-button-success-active-color: mix($-color-black, $-button-success-color, 18%) !default; // 成功按钮点击态颜色
|
||||
$-button-success-disabled-color: mix($-color-white, $-button-success-color, 42%) !default; // 成功按钮禁用颜色
|
||||
$-button-success-box-shadow-color: rgba($-color-success, 0.25) !default; // 主要按钮阴影颜色
|
||||
|
||||
$-button-info-bg-color: #F0F0F0 !default; // 信息按钮背景颜色
|
||||
$-button-info-color: $-color-title !default; // 信息按钮颜色
|
||||
$-button-info-active-bg-color: #E1E1E1 !default; // 信息按钮背景颜色
|
||||
$-button-info-active-color: rgba($-color-black, 0.85) !default; // 信息按钮点击态颜色
|
||||
$-button-info-disabled-bg-color: #F0F0F0 !default; // 信息按钮禁用颜色
|
||||
$-button-info-disabled-color: rgba($-color-black, 0.09) !default; // 信息按钮禁用颜色
|
||||
|
||||
$-button-info-plain-border-color: rgba($-color-black, 0.45) !default; // 信息按钮禁用颜色
|
||||
$-button-info-plain-bg-color: $-color-white !default; // 信息按钮禁用颜色
|
||||
$-button-info-plain-disabled-bg-color: #F0F0F0 !default; // 信息按钮禁用颜色
|
||||
$-button-info-plain-active-color: rgba($-color-black, 0.45) !default; // 信息按钮禁用颜色
|
||||
$-button-info-plain-active-bg-color: #F0F0F0 !default; // 信息按钮禁用颜色
|
||||
$-button-info-plain-normal-color: rgba($-color-black, 0.85) !default; // 信息幽灵按钮默认颜色
|
||||
|
||||
$-button-warning-color: $-color-warning !default; // 警告按钮颜色
|
||||
$-button-warning-active-color: mix($-color-black, $-button-warning-color, 18%) !default; // 警告按钮点击颜色
|
||||
$-button-warning-disabled-color: mix($-color-white, $-button-warning-color, 42%) !default; // 警告按钮禁用颜色
|
||||
$-button-warning-box-shadow-color: rgba($-color-warning, 0.25) !default; // 主要按钮阴影颜色
|
||||
|
||||
$-button-error-color: $-color-danger !default; // 错误按钮颜色
|
||||
$-button-error-active-color: mix($-color-black, $-button-error-color, 18%) !default; // 错误按钮点击颜色
|
||||
$-button-error-disabled-color: mix($-color-white, $-button-error-color, 42%) !default; // 错误按钮禁用颜色
|
||||
$-button-error-box-shadow-color: rgba($-color-danger, 0.25) !default; // 主要按钮阴影颜色
|
||||
|
||||
$-button-suck-height: 50px !default; // suck 类型按钮高度
|
||||
$-button-suck-active-color: $-button-primary-plain-active-bg-color !default; // 错误按钮禁用颜色
|
||||
|
||||
/* cell */
|
||||
$-cell-padding: $-size-side-padding !default; // cell 左右padding距离
|
||||
$-cell-ling-height: 1.43 !default; // 行高
|
||||
|
||||
$-cell-group-title-fs: $-fs-title !default; // 组标题字号
|
||||
$-cell-group-padding: 13px $-cell-padding !default; // 组padding
|
||||
$-cell-group-title-color: rgba($-color-black, 0.85) !default; // 组标题文字颜色
|
||||
$-cell-group-value-fs: $-fs-content !default; // 组值字号
|
||||
$-cell-group-value-color: $-color-content !default; // 组值文字颜色
|
||||
|
||||
$-cell-wrapper-padding: 13px !default; // cell 容器padding
|
||||
$-cell-wrapper-padding-with-label: 16px !default; // cell 容器上下padding(有label情况下)
|
||||
$-cell-icon-right: $-cell-padding !default; // 图标距离右边缘
|
||||
$-cell-icon-size: 16px !default; // 图标大小
|
||||
$-cell-title-fs: 14px !default; // 标题字号
|
||||
$-cell-title-color: rgba($-color-black, 0.85) !default; // 标题文字颜色
|
||||
$-cell-label-fs: 12px !default; // 描述信息字号
|
||||
$-cell-label-color: rgba($-color-black, 0.45) !default; // 描述信息文字颜色
|
||||
$-cell-value-fs: 14px !default; // 右侧内容字号
|
||||
$-cell-value-color: rgba($-color-black, 0.85) !default; // 右侧内容文字颜色
|
||||
$-cell-value-line-height: 1.58 !default; // 右侧内容行高
|
||||
$-cell-arrow-size: 18px !default; // 右箭头大小
|
||||
$-cell-arrow-color: rgba($-color-black, 0.25) !default; // 右箭头颜色
|
||||
$-cell-tap-bg: rgba($-color-black, 0.06) !default; // 点击态背景色
|
||||
|
||||
$-cell-title-fs-large: 16px !default; // 大尺寸标题字号
|
||||
$-cell-label-fs-large: 14px !default; // 描述信息字号
|
||||
$-cell-icon-size-large: 18px !default; // 图标大小
|
||||
|
||||
$-cell-required-color: $-color-danger !default; // 要求必填*颜色
|
||||
$-cell-required-size: 18px !default; // 必填*字号
|
||||
$-cell-vertical-top: 16px !default; // 表单类型-上下结构的间距
|
||||
|
||||
/* calendar */
|
||||
$-calendar-fs: 16px !default;
|
||||
$-calendar-panel-padding: 0 12px !default;
|
||||
$-calendar-panel-title-fs: 14px !default;
|
||||
$-calendar-panel-title-color: rgba(0, 0, 0, 0.85) !default;
|
||||
$-calendar-week-color: rgba(0, 0, 0, 0.85) !default;
|
||||
$-calendar-week-height: 36px !default;
|
||||
$-calendar-week-fs: 12px !default;
|
||||
$-calendar-day-fs: 16px !default;
|
||||
$-calendar-day-color: rgba(0, 0, 0, 0.85) !default;
|
||||
$-calendar-day-fw: 500 !default;
|
||||
$-calendar-day-height: 64px !default;
|
||||
$-calendar-month-width: 50px !default;
|
||||
$-calendar-active-color: $-color-theme !default;
|
||||
$-calendar-disabled-color: rgba(0, 0, 0, 0.25) !default;
|
||||
$-calendar-range-color: rgba($-color-theme, 0.09) !default;
|
||||
$-calendar-active-border: 8px !default;
|
||||
$-calendar-info-fs: 10px !default;
|
||||
|
||||
/* checkbox */
|
||||
$-checkbox-margin: 10px !default; // 多个复选框距离
|
||||
$-checkbox-bg: $-color-white !default; // 多个复选框距离
|
||||
$-checkbox-label-margin: 9px !default; // 右侧文字与左侧图标距离
|
||||
$-checkbox-size: 16px !default; // 左侧图标尺寸
|
||||
$-checkbox-icon-size: 14px !default; // 左侧图标尺寸
|
||||
$-checkbox-border-color: #dcdcdc !default; // 左侧图标边框颜色
|
||||
$-checkbox-check-color: $-color-white !default; // 左侧图标边框颜色
|
||||
$-checkbox-label-fs: 14px !default; // 右侧文字字号
|
||||
$-checkbox-label-color: rgba($-color-black, 0.85); // 右侧文字颜色
|
||||
$-checkbox-checked-color: $-color-theme !default; // 选中颜色
|
||||
|
||||
$-checkbox-disabled-color: rgba($-color-black, 0.04) !default; // 禁用背景颜色
|
||||
$-checkbox-disabled-label-color: rgba($-color-black, 0.25) !default; // 禁用文字颜色
|
||||
$-checkbox-disabled-check-color: rgba($-color-black, 0.15) !default; // 禁用图标颜色
|
||||
$-checkbox-disabled-check-bg: rgba($-color-black, 0.15) !default; // 禁用边框背景颜色
|
||||
$-checkbox-square-radius: 4px !default; // 方型圆角大小
|
||||
|
||||
$-checkbox-large-size: 18px !default; // 左侧图标尺寸
|
||||
$-checkbox-large-label-fs: 16px !default; // 右侧文字字号
|
||||
|
||||
$-checkbox-button-height: 32px !default; // 按钮模式复选框高
|
||||
$-checkbox-button-min-width: 78px !default; // 按钮模式最小宽
|
||||
$-checkbox-button-radius: 16px !default; // 按钮圆角大小
|
||||
$-checkbox-button-bg: rgba($-color-black, 0.04) !default; // 按钮模式背景颜色
|
||||
$-checkbox-button-font-size: 14px !default; // 按钮模式字号
|
||||
$-checkbox-button-border: #f5f5f5 !default; // 按钮边框颜色
|
||||
$-checkbox-button-disabled-border: rgba($-color-black, 0.15) !default; // 按钮禁用边框颜色
|
||||
|
||||
/* collapse */
|
||||
$-collapse-side-padding: $-size-side-padding !default; // 左右间距
|
||||
$-collapse-body-padding: 14px 25px !default; // body padding
|
||||
$-collapse-header-padding: 13px $-size-side-padding !default; // 头部padding
|
||||
$-collapse-title-color: rgba($-color-black, 0.85) !default; // 标题颜色
|
||||
$-collapse-title-fs: 16px !default; // 标题字号
|
||||
$-collapse-arrow-size: 18px !default; // 箭头大小
|
||||
$-collapse-arrow-color: #d8d8d8 !default; // 箭头颜色
|
||||
$-collapse-body-fs: 14px !default; // 内容字号
|
||||
$-collapse-body-color: rgba($-color-black, 0.65) !default; // 内容颜色
|
||||
$-collapse-disabled-color: rgba($-color-black, 0.15) !default; // 禁用颜色
|
||||
$-collapse-retract-fs: 14px !default; // 更多 字号
|
||||
$-collapse-more-color: $-color-theme !default; // 更多 颜色
|
||||
|
||||
/* divider */
|
||||
$-divider-padding: 0 $-size-side-padding !default; // 两边间距
|
||||
$-divider-color: rgba($-color-black, 0.45) !default; // 字体颜色
|
||||
$-divider-line-color: rgba($-color-black, 0.15) !default; // 线条颜色
|
||||
$-divider-fs: 14px !default; // 字体大小
|
||||
|
||||
/* drop-menu */
|
||||
$-drop-menu-height: 48px; // 展示选中项的高度
|
||||
$-drop-menu-color: $-color-content !default; // 展示选中项的颜色
|
||||
$-drop-menu-fs: $-fs-content !default; // 展示选中项的字号
|
||||
$-drop-menu-side-padding: $-size-side-padding !default; // 两边留白间距
|
||||
$-drop-menu-disabled-color: rgba($-color-black, 0.25) !default; // 禁用颜色
|
||||
$-drop-menu-item-height: 48px; // 选项高度
|
||||
$-drop-menu-item-color: $-color-content !default; // 选项颜色
|
||||
$-drop-menu-item-fs: $-fs-content !default; // 选项字号
|
||||
$-drop-menu-item-color-active: $-color-theme !default; // 选中颜色
|
||||
$-drop-menu-item-color-tip: rgba($-color-black, 0.45) !default; // 提示文字颜色
|
||||
$-drop-menu-item-fs-tip: $-fs-secondary !default; // 提示文字字号
|
||||
$-drop-menu-option-check-size: 20px !default; // check 图标大小
|
||||
$-drop-menu-line-color: resultColor(
|
||||
$open-linear,
|
||||
315deg,
|
||||
$-color-theme,
|
||||
"dark" "light",
|
||||
rgba(81, 124, 240, 1) rgba(118, 158, 245, 1),
|
||||
0% 100%
|
||||
) !default; // 下划线颜色
|
||||
$-drop-menu-line-height: 3px !default; // 下划线高度
|
||||
|
||||
/* input-number */
|
||||
$-input-number-color: #262626 !default; // 文字颜色
|
||||
$-input-number-border-color: #e8e8e8 !default; // 边框颜色
|
||||
$-input-number-disabled-color: rgba($-color-black, 0.25) !default; // 禁用颜色
|
||||
$-input-number-height: 24px !default; // 加减号按钮高度
|
||||
$-input-number-btn-width: 26px !default; // 加减号按钮宽度
|
||||
$-input-number-input-width: 36px !default; // 输入框宽度
|
||||
$-input-number-radius: 4px !default; // 加减号按钮圆角大小
|
||||
$-input-number-fs: 12px !default; // 输入框字号
|
||||
$-input-number-icon-size: 14px !default; // 加减号图标大小
|
||||
$-input-number-icon-color: rgba($-color-black, 0.65) !default; // icon颜色
|
||||
|
||||
/* input */
|
||||
$-input-border-color: #dadada !default; // 无label边框颜色
|
||||
$-input-not-empty-border-color: #262626 !default; // 无label边框颜色
|
||||
$-input-fs: $-cell-title-fs !default; // 字号
|
||||
$-input-fs-large: $-cell-title-fs-large !default; // 大尺寸字号
|
||||
$-input-icon-margin: 8px !default; // 图标距离
|
||||
$-input-color: #262626 !default; // 文字颜色
|
||||
$-input-placeholder-color: #bfbfbf !default; // 占位符颜色
|
||||
$-input-disabled-color: #d9d9d9 !default; // 输入框禁用颜色
|
||||
$-input-error-color: $-color-danger !default; // 输入框错误颜色
|
||||
$-input-icon-color: #bfbfbf !default; // 图标颜色
|
||||
$-input-clear-color: #585858 !default; // 关闭按钮颜色
|
||||
$-input-count-color: #bfbfbf !default; // 计数文字颜色
|
||||
$-input-count-current-color: #262626 !default; // 当前长度颜色
|
||||
$-input-label-padding: 11px 10px 11px 0 !default; // label padding
|
||||
$-input-bg: $-color-white !default; // 默认背景颜色
|
||||
|
||||
$-input-cell-bg: $-color-white !default; // cell 类型背景色
|
||||
$-input-cell-border-color: $-color-border-light !default; // cell 类型边框颜色
|
||||
$-input-cell-padding: $-size-side-padding !default; // cell 类型左右间距
|
||||
$-input-cell-height: 46px !default; // cell 高度
|
||||
$-input-cell-height-large: 48px !default; // cell 大尺寸高度
|
||||
$-input-cell-label-width: 33% !default; // cell 下 label 的宽度
|
||||
$-input-inner-height: 34px !default; // 非cell和textarea下的高度
|
||||
$-input-inner-height-no-border: 20px !default; // 无边框下的高度
|
||||
$-input-inner-padding: 6px 0 !default; // 非cell和textarea下的padding
|
||||
$-input-count-fs: 14px !default; // 计数字号
|
||||
$-input-count-fs-large: 14px !default; // 大尺寸计数字号
|
||||
$-input-icon-size: 16px !default; // 图标大小
|
||||
$-input-icon-size-large: 18px !default; // 大尺寸图标大小
|
||||
$-input-textarea-padding: 15px !default; // textarea下的padding
|
||||
|
||||
/* loadmore */
|
||||
$-loadmore-height: 48px !default; // 高度
|
||||
$-loadmore-color: rgba($-color-black, 0.45) !default; // 颜色
|
||||
$-loadmore-fs: 14px !default; // 字号
|
||||
$-loadmore-error-color: $-color-theme !default; // 点击重试颜色
|
||||
|
||||
/* message-box */
|
||||
$-message-box-width: 300px !default; // 宽度
|
||||
$-message-box-bg: $-color-white !default; // 默认背景颜色
|
||||
$-message-box-radius: 16px !default; // 圆角大小
|
||||
$-message-box-padding: 25px 24px 0 !default; // 主体内容padding
|
||||
$-message-box-title-fs: 16px !default; // 标题字号
|
||||
$-message-box-title-color: rgba($-color-black, 0.85) !default; // 标题颜色
|
||||
$-message-box-content-fs: 14px !default; // 内容字号
|
||||
$-message-box-content-color: #666666 !default; // 内容颜色
|
||||
$-message-box-content-max-height: 264px !default; // 内容最大高度
|
||||
$-message-box-content-scrollbar-width: 4px !default; // 内容滚动条宽度
|
||||
$-message-box-content-scrollbar-color: rgba($-color-black, 0.1) !default; // 内容滚动条颜色
|
||||
$-message-box-input-error-color: $-input-error-color !default; // 输入框错误颜色
|
||||
|
||||
/* notice-bar */
|
||||
$-notice-bar-fs: 12px !default; // 字号
|
||||
$-notice-bar-line-height: 18px !default; // 行高
|
||||
$-notice-bar-border-radius: 8px !default; // 圆角
|
||||
$-notice-bar-padding: 9px 20px 9px 15px !default; // 非换行下的padding
|
||||
$-notice-bar-warning-bg: #fff6c8 !default; // 背景色
|
||||
$-notice-bar-info-bg: #f4f9ff !default; // 背景色
|
||||
$-notice-bar-danger-bg: #feeced !default; // 背景色
|
||||
$-notice-bar-warning-color: $-color-warning !default; // 文字和图标颜色
|
||||
$-notice-bar-info-color: $-color-theme !default; // 文字和图标颜色
|
||||
$-notice-bar-danger-color: $-color-danger !default; // 文字和图标颜色
|
||||
$-notice-bar-prefix-size: 18px !default; // 图标大小
|
||||
$-notice-bar-close-bg: rgba($-color-black, 0.15) !default; // 右侧关闭按钮背景颜色
|
||||
$-notice-bar-close-size: 18px !default; // 右侧关闭按钮背景颜色
|
||||
$-notice-bar-close-color: $-color-white !default; // 右侧关闭按钮颜色
|
||||
$-notice-bar-close-size: 10px !default; // 关闭按钮大小
|
||||
$-notice-bar-wrap-padding: 14px $-size-side-padding !default; // 换行下的padding
|
||||
|
||||
/* pagination */
|
||||
$-pagination-content-padding: 10px 15px !default;
|
||||
$-pagination-message-padding: 1px 0 16px 0 !default;
|
||||
$-pagination-message-fs: 12px !default;
|
||||
$-pagination-message-color: rgba($-color-black, 0.69) !default;
|
||||
$-pagination-nav-border: 1px solid rgba($-color-black, 0.45) !default;
|
||||
$-pagination-nav-border-radius: 16px !default;
|
||||
$-pagination-nav-fs: 12px !default;
|
||||
$-pagination-nav-width: 60px !default;
|
||||
$-pagination-nav-color: rgba($-color-black, 0.85) !default;
|
||||
$-pagination-nav-content-fs: 12px !default;
|
||||
$-pagination-nav-sepatator-padding: 0 4px !default;
|
||||
$-pagination-nav-current-color: $-color-theme !default;
|
||||
|
||||
/* picker */
|
||||
$-picker-toolbar-height: 54px !default; // toolbar 操作条的高度
|
||||
$-picker-action-height: 16px !default; // toolbar 操作条的高度
|
||||
$-picker-toolbar-finish-color: $-color-theme !default; // toolbar 操作条完成按钮的颜色
|
||||
$-picker-toolbar-cancel-color: #666666 !default; // toolbar 操作条的边框颜色
|
||||
$-picker-toolbar-fs: $-fs-title !default; // toolbar 操作条的字号
|
||||
$-picker-toolbar-title-color: rgba($-color-black, 0.85) !default; // toolbar 操作台的标题颜色
|
||||
$-picker-column-fs: 16px !default; // 选择器选项的字号
|
||||
$-picker-bg: $-color-white !default; // 选择器选项的字号
|
||||
$-picker-column-active-fs: 18px !default; // 选择器选项被选中的字号
|
||||
$-picker-column-color: rgba($-color-black, 0.85) !default; // 选择器选项的颜色
|
||||
$-picker-column-height: 210px !default; // 列高 滚筒外部的高度
|
||||
$-picker-column-item-height: 35px !default; // 列高 滚筒外部的高度
|
||||
$-picker-column-select-bg: #f5f5f5 !default;
|
||||
$-picker-loading-button-color: rgba($-color-black, 0.25) !default; // loading 背景颜色
|
||||
$-picker-column-padding: 0 $-size-side-padding !default; // 选项内间距
|
||||
|
||||
$-picker-column-disabled-color: rgba($-color-black, 0.25) !default; // 选择器选项禁用的颜色
|
||||
$-picker-mask: linear-gradient(180deg, hsla(0, 0%, 100%, 0.9), hsla(0, 0%, 100%, 0.25)),
|
||||
linear-gradient(0deg, hsla(0, 0%, 100%, 0.9), hsla(0, 0%, 100%, 0.25)) !default; // 上下阴影
|
||||
$-picker-loading-bg: rgba($-color-white, 0.8) !default; // loading 背景颜色
|
||||
$-picker-region-separator-color: rgba($-color-black, 0.65) !default; // 区域选择文字颜色
|
||||
$-picker-cell-arrow-size-large: $-cell-icon-size !default; // cell 类型的大尺寸 右侧icon尺寸
|
||||
|
||||
$-picker-region-color: rgba($-color-black, 0.45) !default; // 区域选择文字颜色
|
||||
$-picker-region-bg-active-color: resultColor(
|
||||
$open-linear,
|
||||
315deg,
|
||||
$-color-theme,
|
||||
"dark" "light" "light",
|
||||
rgba(79,124,248,1) rgba(102,141,248,1) rgba(102,141,248,1),
|
||||
0% 100% 100%
|
||||
) !default; // 区域选择激活选中背景颜色
|
||||
|
||||
$-picker-region-fs: 14px !default; // 区域选择文字字号
|
||||
|
||||
/* col-picker */
|
||||
$-col-picker-selected-height: 44px !default; // 弹框顶部值高度
|
||||
$-col-picker-selected-padding: 0 16px !default; // 弹框顶部值左右间距
|
||||
$-col-picker-selected-fs: 14px !default; // 弹框顶部值字号
|
||||
$-col-picker-selected-color: rgba($-color-black, 0.85) !default; // 弹框顶部值文字颜色
|
||||
$-col-picker-selected-fw: 700 !default; // 弹框顶部值高亮字重
|
||||
$-col-picker-line-width: 16px !default; // 弹框顶部值高亮线条宽度
|
||||
$-col-picker-line-height: 3px !default; // 弹框顶部值高亮线条高度
|
||||
$-col-picker-line-color: linear-gradient(315deg, rgba(81,124,240,1), rgba(118,158,245,1)) !default; // 弹框顶部值高亮线条颜色
|
||||
$-col-picker-line-box-shadow: 0px 1px 2px 0px rgba(1, 87, 255, 0.2) !default; // 弹框顶部值高亮线条阴影
|
||||
$-col-picker-list-height: 53vh !default; // 弹框列表高度
|
||||
$-col-picker-list-padding-bottom: 30px !default; // 弹框列表底部间距
|
||||
$-col-picker-list-color: rgba($-color-black, 0.85) !default; // 弹框列表文字颜色
|
||||
$-col-picker-list-color-disabled: rgba($-color-black, 0.15) !default; // 弹框列表文字禁用颜色
|
||||
$-col-picker-list-color-tip: rgba($-color-black, 0.45) !default; // 弹框列表提示文字颜色
|
||||
$-col-picker-list-fs: 14px !default; // 弹框列表文字字号
|
||||
$-col-picker-list-fs-tip: 12px !default; // 弹框列表提示文字字号
|
||||
$-col-picker-list-item-padding: 12px 15px !default; // 弹框列表选项间距
|
||||
$-col-picker-list-checked-icon-size: 18px !default; // 弹框列表选中箭头大小
|
||||
$-col-picker-list-color-checked: $-color-theme !default; // 弹框列表选中选项颜色
|
||||
|
||||
/* popup */
|
||||
$-popup-close-size: 24px !default; // 关闭按钮尺寸
|
||||
$-popup-close-color: #666 !default; // 关闭按钮颜色
|
||||
|
||||
/* progress */
|
||||
$-progress-padding: 9px 0 8px !default; // 进度条内边距
|
||||
$-progress-bg: rgba(229,229,229,1) !default; // 进度条底色
|
||||
$-progress-danger-color: $-color-danger !default; // 进度条danger颜色
|
||||
$-progress-success-color: $-color-success !default; // 进度条success进度条颜色
|
||||
$-progress-color: resultColor(
|
||||
$open-linear,
|
||||
315deg,
|
||||
$-color-theme,
|
||||
"dark" "light",
|
||||
#517CF0 #769EF5 ,
|
||||
0% 100%
|
||||
) !default; // 进度条渐变色
|
||||
$-progress-linear-success-color: resultColor(
|
||||
$open-linear,
|
||||
315deg,
|
||||
$-color-theme,
|
||||
"dark" "light",
|
||||
#20B080 #2BD69D ,
|
||||
0% 100%
|
||||
) !default; // success进度条渐变色
|
||||
$-progress-linear-danger-color: resultColor(
|
||||
$open-linear,
|
||||
315deg,
|
||||
$-color-theme,
|
||||
"dark" "light",
|
||||
#E04350 #FF5964 ,
|
||||
0% 100%
|
||||
) !default; // danger进度条渐变色
|
||||
$-progress-height: 3px !default; // 进度条高度
|
||||
$-progress-label-color: #333 !default; // 文字颜色
|
||||
$-progress-label-fs: 14px !default; // 文字字号
|
||||
$-progress-icon-fs: 18px !default; // 图标字号
|
||||
|
||||
/* radio */
|
||||
$-radio-margin: $-checkbox-margin !default; // 多个单选框距离
|
||||
$-radio-label-margin: $-checkbox-label-margin !default; // 右侧文字与左侧图标距离
|
||||
$-radio-size: 16px !default; // 左侧图标尺寸
|
||||
$-radio-bg: $-checkbox-bg !default; // 左侧图标尺寸
|
||||
$-radio-label-fs: $-checkbox-label-fs !default; // 右侧文字字号
|
||||
$-radio-label-color: $-checkbox-label-color !default; // 右侧文字颜色
|
||||
$-radio-checked-color: $-checkbox-checked-color !default; // 选中颜色
|
||||
$-radio-disabled-color: $-checkbox-disabled-color !default; // 禁用颜色
|
||||
$-radio-disabled-label-color: $-checkbox-disabled-label-color !default; // 禁用文字颜色
|
||||
|
||||
$-radio-large-size: $-checkbox-large-size !default; // 左侧图标尺寸
|
||||
$-radio-large-label-fs: $-checkbox-large-label-fs !default; // 右侧文字字号
|
||||
|
||||
$-radio-button-height: $-checkbox-button-height !default; // 按钮模式复选框高
|
||||
$-radio-button-min-width: 60px !default; // 按钮模式最小宽
|
||||
$-radio-button-max-width: 144px !default; // 按钮模式最大宽
|
||||
$-radio-button-radius: $-checkbox-button-radius !default; // 按钮圆角大小
|
||||
$-radio-button-bg: $-checkbox-button-bg !default; // 按钮模式背景颜色
|
||||
$-radio-button-fs: $-checkbox-button-font-size !default; // 按钮模式字号
|
||||
$-radio-button-border: $-checkbox-button-border !default; // 按钮边框颜色
|
||||
$-radio-button-disabled-border: $-checkbox-button-disabled-border !default; // 按钮禁用边框颜色
|
||||
|
||||
$-radio-dot-size: 8px !default; // 单选dot模式圆点尺寸
|
||||
$-radio-dot-large-size: 10px !default; // 单选dot模式大尺寸圆点尺寸
|
||||
$-radio-dot-checked-bg: $-color-theme !default; // 单选dot模式选中背景色
|
||||
$-radio-dot-checked-border-color: $-color-theme !default; // 单选dot模式选中边框色
|
||||
$-radio-dot-border-color: #dcdcdc !default; // 单选dot模式边框色
|
||||
$-radio-dot-disabled-border: #d9d9d9 !default; // 单选dot模式禁用边框颜色
|
||||
$-radio-dot-disabled-bg: #d9d9d9 !default; // 单选dot模式禁用背景颜色
|
||||
|
||||
/* search */
|
||||
$-search-side-padding: $-size-side-padding !default; // 左右间距
|
||||
$-search-padding: 10px 0 10px $-search-side-padding !default; // 不包含取消按钮的间距
|
||||
$-search-input-radius: 15px !default; // 输入框圆角大小
|
||||
$-search-input-bg: $-color-bg !default; // 输入框背景色
|
||||
$-search-input-height: 30px !default; // 输入框高度
|
||||
$-search-input-padding: 0 32px 0 42px !default; // 输入框间距
|
||||
$-search-input-fs: $-fs-content !default; // 输入框字号
|
||||
$-search-input-color: #262626 !default; // 输入框文字颜色
|
||||
$-search-icon-color: $-color-icon !default; // 图标颜色
|
||||
$-search-placeholder-color: #bfbfbf !default; // placeholder 颜色
|
||||
$-search-cancel-padding: 0 $-search-side-padding 0 10px !default; // 取消按钮间距
|
||||
$-search-cancel-fs: $-fs-title !default; // 取消按钮字号
|
||||
$-search-cancel-color: rgba($-color-black, 0.65) !default; // 取消按钮颜色
|
||||
$-search-light-bg: $-color-bg !default; // light 类型的容器背景色
|
||||
|
||||
/* slider */
|
||||
$-slider-fs: $-fs-content !default; // 字体大小
|
||||
$-slider-handle-radius: 12px !default; // 滑块半径
|
||||
$-slider-handle-bg: resultColor(
|
||||
$open-linear,
|
||||
139deg,
|
||||
$-color-theme,
|
||||
"dark" "light",
|
||||
#FFFFFF #F7F7F7 ,
|
||||
0% 100%
|
||||
) !default; // 滑块背景
|
||||
$-slider-axie-height: 3px !default; // 滑轴高度
|
||||
$-slider-color: #333 !default; // 字体颜色
|
||||
$-slider-axie-bg: #E5E5E5 !default; // 滑轴的默认背景色
|
||||
$-slider-line-color: resultColor(
|
||||
$open-linear,
|
||||
315deg,
|
||||
$-color-theme,
|
||||
"dark" "light",
|
||||
#517CF0 #769EF5 ,
|
||||
0% 100%
|
||||
) !default; // 进度条颜色
|
||||
$-slider-disabled-color: rgba($-color-black, 0.25) !default; // 禁用状态下字体颜色
|
||||
|
||||
/* sort-button */
|
||||
$-sort-button-fs: $-fs-content !default; // 字号
|
||||
$-sort-button-color: $-color-content !default; // 颜色
|
||||
$-sort-button-height: 48px !default; // 高度
|
||||
$-sort-button-line-height: 3px !default; // 下划线高度
|
||||
$-sort-button-line-color: resultColor(
|
||||
$open-linear,
|
||||
315deg,
|
||||
$-color-theme,
|
||||
"dark" "light",
|
||||
rgba(81, 124, 240, 1) rgba(118, 158, 245, 1),
|
||||
0% 100%
|
||||
) !default; // 下划线颜色
|
||||
|
||||
/* steps */
|
||||
$-steps-icon-size: 22px !default; // 图标尺寸
|
||||
$-steps-inactive-color: rgba($-color-black, 0.25) !default; // 等待状态文字颜色
|
||||
$-steps-finished-color: $-color-theme !default; // 完成文字颜色
|
||||
$-steps-icon-text-fs: $-fs-content !default; // 数字图标文字字号
|
||||
$-steps-error-color: $-color-danger !default; // 异常颜色
|
||||
$-steps-title-fs: $-fs-content !default; // 标题字号
|
||||
$-steps-title-fw: $-fw-medium !default; // 标题字重
|
||||
$-steps-label-fs: $-fs-secondary !default; // 描述信息字号
|
||||
$-steps-description-color: rgba($-color-black, 0.45) !default; // 描述信息颜色
|
||||
$-steps-is-icon-width: 30px !default; // 自定义图标的宽度,给左右留白
|
||||
$-steps-line-color: rgba($-color-black, 0.15) !default; // 线条颜色
|
||||
$-steps-dot-size: 7px !default; // 点状大小
|
||||
$-steps-dot-active-size: 9px !default; // 点状高亮大小
|
||||
|
||||
/* switch */
|
||||
$-switch-width: 51px !default; // 宽度
|
||||
$-switch-height: 32px !default; // 高度
|
||||
$-switch-circle-size: 28px !default; // 圆点大小
|
||||
$-switch-border-color: #e5e5e5 !default; // 边框颜色选中状态背景颜色
|
||||
$-switch-active-color: resultColor(
|
||||
$open-linear,
|
||||
315deg,
|
||||
$-color-theme,
|
||||
"light" "dark",
|
||||
#4f7cf8 #668df8,
|
||||
0% 100%
|
||||
) !default; // 选中状态背景
|
||||
$-switch-active-shadow-color: rgba(0, 83, 162, 0.5) !default; // 选中状态shadow颜色
|
||||
$-switch-inactive-color: resultColor(
|
||||
$open-linear,
|
||||
315deg,
|
||||
#dadada,
|
||||
"light" "dark" "dark",
|
||||
#f2f2f2 #dadada #668df8,
|
||||
0% 100% 100%
|
||||
) !default; // 非选中背景颜色
|
||||
$-switch-inactive-shadow-color: rgba(155, 155, 155, 0.5) !default; // 非选中状态shadow颜色
|
||||
|
||||
|
||||
/* tabs */
|
||||
$-tabs-nav-arrow-fs: 18px !default; // 全部Icon字号
|
||||
$-tabs-nav-arrow-open-fs: 14px !default; // 展开Icon字号
|
||||
$-tabs-nav-width: 100vw; // tabs 头部切换宽度
|
||||
$-tabs-nav-height: 42px !default; // 头部切换高度
|
||||
$-tabs-nav-fs: $-fs-content !default; // 头部切换文字大小
|
||||
$-tabs-nav-color: rgba($-color-black, 0.85) !default; // 头部切换文字颜色
|
||||
$-tabs-nav-bg: $-color-white !default; // 背景颜色
|
||||
$-tabs-nav-active-color: $-color-theme !default; // 头部高亮颜色
|
||||
$-tabs-nav-disabled-color: rgba($-color-black, 0.25) !default; // 头部禁用颜色
|
||||
$-tabs-nav-line-height: 3px !default; // 高亮边框高度
|
||||
$-tabs-nav-line-bg-color: resultColor(
|
||||
$open-linear,
|
||||
315deg,
|
||||
$-color-theme,
|
||||
"dark" "light",
|
||||
rgba(81, 124, 240, 1) rgba(118, 158, 245, 1),
|
||||
0% 100%
|
||||
) !default; // 底部条颜色
|
||||
$-tabs-nav-map-fs: $-fs-content !default; // map 类型按钮字号
|
||||
$-tabs-nav-map-color: rgba($-color-black, 0.85) !default; // map 类型按钮文字颜色
|
||||
$-tabs-nav-map-arrow-color: rgba($-color-black, 0.65) !default; // map 类型箭头颜色
|
||||
$-tabs-nav-map-btn-before-bg: linear-gradient(
|
||||
270deg,
|
||||
rgba(255, 255, 255, 1) 1%,
|
||||
rgba(255, 255, 255, 0) 100%
|
||||
) !default; // 左侧map遮罩阴影
|
||||
$-tabs-nav-map-button-back-color: rgba($-color-black, 0.04) !default; // map 类型按钮边框颜色
|
||||
$-tabs-nav-map-button-radius: 16px !default; // map 类型按钮圆角大小
|
||||
$-tabs-nav-map-modal-bg: $-modal-bg !default; // map 类型蒙层背景色
|
||||
|
||||
/* tag */
|
||||
$-tag-fs: $-fs-secondary !default; // 字号
|
||||
$-tag-color: $-color-white !default; // 字体颜色
|
||||
$-tag-small-fs: $-fs-aid !default; // 小尺寸字号
|
||||
$-tag-info-color: #585858 !default; // info 颜色
|
||||
$-tag-primary-color: $-color-theme !default; // 主颜色
|
||||
$-tag-danger-color: rgba(250,67,80,1) !default; // danger 颜色
|
||||
$-tag-warning-color: rgba(255,144,0,1) !default; // warning 颜色
|
||||
$-tag-success-color: rgba(51,187,68,1) !default; // success 颜色
|
||||
$-tag-info-bg: resultColor(
|
||||
$open-linear,
|
||||
49deg,
|
||||
$-color-black,
|
||||
"dark" "light",
|
||||
#808080 #999999,
|
||||
0% 100%
|
||||
) !default; // info 背景颜色
|
||||
$-tag-primary-bg: resultColor(
|
||||
$open-linear,
|
||||
49deg,
|
||||
$-color-theme,
|
||||
"dark" "light",
|
||||
rgba(81,124,240,1) rgba(118,158,245,1),
|
||||
0% 100%
|
||||
) !default; // 主背景颜色
|
||||
$-tag-danger-bg: resultColor(
|
||||
$open-linear,
|
||||
44deg,
|
||||
$-color-danger,
|
||||
"dark" "light",
|
||||
rgba(230,62,70,1) rgba(255,64,73,1),
|
||||
0% 100%
|
||||
) !default; // danger 背景颜色
|
||||
$-tag-warning-bg: resultColor(
|
||||
$open-linear,
|
||||
45deg,
|
||||
$-color-warning,
|
||||
"dark" "light",
|
||||
rgba(230,113,55,1) rgba(255,151,76,1),
|
||||
0% 100%
|
||||
) !default; // warning 背景颜色
|
||||
$-tag-success-bg: resultColor(
|
||||
$open-linear,
|
||||
45deg,
|
||||
$-color-success,
|
||||
"dark" "light",
|
||||
rgba(32,176,128,1) rgba(43,214,157,1),
|
||||
0% 100%
|
||||
) !default; // success 背景颜色
|
||||
$-tag-round-color: rgba(102, 102, 102, 1) !default; // round 字体颜色
|
||||
$-tag-round-border-color: rgba(225,225,225,1) !default; // round 边框颜色
|
||||
$-tag-round-radius: 12px !default; // round 圆角大小
|
||||
$-tag-mark-radius: 6px 2px 6px 2px !default; // mark 圆角大小
|
||||
$-tag-close-size: 14px !default; // 关闭按钮字号
|
||||
$-tag-close-color: $-tag-info-color !default; // 关闭按钮颜色
|
||||
$-tag-close-active-color: rgba($-color-black, 0.45) !default; // 关闭按钮 active 颜色
|
||||
|
||||
/* toast */
|
||||
$-toast-padding: 16px 24px !default; // padding
|
||||
$-toast-max-width: 300px !default; // 最大宽度
|
||||
$-toast-radius: 8px !default; // 圆角大小
|
||||
$-toast-bg: $-modal-bg !default; // 背景色
|
||||
$-toast-fs: $-fs-content !default; // 字号
|
||||
$-toast-with-icon-min-width: 150px !default; // 有图标的情况下最小宽度
|
||||
$-toast-icon-size: 39px !default; // 图标大小
|
||||
$-toast-loading-padding: 10px !default; // loading 下的padding
|
||||
$-toast-box-shadow: 0px 6px 16px 0px rgba($-color-black, 0.08) !default; // 外部阴影
|
||||
|
||||
/* tooltip */
|
||||
$-tooltip-bg: rgba(38, 39, 40, 0.8) !default; // 背景色
|
||||
$-tooltip-color: $-color-white !default; // 文字颜色
|
||||
$-tooltip-radius: 8px !default; // 圆角大小
|
||||
$-tooltip-arrow-size: 9px !default; // 箭头大小
|
||||
$-tooltip-fs: $-fs-content !default; // 字号
|
||||
$-tooltip-blur: 10px !default; // 背景高斯模糊效果
|
||||
$-tooltip-padding: 9px 20px !default; // 间距
|
||||
$-tooltip-close-size: 6px !default; // 背景高斯模糊效果
|
||||
$-tooltip-z-index: 500 !default;
|
||||
$-tooltip-line-height: 18px !default; // 行高
|
||||
|
||||
/* popover */
|
||||
$-popover-bg: $-color-white !default; // 背景色
|
||||
$-popover-color: rgba($-color-black, 0.85) !default; // 文字颜色
|
||||
$-popover-box-shadow: 0px 2px 10px 0px rgba($-color-black, 0.1) !default; // 阴影颜色
|
||||
$-popover-arrow-box-shadow: 0px 2px 10px 0px rgba($-color-black, 0.2) !default; // 阴影颜色
|
||||
$-popover-border-color: rgba($-color-black, 0.09) !default; // 阴影颜色
|
||||
$-popover-radius: 4px !default; // 圆角大小
|
||||
$-popover-arrow-size: 6px !default; // 箭头大小
|
||||
$-popover-fs: $-fs-content !default; // 字号
|
||||
$-popover-padding: 15px !default; // 间距
|
||||
$-popover-line-height: 18px !default; // 行高
|
||||
$-popover-z-index: $-tooltip-z-index !default;
|
||||
|
||||
/* grid-item */
|
||||
$-grid-item-fs: 12px !default; // 字号
|
||||
$-grid-item-bg: $-color-white !default; // 字号
|
||||
$-grid-item-padding: 14px 0px !default; // 内容的 padding
|
||||
$-grid-item-border-color: $-color-border-light !default; // 边框颜色
|
||||
|
||||
/* statustip */
|
||||
$-statustip-fs: $-fs-content !default; // 字号
|
||||
$-statustip-color: rgba($-color-black, 0.45) !default; // 文字颜色
|
||||
$-statustip-line-height: 16px !default; // 文字行高
|
||||
$-statustip-padding: 5px 10px !default; // 间距
|
||||
|
||||
/* card */
|
||||
$-card-bg: $-color-white !default; // 背景色
|
||||
$-card-fs: $-fs-content !default; // 卡片字号
|
||||
$-card-padding: 0 $-size-side-padding !default; // 内边距
|
||||
$-card-footer-padding: 12px 0 16px !default; // 底部内边距
|
||||
$-card-shadow-color: 0px 4px 8px 0px rgba($-color-black, 0.02) !default; // 阴影
|
||||
$-card-radius: 8px !default; // 圆角大小
|
||||
$-card-line-height: 1.1 !default; // 行高
|
||||
$-card-margin: 0 $-size-side-padding !default; // 外边距
|
||||
$-card-title-color: rgba($-color-black, 0.85) !default; // 标题颜色
|
||||
$-card-title-fs: $-fs-title !default; // 矩形卡片标题字号
|
||||
$-card-content-border-color: rgba($-color-black, 0.09) !default; // 内容边框
|
||||
$-card-rectangle-title-padding: 15px 15px 12px !default; // 矩形卡片头部内边距
|
||||
$-card-rectangle-content-padding: 16px 0 !default; // 矩形卡片内容内边距
|
||||
$-card-rectangle-footer-padding: 12px 0 !default; // 矩形卡片底部内边距
|
||||
$-card-content-color: rgba($-color-black, 0.45) !default; // 文本内容颜色
|
||||
$-card-content-line-height: 1.428 !default; // 文本内容行高
|
||||
$-card-content-margin: 13px 0 12px !default; // 内容外边距
|
||||
$-card-content-rectangle-margin: 14px 0 12px !default; // 矩形卡片内容外边距
|
||||
|
||||
/* upload */
|
||||
$-upload-size: 80px !default; // upload的外边框默认尺寸
|
||||
$-upload-evoke-icon-size: 32px !default; // 唤起项的图标大小
|
||||
$-upload-evoke-bg: rgba($-color-black, 0.04) !default; // 唤起项的背景色
|
||||
$-upload-evoke-color: rgba($-color-black, 0.25) !default; // 唤起项的图标颜色
|
||||
$-upload-evoke-disabled-color: rgba($-color-black, 0.09) !default; // 唤起项禁用颜色
|
||||
$-upload-close-icon-size: 16px !default; // 移除按钮尺寸
|
||||
$-upload-close-icon-color: rgba($-color-black, 0.65) !default; // 移除按钮颜色
|
||||
$-upload-progress-fs: 14px !default; // 进度文字字号
|
||||
$-upload-preview-name-fs: 12px !default; // 预览图片名字号
|
||||
$-upload-preview-icon-size: 24px !default; // 预览内部图标尺寸
|
||||
$-upload-preview-name-bg: rgba($-color-black, 0.6) !default; // 预览文件名背景色
|
||||
$-upload-preview-name-height: 22px !default; // 预览文件名背景高度
|
||||
|
||||
/* curtain */
|
||||
$-curtain-content-radius: 24px !default; // 内容圆角
|
||||
$-curtain-content-close-color: $-color-white !default; // 关闭按钮颜色
|
||||
$-curtain-content-close-fs: $-fs-big !default; // 关闭按钮大小
|
||||
29
src/uni_modules/wot-design-uni/components/common/base64.ts
Normal file
29
src/uni_modules/wot-design-uni/components/common/base64.ts
Normal file
@ -0,0 +1,29 @@
|
||||
const _b64chars = [...'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/']
|
||||
const _mkUriSafe = (src) => src.replace(/[+/]/g, (m0) => (m0 === '+' ? '-' : '_')).replace(/=+$/m, '')
|
||||
const fromUint8Array = (src, rfc4648 = false) => {
|
||||
let b64 = ''
|
||||
for (let i = 0, l = src.length; i < l; i += 3) {
|
||||
const [a0, a1, a2] = [src[i], src[i + 1], src[i + 2]]
|
||||
const ord = (a0 << 16) | (a1 << 8) | a2
|
||||
b64 += _b64chars[ord >>> 18]
|
||||
b64 += _b64chars[(ord >>> 12) & 63]
|
||||
b64 += typeof a1 !== 'undefined' ? _b64chars[(ord >>> 6) & 63] : '='
|
||||
b64 += typeof a2 !== 'undefined' ? _b64chars[ord & 63] : '='
|
||||
}
|
||||
return rfc4648 ? _mkUriSafe(b64) : b64
|
||||
}
|
||||
const _btoa =
|
||||
typeof btoa === 'function'
|
||||
? (s) => btoa(s)
|
||||
: (s) => {
|
||||
if (s.charCodeAt() > 255) {
|
||||
throw new RangeError('The string contains invalid characters.')
|
||||
}
|
||||
return fromUint8Array(Uint8Array.from(s, (c: any) => c.charCodeAt(0)))
|
||||
}
|
||||
const utob = (src) => unescape(encodeURIComponent(src))
|
||||
|
||||
export default function encode(src, rfc4648 = false) {
|
||||
const b64 = _btoa(utob(src))
|
||||
return rfc4648 ? _mkUriSafe(b64) : b64
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
let queue = []
|
||||
let outsideId = 1
|
||||
|
||||
export function pushToQueue(comp) {
|
||||
comp.outsideId = ++outsideId
|
||||
queue.push(comp)
|
||||
}
|
||||
|
||||
export function removeFromQueue(comp) {
|
||||
queue = queue.filter((item) => {
|
||||
return item.outsideId !== comp.outsideId
|
||||
})
|
||||
}
|
||||
|
||||
export function closeOther(comp) {
|
||||
queue.forEach((item) => {
|
||||
if (item.outsideId !== comp.outsideId) {
|
||||
item.close()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default function closeOutside() {
|
||||
queue.forEach((item) => {
|
||||
item.close()
|
||||
})
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
### 使用方法
|
||||
```javascript
|
||||
|
||||
import VueComponent from '/packages/common/component.js'
|
||||
|
||||
VueComponent({
|
||||
props: {},
|
||||
beforeCreate(){},
|
||||
created(){},
|
||||
mounted(){},
|
||||
destroyed(){}
|
||||
})
|
||||
```
|
||||
|
||||
### 映射关系
|
||||
|
||||
>如果使用封装的`VueComponent`组件,以下小程序`原生属性/方法`必须替换为对应的`封装属性/方法`
|
||||
|
||||
| 封装 | 原生 |
|
||||
|--------------|----------- |
|
||||
| props | properties |
|
||||
| beforeCreate | created |
|
||||
| created | attached |
|
||||
| mounted | ready |
|
||||
| destroyed | detached |
|
||||
|
||||
### 全局样式类
|
||||
|
||||
* 使用VueComponent组件时,会自动添加custom-class类,外部可以通过此类修改组件内部的样式。
|
||||
```html
|
||||
<view>
|
||||
<wd-button custom-class="custom">确定</wd-button>
|
||||
</view>
|
||||
```
|
||||
```css
|
||||
.custom{
|
||||
background-color: red;
|
||||
}
|
||||
```
|
||||
### 原生生命周期
|
||||
|
||||
> 必须要弄清楚的声明周期,执行顺序按照降序排列。
|
||||
|
||||
| hook | 描述 |
|
||||
|-------------------------|----------- |
|
||||
| properties | 类型vue的props。 |
|
||||
| data | 类型vue的data。 |
|
||||
| created | 在组件实例刚刚被创建时执行,此时可以拿到data,但是拿不到props的最新值,只能拿到默认值,不能调用setData,可以操作设置this。 |
|
||||
| properties:observer | 如果实例初始化时给properties传值,会触发observer,先于attached执行 |
|
||||
| attached | 在组件实例进入页面节点树时执行,可以调用setData。 |
|
||||
| relations | DOM build,父组件建立连接,双方可以在此hook互相操作对方。 |
|
||||
| ready | DOM painted。 |
|
||||
|
||||
2
src/uni_modules/wot-design-uni/components/common/dayjs.min.js
vendored
Normal file
2
src/uni_modules/wot-design-uni/components/common/dayjs.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/* eslint-disable */
|
||||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.dayjs=e()}(this,function(){"use strict";const t=60,e=60*t,s=24*e,r=7*s,n=(t,e,s)=>!t||t.length>=e?t:`${Array(e+1-t.length).join(s)}${t}`;class i{constructor(t){this.utc=!1;const e=this.parseConfig(t);this.date=new Date(e),this.timeZone=this.date.getTimezoneOffset()/60,this.timeZoneString=n(String(-1*this.timeZone).replace(/^(.)?(\d)/,"$10$200"),5,"+"),this.mYear=this.date.getFullYear(),this.mMonth=this.date.getMonth(),this.mDay=this.date.getDate(),this.mWeek=this.date.getDay(),this.mHour=this.date.getHours(),this.mMinute=this.date.getMinutes(),this.mSecond=this.date.getSeconds()}parseConfig(t){if(!t)return new Date;if(t instanceof Date)return t;if(/^(\d){8}$/.test(t)){return this.utc=!0,`${t.substr(0,4)}-${t.substr(4,2)}-${t.substr(6,2)}`}return t}year(){return this.mYear}month(){return this.mMonth}unix(){const t=this.utc?60*this.timeZone*60*1e3:0;return Math.floor((this.date.getTime()+t)/1e3)}toString(){return this.date.toUTCString()}startOf(t){switch(t){case"year":return new i(new Date(this.year(),0,1));case"month":return new i(new Date(this.year(),this.month(),1));default:return this}}add(n,a){let h;switch(a){case"m":case"minutes":h=t;break;case"h":case"hours":h=e;break;case"d":case"days":h=s;break;case"w":case"weeks":h=r;break;default:h=1}const u=this.unix()+n*h;return new i(1e3*u)}subtract(t,e){return this.add(-1*t,e)}format(t="YYYY-MM-DDTHH:mm:ssZ"){const e=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];return t.replace(/Y{2,4}|M{1,2}|D{1,2}|d{1,4}|H{1,2}|m{1,2}|s{1,2}|Z{1,2}/g,t=>{switch(t){case"YY":return String(this.mYear).slice(-2);case"YYYY":return String(this.mYear);case"M":return String(this.mMonth+1);case"MM":return n(String(this.mMonth+1),2,"0");case"D":return String(this.mDay);case"DD":return n(String(this.mDay),2,"0");case"d":return String(this.mWeek);case"dddd":return e[this.mWeek];case"H":return String(this.mHour);case"HH":return n(String(this.mHour),2,"0");case"m":return String(this.mMinute);case"mm":return n(String(this.mMinute),2,"0");case"s":return String(this.mSecond);case"ss":return n(String(this.mSecond),2,"0");case"Z":return`${this.timeZoneString.slice(0,-2)}:00`;case"ZZ":return this.timeZoneString;default:return t}})}}return t=>new i(t)});
|
||||
@ -0,0 +1,206 @@
|
||||
import isObject from './isObject'
|
||||
import root from './internal/root'
|
||||
|
||||
/**
|
||||
* Creates a debounced function that delays invoking `func` until after `wait`
|
||||
* milliseconds have elapsed since the last time the debounced function was
|
||||
* invoked, or until the next browser frame is drawn. The debounced function
|
||||
* comes with a `cancel` method to cancel delayed `func` invocations and a
|
||||
* `flush` method to immediately invoke them. Provide `options` to indicate
|
||||
* whether `func` should be invoked on the leading and/or trailing edge of the
|
||||
* `wait` timeout. The `func` is invoked with the last arguments provided to the
|
||||
* debounced function. Subsequent calls to the debounced function return the
|
||||
* result of the last `func` invocation.
|
||||
*
|
||||
* **Note:** If `leading` and `trailing` options are `true`, `func` is
|
||||
* invoked on the trailing edge of the timeout only if the debounced function
|
||||
* is invoked more than once during the `wait` timeout.
|
||||
*
|
||||
* If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
|
||||
* until the next tick, similar to `setTimeout` with a timeout of `0`.
|
||||
*
|
||||
* If `wait` is omitted in an environment with `requestAnimationFrame`, `func`
|
||||
* invocation will be deferred until the next frame is drawn (typically about
|
||||
* 16ms).
|
||||
*
|
||||
* See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
|
||||
* for details over the differences between `debounce` and `throttle`.
|
||||
*
|
||||
* @since 0.1.0
|
||||
* @category Function
|
||||
* @param {Function} func The function to debounce.
|
||||
* @param {number} [wait=0]
|
||||
* The number of milliseconds to delay; if omitted, `requestAnimationFrame` is
|
||||
* used (if available).
|
||||
* @param {Object} [options={}] The options object.
|
||||
* @param {boolean} [options.leading=false]
|
||||
* Specify invoking on the leading edge of the timeout.
|
||||
* @param {number} [options.maxWait]
|
||||
* The maximum time `func` is allowed to be delayed before it's invoked.
|
||||
* @param {boolean} [options.trailing=true]
|
||||
* Specify invoking on the trailing edge of the timeout.
|
||||
* @returns {Function} Returns the new debounced function.
|
||||
* @example
|
||||
*
|
||||
* // Avoid costly calculations while the window size is in flux.
|
||||
* jQuery(window).on('resize', debounce(calculateLayout, 150))
|
||||
*
|
||||
* // Invoke `sendMail` when clicked, debouncing subsequent calls.
|
||||
* jQuery(element).on('click', debounce(sendMail, 300, {
|
||||
* 'leading': true,
|
||||
* 'trailing': false
|
||||
* }))
|
||||
*
|
||||
* // Ensure `batchLog` is invoked once after 1 second of debounced calls.
|
||||
* const debounced = debounce(batchLog, 250, { 'maxWait': 1000 })
|
||||
* const source = new EventSource('/stream')
|
||||
* jQuery(source).on('message', debounced)
|
||||
*
|
||||
* // Cancel the trailing debounced invocation.
|
||||
* jQuery(window).on('popstate', debounced.cancel)
|
||||
*
|
||||
* // Check for pending invocations.
|
||||
* const status = debounced.pending() ? "Pending..." : "Ready"
|
||||
*/
|
||||
function debounce(func, wait, options) {
|
||||
let lastArgs, lastThis, maxWait, result, timerId, lastCallTime
|
||||
|
||||
let lastInvokeTime = 0
|
||||
let leading = false
|
||||
let maxing = false
|
||||
let trailing = true
|
||||
|
||||
// Bypass `requestAnimationFrame` by explicitly setting `wait=0`.
|
||||
const useRAF = !wait && wait !== 0 && typeof root.requestAnimationFrame === 'function'
|
||||
|
||||
if (typeof func !== 'function') {
|
||||
throw new TypeError('Expected a function')
|
||||
}
|
||||
wait = +wait || 0
|
||||
if (isObject(options)) {
|
||||
leading = !!options.leading
|
||||
maxing = 'maxWait' in options
|
||||
maxWait = maxing ? Math.max(+options.maxWait || 0, wait) : maxWait
|
||||
trailing = 'trailing' in options ? !!options.trailing : trailing
|
||||
}
|
||||
|
||||
function invokeFunc(time) {
|
||||
const args = lastArgs
|
||||
const thisArg = lastThis
|
||||
|
||||
lastArgs = lastThis = undefined
|
||||
lastInvokeTime = time
|
||||
result = func.apply(thisArg, args)
|
||||
return result
|
||||
}
|
||||
|
||||
function startTimer(pendingFunc, wait) {
|
||||
if (useRAF) {
|
||||
root.cancelAnimationFrame(timerId)
|
||||
return root.requestAnimationFrame(pendingFunc)
|
||||
}
|
||||
return setTimeout(pendingFunc, wait)
|
||||
}
|
||||
|
||||
function cancelTimer(id) {
|
||||
if (useRAF) {
|
||||
return root.cancelAnimationFrame(id)
|
||||
}
|
||||
clearTimeout(id)
|
||||
}
|
||||
|
||||
function leadingEdge(time) {
|
||||
// Reset any `maxWait` timer.
|
||||
lastInvokeTime = time
|
||||
// Start the timer for the trailing edge.
|
||||
timerId = startTimer(timerExpired, wait)
|
||||
// Invoke the leading edge.
|
||||
return leading ? invokeFunc(time) : result
|
||||
}
|
||||
|
||||
function remainingWait(time) {
|
||||
const timeSinceLastCall = time - lastCallTime
|
||||
const timeSinceLastInvoke = time - lastInvokeTime
|
||||
const timeWaiting = wait - timeSinceLastCall
|
||||
|
||||
return maxing ? Math.min(timeWaiting, maxWait - timeSinceLastInvoke) : timeWaiting
|
||||
}
|
||||
|
||||
function shouldInvoke(time) {
|
||||
const timeSinceLastCall = time - lastCallTime
|
||||
const timeSinceLastInvoke = time - lastInvokeTime
|
||||
|
||||
// Either this is the first call, activity has stopped and we're at the
|
||||
// trailing edge, the system time has gone backwards and we're treating
|
||||
// it as the trailing edge, or we've hit the `maxWait` limit.
|
||||
return lastCallTime === undefined || timeSinceLastCall >= wait || timeSinceLastCall < 0 || (maxing && timeSinceLastInvoke >= maxWait)
|
||||
}
|
||||
|
||||
function timerExpired() {
|
||||
const time = Date.now()
|
||||
if (shouldInvoke(time)) {
|
||||
return trailingEdge(time)
|
||||
}
|
||||
// Restart the timer.
|
||||
timerId = startTimer(timerExpired, remainingWait(time))
|
||||
}
|
||||
|
||||
function trailingEdge(time) {
|
||||
timerId = undefined
|
||||
|
||||
// Only invoke if we have `lastArgs` which means `func` has been
|
||||
// debounced at least once.
|
||||
if (trailing && lastArgs) {
|
||||
return invokeFunc(time)
|
||||
}
|
||||
lastArgs = lastThis = undefined
|
||||
return result
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
if (timerId !== undefined) {
|
||||
cancelTimer(timerId)
|
||||
}
|
||||
lastInvokeTime = 0
|
||||
lastArgs = lastCallTime = lastThis = timerId = undefined
|
||||
}
|
||||
|
||||
function flush() {
|
||||
return timerId === undefined ? result : trailingEdge(Date.now())
|
||||
}
|
||||
|
||||
function pending() {
|
||||
return timerId !== undefined
|
||||
}
|
||||
|
||||
function debounced(...args) {
|
||||
const time = Date.now()
|
||||
const isInvoking = shouldInvoke(time)
|
||||
|
||||
lastArgs = args
|
||||
lastThis = this
|
||||
lastCallTime = time
|
||||
|
||||
if (isInvoking) {
|
||||
if (timerId === undefined) {
|
||||
return leadingEdge(lastCallTime)
|
||||
}
|
||||
if (maxing) {
|
||||
// Handle invocations in a tight loop.
|
||||
timerId = startTimer(timerExpired, wait)
|
||||
return invokeFunc(lastCallTime)
|
||||
}
|
||||
}
|
||||
if (timerId === undefined) {
|
||||
timerId = startTimer(timerExpired, wait)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
debounced.cancel = cancel
|
||||
debounced.flush = flush
|
||||
debounced.pending = pending
|
||||
return debounced
|
||||
}
|
||||
|
||||
export default debounce
|
||||
@ -0,0 +1,4 @@
|
||||
/** Detect free variable `global` from Node.js. */
|
||||
const freeGlobal = typeof global === 'object' && global !== null && global.Object === Object && global
|
||||
|
||||
export default freeGlobal
|
||||
@ -0,0 +1,14 @@
|
||||
import freeGlobal from './freeGlobal.js'
|
||||
|
||||
/** Detect free variable `globalThis` */
|
||||
// eslint-disable-next-line eqeqeq
|
||||
const freeGlobalThis = typeof globalThis === 'object' && globalThis !== null && globalThis.Object == Object && globalThis
|
||||
|
||||
/** Detect free variable `self`. */
|
||||
const freeSelf = typeof self === 'object' && self !== null && self.Object === Object && self
|
||||
|
||||
/** Used as a reference to the global object. */
|
||||
// eslint-disable-next-line no-new-func
|
||||
const root = freeGlobalThis || freeGlobal || freeSelf || Function('return this')()
|
||||
|
||||
export default root
|
||||
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Checks if `value` is the
|
||||
* [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
|
||||
* of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
|
||||
*
|
||||
* @since 0.1.0
|
||||
* @category Lang
|
||||
* @param {*} value The value to check.
|
||||
* @returns {boolean} Returns `true` if `value` is an object, else `false`.
|
||||
* @example
|
||||
*
|
||||
* isObject({})
|
||||
* // => true
|
||||
*
|
||||
* isObject([1, 2, 3])
|
||||
* // => true
|
||||
*
|
||||
* isObject(Function)
|
||||
* // => true
|
||||
*
|
||||
* isObject(null)
|
||||
* // => false
|
||||
*/
|
||||
function isObject(value) {
|
||||
const type = typeof value
|
||||
return value != null && (type === 'object' || type === 'function')
|
||||
}
|
||||
|
||||
export default isObject
|
||||
180
src/uni_modules/wot-design-uni/components/common/util.js
Normal file
180
src/uni_modules/wot-design-uni/components/common/util.js
Normal file
@ -0,0 +1,180 @@
|
||||
import debounce from './lodash/debounce'
|
||||
|
||||
/**
|
||||
* @description 对num自动填充px
|
||||
* @param {Number} num
|
||||
* @return {string} num+px
|
||||
*/
|
||||
export function addUnit(num) {
|
||||
return Number.isNaN(Number(num)) ? num : `${num}px`
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取当前页面栈顶(当前显示的页面)
|
||||
* @return {wx.Page}
|
||||
*/
|
||||
export function getContext() {
|
||||
const pages = getCurrentPages()
|
||||
return pages[pages.length - 1]
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 判断target是否对象
|
||||
* @param obj
|
||||
* @return {boolean}
|
||||
*/
|
||||
export function isObj(obj) {
|
||||
// Object.prototype.toString.call(obj).match(/\[object (\w+)\]/)[1].toLowerCase() === 'object'
|
||||
return typeof obj === 'object'
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取目标原始类型
|
||||
* @param target 任意类型
|
||||
* @returns {string} type 数据类型
|
||||
*/
|
||||
export function getType(target) {
|
||||
// 得到原生类型
|
||||
const typeStr = Object.prototype.toString.call(target)
|
||||
// 拿到类型值
|
||||
const type = typeStr.match(/\[object (\w+)\]/)[1]
|
||||
// 类型值转小写并返回
|
||||
return type.toLowerCase()
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 默认的外部格式化函数 - picker组件
|
||||
* @param items
|
||||
* @param labelKey
|
||||
* @return {*}
|
||||
*/
|
||||
export const defaultDisplayFormat = function (items, { labelKey = 'value' }) {
|
||||
// 在props中,this被指向了全局data
|
||||
if (items instanceof Array) {
|
||||
return items.map((item) => item[labelKey]).toString()
|
||||
} else {
|
||||
return items[labelKey]
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @description 默认函数占位符 - pickerView组件
|
||||
* @param value
|
||||
* @return value
|
||||
*/
|
||||
export const defaultFunction = (value) => value
|
||||
/**
|
||||
* @description 是否不为空
|
||||
* @param value
|
||||
* @return {Boolean}
|
||||
*/
|
||||
export const isDef = (value) => value !== undefined && value !== null
|
||||
|
||||
export { debounce }
|
||||
|
||||
/**
|
||||
* @description 防止数字小于零
|
||||
* @param {Number} num
|
||||
* @param {String} label 标签
|
||||
*/
|
||||
export const checkNumRange = (num, label = 'value') => {
|
||||
if (num < 0) {
|
||||
throw Error(`${label} shouldn't be less than zero`)
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @description 防止pixel无意义
|
||||
* @param {Number} num
|
||||
* @param {String} label 标签
|
||||
*/
|
||||
export const checkPixelRange = (num, label = 'value') => {
|
||||
if (num <= 0) {
|
||||
throw Error(`${label} should be greater than zero`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @default 渲染视图
|
||||
* @param {this} node 节点
|
||||
* @param {Object} data 需要渲染的数据
|
||||
* @param {Number} delay 延迟多久
|
||||
*/
|
||||
export const renderData = (node, data, delay = 0) => {
|
||||
const diff = Object.keys(data).reduce((prev, key) => {
|
||||
if (data[key] !== node.data[key]) {
|
||||
prev[key] = data[key]
|
||||
}
|
||||
return prev
|
||||
}, {})
|
||||
if (Object.keys(diff).length === 0) return
|
||||
const render = () => node.setData(diff)
|
||||
delay ? setTimeout(render, delay) : render()
|
||||
}
|
||||
|
||||
function rgbToHex(r, g, b) {
|
||||
const hex = ((r << 16) | (g << 8) | b).toString(16)
|
||||
return '#' + new Array(Math.abs(hex.length - 7)).join('0') + hex
|
||||
}
|
||||
|
||||
function hexToRgb(hex) {
|
||||
const rgb = []
|
||||
for (let i = 1; i < 7; i += 2) {
|
||||
rgb.push(parseInt('0x' + hex.slice(i, i + 2)))
|
||||
}
|
||||
return rgb
|
||||
}
|
||||
|
||||
/**
|
||||
* @default 计算渐变色的中间变量
|
||||
* @param {String} startColor 开始颜色
|
||||
* @param {String} endColor 结束颜色
|
||||
* @param {Number} step 获取渲染位置,默认为中间位置
|
||||
* @return {String} 渐变色中间颜色变量
|
||||
*/
|
||||
export const gradient = (startColor, endColor, step = 2) => {
|
||||
// 将hex转换为rgb
|
||||
const sColor = hexToRgb(startColor)
|
||||
const eColor = hexToRgb(endColor)
|
||||
|
||||
// 计算R\G\B每一步的差值
|
||||
const rStep = (eColor[0] - sColor[0]) / step
|
||||
const gStep = (eColor[1] - sColor[1]) / step
|
||||
const bStep = (eColor[2] - sColor[2]) / step
|
||||
|
||||
const gradientColorArr = []
|
||||
for (let i = 0; i < step; i++) {
|
||||
// 计算每一步的hex值
|
||||
gradientColorArr.push(rgbToHex(parseInt(rStep * i + sColor[0]), parseInt(gStep * i + sColor[1]), parseInt(bStep * i + sColor[2])))
|
||||
}
|
||||
return gradientColorArr
|
||||
}
|
||||
|
||||
/** @description 保证num不超出min和max的范围 */
|
||||
export const range = (num, min, max) => Math.min(Math.max(num, min), max)
|
||||
|
||||
/** @description 比较数值是否相等 */
|
||||
export const isEqual = (value1, value2) => {
|
||||
if (value1 === value2) return true
|
||||
if (!(value1 instanceof Array)) return false
|
||||
if (!(value2 instanceof Array)) return false
|
||||
if (value1.length !== value2.length) return false
|
||||
for (let i = 0; i !== value1.length; ++i) {
|
||||
if (value1[i] !== value2[i]) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/** @description 不满10补0 */
|
||||
export const padZero = (number, length = 2) => {
|
||||
number = number + ''
|
||||
|
||||
while (number.length < length) {
|
||||
number = '0' + number
|
||||
}
|
||||
|
||||
return number
|
||||
}
|
||||
|
||||
/** @description 全局变量id */
|
||||
export const context = {
|
||||
id: 1000
|
||||
}
|
||||
43
src/uni_modules/wot-design-uni/components/mixins/basic.js
Normal file
43
src/uni_modules/wot-design-uni/components/mixins/basic.js
Normal file
@ -0,0 +1,43 @@
|
||||
export default {
|
||||
methods: {
|
||||
$emit(...args) {
|
||||
this.triggerEvent(...args)
|
||||
},
|
||||
/**
|
||||
* @description 获取节点的样式
|
||||
* @param {String} selector -选择器
|
||||
* @param {Boolean} all -selectAll
|
||||
* @return {Promise<Object | Array<Object>>} 样式对象,或者所有节点样式的集合
|
||||
*/
|
||||
getRect(selector, all = false) {
|
||||
return new Promise((resolve) => {
|
||||
jd.createSelectorQuery()
|
||||
.in(this)
|
||||
[all ? 'selectAll' : 'select'](selector)
|
||||
.boundingClientRect((rect) => {
|
||||
if (all && Array.isArray(rect) && rect.length) {
|
||||
resolve(rect)
|
||||
}
|
||||
|
||||
if (!all && rect) {
|
||||
resolve(rect)
|
||||
}
|
||||
})
|
||||
.exec()
|
||||
})
|
||||
},
|
||||
/**
|
||||
* @default 模拟 requestAnimationFrame,支持 Promise 嵌套。
|
||||
* @param {Function} cb 下一渲染帧的回调
|
||||
*/
|
||||
requestAnimationFrame(cb = () => void 0) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (typeof cb !== 'function' || !this || !('setData' in this)) return reject
|
||||
this.setData({}, () => {
|
||||
resolve()
|
||||
cb()
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
24
src/uni_modules/wot-design-uni/components/mixins/cell.js
Normal file
24
src/uni_modules/wot-design-uni/components/mixins/cell.js
Normal file
@ -0,0 +1,24 @@
|
||||
export default Behavior({
|
||||
properties: {
|
||||
border: Boolean
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* @description 从cellGroup获取此组件的索引
|
||||
* @return {Number} 此组件的索引
|
||||
*/
|
||||
getIndex() {
|
||||
if (!this.parent) return
|
||||
return this.parent.children.indexOf(this)
|
||||
},
|
||||
/**
|
||||
* @description 为所有索引非0的组件设置刘海线,此方法由cellGroup调用
|
||||
*/
|
||||
setIndexAndStatus(border) {
|
||||
const index = this.getIndex()
|
||||
this.setData({
|
||||
border: border && index
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
237
src/uni_modules/wot-design-uni/components/mixins/popover.js
Normal file
237
src/uni_modules/wot-design-uni/components/mixins/popover.js
Normal file
@ -0,0 +1,237 @@
|
||||
import { pushToQueue, removeFromQueue, closeOther } from '../common/clickoutside'
|
||||
|
||||
/**
|
||||
* @description 注意点:
|
||||
* 1. 需要控制的位置: 12个
|
||||
* 2. 每一个位置改变都需要控制:
|
||||
* popLeft(弹出坐标x)/ popTop(弹出坐标Y)/ arrowStyle(三角形位置以及尖角朝向)
|
||||
* 尖角样式朝向class控制,位置用js控制
|
||||
* @param {String} [placement=bottom] - Placement of the popper accepted values: top(-start, -end), right(-start, -end), bottom(-start, -end), left(-start, -end)
|
||||
* @param {Number} [offset=5] - Amount of pixels the popper will be shifted (can be negative).
|
||||
* @param {Boolean} [visibleArrow=false] Visibility of the arrow
|
||||
* @param {Boolean} [value=false] Visibility of the component
|
||||
* @param {Boolean} [disabled=false] Disabled to change.
|
||||
*/
|
||||
|
||||
export default function () {
|
||||
return {
|
||||
externalClasses: ['custom-arrow', 'custom-pop'],
|
||||
|
||||
data: {
|
||||
popStyle: {},
|
||||
arrowStyle: {},
|
||||
showStyle: ''
|
||||
},
|
||||
|
||||
props: {
|
||||
visibleArrow: {
|
||||
type: Boolean,
|
||||
value: true
|
||||
},
|
||||
// 显示内容 String || Array
|
||||
content: {
|
||||
type: null,
|
||||
observer(newVal) {
|
||||
const { mode, selector } = this.data
|
||||
// 类型校验,支持所有值(除null、undefined。undefined建议统一写成void (0)防止全局undefined被覆盖)
|
||||
if (newVal === null || newVal === undefined) {
|
||||
throw Error("value can't be null or undefined")
|
||||
}
|
||||
if (selector === 'popover' && mode === 'normal' && typeof newVal !== 'string') {
|
||||
throw Error('The value type must be a string type in normal mode')
|
||||
} else if (selector === 'popover' && mode === 'menu' && this.checkType(newVal) !== 'Array') {
|
||||
throw Error('The value type must be a Array type in menu mode')
|
||||
}
|
||||
}
|
||||
},
|
||||
placement: {
|
||||
type: String,
|
||||
value: 'bottom'
|
||||
},
|
||||
offset: {
|
||||
type: Number,
|
||||
value: 0
|
||||
},
|
||||
useContentSlot: {
|
||||
type: Boolean,
|
||||
value: false
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
value: false
|
||||
},
|
||||
showClose: {
|
||||
type: Boolean,
|
||||
value: false
|
||||
},
|
||||
show: {
|
||||
type: Boolean,
|
||||
observer(newValue, oldValue) {
|
||||
if (newValue) {
|
||||
this.control()
|
||||
closeOther(this)
|
||||
}
|
||||
this.setData({ showStyle: newValue ? 'display: inline-block;' : 'display: none;' })
|
||||
this.$emit('change', { show: newValue })
|
||||
this.$emit(`${newValue ? 'open' : 'close'}`)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.init()
|
||||
},
|
||||
|
||||
beforeCreate() {
|
||||
pushToQueue(this)
|
||||
},
|
||||
|
||||
created() {
|
||||
this.setData({ showStyle: this.data.show ? 'opacity: 1;' : 'opacity: 0;' })
|
||||
},
|
||||
|
||||
destroyed() {
|
||||
removeFromQueue(this)
|
||||
},
|
||||
|
||||
methods: {
|
||||
noop() {},
|
||||
|
||||
open() {
|
||||
this.setData({ show: true })
|
||||
},
|
||||
|
||||
close() {
|
||||
this.setData({ show: false })
|
||||
},
|
||||
|
||||
init() {
|
||||
// 初始化 class
|
||||
const { placement, visibleArrow, selector } = this.data
|
||||
if (visibleArrow) {
|
||||
let arrowClass = [
|
||||
`wd-${selector}__arrow`,
|
||||
placement === 'bottom' || placement === 'bottom-start' || placement === 'bottom-end' ? `wd-${selector}__arrow-up` : '',
|
||||
placement === 'left' || placement === 'left-start' || placement === 'left-end' ? `wd-${selector}__arrow-right` : '',
|
||||
placement === 'right' || placement === 'right-start' || placement === 'right-end' ? `wd-${selector}__arrow-left` : '',
|
||||
placement === 'top' || placement === 'top-start' || placement === 'top-end' ? `wd-${selector}__arrow-down` : ''
|
||||
]
|
||||
arrowClass = arrowClass.join(' ')
|
||||
this.setData({ arrowClass })
|
||||
}
|
||||
|
||||
// 初始化数据获取
|
||||
this.getRect('#target').then((rect) => {
|
||||
if (!rect) return
|
||||
this.left = rect.left
|
||||
this.bottom = rect.bottom
|
||||
this.width = rect.width
|
||||
this.height = rect.height
|
||||
this.top = rect.top
|
||||
})
|
||||
// 用透明度可在初始化时获取到pop尺寸
|
||||
this.getRect('#pos').then((rect) => {
|
||||
if (!rect) return
|
||||
this.popWidth = rect.width
|
||||
this.popHeight = rect.height
|
||||
})
|
||||
},
|
||||
|
||||
toggle(event) {
|
||||
if (this.data.disabled) return
|
||||
const { show } = this.data
|
||||
this.setData({ show: !show })
|
||||
},
|
||||
|
||||
checkType(value) {
|
||||
return Object.prototype.toString.call(value).slice(8, -1)
|
||||
},
|
||||
|
||||
control() {
|
||||
const { placement, offset } = this.data
|
||||
// arrow size
|
||||
const arrowSize = 9
|
||||
// 上下位(纵轴)对应的距离左边的距离
|
||||
const verticalX = this.width / 2
|
||||
// 上下位(纵轴)对应的距离底部的距离
|
||||
const verticalY = arrowSize + this.height + 5
|
||||
// 左右位(横轴)对应的距离左边的距离
|
||||
const horizontalX = this.width + arrowSize + 5
|
||||
// 左右位(横轴)对应的距离底部的距离
|
||||
const horizontalY = this.height / 2
|
||||
|
||||
const offsetX = (verticalX - 17 > 0 ? 0 : verticalX - 25) + offset
|
||||
const offsetY = (horizontalY - 17 > 0 ? 0 : horizontalY - 25) + offset
|
||||
|
||||
const placements = new Map([
|
||||
// 上
|
||||
['top', [`left: ${verticalX}px; bottom: ${verticalY}px; transform: translateX(-50%);`, 'left: 50%;']],
|
||||
[
|
||||
'top-start',
|
||||
[
|
||||
`left: ${offsetX}px; bottom: ${verticalY}px;`,
|
||||
`left: ${(this.popWidth >= this.width ? this.width / 2 : this.popWidth - 25) - offsetX}px;`
|
||||
]
|
||||
],
|
||||
[
|
||||
'top-end',
|
||||
[
|
||||
`right: ${offsetX}px; bottom: ${verticalY}px;`,
|
||||
`right: ${(this.popWidth >= this.width ? this.width / 2 : this.popWidth - 25) - offsetX}px; transform: translateX(50%);`
|
||||
]
|
||||
],
|
||||
// 下
|
||||
['bottom', [`left: ${verticalX}px; top: ${verticalY}px; transform: translateX(-50%);`, 'left: 50%;']],
|
||||
[
|
||||
'bottom-start',
|
||||
[`left: ${offsetX}px; top: ${verticalY}px;`, `left: ${(this.popWidth >= this.width ? this.width / 2 : this.popWidth - 25) - offsetX}px;`]
|
||||
],
|
||||
[
|
||||
'bottom-end',
|
||||
[
|
||||
`right: ${offsetX}px; top: ${verticalY}px;`,
|
||||
`right: ${(this.popWidth >= this.width ? this.width / 2 : this.popWidth - 25) - offsetX}px; transform: translateX(50%);`
|
||||
]
|
||||
],
|
||||
// 左
|
||||
['left', [`right: ${horizontalX}px; top: ${horizontalY}px; transform: translateY(-50%);`, 'top: 50%']],
|
||||
[
|
||||
'left-start',
|
||||
[
|
||||
`right: ${horizontalX}px; top: ${offsetY}px;`,
|
||||
`top: ${(this.popHeight >= this.height ? this.height / 2 : this.popHeight - 20) - offsetY}px;`
|
||||
]
|
||||
],
|
||||
[
|
||||
'left-end',
|
||||
[
|
||||
`right: ${horizontalX}px; bottom: ${offsetY}px;`,
|
||||
`bottom: ${(this.popHeight >= this.height ? this.height / 2 : this.popHeight - 20) - offsetY}px; transform: translateY(50%);`
|
||||
]
|
||||
],
|
||||
// 右
|
||||
['right', [`left: ${horizontalX}px; top: ${horizontalY}px; transform: translateY(-50%);`, 'top: 50%']],
|
||||
[
|
||||
'right-start',
|
||||
[
|
||||
`left: ${horizontalX}px; top: ${offsetY}px;`,
|
||||
`top: ${(this.popHeight >= this.height ? this.height / 2 : this.popHeight - 20) - offsetY}px;`
|
||||
]
|
||||
],
|
||||
[
|
||||
'right-end',
|
||||
[
|
||||
`left: ${horizontalX}px; bottom: ${offsetY}px;`,
|
||||
`bottom: ${(this.popHeight >= this.height ? this.height / 2 : this.popHeight - 20) - offsetY}px; transform: translateY(50%);`
|
||||
]
|
||||
]
|
||||
])
|
||||
|
||||
this.setData({
|
||||
popStyle: placements.get(placement)[0],
|
||||
arrowStyle: placements.get(placement)[1]
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
25
src/uni_modules/wot-design-uni/components/mixins/touch.js
Normal file
25
src/uni_modules/wot-design-uni/components/mixins/touch.js
Normal file
@ -0,0 +1,25 @@
|
||||
export default function () {
|
||||
return {
|
||||
methods: {
|
||||
touchStart(event) {
|
||||
const touch = event.touches[0]
|
||||
this.direction = ''
|
||||
this.deltaX = 0
|
||||
this.deltaY = 0
|
||||
this.offsetX = 0
|
||||
this.offsetY = 0
|
||||
this.startX = touch.clientX
|
||||
this.startY = touch.clientY
|
||||
},
|
||||
|
||||
touchMove(event) {
|
||||
const touch = event.touches[0]
|
||||
this.deltaX = touch.clientX - this.startX
|
||||
this.deltaY = touch.clientY - this.startY
|
||||
this.offsetX = Math.abs(this.deltaX)
|
||||
this.offsetY = Math.abs(this.deltaY)
|
||||
this.direction = this.offsetX > this.offsetY ? 'horizontal' : this.offsetX < this.offsetY ? 'vertical' : ''
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
160
src/uni_modules/wot-design-uni/components/mixins/transition.ts
Normal file
160
src/uni_modules/wot-design-uni/components/mixins/transition.ts
Normal file
@ -0,0 +1,160 @@
|
||||
import { onBeforeMount, ref, watch } from 'vue'
|
||||
import { isObj } from '../common/util'
|
||||
|
||||
const getClassNames = (name) => {
|
||||
if (!name) {
|
||||
return {
|
||||
enter: 'enter-class enter-active-class',
|
||||
'enter-to': 'enter-to-class enter-active-class',
|
||||
leave: 'leave-class leave-active-class',
|
||||
'leave-to': 'leave-to-class leave-active-class'
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
enter: `wd-${name}-enter wd-${name}-enter-active`,
|
||||
'enter-to': `wd-${name}-enter-to wd-${name}-enter-active`,
|
||||
leave: `wd-${name}-leave wd-${name}-leave-active`,
|
||||
'leave-to': `wd-${name}-leave-to wd-${name}-leave-active`
|
||||
}
|
||||
}
|
||||
|
||||
const requestAnimationFrame = (cb = () => void 0) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
uni
|
||||
.createSelectorQuery()
|
||||
.selectViewport()
|
||||
.boundingClientRect()
|
||||
.exec(() => {
|
||||
resolve(true)
|
||||
cb()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
type TransitionName =
|
||||
| 'fade'
|
||||
| 'fade-down'
|
||||
| 'fade-left'
|
||||
| 'fade-right'
|
||||
| 'fade-up'
|
||||
| 'slide-down'
|
||||
| 'slide-left'
|
||||
| 'slide-right'
|
||||
| 'slide-up'
|
||||
| 'zoom-in'
|
||||
| 'zoom-out'
|
||||
|
||||
interface Props {
|
||||
show: boolean
|
||||
duration?: Record<string, number> | number
|
||||
name: TransitionName
|
||||
customStyle: string
|
||||
lazyRender: boolean
|
||||
// 定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。
|
||||
enterClass?: string
|
||||
// 定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。
|
||||
enterActiveClass?: string
|
||||
// 定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 enter-class 被移除),在过渡/动画完成之后移除。
|
||||
enterToClass?: string
|
||||
// 定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。
|
||||
leaveClass?: string
|
||||
// 定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。
|
||||
leaveActiveClass?: string
|
||||
// 定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 leave-class 被删除),在过渡/动画完成之后移除。
|
||||
leaveToClass?: string
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
show: false,
|
||||
name: 'fade',
|
||||
duration: 300,
|
||||
lazyRender: true
|
||||
})
|
||||
|
||||
// 初始化是否完成
|
||||
const inited = ref<boolean>(false)
|
||||
// 是否显示
|
||||
const display = ref<boolean>(false)
|
||||
// 当前动画状态
|
||||
const status = ref<string>('')
|
||||
// 动画是否结束
|
||||
const transitionEnded = ref<boolean>(false)
|
||||
// 动画持续时间
|
||||
const currentDuration = ref<number>(300)
|
||||
// 类名
|
||||
const classes = ref<string>('')
|
||||
|
||||
const emit = defineEmits(['click', 'before-enter', 'enter', 'before-leave', 'leave', 'after-leave', 'after-enter'])
|
||||
|
||||
onBeforeMount(() => {
|
||||
if (props.show) {
|
||||
enter()
|
||||
}
|
||||
})
|
||||
|
||||
watch(
|
||||
() => props.show,
|
||||
(newVal) => {
|
||||
observerShow(newVal)
|
||||
}
|
||||
)
|
||||
|
||||
function observerShow(value: boolean) {
|
||||
value ? enter() : leave()
|
||||
}
|
||||
|
||||
function enter() {
|
||||
const classNames = getClassNames(props.name)
|
||||
const duration = isObj(props.duration) ? (props.duration as any).enter : props.duration
|
||||
status.value = 'enter'
|
||||
emit('before-enter')
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
emit('enter')
|
||||
classes.value = classNames.enter
|
||||
currentDuration.value = duration
|
||||
requestAnimationFrame(() => {
|
||||
inited.value = true
|
||||
display.value = true
|
||||
requestAnimationFrame(() => {
|
||||
transitionEnded.value = false
|
||||
classes.value = classNames['enter-to']
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
function leave() {
|
||||
if (!display.value) return
|
||||
const classNames = getClassNames(props.name)
|
||||
const duration = isObj(props.duration) ? (props.duration as any).leave : props.duration
|
||||
status.value = 'leave'
|
||||
emit('before-leave')
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
emit('leave')
|
||||
classes.value = classNames.leave
|
||||
currentDuration.value = duration
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
transitionEnded.value = false
|
||||
setTimeout(() => onTransitionEnd(), currentDuration.value)
|
||||
classes.value = classNames['leave-to']
|
||||
})
|
||||
})
|
||||
}
|
||||
function onTransitionEnd() {
|
||||
if (transitionEnded.value) return
|
||||
|
||||
transitionEnded.value = true
|
||||
if (status.value === 'leave') {
|
||||
// 离开后触发
|
||||
emit('after-leave')
|
||||
} else if (status.value === 'enter') {
|
||||
// 进入后触发
|
||||
emit('after-enter')
|
||||
}
|
||||
if (!props.show && display.value) {
|
||||
display.value = false
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,101 @@
|
||||
import VueComponent from '../common/component'
|
||||
|
||||
VueComponent({
|
||||
externalClasses: ['custom-header-class'],
|
||||
props: {
|
||||
show: Boolean,
|
||||
actions: {
|
||||
type: Array,
|
||||
value: []
|
||||
},
|
||||
panels: {
|
||||
type: Array,
|
||||
value: [],
|
||||
observer: 'computedValue'
|
||||
},
|
||||
title: String,
|
||||
cancelText: String,
|
||||
closeOnClickAction: {
|
||||
type: Boolean,
|
||||
value: true
|
||||
},
|
||||
closeOnClickModal: {
|
||||
type: Boolean,
|
||||
value: true
|
||||
},
|
||||
duration: {
|
||||
type: Number,
|
||||
value: 200
|
||||
},
|
||||
zIndex: {
|
||||
type: Number,
|
||||
value: 10
|
||||
},
|
||||
lazyRender: {
|
||||
type: Boolean,
|
||||
value: true
|
||||
},
|
||||
safeAreaInsetBottom: {
|
||||
type: Boolean,
|
||||
value: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
formatPanels: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
isArray() {
|
||||
return this.data.panels.length && !(this.data.panels[0] instanceof Array)
|
||||
},
|
||||
computedValue() {
|
||||
this.setData({
|
||||
formatPanels: this.isArray() ? [this.data.panels] : this.data.panels
|
||||
})
|
||||
},
|
||||
select(event) {
|
||||
const { rowIndex, colIndex, type } = event.currentTarget.dataset
|
||||
if (type === 'action') {
|
||||
this.$emit('select', {
|
||||
item: this.data.actions[rowIndex],
|
||||
index: rowIndex
|
||||
})
|
||||
} else if (this.isArray()) {
|
||||
this.$emit('select', {
|
||||
item: this.data.panels[colIndex],
|
||||
index: colIndex
|
||||
})
|
||||
} else {
|
||||
this.$emit('select', {
|
||||
item: this.data.panels[rowIndex][colIndex],
|
||||
rowIndex,
|
||||
colIndex
|
||||
})
|
||||
}
|
||||
this.close()
|
||||
},
|
||||
handleClickModal() {
|
||||
this.$emit('clickmodal')
|
||||
if (this.data.closeOnClickModal) {
|
||||
this.close()
|
||||
}
|
||||
},
|
||||
handleCancel() {
|
||||
this.$emit('cancel')
|
||||
this.close()
|
||||
},
|
||||
close() {
|
||||
this.$emit('close')
|
||||
},
|
||||
handleOpen() {
|
||||
this.$emit('open')
|
||||
},
|
||||
handleOpened() {
|
||||
this.$emit('opened')
|
||||
},
|
||||
handleClosed() {
|
||||
this.$emit('closed')
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -0,0 +1,8 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
"wd-icon": "../icon/index",
|
||||
"wd-loading": "../loading/index",
|
||||
"wd-popup": "../popup/index"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,67 @@
|
||||
<wd-popup
|
||||
custom-class="wd-action-sheet__popup"
|
||||
custom-style="{{ (actions && actions.length || panels && panels.length) ? 'background: transparent;' : '' }}"
|
||||
show="{{ show }}"
|
||||
duration="{{ duration }}"
|
||||
position="bottom"
|
||||
close-on-click-modal="{{ closeOnClickModal }}"
|
||||
safe-area-inset-bottom="{{ safeAreaInsetBottom }}"
|
||||
lazy-render="{{ lazyRender }}"
|
||||
bind:enter="handleOpen"
|
||||
bind:close="close"
|
||||
bind:afterenter="handleOpened"
|
||||
bind:afterleave="handleClosed"
|
||||
z-index="{{ zIndex }}"
|
||||
>
|
||||
<view class="wd-action-sheet" style="{{ (actions && actions.length || panels && panels.length) ? 'margin: 0 10px 10px; border-radius: 16px;' : '' }}">
|
||||
<view v-if="{{ title }}" class="wd-action-sheet__header custom-header-class">
|
||||
{{ title }}
|
||||
<wd-icon custom-class="wd-action-sheet__close" name="add" bind:tap="close"/>
|
||||
</view>
|
||||
<view class="wd-action-sheet__actions" v-if="{{ actions && actions.length }}">
|
||||
<button
|
||||
jd:for="{{ actions }}"
|
||||
jd:key="rowIndex"
|
||||
class="wd-action-sheet__action {{ item.disabled ? 'wd-action-sheet__action--disabled' : '' }} {{ item.loading ? 'wd-action-sheet__action--loading' : '' }}"
|
||||
style="color: {{ item.color }}"
|
||||
jd:for-index="rowIndex"
|
||||
data-row-index="{{ rowIndex }}"
|
||||
data-type = "action"
|
||||
bind:tap="select"
|
||||
>
|
||||
<wd-loading v-if="{{ item.loading }}" size="20px"/>
|
||||
<view v-else class="wd-action-sheet__name">{{ item.name }}</view>
|
||||
<view v-if="{{ !item.loading && item.subname }}" class="wd-action-sheet__subname">{{ item.subname }}</view>
|
||||
</button>
|
||||
</view>
|
||||
<view v-if="{{ formatPanels && formatPanels.length }}">
|
||||
<view
|
||||
jd:for="{{ formatPanels }}"
|
||||
data-index="{{ rowIndex }}"
|
||||
jd:for-item="item"
|
||||
jd:for-index="rowIndex"
|
||||
jd:key="rowIndex"
|
||||
class="wd-action-sheet__panels"
|
||||
>
|
||||
<view class="wd-action-sheet__panels-content">
|
||||
<view
|
||||
jd:for="{{ item }}"
|
||||
data-col-index="{{ colIndex }}"
|
||||
data-row-index="{{ rowIndex }}"
|
||||
data-type = "panels"
|
||||
jd:for-item="panel"
|
||||
jd:for-index="colIndex"
|
||||
jd:key="colIndex"
|
||||
class="wd-action-sheet__panel"
|
||||
bind:tap="select"
|
||||
>
|
||||
<image class="wd-action-sheet__panel-img" src="{{ panel.iconUrl }}" />
|
||||
<view class="wd-action-sheet__panel-title">{{ panel.title }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<slot />
|
||||
<button v-if="{{ cancelText }}" class="wd-action-sheet__cancel" bind:tap="handleCancel">{{ cancelText }}</button>
|
||||
</view>
|
||||
</wd-popup>
|
||||
@ -0,0 +1,147 @@
|
||||
@import '../common/abstracts/variable';
|
||||
@import '../common/abstracts/mixin';
|
||||
|
||||
@include b(action-sheet) {
|
||||
background-color: #fff;
|
||||
padding-bottom: 1px;
|
||||
|
||||
@include e(popup) {
|
||||
border-radius: $-action-sheet-radius $-action-sheet-radius 0 0;
|
||||
}
|
||||
@include e(actions) {
|
||||
padding: 8px 0;
|
||||
max-height: 50vh;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
@include e(action) {
|
||||
position: relative;
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: $-action-sheet-action-height;
|
||||
line-height: $-action-sheet-action-height;
|
||||
color: $-action-sheet-color;
|
||||
font-size: $-action-sheet-fs;
|
||||
text-align: center;
|
||||
border: none;
|
||||
background: $-action-sheet-bg;
|
||||
outline: none;
|
||||
|
||||
&:after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: $-action-sheet-active-color;
|
||||
}
|
||||
|
||||
@include m(disabled) {
|
||||
color: $-action-sheet-disabled-color;
|
||||
}
|
||||
|
||||
@include m(loading) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
line-height: initial;
|
||||
}
|
||||
}
|
||||
|
||||
@include e(name) {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
@include e(subname) {
|
||||
display: inline-block;
|
||||
margin-left: 4px;
|
||||
font-size: $-action-sheet-subname-fs;
|
||||
color: $-action-sheet-subname-color;
|
||||
}
|
||||
|
||||
@include e(cancel) {
|
||||
display: block;
|
||||
width: calc(100% - 48px);
|
||||
line-height: $-action-sheet-cancel-height;
|
||||
padding: 0;
|
||||
color: $-action-sheet-cancel-color;
|
||||
font-size: $-action-sheet-fs;
|
||||
text-align: center;
|
||||
border-radius: $-action-sheet-cancel-radius;
|
||||
border: none;
|
||||
background: $-action-sheet-cancel-bg;
|
||||
outline: none;
|
||||
margin: 0 auto 24px;
|
||||
font-weight: $-action-sheet-weight;
|
||||
|
||||
&:active {
|
||||
background: $-action-sheet-active-color;
|
||||
}
|
||||
|
||||
&:after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@include e(header) {
|
||||
color: $-action-sheet-color;
|
||||
position: relative;
|
||||
height: $-action-sheet-title-height;
|
||||
line-height: $-action-sheet-title-height;
|
||||
text-align: center;
|
||||
font-size: $-action-sheet-title-fs;
|
||||
font-weight: $-action-sheet-weight;
|
||||
}
|
||||
|
||||
@include e(close) {
|
||||
position: absolute;
|
||||
top: $-action-sheet-close-top;
|
||||
right: $-action-sheet-close-right;
|
||||
color: $-action-sheet-close-color;
|
||||
font-size: $-action-sheet-close-fs;
|
||||
transform: rotate(-45deg);
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
@include e(panels) {
|
||||
height: 84px;
|
||||
overflow-y: hidden;
|
||||
|
||||
&:first-of-type {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
&:last-of-type {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
@include e(panels-content) {
|
||||
display: flex;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
@include e(panel) {
|
||||
width: 88px;
|
||||
flex: 0 0 auto;
|
||||
display: inline-block;
|
||||
padding: $-action-sheet-panel-padding;
|
||||
}
|
||||
|
||||
@include e(panel-img) {
|
||||
display: block;
|
||||
width: $-action-sheet-panel-img-fs;
|
||||
height: $-action-sheet-panel-img-fs;
|
||||
margin: 0 auto;
|
||||
margin-bottom: 7px;
|
||||
border-radius: $-action-sheet-panel-img-radius;
|
||||
}
|
||||
|
||||
@include e(panel-title) {
|
||||
font-size: $-action-sheet-subname-fs;
|
||||
line-height: 1.2;
|
||||
text-align: center;
|
||||
color: $-action-sheet-color;
|
||||
@include lineEllipsis;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,323 @@
|
||||
<template>
|
||||
<wd-popup
|
||||
custom-class="wd-action-sheet__popup"
|
||||
custom-style="{{ (actions && actions.length || panels && panels.length) ? 'background: transparent;' : '' }}"
|
||||
show="{{ show }}"
|
||||
duration="{{ duration }}"
|
||||
position="bottom"
|
||||
close-on-click-modal="{{ closeOnClickModal }}"
|
||||
safe-area-inset-bottom="{{ safeAreaInsetBottom }}"
|
||||
lazy-render="{{ lazyRender }}"
|
||||
bind:enter="handleOpen"
|
||||
bind:close="close"
|
||||
bind:afterenter="handleOpened"
|
||||
bind:afterleave="handleClosed"
|
||||
z-index="{{ zIndex }}"
|
||||
>
|
||||
<view
|
||||
class="wd-action-sheet"
|
||||
style="{{ (actions && actions.length || panels && panels.length) ? 'margin: 0 10px 10px; border-radius: 16px;' : '' }}"
|
||||
>
|
||||
<view v-if="{{ title }}" class="wd-action-sheet__header custom-header-class">
|
||||
{{ title }}
|
||||
<wd-icon custom-class="wd-action-sheet__close" name="add" bind:tap="close" />
|
||||
</view>
|
||||
<view class="wd-action-sheet__actions" v-if="{{ actions && actions.length }}">
|
||||
<button
|
||||
jd:for="{{ actions }}"
|
||||
jd:key="rowIndex"
|
||||
class="wd-action-sheet__action {{ item.disabled ? 'wd-action-sheet__action--disabled' : '' }} {{ item.loading ? 'wd-action-sheet__action--loading' : '' }}"
|
||||
style="color: {{ item.color }}"
|
||||
jd:for-index="rowIndex"
|
||||
data-row-index="{{ rowIndex }}"
|
||||
data-type="action"
|
||||
bind:tap="select"
|
||||
>
|
||||
<wd-loading v-if="{{ item.loading }}" size="20px" />
|
||||
<view v-else class="wd-action-sheet__name">{{ item.name }}</view>
|
||||
<view v-if="{{ !item.loading && item.subname }}" class="wd-action-sheet__subname">{{ item.subname }}</view>
|
||||
</button>
|
||||
</view>
|
||||
<view v-if="{{ formatPanels && formatPanels.length }}">
|
||||
<view
|
||||
jd:for="{{ formatPanels }}"
|
||||
data-index="{{ rowIndex }}"
|
||||
jd:for-item="item"
|
||||
jd:for-index="rowIndex"
|
||||
jd:key="rowIndex"
|
||||
class="wd-action-sheet__panels"
|
||||
>
|
||||
<view class="wd-action-sheet__panels-content">
|
||||
<view
|
||||
jd:for="{{ item }}"
|
||||
data-col-index="{{ colIndex }}"
|
||||
data-row-index="{{ rowIndex }}"
|
||||
data-type="panels"
|
||||
jd:for-item="panel"
|
||||
jd:for-index="colIndex"
|
||||
jd:key="colIndex"
|
||||
class="wd-action-sheet__panel"
|
||||
bind:tap="select"
|
||||
>
|
||||
<image class="wd-action-sheet__panel-img" src="{{ panel.iconUrl }}" />
|
||||
<view class="wd-action-sheet__panel-title">{{ panel.title }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<slot />
|
||||
<button v-if="{{ cancelText }}" class="wd-action-sheet__cancel" bind:tap="handleCancel">{{ cancelText }}</button>
|
||||
</view>
|
||||
</wd-popup>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
show: Boolean,
|
||||
actions: {
|
||||
type: Array,
|
||||
value: []
|
||||
},
|
||||
panels: {
|
||||
type: Array,
|
||||
value: [],
|
||||
observer: 'computedValue'
|
||||
},
|
||||
title: String,
|
||||
cancelText: String,
|
||||
closeOnClickAction: {
|
||||
type: Boolean,
|
||||
value: true
|
||||
},
|
||||
closeOnClickModal: {
|
||||
type: Boolean,
|
||||
value: true
|
||||
},
|
||||
duration: {
|
||||
type: Number,
|
||||
value: 200
|
||||
},
|
||||
zIndex: {
|
||||
type: Number,
|
||||
value: 10
|
||||
},
|
||||
lazyRender: {
|
||||
type: Boolean,
|
||||
value: true
|
||||
},
|
||||
safeAreaInsetBottom: {
|
||||
type: Boolean,
|
||||
value: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
formatPanels: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
isArray() {
|
||||
return this.data.panels.length && !(this.data.panels[0] instanceof Array)
|
||||
},
|
||||
computedValue() {
|
||||
this.setData({
|
||||
formatPanels: this.isArray() ? [this.data.panels] : this.data.panels
|
||||
})
|
||||
},
|
||||
select(event) {
|
||||
const { rowIndex, colIndex, type } = event.currentTarget.dataset
|
||||
if (type === 'action') {
|
||||
this.$emit('select', {
|
||||
item: this.data.actions[rowIndex],
|
||||
index: rowIndex
|
||||
})
|
||||
} else if (this.isArray()) {
|
||||
this.$emit('select', {
|
||||
item: this.data.panels[colIndex],
|
||||
index: colIndex
|
||||
})
|
||||
} else {
|
||||
this.$emit('select', {
|
||||
item: this.data.panels[rowIndex][colIndex],
|
||||
rowIndex,
|
||||
colIndex
|
||||
})
|
||||
}
|
||||
this.close()
|
||||
},
|
||||
handleClickModal() {
|
||||
this.$emit('clickmodal')
|
||||
if (this.data.closeOnClickModal) {
|
||||
this.close()
|
||||
}
|
||||
},
|
||||
handleCancel() {
|
||||
this.$emit('cancel')
|
||||
this.close()
|
||||
},
|
||||
close() {
|
||||
this.$emit('close')
|
||||
},
|
||||
handleOpen() {
|
||||
this.$emit('open')
|
||||
},
|
||||
handleOpened() {
|
||||
this.$emit('opened')
|
||||
},
|
||||
handleClosed() {
|
||||
this.$emit('closed')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '../common/abstracts/variable';
|
||||
@import '../common/abstracts/mixin';
|
||||
|
||||
@include b(action-sheet) {
|
||||
background-color: #fff;
|
||||
padding-bottom: 1px;
|
||||
|
||||
@include e(popup) {
|
||||
border-radius: $-action-sheet-radius $-action-sheet-radius 0 0;
|
||||
}
|
||||
@include e(actions) {
|
||||
padding: 8px 0;
|
||||
max-height: 50vh;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
@include e(action) {
|
||||
position: relative;
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: $-action-sheet-action-height;
|
||||
line-height: $-action-sheet-action-height;
|
||||
color: $-action-sheet-color;
|
||||
font-size: $-action-sheet-fs;
|
||||
text-align: center;
|
||||
border: none;
|
||||
background: $-action-sheet-bg;
|
||||
outline: none;
|
||||
|
||||
&:after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: $-action-sheet-active-color;
|
||||
}
|
||||
|
||||
@include m(disabled) {
|
||||
color: $-action-sheet-disabled-color;
|
||||
}
|
||||
|
||||
@include m(loading) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
line-height: initial;
|
||||
}
|
||||
}
|
||||
|
||||
@include e(name) {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
@include e(subname) {
|
||||
display: inline-block;
|
||||
margin-left: 4px;
|
||||
font-size: $-action-sheet-subname-fs;
|
||||
color: $-action-sheet-subname-color;
|
||||
}
|
||||
|
||||
@include e(cancel) {
|
||||
display: block;
|
||||
width: calc(100% - 48px);
|
||||
line-height: $-action-sheet-cancel-height;
|
||||
padding: 0;
|
||||
color: $-action-sheet-cancel-color;
|
||||
font-size: $-action-sheet-fs;
|
||||
text-align: center;
|
||||
border-radius: $-action-sheet-cancel-radius;
|
||||
border: none;
|
||||
background: $-action-sheet-cancel-bg;
|
||||
outline: none;
|
||||
margin: 0 auto 24px;
|
||||
font-weight: $-action-sheet-weight;
|
||||
|
||||
&:active {
|
||||
background: $-action-sheet-active-color;
|
||||
}
|
||||
|
||||
&:after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@include e(header) {
|
||||
color: $-action-sheet-color;
|
||||
position: relative;
|
||||
height: $-action-sheet-title-height;
|
||||
line-height: $-action-sheet-title-height;
|
||||
text-align: center;
|
||||
font-size: $-action-sheet-title-fs;
|
||||
font-weight: $-action-sheet-weight;
|
||||
}
|
||||
|
||||
@include e(close) {
|
||||
position: absolute;
|
||||
top: $-action-sheet-close-top;
|
||||
right: $-action-sheet-close-right;
|
||||
color: $-action-sheet-close-color;
|
||||
font-size: $-action-sheet-close-fs;
|
||||
transform: rotate(-45deg);
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
@include e(panels) {
|
||||
height: 84px;
|
||||
overflow-y: hidden;
|
||||
|
||||
&:first-of-type {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
&:last-of-type {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
@include e(panels-content) {
|
||||
display: flex;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
@include e(panel) {
|
||||
width: 88px;
|
||||
flex: 0 0 auto;
|
||||
display: inline-block;
|
||||
padding: $-action-sheet-panel-padding;
|
||||
}
|
||||
|
||||
@include e(panel-img) {
|
||||
display: block;
|
||||
width: $-action-sheet-panel-img-fs;
|
||||
height: $-action-sheet-panel-img-fs;
|
||||
margin: 0 auto;
|
||||
margin-bottom: 7px;
|
||||
border-radius: $-action-sheet-panel-img-radius;
|
||||
}
|
||||
|
||||
@include e(panel-title) {
|
||||
font-size: $-action-sheet-subname-fs;
|
||||
line-height: 1.2;
|
||||
text-align: center;
|
||||
color: $-action-sheet-color;
|
||||
@include lineEllipsis;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
39
src/uni_modules/wot-design-uni/components/wd-badge/index.js
Normal file
39
src/uni_modules/wot-design-uni/components/wd-badge/index.js
Normal file
@ -0,0 +1,39 @@
|
||||
import VueComponent from '../common/component'
|
||||
|
||||
VueComponent({
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
value: null,
|
||||
observer: 'notice'
|
||||
},
|
||||
bgColor: String,
|
||||
max: {
|
||||
type: Number,
|
||||
observer: 'notice'
|
||||
},
|
||||
isDot: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
observer: 'notice'
|
||||
},
|
||||
hidden: Boolean,
|
||||
type: String,
|
||||
top: Number,
|
||||
right: Number
|
||||
},
|
||||
data: {
|
||||
content: ''
|
||||
},
|
||||
methods: {
|
||||
notice () {
|
||||
if (this.data.isDot) return
|
||||
let value = this.data.value
|
||||
const max = this.data.max
|
||||
if (value && max && !Number.isNaN(value) && !Number.isNaN(max)) {
|
||||
value = max < value ? `${parseInt(max)}+` : value
|
||||
}
|
||||
this.setData({ content: value })
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -0,0 +1,7 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
"wd-icon": "../icon/index",
|
||||
"wd-button": "../button/index"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
<div class="wd-badge custom-class">
|
||||
<slot></slot>
|
||||
<view
|
||||
v-if="{{!hidden && (content || content === 0 || isDot)}}"
|
||||
class="wd-badge__content is-fixed {{type ? 'wd-badge__content--' + type : ''}} {{isDot?'is-dot':'' }}"
|
||||
style="background-color: {{bgColor}}; top: {{top || 0}}px; right: {{right || 0}}px">
|
||||
{{content}}
|
||||
</view>
|
||||
</div>
|
||||
@ -0,0 +1,51 @@
|
||||
@import "./../common/abstracts/_mixin.scss";
|
||||
@import "./../common/abstracts/variable.scss";
|
||||
|
||||
@include b(badge) {
|
||||
position: relative;
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
|
||||
@include e(content) {
|
||||
display: inline-block;
|
||||
height: $-badge-height;
|
||||
line-height: $-badge-height;
|
||||
padding: $-badge-padding;
|
||||
background-color: $-badge-bg;
|
||||
border-radius: calc($-badge-height / 2 + 2px);
|
||||
color: $-badge-color;
|
||||
font-size: $-badge-fs;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
border: $-badge-border;
|
||||
font-weight: 500;
|
||||
|
||||
@include when(fixed) {
|
||||
position: absolute;
|
||||
transform: translateY(-50%) translateX(50%);
|
||||
}
|
||||
|
||||
@include when(dot) {
|
||||
height: $-badge-dot-size;
|
||||
width: $-badge-dot-size;
|
||||
padding: 0;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
@each $type in (primary, success, warning, info, danger) {
|
||||
@include m($type) {
|
||||
@if $type == primary {
|
||||
background-color: $-badge-primary;
|
||||
} @else if $type == success {
|
||||
background-color: $-badge-success;
|
||||
} @else if $type == warning {
|
||||
background-color: $-badge-warning;
|
||||
} @else if $type == info {
|
||||
background-color: $-badge-info;
|
||||
} @else {
|
||||
background-color: $-badge-danger;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
108
src/uni_modules/wot-design-uni/components/wd-badge/wd-badge.vue
Normal file
108
src/uni_modules/wot-design-uni/components/wd-badge/wd-badge.vue
Normal file
@ -0,0 +1,108 @@
|
||||
<template>
|
||||
<view class="wd-badge custom-class">
|
||||
<slot></slot>
|
||||
<view
|
||||
v-if="!hidden && (content || content === 0 || isDot)"
|
||||
:class="['wd-badge__content', 'is-fixed', type ? 'wd-badge__content--' + type : '', isDot ? 'is-dot' : '']"
|
||||
:style="contentStyle"
|
||||
>
|
||||
{{ content }}
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, watch } from 'vue'
|
||||
|
||||
interface Props {
|
||||
modelValue: number | null
|
||||
bgColor?: string
|
||||
max?: number
|
||||
isDot?: boolean
|
||||
hidden?: boolean
|
||||
type?: string
|
||||
top?: number
|
||||
right?: number
|
||||
}
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
modelValue: null
|
||||
})
|
||||
const content = ref<number | null>(null)
|
||||
|
||||
watch(
|
||||
[() => props.modelValue, () => props.max, () => props.isDot],
|
||||
() => {
|
||||
notice()
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
)
|
||||
|
||||
const contentStyle = computed(() => {
|
||||
return `'background-color': ${props.bgColor};top:${props.top || 0}px; right: ${props.right || 0} px`
|
||||
})
|
||||
|
||||
function notice() {
|
||||
if (props.isDot) return
|
||||
let value = props.modelValue
|
||||
const max = props.max
|
||||
if (value && max && !Number.isNaN(value) && !Number.isNaN(max)) {
|
||||
value = max < value ? max : value
|
||||
}
|
||||
content.value = value
|
||||
}
|
||||
</script>
|
||||
|
||||
<script></script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import './../common/abstracts/_mixin.scss';
|
||||
@import './../common/abstracts/variable.scss';
|
||||
|
||||
@include b(badge) {
|
||||
position: relative;
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
|
||||
@include e(content) {
|
||||
display: inline-block;
|
||||
height: $-badge-height;
|
||||
line-height: $-badge-height;
|
||||
padding: $-badge-padding;
|
||||
background-color: $-badge-bg;
|
||||
border-radius: calc($-badge-height / 2 + 2px);
|
||||
color: $-badge-color;
|
||||
font-size: $-badge-fs;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
border: $-badge-border;
|
||||
font-weight: 500;
|
||||
|
||||
@include when(fixed) {
|
||||
position: absolute;
|
||||
transform: translateY(-50%) translateX(50%);
|
||||
}
|
||||
|
||||
@include when(dot) {
|
||||
height: $-badge-dot-size;
|
||||
width: $-badge-dot-size;
|
||||
padding: 0;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
@each $type in (primary, success, warning, info, danger) {
|
||||
@include m($type) {
|
||||
@if $type == primary {
|
||||
background-color: $-badge-primary;
|
||||
} @else if $type == success {
|
||||
background-color: $-badge-success;
|
||||
} @else if $type == warning {
|
||||
background-color: $-badge-warning;
|
||||
} @else if $type == info {
|
||||
background-color: $-badge-info;
|
||||
} @else {
|
||||
background-color: $-badge-danger;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
119
src/uni_modules/wot-design-uni/components/wd-button/index.js
Normal file
119
src/uni_modules/wot-design-uni/components/wd-button/index.js
Normal file
@ -0,0 +1,119 @@
|
||||
import VueComponent from '../common/component'
|
||||
import base64 from '../common/base64'
|
||||
|
||||
const loadingIcon = (color = '#4D80F0', reverse = true) => {
|
||||
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 42 42"><defs><linearGradient x1="100%" y1="0%" x2="0%" y2="0%" id="a"><stop stop-color="${reverse ? color : '#fff'}" offset="0%" stop-opacity="0"/><stop stop-color="${reverse ? color : '#fff'}" offset="100%"/></linearGradient></defs><g fill="none" fill-rule="evenodd"><path d="M21 1c11.046 0 20 8.954 20 20s-8.954 20-20 20S1 32.046 1 21 9.954 1 21 1zm0 7C13.82 8 8 13.82 8 21s5.82 13 13 13 13-5.82 13-13S28.18 8 21 8z" fill="${reverse ? '#fff' : color}"/><path d="M4.599 21c0 9.044 7.332 16.376 16.376 16.376 9.045 0 16.376-7.332 16.376-16.376" stroke="url(#a)" stroke-width="3.5" stroke-linecap="round"/></g></svg>`
|
||||
}
|
||||
|
||||
VueComponent({
|
||||
props: {
|
||||
plain: Boolean,
|
||||
disabled: Boolean,
|
||||
round: {
|
||||
type: Boolean,
|
||||
value: true
|
||||
},
|
||||
suck: Boolean,
|
||||
block: Boolean,
|
||||
type: {
|
||||
type: String,
|
||||
value: 'primary'
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
value: 'medium'
|
||||
},
|
||||
icon: String,
|
||||
loading: {
|
||||
type: Boolean,
|
||||
observer: 'buildLoadingSvg'
|
||||
},
|
||||
loadingColor: String,
|
||||
openType: String,
|
||||
formType: String,
|
||||
hoverStopPropagation: {
|
||||
type: Boolean,
|
||||
value: false
|
||||
},
|
||||
lang: {
|
||||
type: String,
|
||||
value: 'en'
|
||||
},
|
||||
sessionFrom: String,
|
||||
sendMessageTitle: String,
|
||||
sendMessagePath: String,
|
||||
sendMessageImg: String,
|
||||
appParameter: String,
|
||||
showMessageCard: {
|
||||
type: Boolean,
|
||||
value: false
|
||||
}
|
||||
},
|
||||
data: {
|
||||
hoverStartTime: 20,
|
||||
hoverStayTime: 70,
|
||||
loadingIconSvg: ''
|
||||
},
|
||||
methods: {
|
||||
handleClick (event) {
|
||||
if (!this.data.disabled && !this.data.loading) {
|
||||
this.$emit('click', event.detail)
|
||||
}
|
||||
},
|
||||
handleGetuserinfo (event) {
|
||||
this.$emit('getuserinfo', event.detail)
|
||||
},
|
||||
|
||||
handleConcat (event) {
|
||||
this.$emit('contact', event.detail)
|
||||
},
|
||||
|
||||
handleGetphonenumber (event) {
|
||||
this.$emit('getphonenumber', event.detail)
|
||||
},
|
||||
|
||||
handleError (event) {
|
||||
this.$emit('error', event.detail)
|
||||
},
|
||||
|
||||
handleLaunchapp (event) {
|
||||
this.$emit('launchapp', event.detail)
|
||||
},
|
||||
|
||||
handleOpensetting (event) {
|
||||
this.$emit('opensetting', event.detail)
|
||||
},
|
||||
|
||||
buildLoadingSvg () {
|
||||
const { loadingColor, type, plain } = this.data
|
||||
let color = loadingColor
|
||||
|
||||
if (!color) {
|
||||
switch (type) {
|
||||
case 'primary':
|
||||
color = '#4D80F0'
|
||||
break
|
||||
case 'success':
|
||||
color = '#34d19d'
|
||||
break
|
||||
case 'info':
|
||||
color = '#333'
|
||||
break
|
||||
case 'warning':
|
||||
color = '#f0883a'
|
||||
break
|
||||
case 'error':
|
||||
color = '#fa4350'
|
||||
break
|
||||
case 'default':
|
||||
color = '#333'
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const svg = loadingIcon(color, !plain)
|
||||
const svgStr = `"data:image/svg+xml;base64,${base64(svg)}"`
|
||||
this.setData({ loadingIconSvg: svgStr })
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -0,0 +1,7 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
"wd-icon": "../icon/index",
|
||||
"wd-loading": "../loading/index"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
<button
|
||||
hover-class="wd-button--active"
|
||||
class="wd-button custom-class is-{{type}} is-{{size}} {{ plain ? 'is-plain' : '' }} {{ disabled ? 'is-disabled' : '' }} {{ round ? 'is-round' : '' }} {{ suck ? 'is-suck' : '' }} {{ block ? 'is-block' : '' }} {{ loading ? 'is-loading' : '' }}"
|
||||
open-type="{{ openType }}"
|
||||
send-message-title="{{sendMessageTitle}}"
|
||||
send-message-path="{{sendMessagePath}}"
|
||||
send-message-img="{{sendMessageImg}}"
|
||||
app-parameter="{{appParameter}}"
|
||||
show-message-card="{{showMessageCard}}"
|
||||
session-from="{{sessionFrom}}"
|
||||
session-message-title="{{sessionMessageTitle}}"
|
||||
session-message-path="{{sessionMessagePath}}"
|
||||
session-message-img="{{sessionMessageImg}}"
|
||||
lang="{{lang}}"
|
||||
hover-stop-propagation="{{hoverStopPropagation}}"
|
||||
form-type="{{formType}}"
|
||||
bindtap="handleClick"
|
||||
bindgetuserinfo="handleGetuserinfo"
|
||||
bindcontact="handleConcat"
|
||||
bindgetphonenumber="handleGetphonenumber"
|
||||
binderror="handleError"
|
||||
bindlaunchapp="handleLaunchapp"
|
||||
bindopensetting="handleOpensetting"
|
||||
>
|
||||
<view v-if="{{loading}}" class="wd-button__loading">
|
||||
<view class="wd-button__loading-svg" style="background-image: url({{loadingIconSvg}});"></view>
|
||||
</view>
|
||||
<wd-icon v-if="{{icon}}" class="wd-button__icon" name="{{icon}}" ></wd-icon>
|
||||
<view class="wd-button__text"><slot/></view>
|
||||
</button>
|
||||
503
src/uni_modules/wot-design-uni/components/wd-button/index.scss
Normal file
503
src/uni_modules/wot-design-uni/components/wd-button/index.scss
Normal file
@ -0,0 +1,503 @@
|
||||
@import "./../common/abstracts/_mixin.scss";
|
||||
@import "./../common/abstracts/variable.scss";
|
||||
|
||||
@mixin button-type-style($color, $normal, $active, $disabled, $disabledcolor) {
|
||||
background: $normal;
|
||||
color: $color;
|
||||
font-weight: $-fw-medium;
|
||||
|
||||
&::after {
|
||||
border-color: $normal;
|
||||
}
|
||||
&.wd-button--active {
|
||||
background: $active;
|
||||
}
|
||||
@include when(disabled) {
|
||||
&.wd-button--active {
|
||||
background: $disabled;
|
||||
color: $disabledcolor;
|
||||
}
|
||||
|
||||
background: $disabled;
|
||||
color: $disabledcolor;
|
||||
|
||||
&::after {
|
||||
border-color: $disabled;
|
||||
}
|
||||
}
|
||||
@include when(loading) {
|
||||
&,
|
||||
&.wd-button--active {
|
||||
color: $color;
|
||||
background: $normal;
|
||||
}
|
||||
&::after {
|
||||
border-color: $normal;
|
||||
}
|
||||
}
|
||||
@include when(suck) {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin button-plain-style($color, $normal, $active, $disabled) {
|
||||
color: $color;
|
||||
background: transparent;
|
||||
|
||||
&::after {
|
||||
border-color: $normal;
|
||||
}
|
||||
&.wd-button--active {
|
||||
color: $active;
|
||||
background: transparent;
|
||||
|
||||
&::after {
|
||||
border-color: $active;
|
||||
}
|
||||
}
|
||||
@include when(disabled) {
|
||||
color: $disabled;
|
||||
background: transparent;
|
||||
|
||||
&::after {
|
||||
border-color: $disabled;
|
||||
}
|
||||
&.wd-button--active {
|
||||
background: transparent;
|
||||
|
||||
&::after {
|
||||
border-color: $disabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
@include when(loading) {
|
||||
&,
|
||||
&.wd-button--active {
|
||||
color: $color;
|
||||
background: transparent;
|
||||
|
||||
&::after {
|
||||
border-color: $normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@include b(button) {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
outline: none;
|
||||
-webkit-appearance: none;
|
||||
outline: none;
|
||||
background: transparent;
|
||||
box-sizing: border-box;
|
||||
border: none;
|
||||
color: $-button-normal-color;
|
||||
transition: all 0.2s;
|
||||
user-select: none;
|
||||
font-weight: normal;
|
||||
|
||||
&::after {
|
||||
display: none;
|
||||
}
|
||||
&.wd-button--active {
|
||||
color: $-button-normal-active-color;
|
||||
background: $-button-normal-active-bg;
|
||||
|
||||
&::after {
|
||||
border-color: $-button-normal-border-active-color;
|
||||
}
|
||||
}
|
||||
@include when(disabled) {
|
||||
color: $-button-normal-disabled-color;
|
||||
background: $-button-normal-disabled-bg;
|
||||
|
||||
&::after {
|
||||
border-color: $-button-normal-border-disabled-color;
|
||||
}
|
||||
&.wd-button--active {
|
||||
color: $-button-normal-disabled-color;
|
||||
background: $-button-normal-disabled-bg;
|
||||
|
||||
&::after {
|
||||
border-color: $-button-normal-border-disabled-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include e(loading) {
|
||||
margin-right: 5px;
|
||||
animation: wd-rotate 0.8s linear infinite;
|
||||
animation-duration: 2s;
|
||||
}
|
||||
@include e(loading-svg) {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
@include when(loading) {
|
||||
&.wd-button--active {
|
||||
color: $-button-normal-color;
|
||||
background: transparent;
|
||||
|
||||
&::after {
|
||||
border-color: $-button-border-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include when(primary) {
|
||||
@include button-type-style(
|
||||
$-color-white,
|
||||
$-button-primary-bg-color,
|
||||
$-button-primary-active-color,
|
||||
$-button-primary-disabled-color,
|
||||
$-color-white
|
||||
);
|
||||
}
|
||||
@include when(success) {
|
||||
@include button-type-style(
|
||||
$-color-white,
|
||||
$-button-success-color,
|
||||
$-button-success-active-color,
|
||||
$-button-success-disabled-color,
|
||||
$-color-white
|
||||
);
|
||||
}
|
||||
@include when(info) {
|
||||
@include button-type-style(
|
||||
$-button-info-color,
|
||||
$-button-info-bg-color,
|
||||
$-button-info-active-bg-color,
|
||||
$-button-info-disabled-bg-color,
|
||||
$-button-info-disabled-color
|
||||
);
|
||||
}
|
||||
@include when(warning) {
|
||||
@include button-type-style(
|
||||
$-color-white,
|
||||
$-button-warning-color,
|
||||
$-button-warning-active-color,
|
||||
$-button-warning-disabled-color,
|
||||
$-color-white
|
||||
);
|
||||
}
|
||||
@include when(error) {
|
||||
@include button-type-style(
|
||||
$-color-white,
|
||||
$-button-error-color,
|
||||
$-button-error-active-color,
|
||||
$-button-error-disabled-color,
|
||||
$-color-white
|
||||
);
|
||||
}
|
||||
|
||||
@include when(small) {
|
||||
height: $-button-small-height;
|
||||
padding: $-button-small-padding;
|
||||
border-radius: $-button-small-radius;
|
||||
font-size: $-button-small-fs;
|
||||
font-weight: normal;
|
||||
|
||||
@include when(round) {
|
||||
border-radius: calc($-button-small-height / 2);
|
||||
|
||||
&::after {
|
||||
border-radius: $-button-small-height;
|
||||
}
|
||||
}
|
||||
|
||||
.wd-button__loading {
|
||||
width: $-button-small-loading;
|
||||
height: $-button-small-loading;
|
||||
}
|
||||
}
|
||||
|
||||
@include when(medium) {
|
||||
height: $-button-medium-height;
|
||||
padding: $-button-medium-padding;
|
||||
border-radius: $-button-medium-radius;
|
||||
font-size: $-button-medium-fs;
|
||||
|
||||
&::after {
|
||||
border-radius: $-button-medium-radius * 2;
|
||||
}
|
||||
@include when(primary) {
|
||||
box-shadow: $-button-medium-box-shadow-size $-button-primary-box-shadow-color;
|
||||
}
|
||||
|
||||
@include when(success) {
|
||||
box-shadow: $-button-medium-box-shadow-size $-button-success-box-shadow-color;
|
||||
}
|
||||
|
||||
@include when(warning) {
|
||||
box-shadow: $-button-medium-box-shadow-size $-button-warning-box-shadow-color;
|
||||
}
|
||||
|
||||
@include when(error) {
|
||||
box-shadow: $-button-medium-box-shadow-size $-button-error-box-shadow-color;
|
||||
}
|
||||
|
||||
@include when(plain) {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
@include when(round) {
|
||||
min-width: 118px;
|
||||
border-radius: calc($-button-medium-height / 2);
|
||||
|
||||
&::after {
|
||||
border-radius: $-button-medium-height;
|
||||
}
|
||||
@include when(icon) {
|
||||
min-width: 0;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
@include when(text) {
|
||||
min-width: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.wd-button__loading {
|
||||
width: $-button-medium-loading;
|
||||
height: $-button-medium-loading;
|
||||
}
|
||||
}
|
||||
@include when(large) {
|
||||
height: $-button-large-height;
|
||||
padding: $-button-large-padding;
|
||||
border-radius: $-button-large-radius;
|
||||
font-size: $-button-large-fs;
|
||||
|
||||
&::after {
|
||||
border-radius: $-button-large-radius * 2;
|
||||
}
|
||||
&:not(.is-plain) {
|
||||
@include when(primary) {
|
||||
box-shadow: $-button-large-box-shadow-size $-button-primary-box-shadow-color;
|
||||
}
|
||||
|
||||
@include when(success) {
|
||||
box-shadow: $-button-large-box-shadow-size $-button-success-box-shadow-color;
|
||||
}
|
||||
|
||||
@include when(warning) {
|
||||
box-shadow: $-button-large-box-shadow-size $-button-warning-box-shadow-color;
|
||||
}
|
||||
|
||||
@include when(error) {
|
||||
box-shadow: $-button-large-box-shadow-size $-button-error-box-shadow-color;
|
||||
}
|
||||
}
|
||||
|
||||
@include when(round) {
|
||||
border-radius: calc($-button-large-height / 2);
|
||||
|
||||
&::after {
|
||||
border-radius: $-button-large-height;
|
||||
}
|
||||
@include when(icon) {
|
||||
border-radius: 50%;
|
||||
}
|
||||
@include when(text) {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
.wd-button__loading {
|
||||
width: $-button-large-loading;
|
||||
height: $-button-large-loading;
|
||||
}
|
||||
}
|
||||
|
||||
@include when(text) {
|
||||
color: $-button-primary-color;
|
||||
padding: 4px 0;
|
||||
|
||||
&::after {
|
||||
display: none;
|
||||
}
|
||||
&.wd-button--active {
|
||||
color: $-button-primary-active-color;
|
||||
background: transparent;
|
||||
}
|
||||
@include when(disabled) {
|
||||
color: $-button-normal-disabled-color;
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
@include when(plain) {
|
||||
background: $-color-white;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
display: block;
|
||||
content: '';
|
||||
width: 200%;
|
||||
height: 200%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
border: 1px solid $-button-border-color;
|
||||
box-sizing: border-box;
|
||||
transform: scale(0.5);
|
||||
transform-origin: left top;
|
||||
}
|
||||
@include when(primary) {
|
||||
@include button-plain-style(
|
||||
$-button-primary-color,
|
||||
$-button-primary-color,
|
||||
$-button-primary-active-color,
|
||||
$-button-primary-disabled-color
|
||||
);
|
||||
&.wd-button--active {
|
||||
background-color: $-button-primary-plain-active-bg-color;
|
||||
}
|
||||
@include when(disabled) {
|
||||
&.wd-button--active {
|
||||
background-color: $-button-primary-plain-active-bg-color;
|
||||
}
|
||||
opacity: 1;
|
||||
background-color: $-button-primary-plain-active-bg-color;
|
||||
color: $-button-primary-plain-disabled-color;
|
||||
}
|
||||
}
|
||||
@include when(success) {
|
||||
@include button-plain-style(
|
||||
$-button-success-color,
|
||||
$-button-success-color,
|
||||
$-button-success-active-color,
|
||||
$-button-success-disabled-color
|
||||
);
|
||||
}
|
||||
@include when(info) {
|
||||
@include button-plain-style(
|
||||
$-button-info-plain-normal-color,
|
||||
$-button-info-bg-color,
|
||||
$-button-info-active-color,
|
||||
$-button-info-disabled-color
|
||||
);
|
||||
&::after {
|
||||
border-color: $-button-info-plain-border-color;
|
||||
}
|
||||
&.wd-button--active {
|
||||
background-color: $-button-info-plain-active-bg-color;
|
||||
|
||||
&::after {
|
||||
border-color: $-button-info-plain-active-color;
|
||||
}
|
||||
}
|
||||
@include when(disabled) {
|
||||
&,
|
||||
&.wd-button--active {
|
||||
background-color: $-button-info-plain-disabled-bg-color;
|
||||
|
||||
&::after {
|
||||
border-color: $-button-info-plain-disabled-bg-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
@include when(loading) {
|
||||
&::after,
|
||||
&.wd-button--active::after {
|
||||
border-color: $-button-info-plain-border-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
@include when(warning) {
|
||||
@include button-plain-style(
|
||||
$-button-warning-color,
|
||||
$-button-warning-color,
|
||||
$-button-warning-active-color,
|
||||
$-button-warning-disabled-color
|
||||
);
|
||||
}
|
||||
@include when(error) {
|
||||
@include button-plain-style(
|
||||
$-button-error-color,
|
||||
$-button-error-color,
|
||||
$-button-error-active-color,
|
||||
$-button-error-disabled-color
|
||||
);
|
||||
}
|
||||
@include when(suck) {
|
||||
&.wd-button--active {
|
||||
background: $-button-suck-active-color;
|
||||
}
|
||||
@include when(disabled) {
|
||||
background: $-color-white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include when(suck) {
|
||||
display: flex;
|
||||
font-size: $-button-large-fs;
|
||||
height: $-button-suck-height;
|
||||
border-radius: 0;
|
||||
|
||||
&::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@include when(block) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@include when(icon) {
|
||||
width: $-button-icon-size;
|
||||
height: $-button-icon-size;
|
||||
padding: 0;
|
||||
border-radius: 50%;
|
||||
font-size: 0;
|
||||
color: $-button-icon-color;
|
||||
|
||||
&::after {
|
||||
display: none;
|
||||
}
|
||||
&.wd-button--active {
|
||||
background: $-button-icon-active-color;
|
||||
}
|
||||
.wd-button__icon {
|
||||
margin-right: 0;
|
||||
}
|
||||
@include when(disabled) {
|
||||
color: $-button-icon-disabled-color;
|
||||
background: transparent;
|
||||
|
||||
&.wd-button--active {
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include e(icon) {
|
||||
display: block;
|
||||
margin-right: 6px;
|
||||
font-size: $-button-icon-fs;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
@include e(text) {
|
||||
user-select: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
// 微信2.8.0以上版本加了较高层级的默认样式,需要重置掉
|
||||
.wd-button {
|
||||
min-height: auto;
|
||||
width: auto;
|
||||
}
|
||||
@keyframes wd-rotate {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,630 @@
|
||||
<template>
|
||||
<button
|
||||
hover-class="wd-button--active"
|
||||
:class="[
|
||||
'wd-button',
|
||||
'custom-class',
|
||||
'is-' + type,
|
||||
'is-' + size,
|
||||
plain ? 'is-plain' : '',
|
||||
disabled ? 'is-disabled' : '',
|
||||
round ? 'is-round' : '',
|
||||
suck ? 'is-suck' : '',
|
||||
block ? 'is-block' : '',
|
||||
loading ? 'is-loading' : ''
|
||||
]"
|
||||
:hover-start-time="hoverStartTime"
|
||||
:hover-stay-time="hoverStayTime"
|
||||
:open-type="openType"
|
||||
:send-message-title="sendMessageTitle"
|
||||
:send-message-path="sendMessagePath"
|
||||
:send-message-img="sendMessageImg"
|
||||
:app-parameter="appParameter"
|
||||
:show-message-card="showMessageCard"
|
||||
:session-from="sessionFrom"
|
||||
:lang="lang"
|
||||
:hover-stop-propagation="hoverStopPropagation"
|
||||
:form-type="formType"
|
||||
@click="handleClick"
|
||||
@getuserinfo="handleGetuserinfo"
|
||||
@contact="handleConcat"
|
||||
@getphonenumber="handleGetphonenumber"
|
||||
@error="handleError"
|
||||
@launchapp="handleLaunchapp"
|
||||
@opensetting="handleOpensetting"
|
||||
>
|
||||
<view v-if="loading" class="wd-button__loading">
|
||||
<view class="wd-button__loading-svg" :style="loadingStyle"></view>
|
||||
</view>
|
||||
<wd-icon v-if="icon" class="wd-button__icon" :name="icon"></wd-icon>
|
||||
<view class="wd-button__text"><slot /></view>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, watch } from 'vue'
|
||||
import { ref } from 'vue'
|
||||
import base64 from '../common/base64'
|
||||
|
||||
const loadingIcon = (color = '#4D80F0', reverse = true) => {
|
||||
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 42 42"><defs><linearGradient x1="100%" y1="0%" x2="0%" y2="0%" id="a"><stop stop-color="${
|
||||
reverse ? color : '#fff'
|
||||
}" offset="0%" stop-opacity="0"/><stop stop-color="${
|
||||
reverse ? color : '#fff'
|
||||
}" offset="100%"/></linearGradient></defs><g fill="none" fill-rule="evenodd"><path d="M21 1c11.046 0 20 8.954 20 20s-8.954 20-20 20S1 32.046 1 21 9.954 1 21 1zm0 7C13.82 8 8 13.82 8 21s5.82 13 13 13 13-5.82 13-13S28.18 8 21 8z" fill="${
|
||||
reverse ? '#fff' : color
|
||||
}"/><path d="M4.599 21c0 9.044 7.332 16.376 16.376 16.376 9.045 0 16.376-7.332 16.376-16.376" stroke="url(#a)" stroke-width="3.5" stroke-linecap="round"/></g></svg>`
|
||||
}
|
||||
type ButtonType = 'primary' | 'success' | 'info' | 'warning' | 'error' | 'default'
|
||||
type ButtonSize = 'small' | 'medium' | 'large'
|
||||
|
||||
interface Props {
|
||||
plain: boolean
|
||||
disabled: boolean
|
||||
round: {
|
||||
type: boolean
|
||||
value: true
|
||||
}
|
||||
suck: boolean
|
||||
block: boolean
|
||||
type: ButtonType
|
||||
size: ButtonSize
|
||||
icon: string
|
||||
loading: boolean
|
||||
loadingColor: string
|
||||
openType: string
|
||||
formType: string
|
||||
hoverStopPropagation: boolean
|
||||
lang: string
|
||||
sessionFrom: string
|
||||
sendMessageTitle: string
|
||||
sendMessagePath: string
|
||||
sendMessageImg: string
|
||||
appParameter: string
|
||||
showMessageCard: boolean
|
||||
}
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
type: 'primary',
|
||||
size: 'medium'
|
||||
})
|
||||
|
||||
const hoverStartTime = ref<number>(20)
|
||||
const hoverStayTime = ref<number>(70)
|
||||
const loadingIconSvg = ref<string>('')
|
||||
|
||||
watch(
|
||||
() => props.loading,
|
||||
() => {
|
||||
buildLoadingSvg()
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
)
|
||||
|
||||
const loadingStyle = computed(() => {
|
||||
return `background-image: url(${loadingIconSvg.value});`
|
||||
})
|
||||
|
||||
const emit = defineEmits(['click', 'getuserinfo', 'contact', 'getphonenumber', 'error', 'launchapp', 'opensetting'])
|
||||
|
||||
function handleClick(event) {
|
||||
if (!props.disabled && !props.loading) {
|
||||
emit('click', event.detail)
|
||||
}
|
||||
}
|
||||
|
||||
function handleGetuserinfo(event) {
|
||||
emit('getuserinfo', event.detail)
|
||||
}
|
||||
|
||||
function handleConcat(event) {
|
||||
emit('contact', event.detail)
|
||||
}
|
||||
|
||||
function handleGetphonenumber(event) {
|
||||
emit('getphonenumber', event.detail)
|
||||
}
|
||||
|
||||
function handleError(event) {
|
||||
emit('error', event.detail)
|
||||
}
|
||||
|
||||
function handleLaunchapp(event) {
|
||||
emit('launchapp', event.detail)
|
||||
}
|
||||
|
||||
function handleOpensetting(event) {
|
||||
emit('opensetting', event.detail)
|
||||
}
|
||||
function buildLoadingSvg() {
|
||||
const { loadingColor, type, plain } = props
|
||||
let color = loadingColor
|
||||
if (!color) {
|
||||
switch (type) {
|
||||
case 'primary':
|
||||
color = '#4D80F0'
|
||||
break
|
||||
case 'success':
|
||||
color = '#34d19d'
|
||||
break
|
||||
case 'info':
|
||||
color = '#333'
|
||||
break
|
||||
case 'warning':
|
||||
color = '#f0883a'
|
||||
break
|
||||
case 'error':
|
||||
color = '#fa4350'
|
||||
break
|
||||
case 'default':
|
||||
color = '#333'
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const svg = loadingIcon(color, !plain)
|
||||
loadingIconSvg.value = `"data:image/svg+xml;base64,${base64(svg)}"`
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import './../common/abstracts/_mixin.scss';
|
||||
@import './../common/abstracts/variable.scss';
|
||||
|
||||
@mixin button-type-style($color, $normal, $active, $disabled, $disabledcolor) {
|
||||
background: $normal;
|
||||
color: $color;
|
||||
font-weight: $-fw-medium;
|
||||
|
||||
&::after {
|
||||
border-color: $normal;
|
||||
}
|
||||
&.wd-button--active {
|
||||
background: $active;
|
||||
}
|
||||
@include when(disabled) {
|
||||
&.wd-button--active {
|
||||
background: $disabled;
|
||||
color: $disabledcolor;
|
||||
}
|
||||
|
||||
background: $disabled;
|
||||
color: $disabledcolor;
|
||||
|
||||
&::after {
|
||||
border-color: $disabled;
|
||||
}
|
||||
}
|
||||
@include when(loading) {
|
||||
&,
|
||||
&.wd-button--active {
|
||||
color: $color;
|
||||
background: $normal;
|
||||
}
|
||||
&::after {
|
||||
border-color: $normal;
|
||||
}
|
||||
}
|
||||
@include when(suck) {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin button-plain-style($color, $normal, $active, $disabled) {
|
||||
color: $color;
|
||||
background: transparent;
|
||||
|
||||
&::after {
|
||||
border-color: $normal;
|
||||
}
|
||||
&.wd-button--active {
|
||||
color: $active;
|
||||
background: transparent;
|
||||
|
||||
&::after {
|
||||
border-color: $active;
|
||||
}
|
||||
}
|
||||
@include when(disabled) {
|
||||
color: $disabled;
|
||||
background: transparent;
|
||||
|
||||
&::after {
|
||||
border-color: $disabled;
|
||||
}
|
||||
&.wd-button--active {
|
||||
background: transparent;
|
||||
|
||||
&::after {
|
||||
border-color: $disabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
@include when(loading) {
|
||||
&,
|
||||
&.wd-button--active {
|
||||
color: $color;
|
||||
background: transparent;
|
||||
|
||||
&::after {
|
||||
border-color: $normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@include b(button) {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
outline: none;
|
||||
-webkit-appearance: none;
|
||||
outline: none;
|
||||
background: transparent;
|
||||
box-sizing: border-box;
|
||||
border: none;
|
||||
color: $-button-normal-color;
|
||||
transition: all 0.2s;
|
||||
user-select: none;
|
||||
font-weight: normal;
|
||||
|
||||
&::after {
|
||||
display: none;
|
||||
}
|
||||
&.wd-button--active {
|
||||
color: $-button-normal-active-color;
|
||||
background: $-button-normal-active-bg;
|
||||
|
||||
&::after {
|
||||
border-color: $-button-normal-border-active-color;
|
||||
}
|
||||
}
|
||||
@include when(disabled) {
|
||||
color: $-button-normal-disabled-color;
|
||||
background: $-button-normal-disabled-bg;
|
||||
|
||||
&::after {
|
||||
border-color: $-button-normal-border-disabled-color;
|
||||
}
|
||||
&.wd-button--active {
|
||||
color: $-button-normal-disabled-color;
|
||||
background: $-button-normal-disabled-bg;
|
||||
|
||||
&::after {
|
||||
border-color: $-button-normal-border-disabled-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include e(loading) {
|
||||
margin-right: 5px;
|
||||
animation: wd-rotate 0.8s linear infinite;
|
||||
animation-duration: 2s;
|
||||
}
|
||||
@include e(loading-svg) {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
@include when(loading) {
|
||||
&.wd-button--active {
|
||||
color: $-button-normal-color;
|
||||
background: transparent;
|
||||
|
||||
&::after {
|
||||
border-color: $-button-border-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include when(primary) {
|
||||
@include button-type-style(
|
||||
$-color-white,
|
||||
$-button-primary-bg-color,
|
||||
$-button-primary-active-color,
|
||||
$-button-primary-disabled-color,
|
||||
$-color-white
|
||||
);
|
||||
}
|
||||
@include when(success) {
|
||||
@include button-type-style($-color-white, $-button-success-color, $-button-success-active-color, $-button-success-disabled-color, $-color-white);
|
||||
}
|
||||
@include when(info) {
|
||||
@include button-type-style(
|
||||
$-button-info-color,
|
||||
$-button-info-bg-color,
|
||||
$-button-info-active-bg-color,
|
||||
$-button-info-disabled-bg-color,
|
||||
$-button-info-disabled-color
|
||||
);
|
||||
}
|
||||
@include when(warning) {
|
||||
@include button-type-style($-color-white, $-button-warning-color, $-button-warning-active-color, $-button-warning-disabled-color, $-color-white);
|
||||
}
|
||||
@include when(error) {
|
||||
@include button-type-style($-color-white, $-button-error-color, $-button-error-active-color, $-button-error-disabled-color, $-color-white);
|
||||
}
|
||||
|
||||
@include when(small) {
|
||||
height: $-button-small-height;
|
||||
padding: $-button-small-padding;
|
||||
border-radius: $-button-small-radius;
|
||||
font-size: $-button-small-fs;
|
||||
font-weight: normal;
|
||||
|
||||
@include when(round) {
|
||||
border-radius: calc($-button-small-height / 2);
|
||||
|
||||
&::after {
|
||||
border-radius: $-button-small-height;
|
||||
}
|
||||
}
|
||||
|
||||
.wd-button__loading {
|
||||
width: $-button-small-loading;
|
||||
height: $-button-small-loading;
|
||||
}
|
||||
}
|
||||
|
||||
@include when(medium) {
|
||||
height: $-button-medium-height;
|
||||
padding: $-button-medium-padding;
|
||||
border-radius: $-button-medium-radius;
|
||||
font-size: $-button-medium-fs;
|
||||
|
||||
&::after {
|
||||
border-radius: $-button-medium-radius * 2;
|
||||
}
|
||||
@include when(primary) {
|
||||
box-shadow: $-button-medium-box-shadow-size $-button-primary-box-shadow-color;
|
||||
}
|
||||
|
||||
@include when(success) {
|
||||
box-shadow: $-button-medium-box-shadow-size $-button-success-box-shadow-color;
|
||||
}
|
||||
|
||||
@include when(warning) {
|
||||
box-shadow: $-button-medium-box-shadow-size $-button-warning-box-shadow-color;
|
||||
}
|
||||
|
||||
@include when(error) {
|
||||
box-shadow: $-button-medium-box-shadow-size $-button-error-box-shadow-color;
|
||||
}
|
||||
|
||||
@include when(plain) {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
@include when(round) {
|
||||
min-width: 118px;
|
||||
border-radius: calc($-button-medium-height / 2);
|
||||
|
||||
&::after {
|
||||
border-radius: $-button-medium-height;
|
||||
}
|
||||
@include when(icon) {
|
||||
min-width: 0;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
@include when(text) {
|
||||
min-width: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.wd-button__loading {
|
||||
width: $-button-medium-loading;
|
||||
height: $-button-medium-loading;
|
||||
}
|
||||
}
|
||||
@include when(large) {
|
||||
height: $-button-large-height;
|
||||
padding: $-button-large-padding;
|
||||
border-radius: $-button-large-radius;
|
||||
font-size: $-button-large-fs;
|
||||
|
||||
&::after {
|
||||
border-radius: $-button-large-radius * 2;
|
||||
}
|
||||
&:not(.is-plain) {
|
||||
@include when(primary) {
|
||||
box-shadow: $-button-large-box-shadow-size $-button-primary-box-shadow-color;
|
||||
}
|
||||
|
||||
@include when(success) {
|
||||
box-shadow: $-button-large-box-shadow-size $-button-success-box-shadow-color;
|
||||
}
|
||||
|
||||
@include when(warning) {
|
||||
box-shadow: $-button-large-box-shadow-size $-button-warning-box-shadow-color;
|
||||
}
|
||||
|
||||
@include when(error) {
|
||||
box-shadow: $-button-large-box-shadow-size $-button-error-box-shadow-color;
|
||||
}
|
||||
}
|
||||
|
||||
@include when(round) {
|
||||
border-radius: calc($-button-large-height / 2);
|
||||
|
||||
&::after {
|
||||
border-radius: $-button-large-height;
|
||||
}
|
||||
@include when(icon) {
|
||||
border-radius: 50%;
|
||||
}
|
||||
@include when(text) {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
.wd-button__loading {
|
||||
width: $-button-large-loading;
|
||||
height: $-button-large-loading;
|
||||
}
|
||||
}
|
||||
|
||||
@include when(text) {
|
||||
color: $-button-primary-color;
|
||||
padding: 4px 0;
|
||||
|
||||
&::after {
|
||||
display: none;
|
||||
}
|
||||
&.wd-button--active {
|
||||
color: $-button-primary-active-color;
|
||||
background: transparent;
|
||||
}
|
||||
@include when(disabled) {
|
||||
color: $-button-normal-disabled-color;
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
@include when(plain) {
|
||||
background: $-color-white;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
display: block;
|
||||
content: '';
|
||||
width: 200%;
|
||||
height: 200%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
border: 1px solid $-button-border-color;
|
||||
box-sizing: border-box;
|
||||
transform: scale(0.5);
|
||||
transform-origin: left top;
|
||||
}
|
||||
@include when(primary) {
|
||||
@include button-plain-style($-button-primary-color, $-button-primary-color, $-button-primary-active-color, $-button-primary-disabled-color);
|
||||
&.wd-button--active {
|
||||
background-color: $-button-primary-plain-active-bg-color;
|
||||
}
|
||||
@include when(disabled) {
|
||||
&.wd-button--active {
|
||||
background-color: $-button-primary-plain-active-bg-color;
|
||||
}
|
||||
opacity: 1;
|
||||
background-color: $-button-primary-plain-active-bg-color;
|
||||
color: $-button-primary-plain-disabled-color;
|
||||
}
|
||||
}
|
||||
@include when(success) {
|
||||
@include button-plain-style($-button-success-color, $-button-success-color, $-button-success-active-color, $-button-success-disabled-color);
|
||||
}
|
||||
@include when(info) {
|
||||
@include button-plain-style($-button-info-plain-normal-color, $-button-info-bg-color, $-button-info-active-color, $-button-info-disabled-color);
|
||||
&::after {
|
||||
border-color: $-button-info-plain-border-color;
|
||||
}
|
||||
&.wd-button--active {
|
||||
background-color: $-button-info-plain-active-bg-color;
|
||||
|
||||
&::after {
|
||||
border-color: $-button-info-plain-active-color;
|
||||
}
|
||||
}
|
||||
@include when(disabled) {
|
||||
&,
|
||||
&.wd-button--active {
|
||||
background-color: $-button-info-plain-disabled-bg-color;
|
||||
|
||||
&::after {
|
||||
border-color: $-button-info-plain-disabled-bg-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
@include when(loading) {
|
||||
&::after,
|
||||
&.wd-button--active::after {
|
||||
border-color: $-button-info-plain-border-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
@include when(warning) {
|
||||
@include button-plain-style($-button-warning-color, $-button-warning-color, $-button-warning-active-color, $-button-warning-disabled-color);
|
||||
}
|
||||
@include when(error) {
|
||||
@include button-plain-style($-button-error-color, $-button-error-color, $-button-error-active-color, $-button-error-disabled-color);
|
||||
}
|
||||
@include when(suck) {
|
||||
&.wd-button--active {
|
||||
background: $-button-suck-active-color;
|
||||
}
|
||||
@include when(disabled) {
|
||||
background: $-color-white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include when(suck) {
|
||||
display: flex;
|
||||
font-size: $-button-large-fs;
|
||||
height: $-button-suck-height;
|
||||
border-radius: 0;
|
||||
|
||||
&::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@include when(block) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@include when(icon) {
|
||||
width: $-button-icon-size;
|
||||
height: $-button-icon-size;
|
||||
padding: 0;
|
||||
border-radius: 50%;
|
||||
font-size: 0;
|
||||
color: $-button-icon-color;
|
||||
|
||||
&::after {
|
||||
display: none;
|
||||
}
|
||||
&.wd-button--active {
|
||||
background: $-button-icon-active-color;
|
||||
}
|
||||
.wd-button__icon {
|
||||
margin-right: 0;
|
||||
}
|
||||
@include when(disabled) {
|
||||
color: $-button-icon-disabled-color;
|
||||
background: transparent;
|
||||
|
||||
&.wd-button--active {
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include e(icon) {
|
||||
display: block;
|
||||
margin-right: 6px;
|
||||
font-size: $-button-icon-fs;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
@include e(text) {
|
||||
user-select: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
// 微信2.8.0以上版本加了较高层级的默认样式,需要重置掉
|
||||
.wd-button {
|
||||
min-height: auto;
|
||||
width: auto;
|
||||
}
|
||||
@keyframes wd-rotate {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,320 @@
|
||||
import VueComponent from '../../../common/component'
|
||||
import { compareDate, getMonthEndDay, getWeekRange, getDayOffset, getDayByOffset, getDateByDefaultTime } from '../../utils'
|
||||
import { getType } from '../../../common/util'
|
||||
import Toast from '../../../toast/toast.js'
|
||||
|
||||
VueComponent({
|
||||
data: {
|
||||
days: []
|
||||
},
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
observer: 'setDays'
|
||||
},
|
||||
date: {
|
||||
type: Number,
|
||||
observer: 'setDays'
|
||||
},
|
||||
value: {
|
||||
type: [null, Number, Array],
|
||||
observer: 'setDays'
|
||||
},
|
||||
minDate: {
|
||||
type: Number,
|
||||
observer: 'setDays'
|
||||
},
|
||||
maxDate: {
|
||||
type: Number,
|
||||
observer: 'setDays'
|
||||
},
|
||||
firstDayOfWeek: Number,
|
||||
formatter: {
|
||||
type: null,
|
||||
observer: 'setDays'
|
||||
},
|
||||
maxRange: Number,
|
||||
rangePrompt: String,
|
||||
allowSameDay: Boolean,
|
||||
defaultTime: Array
|
||||
},
|
||||
methods: {
|
||||
setDays () {
|
||||
const days = []
|
||||
const date = new Date(this.data.date)
|
||||
const year = date.getFullYear()
|
||||
const month = date.getMonth()
|
||||
|
||||
const totalDay = getMonthEndDay(year, month + 1)
|
||||
|
||||
let value = this.data.value
|
||||
|
||||
if ((this.data.type === 'week' || this.data.type === 'weekrange') && value) {
|
||||
value = this.getWeekValue()
|
||||
}
|
||||
|
||||
for (let day = 1; day <= totalDay; day++) {
|
||||
const date = new Date(year, month, day).getTime()
|
||||
let type = this.getDayType(date, value)
|
||||
if (!type && compareDate(date, Date.now()) === 0) {
|
||||
type = 'current'
|
||||
}
|
||||
const dayObj = this.getFormatterDate(date, day, type)
|
||||
days.push(dayObj)
|
||||
}
|
||||
|
||||
this.setData({
|
||||
days
|
||||
})
|
||||
},
|
||||
getDayType (date, value) {
|
||||
switch (this.data.type) {
|
||||
case 'date':
|
||||
case 'datetime':
|
||||
return this.getDateType(date)
|
||||
case 'dates':
|
||||
return this.getDatesType(date)
|
||||
case 'daterange':
|
||||
case 'datetimerange':
|
||||
return this.getDatetimeType(date, value)
|
||||
case 'week':
|
||||
return this.getWeektimeType(date, value)
|
||||
case 'weekrange':
|
||||
return this.getWeektimeType(date, value)
|
||||
default:
|
||||
return this.getDateType(date)
|
||||
}
|
||||
},
|
||||
getDateType (date) {
|
||||
if (this.data.value && compareDate(date, this.data.value) === 0) {
|
||||
return 'selected'
|
||||
}
|
||||
|
||||
return ''
|
||||
},
|
||||
getDatesType (date) {
|
||||
if (!this.data.value) return ''
|
||||
|
||||
let type = ''
|
||||
|
||||
this.data.value.some((item) => {
|
||||
if (compareDate(date, item) === 0) {
|
||||
type = 'selected'
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
})
|
||||
|
||||
return type
|
||||
},
|
||||
getDatetimeType (date, value) {
|
||||
const [startDate, endDate] = value || []
|
||||
|
||||
if (startDate && compareDate(date, startDate) === 0) {
|
||||
if (this.data.allowSameDay && endDate && compareDate(startDate, endDate) === 0) {
|
||||
return 'same'
|
||||
}
|
||||
return 'start'
|
||||
} else if (endDate && compareDate(date, endDate) === 0) {
|
||||
return 'end'
|
||||
} else if (startDate && endDate && compareDate(date, startDate) === 1 && compareDate(date, endDate) === -1) {
|
||||
return 'middle'
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
},
|
||||
getWeektimeType (date, value) {
|
||||
const [startDate, endDate] = value || []
|
||||
|
||||
if (startDate && compareDate(date, startDate) === 0) {
|
||||
return 'start'
|
||||
} else if (endDate && compareDate(date, endDate) === 0) {
|
||||
return 'end'
|
||||
} else if (startDate && endDate && compareDate(date, startDate) === 1 && compareDate(date, endDate) === -1) {
|
||||
return 'middle'
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
},
|
||||
getWeekValue () {
|
||||
if (this.data.type === 'week') {
|
||||
return getWeekRange(this.data.value, this.data.firstDayOfWeek)
|
||||
} else {
|
||||
const [startDate, endDate] = this.data.value || []
|
||||
|
||||
if (startDate) {
|
||||
const firstWeekRange = getWeekRange(startDate, this.data.firstDayOfWeek)
|
||||
|
||||
if (endDate) {
|
||||
const endWeekRange = getWeekRange(endDate, this.data.firstDayOfWeek)
|
||||
|
||||
return [firstWeekRange[0], endWeekRange[1]]
|
||||
} else {
|
||||
return firstWeekRange
|
||||
}
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
},
|
||||
handleDateClick (event) {
|
||||
const { index } = event.currentTarget.dataset
|
||||
const date = this.data.days[index]
|
||||
|
||||
switch (this.data.type) {
|
||||
case 'date':
|
||||
case 'datetime':
|
||||
this.handleDateChange(date)
|
||||
break
|
||||
case 'dates':
|
||||
this.handleDatesChange(date)
|
||||
break
|
||||
case 'daterange':
|
||||
case 'datetimerange':
|
||||
this.handleDateRangeChange(date)
|
||||
break
|
||||
case 'week':
|
||||
this.handleWeekChange(date)
|
||||
break
|
||||
case 'weekrange':
|
||||
this.handleWeekRangeChange(date)
|
||||
break
|
||||
default:
|
||||
this.handleDateChange(date)
|
||||
}
|
||||
},
|
||||
getDate (date, isEnd) {
|
||||
date = this.data.defaultTime && this.data.defaultTime.length > 0
|
||||
? getDateByDefaultTime(date, isEnd ? this.data.defaultTime[1] : this.data.defaultTime[0])
|
||||
: date
|
||||
|
||||
if (date < this.data.minDate) return this.data.minDate
|
||||
|
||||
if (date > this.data.maxDate) return this.data.maxDate
|
||||
|
||||
return date
|
||||
},
|
||||
handleDateChange (date) {
|
||||
if (date.disabled) return
|
||||
|
||||
if (date.type !== 'selected') {
|
||||
this.$emit('change', {
|
||||
value: this.getDate(date.date),
|
||||
type: 'start'
|
||||
})
|
||||
}
|
||||
},
|
||||
handleDatesChange (date) {
|
||||
if (date.disabled) return
|
||||
|
||||
const value = this.data.value || []
|
||||
if (date.type !== 'selected') {
|
||||
value.push(this.getDate(date.date))
|
||||
} else {
|
||||
value.splice(value.indexOf(date.date), 1)
|
||||
}
|
||||
this.$emit('change', {
|
||||
value
|
||||
})
|
||||
},
|
||||
handleDateRangeChange (date) {
|
||||
if (date.disabled) return
|
||||
|
||||
let value
|
||||
let type
|
||||
const [startDate, endDate] = this.data.value || []
|
||||
const compare = compareDate(date.date, startDate)
|
||||
|
||||
// 禁止选择同个日期
|
||||
if (!this.data.allowSameDay && compare === 0 && (this.data.type === 'daterange' || this.data.type === 'datetimerange') && !endDate) {
|
||||
return
|
||||
}
|
||||
|
||||
if (startDate && !endDate && compare > -1) {
|
||||
// 不能选择超过最大范围的日期
|
||||
if (this.data.maxRange && getDayOffset(date.date, startDate) > this.data.maxRange) {
|
||||
const maxEndDate = getDayByOffset(startDate, this.data.maxRange - 1)
|
||||
value = [startDate, this.getDate(maxEndDate, true)]
|
||||
Toast({
|
||||
msg: this.data.rangePrompt || `选择天数不能超过${this.data.maxRange}天`,
|
||||
context: this
|
||||
})
|
||||
} else {
|
||||
value = [startDate, this.getDate(date.date, true)]
|
||||
}
|
||||
} else if (this.data.type === 'datetimerange' && startDate && endDate) {
|
||||
// 时间范围类型,且有开始时间和结束时间,需要支持重新点击开始日期和结束日期可以重新修改时间
|
||||
if (compare === 0) {
|
||||
type = 'start'
|
||||
value = this.data.value
|
||||
} else if (compareDate(date.date, endDate) === 0) {
|
||||
type = 'end'
|
||||
value = this.data.value
|
||||
} else {
|
||||
value = [this.getDate(date.date), null]
|
||||
}
|
||||
} else {
|
||||
value = [this.getDate(date.date), null]
|
||||
}
|
||||
|
||||
this.$emit('change', {
|
||||
value,
|
||||
type: type || (value[1] ? 'end' : 'start')
|
||||
})
|
||||
},
|
||||
handleWeekChange (date) {
|
||||
const [weekStart] = getWeekRange(date.date, this.data.firstDayOfWeek)
|
||||
|
||||
// 周的第一天如果是禁用状态,则不可选中
|
||||
if (this.getFormatterDate(weekStart, new Date(weekStart).getDate()).disabled) return
|
||||
|
||||
this.$emit('change', {
|
||||
value: this.getDate(weekStart) + 24 * 60 * 60 * 1000
|
||||
})
|
||||
},
|
||||
handleWeekRangeChange (date) {
|
||||
const [weekStartDate] = getWeekRange(date.date, this.data.firstDayOfWeek)
|
||||
|
||||
// 周的第一天如果是禁用状态,则不可选中
|
||||
if (this.getFormatterDate(weekStartDate, new Date(weekStartDate).getDate()).disabled) return
|
||||
|
||||
let value
|
||||
const [startDate, endDate] = this.data.value || []
|
||||
const [startWeekStartDate] = startDate ? getWeekRange(startDate, this.data.firstDayOfWeek) : []
|
||||
const compare = compareDate(weekStartDate, startWeekStartDate)
|
||||
|
||||
if (startDate && !endDate && compare > -1) {
|
||||
if (!this.data.allowSameDay && compare === 0) return
|
||||
|
||||
value = [this.getDate(startWeekStartDate) + 24 * 60 * 60 * 1000, this.getDate(weekStartDate) + 24 * 60 * 60 * 1000]
|
||||
} else {
|
||||
value = [this.getDate(weekStartDate) + 24 * 60 * 60 * 1000, null]
|
||||
}
|
||||
|
||||
this.$emit('change', {
|
||||
value
|
||||
})
|
||||
},
|
||||
getFormatterDate (date, day, type) {
|
||||
let dayObj = {
|
||||
date: date,
|
||||
text: day,
|
||||
topInfo: '',
|
||||
bottomInfo: '',
|
||||
type,
|
||||
disabled: compareDate(date, this.data.minDate) === -1 || compareDate(date, this.data.maxDate) === 1
|
||||
}
|
||||
if (this.data.formatter) {
|
||||
if (getType(this.data.formatter) === 'function') {
|
||||
dayObj = this.data.formatter(dayObj)
|
||||
} else {
|
||||
console.error('[wot-design] error(wd-calendar-view): the formatter prop of wd-calendar-view should be a function')
|
||||
}
|
||||
}
|
||||
|
||||
return dayObj
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -0,0 +1,6 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
"wd-toast": "../../../toast/index"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
<jds src="../../utils.jds" module="utils" />
|
||||
|
||||
<wd-toast id="wd-toast" />
|
||||
|
||||
<view class="wd-month">
|
||||
<view class="wd-month__title">{{ utils.formatMonthTitle(date) }}</view>
|
||||
<view class="wd-month__days">
|
||||
<view
|
||||
jd:for="{{ days }}"
|
||||
jd:key="date"
|
||||
class="wd-month__day {{ item.disabled ? 'is-disabled' : '' }} {{ item.type ? utils.getItemClass(item.type, value, type) : '' }}"
|
||||
style="{{ utils.getFirstDayStyle(index, item.date, firstDayOfWeek) }}"
|
||||
data-index="{{ index }}"
|
||||
catchtap="handleDateClick"
|
||||
>
|
||||
<view class="wd-month__day-container">
|
||||
<view class="wd-month__day-top">{{ item.topInfo }}</view>
|
||||
<view class="wd-month__day-text">
|
||||
{{ item.text }}
|
||||
</view>
|
||||
<view class="wd-month__day-bottom">{{ item.bottomInfo }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@ -0,0 +1,114 @@
|
||||
@import '../../../common/abstracts/variable';
|
||||
@import '../../../common/abstracts/mixin';
|
||||
|
||||
@include b(month) {
|
||||
@include e(title) {
|
||||
padding: 13px 0;
|
||||
text-align: center;
|
||||
font-size: $-calendar-panel-title-fs;
|
||||
color: $-calendar-panel-title-color;
|
||||
}
|
||||
@include e(days) {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
font-size: $-calendar-day-fs;
|
||||
color: $-calendar-day-color;
|
||||
}
|
||||
@include e(day) {
|
||||
position: relative;
|
||||
width: 14.285%;
|
||||
height: $-calendar-day-height;
|
||||
line-height: $-calendar-day-height;
|
||||
text-align: center;
|
||||
|
||||
@include when(disabled) {
|
||||
.wd-month__day-text {
|
||||
color: $-calendar-disabled-color;
|
||||
}
|
||||
}
|
||||
@include when(current) {
|
||||
color: $-calendar-active-color;
|
||||
}
|
||||
@include when(selected) {
|
||||
.wd-month__day-container {
|
||||
border-radius: $-calendar-active-border;
|
||||
background: $-calendar-active-color;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
@include when(middle) {
|
||||
.wd-month__day-container {
|
||||
background: $-calendar-range-color;
|
||||
}
|
||||
}
|
||||
@include when(start) {
|
||||
&::after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
height: $-calendar-day-height;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 50%;
|
||||
background: $-calendar-range-color;
|
||||
z-index: 1;
|
||||
}
|
||||
&.is-without-end::after {
|
||||
display: none;
|
||||
}
|
||||
.wd-month__day-container {
|
||||
background: $-calendar-active-color;
|
||||
color: #fff;
|
||||
border-radius: $-calendar-active-border;
|
||||
}
|
||||
}
|
||||
@include when(end) {
|
||||
&::after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
height: $-calendar-day-height;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 50%;
|
||||
background: $-calendar-range-color;
|
||||
z-index: 1;
|
||||
}
|
||||
.wd-month__day-container {
|
||||
background: $-calendar-active-color;
|
||||
color: #fff;
|
||||
border-radius: $-calendar-active-border;
|
||||
}
|
||||
}
|
||||
@include when(same) {
|
||||
.wd-month__day-container {
|
||||
background: $-calendar-active-color;
|
||||
color: #fff;
|
||||
border-radius: $-calendar-active-border;
|
||||
}
|
||||
}
|
||||
}
|
||||
@include e(day-container) {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
@include e(day-text) {
|
||||
font-weight: $-calendar-day-fw;
|
||||
}
|
||||
@include e(day-top) {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
line-height: 1.1;
|
||||
font-size: $-calendar-info-fs;
|
||||
text-align: center;
|
||||
}
|
||||
@include e(day-bottom) {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
line-height: 1.1;
|
||||
font-size: $-calendar-info-fs;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,242 @@
|
||||
import VueComponent from '../../../common/component'
|
||||
import { formatMonthTitle, getMonths, compareMonth, getTimeData } from '../../utils'
|
||||
import { getType, debounce, isEqual } from '../../../common/util'
|
||||
|
||||
VueComponent({
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
observer (val) {
|
||||
if ((val === 'datetime' && this.data.value) || (val === 'datetimerange' && this.data.value && this.data.value.length > 0 && this.data.value[0])) {
|
||||
this.setTime(this.data.value, 'start')
|
||||
}
|
||||
}
|
||||
},
|
||||
value: {
|
||||
type: [null, Number, Array],
|
||||
observer (val, oldVal) {
|
||||
if (isEqual(val, this.data.innerValue)) return
|
||||
|
||||
if ((this.data.type === 'datetime' && val) || (this.data.type === 'datetimerange' && val && val.length > 0 && val[0])) {
|
||||
this.setTime(val, 'start')
|
||||
}
|
||||
}
|
||||
},
|
||||
minDate: Number,
|
||||
maxDate: Number,
|
||||
firstDayOfWeek: Number,
|
||||
formatter: null,
|
||||
maxRange: Number,
|
||||
rangePrompt: String,
|
||||
allowSameDay: Boolean,
|
||||
showPanelTitle: Boolean,
|
||||
defaultTime: Array,
|
||||
panelHeight: Number,
|
||||
timeFilter: null,
|
||||
hideSecond: Boolean
|
||||
},
|
||||
data: {
|
||||
title: '',
|
||||
scrollIntoView: '',
|
||||
timeValue: [],
|
||||
timeData: [],
|
||||
timeType: '', // 当前时间类型,是开始还是结束
|
||||
innerValue: '' // 内部保存一个值,用于判断新老值,避免监听器触发
|
||||
},
|
||||
mounted () {
|
||||
this.initRect()
|
||||
this.scrollIntoView()
|
||||
},
|
||||
methods: {
|
||||
initRect (thresholds = [0, 0.7, 0.8, 0.9, 1]) {
|
||||
if (!this.data.showPanelTitle) return
|
||||
|
||||
if (this.contentObserver != null) {
|
||||
this.contentObserver.disconnect()
|
||||
}
|
||||
|
||||
const contentObserver = this.createIntersectionObserver({
|
||||
thresholds,
|
||||
observeAll: true
|
||||
})
|
||||
|
||||
this.contentObserver = contentObserver
|
||||
|
||||
contentObserver.relativeTo('.wd-month-panel__container')
|
||||
contentObserver.observe('.month', (res) => {
|
||||
if (res.boundingClientRect.top <= res.relativeRect.top) {
|
||||
this.setData({
|
||||
title: formatMonthTitle(res.dataset.date)
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
scrollIntoView () {
|
||||
setTimeout(() => {
|
||||
let activeDate
|
||||
const type = getType(this.data.value)
|
||||
if (type === 'array') {
|
||||
activeDate = this.data.value[0]
|
||||
} else if (type === 'number') {
|
||||
activeDate = this.data.value
|
||||
}
|
||||
|
||||
if (!activeDate) {
|
||||
activeDate = Date.now()
|
||||
}
|
||||
|
||||
const months = getMonths(this.data.minDate, this.data.maxDate)
|
||||
|
||||
months.some((month, index) => {
|
||||
if (compareMonth(month, activeDate) === 0) {
|
||||
this.setData({
|
||||
scrollIntoView: `month${index}`
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
})
|
||||
}, 50)
|
||||
},
|
||||
/**
|
||||
* 获取时间 picker 的数据
|
||||
* @param {timestamp|array} value 当前时间
|
||||
* @param {string} type 类型,是开始还是结束
|
||||
*/
|
||||
getTimeData (value, type) {
|
||||
if (this.data.type === 'datetime') {
|
||||
return getTimeData({
|
||||
date: value,
|
||||
minDate: this.data.minDate,
|
||||
maxDate: this.data.maxDate,
|
||||
filter: this.data.timeFilter,
|
||||
isHideSecond: this.data.hideSecond
|
||||
})
|
||||
} else {
|
||||
if (type === 'start') {
|
||||
return getTimeData({
|
||||
date: value[0],
|
||||
minDate: this.data.minDate,
|
||||
maxDate: this.data.value[1] ? this.data.value[1] : this.data.maxDate,
|
||||
filter: this.data.timeFilter,
|
||||
isHideSecond: this.data.hideSecond
|
||||
})
|
||||
} else {
|
||||
return getTimeData({
|
||||
date: value[1],
|
||||
minDate: value[0],
|
||||
maxDate: this.data.maxDate,
|
||||
filter: this.data.timeFilter,
|
||||
isHideSecond: this.data.hideSecond
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 获取 date 的时分秒
|
||||
* @param {timestamp} date 时间
|
||||
* @param {string} type 类型,是开始还是结束
|
||||
*/
|
||||
getTimeValue (date, type) {
|
||||
if (this.data.type === 'datetime') {
|
||||
date = new Date(date)
|
||||
} else {
|
||||
if (type === 'start') {
|
||||
date = new Date(date[0])
|
||||
} else {
|
||||
date = new Date(date[1])
|
||||
}
|
||||
}
|
||||
|
||||
const hour = date.getHours()
|
||||
const minute = date.getMinutes()
|
||||
const second = date.getSeconds()
|
||||
|
||||
return this.data.hideSecond ? [hour, minute] : [hour, minute, second]
|
||||
},
|
||||
setTime (value, type) {
|
||||
if (getType(value) === 'array' && value[0] && value[1] && type === 'start' && this.data.timeType === 'start') {
|
||||
type = 'end'
|
||||
}
|
||||
|
||||
this.setData({
|
||||
timeData: this.getTimeData(value, type),
|
||||
timeValue: this.getTimeValue(value, type),
|
||||
timeType: type
|
||||
}, () => {
|
||||
// 重新设置 thresholds
|
||||
this.initRect([0, 0.58, 0.69, 0.83, 1])
|
||||
})
|
||||
},
|
||||
handleDateChange ({ detail: { value, type } }) {
|
||||
if (!isEqual(value, this.data.value)) {
|
||||
// 内部保存一个值,用于判断新老值,避免监听器触发
|
||||
this.setData({
|
||||
innerValue: value
|
||||
})
|
||||
this.handleChange(value)
|
||||
}
|
||||
// datetime 和 datetimerange 类型,需要计算 timeData 并做展示
|
||||
if (this.data.type.indexOf('time') > -1) {
|
||||
this.setTime(value, type)
|
||||
}
|
||||
},
|
||||
handleChange (value) {
|
||||
this.$emit('change', {
|
||||
value
|
||||
})
|
||||
},
|
||||
handleTimeChange (event) {
|
||||
const { value } = event.detail
|
||||
|
||||
if (this.data.type === 'datetime') {
|
||||
const date = new Date(this.data.value)
|
||||
date.setHours(value[0])
|
||||
date.setMinutes(value[1])
|
||||
date.setSeconds(this.data.hideSecond ? 0 : value[2])
|
||||
const dateTime = date.getTime()
|
||||
|
||||
this.setData({
|
||||
timeData: this.getTimeData(dateTime),
|
||||
timeValue: value
|
||||
})
|
||||
this.handleChange(dateTime)
|
||||
} else {
|
||||
const [start, end] = this.data.value
|
||||
const dataValue = this.data.timeType === 'start' ? start : end
|
||||
const date = new Date(dataValue)
|
||||
date.setHours(value[0])
|
||||
date.setMinutes(value[1])
|
||||
date.setSeconds(this.data.hideSecond ? 0 : value[2])
|
||||
const dateTime = date.getTime()
|
||||
|
||||
if (dateTime === dataValue) return
|
||||
|
||||
const finalValue = [start, end]
|
||||
if (this.data.timeType === 'start') {
|
||||
finalValue[0] = dateTime
|
||||
} else {
|
||||
finalValue[1] = dateTime
|
||||
}
|
||||
|
||||
this.setData({
|
||||
timeData: this.getTimeData(finalValue, this.data.timeType),
|
||||
timeValue: value,
|
||||
innerValue: finalValue // 内部保存一个值,用于判断新老值,避免监听器触发
|
||||
})
|
||||
|
||||
this.handleChange(finalValue)
|
||||
}
|
||||
},
|
||||
handlePickStart () {
|
||||
this.$emit('pickstart')
|
||||
},
|
||||
handlePickEnd () {
|
||||
this.$emit('pickend')
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
this.handleChange = debounce(this.handleChange, 50)
|
||||
}
|
||||
})
|
||||
@ -0,0 +1,7 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
"month": "../month/index",
|
||||
"wd-picker-view": "../../../pickerView/index"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
<jds src="../../utils.jds" module="utils" />
|
||||
|
||||
<view class="wd-month-panel">
|
||||
<view v-if="{{ showPanelTitle }}" class="wd-month-panel__title">
|
||||
{{ title }}
|
||||
</view>
|
||||
<view class="wd-month-panel__weeks">
|
||||
<view jd:for="{{ 7 }}" jd:key="*this" class="wd-month-panel__week">{{ utils.getWeekLabel(item + firstDayOfWeek) }}</view>
|
||||
</view>
|
||||
<scroll-view
|
||||
class="wd-month-panel__container {{ !!timeType ? 'wd-month-panel__container--time' : '' }}"
|
||||
style="height: {{ !!timeType ? ((panelHeight || 378) - 125) : (panelHeight || 378) }}px"
|
||||
scroll-y
|
||||
scroll-into-view="{{ scrollIntoView }}"
|
||||
>
|
||||
<month
|
||||
jd:for="{{ utils.getMonths(minDate, maxDate) }}"
|
||||
jd:key="*this"
|
||||
id="month{{index}}"
|
||||
class="month"
|
||||
type="{{ type }}"
|
||||
date="{{ item }}"
|
||||
data-date="{{ item }}"
|
||||
value="{{ value }}"
|
||||
min-date="{{ minDate }}"
|
||||
max-date="{{ maxDate }}"
|
||||
first-day-of-week="{{ firstDayOfWeek }}"
|
||||
formatter="{{ formatter }}"
|
||||
max-range="{{ maxRange }}"
|
||||
range-prompt="{{ rangePrompt }}"
|
||||
allow-same-day="{{ allowSameDay }}"
|
||||
default-time="{{ defaultTime }}"
|
||||
bind:change="handleDateChange"
|
||||
/>
|
||||
</scroll-view>
|
||||
<view v-if="{{ !!timeType }}" class="wd-month-panel__time">
|
||||
<view v-if="{{ type === 'datetimerange' }}" class="wd-month-panel__time-label">
|
||||
<view class="wd-month-panel__time-text">{{ timeType === 'start' ? '开始' : '结束' }}</view>
|
||||
</view>
|
||||
<view class="wd-month-panel__time-picker">
|
||||
<wd-picker-view
|
||||
value="{{ timeValue }}"
|
||||
columns="{{ timeData }}"
|
||||
columns-height="{{ 125 }}"
|
||||
bind:change="handleTimeChange"
|
||||
bind:pickstart="handlePickStart"
|
||||
bind:pickend="handlePickEnd"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@ -0,0 +1,62 @@
|
||||
@import '../../../common/abstracts/variable';
|
||||
@import '../../../common/abstracts/mixin';
|
||||
|
||||
@include b(month-panel) {
|
||||
font-size: $-calendar-fs;
|
||||
|
||||
@include e(title) {
|
||||
padding: 5px 0;
|
||||
text-align: center;
|
||||
font-size: $-calendar-panel-title-fs;
|
||||
color: $-calendar-panel-title-color;
|
||||
padding: $-calendar-panel-padding;
|
||||
}
|
||||
@include e(weeks) {
|
||||
display: flex;
|
||||
height: $-calendar-week-height;
|
||||
line-height: $-calendar-week-height;
|
||||
box-shadow: 0px 4px 8px 0 rgba(0, 0, 0, 0.02);
|
||||
color: $-calendar-week-color;
|
||||
font-size: $-calendar-week-fs;
|
||||
padding: $-calendar-panel-padding;
|
||||
}
|
||||
@include e(week) {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
}
|
||||
@include e(container) {
|
||||
padding: $-calendar-panel-padding;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@include e(time) {
|
||||
display: flex;
|
||||
box-shadow: 0px -4px 8px 0px rgba(0, 0, 0, 0.02);
|
||||
}
|
||||
@include e(time-label) {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
font-size: $-picker-column-fs;
|
||||
text-align: center;
|
||||
line-height: 125px;
|
||||
color: $-picker-column-color;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
height: 35px;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
transform: translateY(-50%);
|
||||
background: $-picker-column-select-bg;
|
||||
z-index: 0;
|
||||
}
|
||||
}
|
||||
@include e(time-text) {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
@include e(time-picker) {
|
||||
flex: 3;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,165 @@
|
||||
import VueComponent from '../../../common/component'
|
||||
import { compareMonth, getMonthOffset, getMonthByOffset, getDateByDefaultTime } from '../../utils'
|
||||
import { getType } from '../../../common/util'
|
||||
import Toast from '../../../toast/toast.js'
|
||||
|
||||
VueComponent({
|
||||
data: {
|
||||
months: []
|
||||
},
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
observer: 'setMonths'
|
||||
},
|
||||
date: {
|
||||
type: Number,
|
||||
observer: 'setMonths'
|
||||
},
|
||||
value: {
|
||||
type: [null, Number, Array],
|
||||
observer: 'setMonths'
|
||||
},
|
||||
minDate: {
|
||||
type: Number,
|
||||
observer: 'setMonths'
|
||||
},
|
||||
maxDate: {
|
||||
type: Number,
|
||||
observer: 'setMonths'
|
||||
},
|
||||
formatter: {
|
||||
type: null,
|
||||
observer: 'setMonths'
|
||||
},
|
||||
maxRange: Number,
|
||||
rangePrompt: String,
|
||||
allowSameDay: Boolean,
|
||||
defaultTime: Array
|
||||
},
|
||||
methods: {
|
||||
setMonths () {
|
||||
const months = []
|
||||
const date = new Date(this.data.date)
|
||||
const year = date.getFullYear()
|
||||
|
||||
const value = this.data.value
|
||||
const valueType = getType(value)
|
||||
|
||||
if (this.data.type.indexOf('range') > -1 && value && valueType !== 'array') {
|
||||
console.error('[wot-design] value should be array when type is range')
|
||||
return
|
||||
}
|
||||
|
||||
for (let month = 0; month < 12; month++) {
|
||||
const date = new Date(year, month, 1).getTime()
|
||||
let type = this.getMonthType(date, value)
|
||||
if (!type && compareMonth(date, Date.now()) === 0) {
|
||||
type = 'current'
|
||||
}
|
||||
const monthObj = this.getFormatterDate(date, month, type)
|
||||
months.push(monthObj)
|
||||
}
|
||||
|
||||
this.setData({
|
||||
months
|
||||
})
|
||||
},
|
||||
getMonthType (date) {
|
||||
if (this.data.type === 'monthrange') {
|
||||
const [startDate, endDate] = this.data.value || []
|
||||
|
||||
if (startDate && compareMonth(date, startDate) === 0) {
|
||||
if (endDate && compareMonth(startDate, endDate) === 0) {
|
||||
return 'same'
|
||||
}
|
||||
return 'start'
|
||||
} else if (endDate && compareMonth(date, endDate) === 0) {
|
||||
return 'end'
|
||||
} else if (startDate && endDate && compareMonth(date, startDate) === 1 && compareMonth(date, endDate) === -1) {
|
||||
return 'middle'
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
} else {
|
||||
if (this.data.value && compareMonth(date, this.data.value) === 0) {
|
||||
return 'selected'
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
},
|
||||
handleDateClick (event) {
|
||||
const { index } = event.currentTarget.dataset
|
||||
const date = this.data.months[index]
|
||||
|
||||
if (date.disabled) return
|
||||
|
||||
switch (this.data.type) {
|
||||
case 'month':
|
||||
this.handleMonthChange(date)
|
||||
break
|
||||
case 'monthrange':
|
||||
this.handleMonthRangeChange(date)
|
||||
break
|
||||
default:
|
||||
this.handleMonthChange(date)
|
||||
}
|
||||
},
|
||||
getDate (date) {
|
||||
return this.data.defaultTime && this.data.defaultTime.length > 0 ? getDateByDefaultTime(date, this.data.defaultTime[0]) : date
|
||||
},
|
||||
handleMonthChange (date) {
|
||||
if (date.type !== 'selected') {
|
||||
this.$emit('change', {
|
||||
value: this.getDate(date.date)
|
||||
})
|
||||
}
|
||||
},
|
||||
handleMonthRangeChange (date) {
|
||||
let value
|
||||
const [startDate, endDate] = this.data.value || []
|
||||
const compare = compareMonth(date.date, startDate)
|
||||
|
||||
// 禁止选择同个日期
|
||||
if (!this.data.allowSameDay && !endDate && compare === 0) return
|
||||
|
||||
if (startDate && !endDate && compare > -1) {
|
||||
if (this.data.maxRange && getMonthOffset(date.date, startDate) > this.data.maxRange) {
|
||||
const maxEndDate = getMonthByOffset(startDate, this.data.maxRange - 1)
|
||||
value = [startDate, this.getDate(maxEndDate)]
|
||||
Toast({
|
||||
msg: this.data.rangePrompt || `选择月份不能超过${this.data.maxRange}个月`,
|
||||
context: this
|
||||
})
|
||||
} else {
|
||||
value = [startDate, this.getDate(date.date)]
|
||||
}
|
||||
} else {
|
||||
value = [this.getDate(date.date), null]
|
||||
}
|
||||
this.$emit('change', {
|
||||
value
|
||||
})
|
||||
},
|
||||
getFormatterDate (date, month, type) {
|
||||
let monthObj = {
|
||||
date: date,
|
||||
text: month + 1,
|
||||
topInfo: '',
|
||||
bottomInfo: '',
|
||||
type,
|
||||
disabled: compareMonth(date, this.data.minDate) === -1 || compareMonth(date, this.data.maxDate) === 1
|
||||
}
|
||||
if (this.data.formatter) {
|
||||
if (getType(this.data.formatter) === 'function') {
|
||||
monthObj = this.data.formatter(monthObj)
|
||||
} else {
|
||||
console.error('[wot-design] error(wd-calendar-view): the formatter prop of wd-calendar-view should be a function')
|
||||
}
|
||||
}
|
||||
|
||||
return monthObj
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -0,0 +1,6 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
"wd-toast": "../../../toast/index"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
<jds src="../../utils.jds" module="utils" />
|
||||
|
||||
<wd-toast id="wd-toast" />
|
||||
|
||||
<view class="wd-year">
|
||||
<view class="wd-year__title">{{ utils.formatYearTitle(date) }}</view>
|
||||
<view class="wd-year__months">
|
||||
<view
|
||||
jd:for="{{ months }}"
|
||||
jd:key="date"
|
||||
class="wd-year__month {{ item.disabled ? 'is-disabled' : '' }} {{ item.type ? utils.getItemClass(item.type, value, type) : '' }}"
|
||||
data-index="{{ index }}"
|
||||
catchtap="handleDateClick"
|
||||
>
|
||||
<view class="wd-year__month-top">{{ item.topInfo }}</view>
|
||||
<view class="wd-year__month-text">
|
||||
{{ item.text }}月
|
||||
</view>
|
||||
<view class="wd-year__month-bottom">{{ item.bottomInfo }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@ -0,0 +1,112 @@
|
||||
@import '../../../common/abstracts/variable';
|
||||
@import '../../../common/abstracts/mixin';
|
||||
|
||||
@include b(year) {
|
||||
@include e(title) {
|
||||
padding: 13px 0;
|
||||
text-align: center;
|
||||
font-size: $-calendar-panel-title-fs;
|
||||
color: $-calendar-panel-title-color;
|
||||
}
|
||||
@include e(months) {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
font-size: $-calendar-day-fs;
|
||||
color: $-calendar-day-color;
|
||||
}
|
||||
@include e(month) {
|
||||
position: relative;
|
||||
width: 25%;
|
||||
height: $-calendar-day-height;
|
||||
line-height: $-calendar-day-height;
|
||||
text-align: center;
|
||||
|
||||
@include when(disabled) {
|
||||
.wd-year__month-text {
|
||||
color: $-calendar-disabled-color;
|
||||
}
|
||||
}
|
||||
@include when(current) {
|
||||
color: $-calendar-active-color;
|
||||
}
|
||||
@include when(selected) {
|
||||
color: #fff;
|
||||
|
||||
.wd-year__month-text {
|
||||
border-radius: $-calendar-active-border;
|
||||
background: $-calendar-active-color;
|
||||
}
|
||||
}
|
||||
@include when(middle) {
|
||||
background: $-calendar-range-color;
|
||||
}
|
||||
@include when(start) {
|
||||
color: #fff;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 50%;
|
||||
bottom: 0;
|
||||
content: '';
|
||||
background: $-calendar-range-color;
|
||||
}
|
||||
.wd-year__month-text {
|
||||
background: $-calendar-active-color;
|
||||
border-radius: $-calendar-active-border;
|
||||
}
|
||||
&.is-without-end::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@include when(end) {
|
||||
color: #fff;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 50%;
|
||||
bottom: 0;
|
||||
content: '';
|
||||
background: $-calendar-range-color;
|
||||
}
|
||||
.wd-year__month-text {
|
||||
background: $-calendar-active-color;
|
||||
border-radius: $-calendar-active-border;
|
||||
}
|
||||
}
|
||||
@include when(same) {
|
||||
color: #fff;
|
||||
|
||||
.wd-year__month-text {
|
||||
background: $-calendar-active-color;
|
||||
border-radius: $-calendar-active-border;
|
||||
}
|
||||
}
|
||||
}
|
||||
@include e(month-text) {
|
||||
width: $-calendar-month-width;
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
}
|
||||
@include e(month-top) {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
line-height: 1.1;
|
||||
font-size: $-calendar-info-fs;
|
||||
text-align: center;
|
||||
}
|
||||
@include e(month-bottom) {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
line-height: 1.1;
|
||||
font-size: $-calendar-info-fs;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,87 @@
|
||||
import VueComponent from '../../../common/component'
|
||||
import { getYears, compareYear, formatYearTitle } from '../../utils'
|
||||
import { getType } from '../../../common/util'
|
||||
|
||||
VueComponent({
|
||||
props: {
|
||||
type: String,
|
||||
value: {
|
||||
type: [null, Number, Array]
|
||||
},
|
||||
minDate: Number,
|
||||
maxDate: Number,
|
||||
formatter: null,
|
||||
maxRange: Number,
|
||||
rangePrompt: String,
|
||||
allowSameDay: Boolean,
|
||||
showPanelTitle: Boolean,
|
||||
defaultTime: Array,
|
||||
panelHeight: Number
|
||||
},
|
||||
data: {
|
||||
title: '',
|
||||
scrollIntoView: ''
|
||||
},
|
||||
mounted () {
|
||||
this.initRect()
|
||||
this.scrollIntoView()
|
||||
},
|
||||
methods: {
|
||||
initRect (thresholds = [0, 0.15, 0.7, 0.8, 0.9, 1]) {
|
||||
if (!this.data.showPanelTitle) return
|
||||
|
||||
if (this.contentObserver != null) {
|
||||
this.contentObserver.disconnect()
|
||||
}
|
||||
|
||||
const contentObserver = this.createIntersectionObserver({
|
||||
thresholds,
|
||||
observeAll: true
|
||||
})
|
||||
|
||||
this.contentObserver = contentObserver
|
||||
|
||||
contentObserver.relativeTo('.wd-year-panel__container')
|
||||
contentObserver.observe('.year', (res) => {
|
||||
if (res.boundingClientRect.top <= res.relativeRect.top) {
|
||||
this.setData({
|
||||
title: formatYearTitle(res.dataset.date)
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
scrollIntoView () {
|
||||
this.requestAnimationFrame().then(() => {
|
||||
let activeDate
|
||||
const type = getType(this.data.value)
|
||||
if (type === 'array') {
|
||||
activeDate = this.data.value[0]
|
||||
} else if (type === 'number') {
|
||||
activeDate = this.data.value
|
||||
}
|
||||
|
||||
if (!activeDate) {
|
||||
activeDate = Date.now()
|
||||
}
|
||||
|
||||
const years = getYears(this.data.minDate, this.data.maxDate)
|
||||
|
||||
years.some((year, index) => {
|
||||
if (compareYear(year, activeDate) === 0) {
|
||||
this.setData({
|
||||
scrollIntoView: `year${index}`
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
})
|
||||
})
|
||||
},
|
||||
handleDateChange ({ detail: { value } }) {
|
||||
this.$emit('change', {
|
||||
value
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -0,0 +1,6 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
"year": "../year/index"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
<jds src="../../utils.jds" module="utils" />
|
||||
|
||||
<view class="wd-year-panel">
|
||||
<view v-if="{{ showPanelTitle }}" class="wd-year-panel__title">{{ title }}</view>
|
||||
<scroll-view class="wd-year-panel__container" style="height: {{ (panelHeight || 378) + (showPanelTitle ? 26 : 16) }}px" scroll-y scroll-into-view="{{ scrollIntoView }}">
|
||||
<year
|
||||
jd:for="{{ utils.getYears(minDate, maxDate) }}"
|
||||
jd:key="*this"
|
||||
id="year{{index}}"
|
||||
class="year"
|
||||
type="{{ type }}"
|
||||
date="{{ item }}"
|
||||
data-date="{{ item }}"
|
||||
value="{{ value }}"
|
||||
min-date="{{ minDate }}"
|
||||
max-date="{{ maxDate }}"
|
||||
max-range="{{ maxRange }}"
|
||||
formatter="{{ formatter }}"
|
||||
range-prompt="{{ rangePrompt }}"
|
||||
allow-same-day="{{ allowSameDay }}"
|
||||
default-time="{{ defaultTime }}"
|
||||
bind:change="handleDateChange"
|
||||
/>
|
||||
</scroll-view>
|
||||
</view>
|
||||
@ -0,0 +1,15 @@
|
||||
@import '../../../common/abstracts/variable';
|
||||
@import '../../../common/abstracts/mixin';
|
||||
|
||||
@include b(year-panel) {
|
||||
font-size: $-calendar-fs;
|
||||
padding: $-calendar-panel-padding;
|
||||
|
||||
@include e(title) {
|
||||
padding: 5px 0;
|
||||
text-align: center;
|
||||
font-size: $-calendar-panel-title-fs;
|
||||
color: $-calendar-panel-title-color;
|
||||
box-shadow: 0px 4px 8px 0 rgba(0, 0, 0, 0.02);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
import VueComponent from '../common/component'
|
||||
import { getDefaultTime } from './utils'
|
||||
|
||||
const current = new Date()
|
||||
const currentYear = current.getFullYear()
|
||||
const currentMonth = current.getMonth()
|
||||
const currentDay = current.getDate()
|
||||
|
||||
VueComponent({
|
||||
behaviors: ['jd://form-field'],
|
||||
props: {
|
||||
value: {
|
||||
type: [null, Number, Array]
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
value: 'date'
|
||||
},
|
||||
minDate: {
|
||||
type: Number,
|
||||
value: new Date(currentYear, currentMonth - 6, currentDay).getTime()
|
||||
},
|
||||
maxDate: {
|
||||
type: Number,
|
||||
value: new Date(currentYear, currentMonth + 6, currentDay, 23, 59, 59).getTime()
|
||||
},
|
||||
firstDayOfWeek: {
|
||||
type: Number,
|
||||
value: 0
|
||||
},
|
||||
formatter: null,
|
||||
maxRange: Number,
|
||||
rangePrompt: String,
|
||||
allowSameDay: Boolean,
|
||||
showPanelTitle: {
|
||||
type: Boolean,
|
||||
value: true
|
||||
},
|
||||
defaultTime: {
|
||||
type: [String, Array],
|
||||
observer (val) {
|
||||
this.setData({
|
||||
formatDefauleTime: getDefaultTime(val)
|
||||
})
|
||||
}
|
||||
},
|
||||
panelHeight: Number,
|
||||
timeFilter: null,
|
||||
hideSecond: Boolean
|
||||
},
|
||||
data: {
|
||||
formatDefauleTime: []
|
||||
},
|
||||
methods: {
|
||||
// 对外暴露方法
|
||||
scrollIntoView (thresholds) {
|
||||
const panel = this.getPanel()
|
||||
panel.initRect && panel.initRect(thresholds)
|
||||
panel.scrollIntoView()
|
||||
},
|
||||
getPanel () {
|
||||
return this.data.type.indexOf('month') > -1 ? this.selectComponent('#yearPanel') : this.selectComponent('#monthPanel')
|
||||
},
|
||||
handleChange ({ detail: { value } }) {
|
||||
this.setData({
|
||||
value
|
||||
})
|
||||
this.$emit('change', {
|
||||
value
|
||||
})
|
||||
},
|
||||
handlePickStart () {
|
||||
this.$emit('pickstart')
|
||||
},
|
||||
handlePickEnd () {
|
||||
this.$emit('pickend')
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -0,0 +1,8 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
"wd-icon": "../icon/index",
|
||||
"year-panel": "./components/yearPanel/index",
|
||||
"month-panel": "./components/monthPanel/index"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
<view class="wd-calendar-view custom-class">
|
||||
<year-panel
|
||||
v-if="{{ type === 'month' || type === 'monthrange' }}"
|
||||
id="yearPanel"
|
||||
type="{{ type }}"
|
||||
value="{{ value }}"
|
||||
min-date="{{ minDate }}"
|
||||
max-date="{{ maxDate }}"
|
||||
formatter="{{ formatter }}"
|
||||
max-range="{{ maxRange }}"
|
||||
range-prompt="{{ rangePrompt }}"
|
||||
allow-same-day="{{ allowSameDay }}"
|
||||
show-panel-title="{{ showPanelTitle }}"
|
||||
default-time="{{ formatDefauleTime }}"
|
||||
panel-height="{{ panelHeight }}"
|
||||
bind:change="handleChange"
|
||||
/>
|
||||
<month-panel
|
||||
v-else
|
||||
id="monthPanel"
|
||||
type="{{ type }}"
|
||||
value="{{ value }}"
|
||||
min-date="{{ minDate }}"
|
||||
max-date="{{ maxDate }}"
|
||||
first-day-of-week="{{ firstDayOfWeek }}"
|
||||
formatter="{{ formatter }}"
|
||||
max-range="{{ maxRange }}"
|
||||
range-prompt="{{ rangePrompt }}"
|
||||
allow-same-day="{{ allowSameDay }}"
|
||||
show-panel-title="{{ showPanelTitle }}"
|
||||
default-time="{{ formatDefauleTime }}"
|
||||
panel-height="{{ panelHeight }}"
|
||||
time-filter="{{ timeFilter }}"
|
||||
hide-second="{{ hideSecond }}"
|
||||
bind:change="handleChange"
|
||||
bind:pickstart="handlePickStart"
|
||||
bind:pickend="handlePickEnd"
|
||||
/>
|
||||
</view>
|
||||
@ -0,0 +1,176 @@
|
||||
var weeks = ['日', '一', '二', '三', '四', '五', '六']
|
||||
|
||||
/**
|
||||
* 比较两个日期的月份是否相等
|
||||
* @param {timestamp} date1
|
||||
* @param {timestamp} date2
|
||||
*/
|
||||
function compareMonth (date1, date2) {
|
||||
date1 = getDate(date1)
|
||||
date2 = getDate(date2)
|
||||
|
||||
var year1 = date1.getFullYear()
|
||||
var year2 = date2.getFullYear()
|
||||
var month1 = date1.getMonth()
|
||||
var month2 = date2.getMonth()
|
||||
|
||||
if (year1 === year2) {
|
||||
return month1 === month2 ? 0 : (month1 > month2 ? 1 : -1)
|
||||
}
|
||||
|
||||
return year1 > year2 ? 1 : -1
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较两个日期的年份是否相等
|
||||
* @param {timestamp} date1
|
||||
* @param {timestamp} date2
|
||||
*/
|
||||
function compareYear (date1, date2) {
|
||||
date1 = getDate(date1)
|
||||
date2 = getDate(date2)
|
||||
|
||||
var year1 = date1.getFullYear()
|
||||
var year2 = date2.getFullYear()
|
||||
|
||||
return year1 === year2 ? 0 : (year1 > year2 ? 1 : -1)
|
||||
}
|
||||
|
||||
function compareDay (date1, date2) {
|
||||
date1 = getDate(date1)
|
||||
date2 = getDate(date2)
|
||||
|
||||
var year1 = date1.getFullYear()
|
||||
var year2 = date2.getFullYear()
|
||||
var month1 = date1.getMonth()
|
||||
var month2 = date2.getMonth()
|
||||
var day1 = date1.getDate()
|
||||
var day2 = date2.getDate()
|
||||
|
||||
if (year1 === year2) {
|
||||
if (month1 === month2) {
|
||||
return day1 === day2 ? 0 : (day1 > day2 ? 1 : -1)
|
||||
}
|
||||
|
||||
return month1 > month2 ? 1 : -1
|
||||
}
|
||||
|
||||
return year1 > year2 ? 1 : -1
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据最小日期和最大日期获取这之间总共有几个月份
|
||||
* @param {timestamp} minDate
|
||||
* @param {timestamp} maxDate
|
||||
*/
|
||||
function getMonths (minDate, maxDate) {
|
||||
var months = []
|
||||
var month = getDate(minDate)
|
||||
month.setDate(1)
|
||||
|
||||
while (compareMonth(month, maxDate) < 1) {
|
||||
months.push(month.getTime())
|
||||
month.setMonth(month.getMonth() + 1)
|
||||
}
|
||||
|
||||
return months
|
||||
}
|
||||
|
||||
function getYears (minDate, maxDate) {
|
||||
var years = []
|
||||
var year = getDate(minDate)
|
||||
year.setMonth(0)
|
||||
year.setDate(1)
|
||||
|
||||
while (compareYear(year, maxDate) < 1) {
|
||||
years.push(year.getTime())
|
||||
year.setFullYear(year.getFullYear() + 1)
|
||||
}
|
||||
|
||||
return years
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据下标获取星期
|
||||
* @param {number} index
|
||||
*/
|
||||
function getWeekLabel (index) {
|
||||
if (index >= 7) {
|
||||
index = index % 7
|
||||
}
|
||||
|
||||
return weeks[index]
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化年月
|
||||
* @param {timestamp} date
|
||||
*/
|
||||
function formatMonthTitle (date) {
|
||||
date = getDate(date)
|
||||
var year = date.getFullYear()
|
||||
var month = date.getMonth() + 1
|
||||
|
||||
return year + '年' + month + '月'
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化年
|
||||
* @param {timestamp} date
|
||||
*/
|
||||
function formatYearTitle (date) {
|
||||
date = getDate(date)
|
||||
var year = date.getFullYear()
|
||||
|
||||
return year + '年'
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取一个月第一天的样式
|
||||
* @param {number} index
|
||||
* @param {timestamp} date
|
||||
* @param {number} firstDayOfWeek
|
||||
*/
|
||||
function getFirstDayStyle (index, date, firstDayOfWeek) {
|
||||
if (firstDayOfWeek >= 7) {
|
||||
firstDayOfWeek = firstDayOfWeek % 7
|
||||
}
|
||||
|
||||
if (index !== 0) return ''
|
||||
|
||||
date = getDate(date)
|
||||
var offset = (7 + date.getDay() - firstDayOfWeek) % 7
|
||||
|
||||
return 'margin-left: ' + (100 / 7) * offset + '%'
|
||||
}
|
||||
|
||||
function getItemClass (monthType, value, type) {
|
||||
var classList = [('is-' + monthType)]
|
||||
|
||||
if (type.indexOf('range') > -1) {
|
||||
if (!value || !value[1]) {
|
||||
classList.push('is-without-end')
|
||||
}
|
||||
}
|
||||
|
||||
return classList.join(' ')
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否是范围选择
|
||||
* @param {string} type
|
||||
*/
|
||||
function isRange (type) {
|
||||
return type.indexOf('range') > -1
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getMonths: getMonths,
|
||||
getWeekLabel: getWeekLabel,
|
||||
getFirstDayStyle: getFirstDayStyle,
|
||||
formatMonthTitle: formatMonthTitle,
|
||||
getYears: getYears,
|
||||
formatYearTitle: formatYearTitle,
|
||||
getItemClass: getItemClass,
|
||||
isRange: isRange
|
||||
}
|
||||
@ -0,0 +1,374 @@
|
||||
import { getType, padZero } from '../common/util'
|
||||
|
||||
/**
|
||||
* 比较两个时间的日期是否相等
|
||||
* @param {timestamp} date1
|
||||
* @param {timestamp} date2
|
||||
*/
|
||||
export function compareDate (date1, date2) {
|
||||
date1 = new Date(date1)
|
||||
date2 = new Date(date2)
|
||||
|
||||
const year1 = date1.getFullYear()
|
||||
const year2 = date2.getFullYear()
|
||||
const month1 = date1.getMonth()
|
||||
const month2 = date2.getMonth()
|
||||
const day1 = date1.getDate()
|
||||
const day2 = date2.getDate()
|
||||
|
||||
if (year1 === year2) {
|
||||
if (month1 === month2) {
|
||||
return day1 === day2 ? 0 : (day1 > day2 ? 1 : -1)
|
||||
}
|
||||
return month1 === month2 ? 0 : (month1 > month2 ? 1 : -1)
|
||||
}
|
||||
|
||||
return year1 > year2 ? 1 : -1
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较两个日期的月份是否相等
|
||||
* @param {timestamp} date1
|
||||
* @param {timestamp} date2
|
||||
*/
|
||||
export function compareMonth (date1, date2) {
|
||||
date1 = new Date(date1)
|
||||
date2 = new Date(date2)
|
||||
|
||||
const year1 = date1.getFullYear()
|
||||
const year2 = date2.getFullYear()
|
||||
const month1 = date1.getMonth()
|
||||
const month2 = date2.getMonth()
|
||||
|
||||
if (year1 === year2) {
|
||||
return month1 === month2 ? 0 : (month1 > month2 ? 1 : -1)
|
||||
}
|
||||
|
||||
return year1 > year2 ? 1 : -1
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较两个日期的年份是否一致
|
||||
* @param {timestamp} date1
|
||||
* @param {timestamp} date2
|
||||
*/
|
||||
export function compareYear (date1, date2) {
|
||||
date1 = new Date(date1)
|
||||
date2 = new Date(date2)
|
||||
|
||||
const year1 = date1.getFullYear()
|
||||
const year2 = date2.getFullYear()
|
||||
|
||||
return year1 === year2 ? 0 : (year1 > year2 ? 1 : -1)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取一个月的最后一天
|
||||
* @param {number} year
|
||||
* @param {number} month
|
||||
*/
|
||||
export function getMonthEndDay (year, month) {
|
||||
return 32 - new Date(year, month - 1, 32).getDate()
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化年月
|
||||
* @param {timestamp} date
|
||||
*/
|
||||
export function formatMonthTitle (date) {
|
||||
date = new Date(date)
|
||||
|
||||
const year = date.getFullYear()
|
||||
const month = date.getMonth() + 1
|
||||
|
||||
return year + '年' + month + '月'
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化年份
|
||||
* @param {timestamp} date
|
||||
*/
|
||||
export function formatYearTitle (date) {
|
||||
date = new Date(date)
|
||||
|
||||
const year = date.getFullYear()
|
||||
|
||||
return year + '年'
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据最小日期和最大日期获取这之间总共有几个月份
|
||||
* @param {timestamp} minDate
|
||||
* @param {timestamp} maxDate
|
||||
*/
|
||||
export function getMonths (minDate, maxDate) {
|
||||
const months = []
|
||||
const month = new Date(minDate)
|
||||
month.setDate(1)
|
||||
|
||||
while (compareMonth(month, maxDate) < 1) {
|
||||
months.push(month.getTime())
|
||||
month.setMonth(month.getMonth() + 1)
|
||||
}
|
||||
|
||||
return months
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据最小日期和最大日期获取这之间总共有几年
|
||||
* @param {timestamp} minDate
|
||||
* @param {timestamp} maxDate
|
||||
*/
|
||||
export function getYears (minDate, maxDate) {
|
||||
const years = []
|
||||
const year = new Date(minDate)
|
||||
year.setMonth(0)
|
||||
year.setDate(1)
|
||||
|
||||
while (compareYear(year, maxDate) < 1) {
|
||||
years.push(year.getTime())
|
||||
year.setFullYear(year.getFullYear() + 1)
|
||||
}
|
||||
|
||||
return years
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取一个日期所在周的第一天和最后一天
|
||||
* @param {timestamp} date
|
||||
*/
|
||||
export function getWeekRange (date, firstDayOfWeek) {
|
||||
if (firstDayOfWeek >= 7) {
|
||||
firstDayOfWeek = firstDayOfWeek % 7
|
||||
}
|
||||
|
||||
date = new Date(date)
|
||||
date.setHours(0, 0, 0, 0)
|
||||
const year = date.getFullYear()
|
||||
const month = date.getMonth()
|
||||
const day = date.getDate()
|
||||
const week = date.getDay()
|
||||
|
||||
const weekStart = new Date(year, month, day - (7 + week - firstDayOfWeek) % 7)
|
||||
const weekEnd = new Date(year, month, day + 6 - (7 + week - firstDayOfWeek) % 7)
|
||||
|
||||
return [weekStart.getTime(), weekEnd.getTime()]
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取日期偏移量
|
||||
* @param {timestamp} date1
|
||||
* @param {timestamp} date2
|
||||
*/
|
||||
export function getDayOffset (date1, date2) {
|
||||
return (date1 - date2) / (24 * 60 * 60 * 1000) + 1
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取偏移日期
|
||||
* @param {timestamp} date
|
||||
* @param {number} offset
|
||||
*/
|
||||
export function getDayByOffset (date, offset) {
|
||||
date = new Date(date)
|
||||
date.setDate(date.getDate() + offset)
|
||||
|
||||
return date.getTime()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取月份偏移量
|
||||
* @param {timestamp} date1
|
||||
* @param {timestamp} date2
|
||||
*/
|
||||
export function getMonthOffset (date1, date2) {
|
||||
date1 = new Date(date1)
|
||||
date2 = new Date(date2)
|
||||
|
||||
const year1 = date1.getFullYear()
|
||||
const year2 = date2.getFullYear()
|
||||
let month1 = date1.getMonth()
|
||||
const month2 = date2.getMonth()
|
||||
|
||||
month1 = (year1 - year2) * 12 + month1
|
||||
|
||||
return month1 - month2 + 1
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取偏移月份
|
||||
* @param {timestamp} date
|
||||
* @param {number} offset
|
||||
*/
|
||||
export function getMonthByOffset (date, offset) {
|
||||
date = new Date(date)
|
||||
date.setMonth(date.getMonth() + offset)
|
||||
|
||||
return date.getTime()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取默认时间,格式化为数组
|
||||
* @param {array|string|null} defaultTime
|
||||
*/
|
||||
export function getDefaultTime (defaultTime) {
|
||||
if (getType(defaultTime) === 'array') {
|
||||
const startTime = (defaultTime[0] || '00:00:00').split(':').map(item => {
|
||||
return parseInt(item)
|
||||
})
|
||||
const endTime = (defaultTime[1] || '00:00:00').split(':').map(item => {
|
||||
return parseInt(item)
|
||||
})
|
||||
return [startTime, endTime]
|
||||
} else {
|
||||
const time = (defaultTime || '00:00:00').split(':').map(item => {
|
||||
return parseInt(item)
|
||||
})
|
||||
|
||||
return [time, time]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据默认时间获取日期
|
||||
* @param {timestamp} date
|
||||
* @param {array} defaultTime
|
||||
*/
|
||||
export function getDateByDefaultTime (date, defaultTime) {
|
||||
date = new Date(date)
|
||||
date.setHours(defaultTime[0])
|
||||
date.setMinutes(defaultTime[1])
|
||||
date.setSeconds(defaultTime[2])
|
||||
|
||||
return date.getTime()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取经过 iteratee 格式化后的长度为 n 的数组
|
||||
* @param {number} n
|
||||
* @param {function} iteratee
|
||||
*/
|
||||
const times = (n, iteratee) => {
|
||||
let index = -1
|
||||
const result = Array(n < 0 ? 0 : n)
|
||||
while (++index < n) {
|
||||
result[index] = iteratee(index)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取时分秒
|
||||
* @param {timestamp}} date
|
||||
*/
|
||||
const getTime = (date) => {
|
||||
date = new Date(date)
|
||||
return [date.getHours(), date.getMinutes(), date.getSeconds()]
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据最小最大日期获取时间数据,用于填入picker
|
||||
* @param {*} param0
|
||||
*/
|
||||
export function getTimeData ({ date, minDate, maxDate, isHideSecond, filter } = {}) {
|
||||
const compareMin = compareDate(date, minDate)
|
||||
const compareMax = compareDate(date, maxDate)
|
||||
|
||||
let minHour = 0
|
||||
let maxHour = 23
|
||||
let minMinute = 0
|
||||
let maxMinute = 59
|
||||
let minSecond = 0
|
||||
let maxSecond = 59
|
||||
|
||||
if (compareMin === 0) {
|
||||
const minTime = getTime(minDate)
|
||||
const currentTime = getTime(date)
|
||||
|
||||
minHour = minTime[0]
|
||||
if (minTime[0] === currentTime[0]) {
|
||||
minMinute = minTime[1]
|
||||
|
||||
if (minTime[1] === currentTime[1]) {
|
||||
minSecond = minTime[2]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (compareMax === 0) {
|
||||
const maxTime = getTime(maxDate)
|
||||
const currentTime = getTime(date)
|
||||
|
||||
maxHour = maxTime[0]
|
||||
if (maxTime[0] === currentTime[0]) {
|
||||
maxMinute = maxTime[1]
|
||||
|
||||
if (maxTime[1] === currentTime[1]) {
|
||||
maxSecond = maxTime[2]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let columns = []
|
||||
let hours = times(24, index => {
|
||||
return {
|
||||
label: `${padZero(index)}时`,
|
||||
value: index,
|
||||
disabled: index < minHour || index > maxHour
|
||||
}
|
||||
})
|
||||
let minutes = times(60, index => {
|
||||
return {
|
||||
label: `${padZero(index)}分`,
|
||||
value: index,
|
||||
disabled: index < minMinute || index > maxMinute
|
||||
}
|
||||
})
|
||||
let seconds
|
||||
if (filter && getType(filter) === 'function') {
|
||||
hours = filter({
|
||||
type: 'hour',
|
||||
values: hours
|
||||
})
|
||||
minutes = filter({
|
||||
type: 'minute',
|
||||
values: minutes
|
||||
})
|
||||
}
|
||||
|
||||
if (!isHideSecond) {
|
||||
seconds = times(60, index => {
|
||||
return {
|
||||
label: `${padZero(index)}秒`,
|
||||
value: index,
|
||||
disabled: index < minSecond || index > maxSecond
|
||||
}
|
||||
})
|
||||
if (filter && getType(filter) === 'function') {
|
||||
seconds = filter({
|
||||
type: 'second',
|
||||
values: seconds
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
columns = isHideSecond ? [hours, minutes] : [hours, minutes, seconds]
|
||||
|
||||
return columns
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前是第几周
|
||||
* @param {timestamp} date
|
||||
*/
|
||||
export function getWeekNumber (date) {
|
||||
date = new Date(date)
|
||||
date.setHours(0, 0, 0, 0)
|
||||
// Thursday in current week decides the year.
|
||||
date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7)
|
||||
// January 4 is always in week 1.
|
||||
const week = new Date(date.getFullYear(), 0, 4)
|
||||
// Adjust to Thursday in week 1 and count number of weeks from date to week 1.
|
||||
// Rounding should be fine for Daylight Saving Time. Its shift should never be more than 12 hours.
|
||||
return 1 + Math.round(((date.getTime() - week.getTime()) / 86400000 - 3 + (week.getDay() + 6) % 7) / 7)
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
<template>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
377
src/uni_modules/wot-design-uni/components/wd-calendar/index.js
Normal file
377
src/uni_modules/wot-design-uni/components/wd-calendar/index.js
Normal file
@ -0,0 +1,377 @@
|
||||
import VueComponent from '../common/component'
|
||||
import { isEqual, padZero } from '../common/util'
|
||||
import { getDefaultTime, getWeekNumber } from '../calendarView/utils'
|
||||
import cell from '../mixins/cell'
|
||||
import dayjs from '../common/dayjs.min'
|
||||
|
||||
const current = new Date()
|
||||
const currentYear = current.getFullYear()
|
||||
const currentMonth = current.getMonth()
|
||||
const currentDay = current.getDate()
|
||||
|
||||
const defaultDisplayFormat = (value, type) => {
|
||||
switch (type) {
|
||||
case 'date':
|
||||
return dayjs(value).format('YYYY-MM-DD')
|
||||
case 'dates':
|
||||
return value
|
||||
.map((item) => {
|
||||
return dayjs(item).format('YYYY-MM-DD')
|
||||
})
|
||||
.join(', ')
|
||||
case 'daterange':
|
||||
return `${value[0] ? dayjs(value[0]).format('YYYY-MM-DD') : '开始时间'} 至 ${value[1] ? dayjs(value[1]).format('YYYY-MM-DD') : '结束时间'}`
|
||||
case 'datetime':
|
||||
return dayjs(value).format('YYYY-MM-DD HH:mm:ss')
|
||||
case 'datetimerange':
|
||||
return `${value[0] ? dayjs(value[0]).format('YY年MM月DD日 HH:mm:ss') : '开始时间'} 至\n${
|
||||
value[1] ? dayjs(value[1]).format('YY年MM月DD日 HH:mm:ss') : '结束时间'
|
||||
}`
|
||||
case 'week': {
|
||||
const year = new Date(value).getFullYear()
|
||||
const week = getWeekNumber(value)
|
||||
return `${year} 第 ${padZero(week)} 周`
|
||||
}
|
||||
case 'weekrange': {
|
||||
const year1 = new Date(value[0]).getFullYear()
|
||||
const week1 = getWeekNumber(value[0])
|
||||
const year2 = new Date(value[1]).getFullYear()
|
||||
const week2 = getWeekNumber(value[1])
|
||||
return `${value[0] ? `${year1} 第 ${padZero(week1)} 周` : '开始周'} - ${value[1] ? `${year2} 第 ${padZero(week2)} 周` : '结束周'}`
|
||||
}
|
||||
case 'month':
|
||||
return dayjs(value).format('YYYY / MM')
|
||||
case 'monthrange':
|
||||
return `${value[0] ? dayjs(value[0]).format('YYYY / MM') : '开始月'} 至 ${value[1] ? dayjs(value[1]).format('YYYY / MM') : '结束月'}`
|
||||
}
|
||||
}
|
||||
|
||||
const formatRange = (value, rangeType, type) => {
|
||||
switch (type) {
|
||||
case 'daterange':
|
||||
if (!value) {
|
||||
return rangeType === 'end' ? '结束时间' : '开始时间'
|
||||
}
|
||||
return dayjs(value).format('YYYY年MM月DD日')
|
||||
case 'datetimerange':
|
||||
if (!value) {
|
||||
return rangeType === 'end' ? '结束时间' : '开始时间'
|
||||
}
|
||||
return dayjs(value).format('YY年MM月DD日 HH:mm:ss')
|
||||
case 'weekrange': {
|
||||
if (!value) {
|
||||
return rangeType === 'end' ? '结束周' : '开始周'
|
||||
}
|
||||
const date = new Date(value)
|
||||
const year = date.getFullYear()
|
||||
const week = getWeekNumber(value)
|
||||
return year + '年第' + week + '周'
|
||||
}
|
||||
case 'monthrange':
|
||||
if (!value) {
|
||||
return rangeType === 'end' ? '结束月' : '开始月'
|
||||
}
|
||||
return dayjs(value).format('YYYY年MM月')
|
||||
}
|
||||
}
|
||||
|
||||
VueComponent({
|
||||
externalClasses: ['custom-view-class', 'custom-label-class', 'custom-value-class'],
|
||||
behaviors: [cell, 'jd://form-field'],
|
||||
relations: {
|
||||
'../cellGroup/index': {
|
||||
type: 'ancestor',
|
||||
linked(target) {
|
||||
this.parent = target
|
||||
},
|
||||
unlinked() {
|
||||
this.parent = null
|
||||
}
|
||||
}
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: [null, Number, Array],
|
||||
observer(val, oldVal) {
|
||||
if (isEqual(val, oldVal)) return
|
||||
|
||||
this.setData(
|
||||
{
|
||||
calendarValue: val,
|
||||
confirmBtnDisabled: this.getConfirmBtnStatus(val)
|
||||
},
|
||||
() => {
|
||||
this.scrollIntoView()
|
||||
}
|
||||
)
|
||||
|
||||
this.setShowValue()
|
||||
|
||||
if (this.data.type.indexOf('range') > -1) {
|
||||
this.setInnerLabel()
|
||||
}
|
||||
}
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
value: 'date',
|
||||
observer(val) {
|
||||
if (this.data.showTypeSwitch) {
|
||||
const tabs = ['date', 'week', 'month']
|
||||
const rangeTabs = ['daterange', 'weekrange', 'monthrange']
|
||||
|
||||
const index = val.indexOf('range') > -1 ? rangeTabs.indexOf(val) || 0 : tabs.indexOf(val)
|
||||
this.setData({
|
||||
currentTab: index
|
||||
})
|
||||
}
|
||||
|
||||
this.setData({
|
||||
panelHeight: this.data.showConfirm ? 338 : 400,
|
||||
currentType: val
|
||||
})
|
||||
|
||||
if (this.data.type.indexOf('range') > -1) {
|
||||
this.setInnerLabel()
|
||||
}
|
||||
}
|
||||
},
|
||||
minDate: {
|
||||
type: Number,
|
||||
value: new Date(currentYear, currentMonth - 6, currentDay).getTime()
|
||||
},
|
||||
maxDate: {
|
||||
type: Number,
|
||||
value: new Date(currentYear, currentMonth + 6, currentDay, 23, 59, 59).getTime()
|
||||
},
|
||||
firstDayOfWeek: {
|
||||
type: Number,
|
||||
value: 0
|
||||
},
|
||||
formatter: null,
|
||||
maxRange: Number,
|
||||
rangePrompt: String,
|
||||
allowSameDay: Boolean,
|
||||
defaultTime: {
|
||||
type: [String, Array],
|
||||
observer(val) {
|
||||
this.setData({
|
||||
formatDefauleTime: getDefaultTime(val)
|
||||
})
|
||||
}
|
||||
},
|
||||
timeFilter: null,
|
||||
hideSecond: Boolean,
|
||||
label: String,
|
||||
labelWidth: String,
|
||||
useLabelSlot: Boolean,
|
||||
useDefaultSlot: Boolean,
|
||||
disabled: Boolean,
|
||||
readonly: Boolean,
|
||||
placeholder: String,
|
||||
title: String,
|
||||
alignRight: Boolean,
|
||||
error: Boolean,
|
||||
required: Boolean,
|
||||
size: String,
|
||||
center: Boolean,
|
||||
closeOnClickModal: {
|
||||
type: Boolean,
|
||||
value: true
|
||||
},
|
||||
zIndex: {
|
||||
type: Number,
|
||||
value: 15
|
||||
},
|
||||
showConfirm: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
observer(val) {
|
||||
this.setData({
|
||||
panelHeight: val ? 338 : 400
|
||||
})
|
||||
}
|
||||
},
|
||||
confirmText: String,
|
||||
displayFormat: null,
|
||||
innerDisplayFormat: null,
|
||||
ellipsis: Boolean,
|
||||
showTypeSwitch: Boolean,
|
||||
shortcuts: Array,
|
||||
onShortcutsClick: null,
|
||||
safeAreaInsetBottom: {
|
||||
type: Boolean,
|
||||
value: true
|
||||
},
|
||||
beforeConfirm: null
|
||||
},
|
||||
data: {
|
||||
pickerShow: false,
|
||||
calendarValue: '',
|
||||
lastCalendarValue: '',
|
||||
panelHeight: 338,
|
||||
confirmBtnDisabled: true,
|
||||
showValue: '',
|
||||
currentTab: 0,
|
||||
lastTab: 0,
|
||||
currentType: 'date',
|
||||
lastCurrentType: 'date',
|
||||
inited: false,
|
||||
rangeLabel: []
|
||||
},
|
||||
methods: {
|
||||
scrollIntoView() {
|
||||
const calendarView = this.selectComponent('#calendarView')
|
||||
calendarView && calendarView.scrollIntoView()
|
||||
},
|
||||
// 对外暴露方法
|
||||
open() {
|
||||
const { disabled, readonly } = this.data
|
||||
|
||||
if (disabled || readonly) return
|
||||
|
||||
this.setData(
|
||||
{
|
||||
inited: true,
|
||||
pickerShow: true,
|
||||
lastCalendarValue: this.data.calendarValue,
|
||||
lastTab: this.data.currentTab,
|
||||
lastCurrentType: this.data.currentType
|
||||
},
|
||||
() => {
|
||||
setTimeout(() => {
|
||||
this.scrollIntoView()
|
||||
|
||||
if (this.data.showTypeSwitch) {
|
||||
const tab = this.selectComponent('#tabs')
|
||||
tab.scrollIntoView()
|
||||
tab.updateLineStyle(false)
|
||||
}
|
||||
}, 250)
|
||||
}
|
||||
)
|
||||
},
|
||||
// 对外暴露方法
|
||||
close() {
|
||||
this.setData({
|
||||
pickerShow: false
|
||||
})
|
||||
setTimeout(() => {
|
||||
const confirmBtnDisabled = this.getConfirmBtnStatus(this.data.lastCalendarValue)
|
||||
|
||||
this.setData({
|
||||
calendarValue: this.data.lastCalendarValue,
|
||||
currentTab: this.data.lastTab,
|
||||
currentType: this.data.lastCurrentType,
|
||||
confirmBtnDisabled
|
||||
})
|
||||
}, 250)
|
||||
this.$emit('cancel')
|
||||
},
|
||||
handleTypeChange({ detail: { index } }) {
|
||||
const tabs = ['date', 'week', 'month']
|
||||
const rangeTabs = ['daterange', 'weekrange', 'monthrange']
|
||||
const type = this.data.type.indexOf('range') > -1 ? rangeTabs[index] : tabs[index]
|
||||
|
||||
this.setData({
|
||||
currentTab: index,
|
||||
currentType: type
|
||||
})
|
||||
},
|
||||
getConfirmBtnStatus(value) {
|
||||
let confirmBtnDisabled = false
|
||||
// 范围选择未选择满,或者多日期选择未选择日期,按钮置灰不可点击
|
||||
if (
|
||||
(this.data.type.indexOf('range') > -1 && (!value[0] || !value[1] || !value)) ||
|
||||
(this.data.type === 'dates' && (value.length === 0 || !value)) ||
|
||||
!value
|
||||
) {
|
||||
confirmBtnDisabled = true
|
||||
}
|
||||
|
||||
return confirmBtnDisabled
|
||||
},
|
||||
handleChange({ detail: { value } }) {
|
||||
const confirmBtnDisabled = this.getConfirmBtnStatus(value)
|
||||
this.setData({
|
||||
calendarValue: value,
|
||||
confirmBtnDisabled
|
||||
})
|
||||
|
||||
this.$emit('change', {
|
||||
value
|
||||
})
|
||||
|
||||
if (this.data.type.indexOf('range') > -1) {
|
||||
this.setInnerLabel()
|
||||
}
|
||||
|
||||
if (!this.data.showConfirm && !confirmBtnDisabled) {
|
||||
this.handleConfirm()
|
||||
}
|
||||
},
|
||||
handleConfirm() {
|
||||
if (this.data.beforeConfirm) {
|
||||
this.data.beforeConfirm({
|
||||
value: this.data.calendarValue,
|
||||
resolve: (isPass) => {
|
||||
isPass && this.onConfirm()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.onConfirm()
|
||||
}
|
||||
},
|
||||
onConfirm() {
|
||||
this.setData({
|
||||
pickerShow: false,
|
||||
value: this.data.calendarValue
|
||||
})
|
||||
this.$emit('confirm', {
|
||||
value: this.data.calendarValue
|
||||
})
|
||||
this.setShowValue()
|
||||
},
|
||||
setInnerLabel() {
|
||||
const [start, end] = this.data.calendarValue || []
|
||||
this.setData({
|
||||
rangeLabel: [start, end].map((item, index) => {
|
||||
return (this.data.innerDisplayFormat || formatRange)(item, index === 0 ? 'start' : 'end', this.data.currentType)
|
||||
})
|
||||
})
|
||||
},
|
||||
setShowValue() {
|
||||
if (
|
||||
(!(this.data.calendarValue instanceof Array) && this.data.calendarValue) ||
|
||||
(this.data.calendarValue instanceof Array && this.data.calendarValue.length)
|
||||
) {
|
||||
this.setData({
|
||||
showValue: (this.data.displayFormat || defaultDisplayFormat)(this.data.calendarValue, this.data.currentType)
|
||||
})
|
||||
} else {
|
||||
this.setData({
|
||||
showValue: ''
|
||||
})
|
||||
}
|
||||
},
|
||||
handleShortcutClick(event) {
|
||||
const { index } = event.target.dataset
|
||||
|
||||
if (this.data.onShortcutsClick && typeof this.data.onShortcutsClick === 'function') {
|
||||
const calendarValue = this.data.onShortcutsClick({
|
||||
item: this.data.shortcuts[index],
|
||||
index
|
||||
})
|
||||
const confirmBtnDisabled = this.getConfirmBtnStatus(calendarValue)
|
||||
this.setData({
|
||||
calendarValue,
|
||||
confirmBtnDisabled
|
||||
})
|
||||
}
|
||||
|
||||
if (!this.data.showConfirm) {
|
||||
this.handleConfirm()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -0,0 +1,12 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
"wd-action-sheet": "../actionSheet/index",
|
||||
"wd-icon": "../icon/index",
|
||||
"wd-calendar-view": "../calendarView/index",
|
||||
"wd-button": "../button/index",
|
||||
"wd-tabs": "../tabs/index",
|
||||
"wd-tab": "../tab/index",
|
||||
"wd-tag": "../tag/index"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,87 @@
|
||||
<jds src="../calendarView/utils.jds" module="utils" />
|
||||
|
||||
<view class="wd-calendar {{ border ? 'is-border' : '' }} custom-class">
|
||||
<view class="wd-calendar__field" bind:tap="open">
|
||||
<slot v-if="{{ useDefaultSlot }}"></slot>
|
||||
<view v-else class="wd-calendar__cell {{ disabled && 'is-disabled' }} {{ readonly && 'is-readonly' }} {{ alignRight && 'is-align-right' }} {{ error && 'is-error' }} {{ size && ('is-' + size) }} {{ center && 'is-center' }}">
|
||||
<view
|
||||
v-if="{{ label || useLabelSlot }}"
|
||||
class="wd-calendar__label {{ required && 'is-required' }} custom-label-class"
|
||||
style="{{ labelWidth ? 'min-width:' + labelWidth + ';max-width:' + labelWidth + ';' : '' }}"
|
||||
>
|
||||
<block v-if="{{ label }}">{{ label }}</block>
|
||||
<slot v-else name="label"></slot>
|
||||
</view>
|
||||
<view class="wd-calendar__value {{ ellipsis && 'is-ellipsis' }} custom-value-class {{ showValue ? '' : 'wd-calendar__value--placeholder' }}">{{ showValue || placeholder || '请选择' }}</view>
|
||||
<wd-icon
|
||||
v-if="{{!disabled && !readonly}}"
|
||||
custom-class="wd-calendar__arrow"
|
||||
name="arrow-right"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
<wd-action-sheet
|
||||
show="{{ pickerShow }}"
|
||||
duration="{{ 250 }}"
|
||||
close-on-click-modal="{{ closeOnClickModal }}"
|
||||
safe-area-inset-bottom="{{ safeAreaInsetBottom }}"
|
||||
z-index="{{ zIndex }}"
|
||||
bind:close="close"
|
||||
>
|
||||
<view class="wd-calendar__header">
|
||||
<view v-if="{{ !showTypeSwitch && shortcuts.length === 0 }}" class="wd-calendar__title">{{ title || '选择日期' }}</view>
|
||||
<view v-if="{{ showTypeSwitch }}" class="wd-calendar__tabs">
|
||||
<wd-tabs id="tabs" value="{{ currentTab }}" bind:change="handleTypeChange">
|
||||
<wd-tab title="日" />
|
||||
<wd-tab title="周" />
|
||||
<wd-tab title="月" />
|
||||
</wd-tabs>
|
||||
</view>
|
||||
<view v-if="{{ shortcuts.length > 0 }}" class="wd-calendar__shortcuts">
|
||||
<wd-tag
|
||||
jd:for="{{ shortcuts }}"
|
||||
jd:key="index"
|
||||
custom-class="wd-calendar__tag"
|
||||
type="primary"
|
||||
plain
|
||||
round
|
||||
data-index="{{ index }}"
|
||||
bind:click="handleShortcutClick"
|
||||
>{{ item.text }}</wd-tag>
|
||||
</view>
|
||||
<wd-icon custom-class="wd-calendar__close" name="add" bind:tap="close"/>
|
||||
</view>
|
||||
<view v-if="{{ inited }}" class="wd-calendar__view {{ currentType.indexOf('range') > -1 && 'is-range' }} {{ showConfirm && 'is-show-confirm' }}">
|
||||
<view v-if="{{ utils.isRange(type) }}" class="wd-calendar__range-label {{ type === 'monthrange' && 'is-monthrange' }}">
|
||||
<view class="wd-calendar__range-label-item {{ (!calendarValue || !calendarValue[0]) && 'is-placeholder' }}" style="text-align: right;">
|
||||
{{ rangeLabel[0] }}
|
||||
</view>
|
||||
<view class="wd-calendar__range-sperator">/</view>
|
||||
<view class="wd-calendar__range-label-item {{ (!calendarValue || !calendarValue[1]) && 'is-placeholder' }}">
|
||||
{{ rangeLabel[1] }}
|
||||
</view>
|
||||
</view>
|
||||
<wd-calendar-view
|
||||
id="calendarView"
|
||||
value="{{ calendarValue }}"
|
||||
type="{{ currentType }}"
|
||||
min-date="{{ minDate }}"
|
||||
max-date="{{ maxDate }}"
|
||||
first-day-of-week="{{ firstDayOfWeek }}"
|
||||
formatter="{{ formatter }}"
|
||||
panel-height="{{ panelHeight }}"
|
||||
max-range="{{ maxRange }}"
|
||||
range-prompt="{{ rangePrompt }}"
|
||||
allow-same-day="{{ allowSameDay }}"
|
||||
default-time="{{ defaultTime }}"
|
||||
time-filter="{{ timeFilter }}"
|
||||
hide-second="{{ hideSecond }}"
|
||||
show-panel-title="{{ !utils.isRange(type) }}"
|
||||
bind:change="handleChange"
|
||||
/>
|
||||
</view>
|
||||
<view v-if="{{ showConfirm }}" class="wd-calendar__confirm">
|
||||
<wd-button block disabled="{{ confirmBtnDisabled }}" bind:click="handleConfirm">{{ confirmText || '确定' }}</wd-button>
|
||||
</view>
|
||||
</wd-action-sheet>
|
||||
</view>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user