wip: 临时提交
This commit is contained in:
@@ -1,14 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
import { onLaunch, onShow, onHide } from "@dcloudio/uni-app";
|
||||
import { useThemeStore } from "@/store";
|
||||
import { useTheme } from "@/composables/useTheme";
|
||||
|
||||
// 主题初始化
|
||||
const themeStore = useThemeStore();
|
||||
// 使用主题 composable
|
||||
const { initTheme } = useTheme();
|
||||
|
||||
onLaunch(() => {
|
||||
console.log("App Launch");
|
||||
// 初始化主题
|
||||
themeStore.initTheme();
|
||||
initTheme();
|
||||
});
|
||||
|
||||
onShow(() => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<template v-if="tagType">
|
||||
<wd-tag :type="tagType" :round="round">{{ label }}</wd-tag>
|
||||
<wd-tag :type="tagType as any" :round="round">{{ label }}</wd-tag>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view>{{ label }}</view>
|
||||
|
||||
@@ -1,196 +0,0 @@
|
||||
# 1.4.2
|
||||
|
||||
新增
|
||||
|
||||
1. 新增`filterValue`属性,支持通过此关键词来搜索并筛选树结构的内容
|
||||
|
||||
# 1.4.1
|
||||
|
||||
修复
|
||||
|
||||
1. 修复单选 onlyRadioLeaf 时末级节点无法选中的 bug
|
||||
|
||||
# 1.4.0
|
||||
|
||||
版本调整
|
||||
|
||||
建议更新,但需要注意,异步数据的时候,后台需返回 leaf 字段来判断是否末项数据
|
||||
|
||||
1. **调整数据项格式,新增 `leaf` 字段,来判断是否为末节点**
|
||||
2. **调整数据项格式,新增 `sort` 字段,来排序节点位置**
|
||||
3. **注意:异步加载数据,当为末项的时候,需要服务端数据返回 `leaf` 字段**
|
||||
4. 新增 `alwaysFirstLoad` ,即异步数据总会在第一次展开节点时,拉取一次后台数据,来比对是否一致
|
||||
5. 拆分 `field` 属性,**注意: 1.5.0 版本后将移除 `field` 属性**
|
||||
6. 新增 `labelField` 同 `field.label`,指定节点对象中某个属性为**标签**字段,默认`label`
|
||||
7. 新增 `valueField` 同 `field.key`,指定节点对象中某个属性为**值**字段,默认`value`
|
||||
8. 新增 `childrenField` 同 `field.children`,指定节点对象中某个属性为**子树节点**字段,默认`children`
|
||||
9. 新增 `disabledField` 同 `field.disabled`,指定节点对象中某个属性为**禁用**字段,默认`disabled`
|
||||
10. 新增 `appendField` 同 `field.append`,指定节点对象中某个属性为**副标签**字段,默认`append`
|
||||
11. 新增 `leafField` 同 `field.label`,指定节点对象中某个属性为**末级节点**字段,默认`leaf`
|
||||
12. 新增 `sortField` 同 `field.label`,指定节点对象中某个属性为**排序**字段,默认`sort`
|
||||
13. 新增 `isLeafFn` ,用来自定义控制数据项的末项
|
||||
14. 更多的项目示例
|
||||
15. 支持单选取消选中
|
||||
16. 修复节点展开时可能存在的 bug
|
||||
17. 修复节点选择可能存在的 bug
|
||||
18. 调整为子节点默认继承父节点禁用属性
|
||||
19. `setExpandedKeys` 添加参数一为 `all` 即可支持一键展开/收起全部节点
|
||||
20. 其它更多优化
|
||||
|
||||
# 1.3.4
|
||||
|
||||
优化
|
||||
|
||||
1. 优化图标字体命名
|
||||
|
||||
# 1.3.3
|
||||
|
||||
优化
|
||||
|
||||
1. 新增方法调用
|
||||
> - 新增`getUncheckedKeys`,返回未选的 key
|
||||
> - 新增`getUncheckedNodes`,返回未选的节点
|
||||
> - 新增`getUnexpandedKeys`,返回未展开的 key
|
||||
> - 新增`getUnexpandedNodes`,返回未展开的节点
|
||||
2. 优化示例项目
|
||||
|
||||
# 1.3.2
|
||||
|
||||
修复
|
||||
|
||||
1. 修复在 APP 真机环境中的报错
|
||||
|
||||
# 1.3.1
|
||||
|
||||
修复
|
||||
|
||||
1. 修复方法`setExpandedKeys`没联动展开上级父子节点
|
||||
|
||||
# 1.3.0
|
||||
|
||||
优化
|
||||
|
||||
1. `field`新增字段 `append` 用于在标签后面显示小提示
|
||||
2. 新增支持点击标签也能选中节点
|
||||
3. 方法`setExpandedKeys`支持加载动态数据
|
||||
4. 修复父节点禁用,则不能展开及图标展开显示
|
||||
5. 修复动态加载数据时,末级节点的 `children` 为 `null` 时仍显示展开图标
|
||||
|
||||
# 1.2.6
|
||||
|
||||
新增
|
||||
|
||||
1. 新增支持主题换色
|
||||
2. 支持单选的`onlyRadioLeaf`为`true`时可点父节点展开/收起
|
||||
3. 优化`expandChecked`调整为不展开无子节点的节点
|
||||
|
||||
# 1.2.5
|
||||
|
||||
新增
|
||||
|
||||
1. 新增 `expandChecked`,控制选择时是否展开当前已选的所有下级节点
|
||||
|
||||
# 1.2.4
|
||||
|
||||
修复
|
||||
|
||||
1. 修复动态数据展开状态异常问题
|
||||
|
||||
# 1.2.3
|
||||
|
||||
新增
|
||||
|
||||
1. 新增 `checkedDisabled`,是否渲染禁用值
|
||||
2. 新增 `packDisabledkey`,是否返回已禁用并选中的 key
|
||||
3. 修复选择父级时,子级已禁用但仍被选中的问题
|
||||
|
||||
# 1.2.2
|
||||
|
||||
优化
|
||||
|
||||
1. 调整动态数据载入处理方式
|
||||
2. 修复节点数据因动态数据引起的状态异常
|
||||
3. 修复初始节点数据默认选中
|
||||
|
||||
# 1.2.1
|
||||
|
||||
修复
|
||||
|
||||
1. 修复切换`选中状态`被重复选中问题
|
||||
2. 修复动态数据引起的重复选择问题
|
||||
|
||||
# 1.2.0
|
||||
|
||||
新增
|
||||
|
||||
1. 新增方法调用
|
||||
> - 新增`setCheckedKeys`,方法设置指定 key 的节点选中状态
|
||||
> - 新增`setExpandedKeys`,方法设置指定 key 的节点展开状态
|
||||
2. 修复小程序重复插槽一直刷报错问题
|
||||
3. 优化展开时,会展开子级所以下级节点
|
||||
|
||||
# 1.1.1
|
||||
|
||||
新增
|
||||
|
||||
1. 新增`data`的`disabled`,支持节点禁用状态
|
||||
2. 新增`field`的`disabled`,可自定`disabled`字段值
|
||||
|
||||
# 1.1.0
|
||||
|
||||
新增
|
||||
|
||||
1. 新增`loadMode`、`loadApi`,支持展开时加载异步数据
|
||||
2. 新增方法调用
|
||||
> - 新增`getCheckedKeys`,方法返回已选的 key
|
||||
> - 新增`getHalfCheckedKeys`,方法返回半选的 key
|
||||
> - 新增`getExpandedKeys`,方法返回已展开的 key
|
||||
> - 新增`getCheckedNodes`,方法返回已选的节点
|
||||
> - 新增`getHalfCheckedNodes`,方法返回半选的节点
|
||||
> - 新增`getExpandedNodes`,方法返回已展开的节点
|
||||
3. 对代码进行重构,更易于后期拓展
|
||||
4. 此次更新后,页面多个的 DaTee 组件间的数据不再关联
|
||||
|
||||
# 1.0.6
|
||||
|
||||
新增
|
||||
|
||||
1. 新增`checkStrictly`,多选模式下选中时是否父子不关联
|
||||
|
||||
# 1.0.5
|
||||
|
||||
修复
|
||||
|
||||
1. 修复多选时已选数据重复问题
|
||||
|
||||
# 1.0.4
|
||||
|
||||
修复
|
||||
|
||||
1. 修复 `change` 事件回调数据的问题
|
||||
|
||||
# 1.0.3
|
||||
|
||||
优化
|
||||
|
||||
1. 优化文档及示例说明
|
||||
|
||||
# 1.0.2
|
||||
|
||||
新增
|
||||
|
||||
1. 新增 `onlyRadioLeaf` ,单选时只允许选中末级
|
||||
2. 优化默认展开及默认选择的展开问题
|
||||
|
||||
# 1.0.1
|
||||
|
||||
新增
|
||||
|
||||
1. 支持展开/收起回调事件`@expand`
|
||||
|
||||
# 1.0.0
|
||||
|
||||
初始版本 1.0.0,基于 Vue3 进行开发,支持单选、多选,兼容各大平台
|
||||
|
||||
1. 支持单选
|
||||
2. 支持多选
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,197 +0,0 @@
|
||||
export default {
|
||||
/**
|
||||
* 树的数据
|
||||
*/
|
||||
data: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
/**
|
||||
* 主题色
|
||||
*/
|
||||
themeColor: {
|
||||
type: String,
|
||||
default: "#007aff",
|
||||
},
|
||||
/**
|
||||
* 是否开启多选,默认单选
|
||||
*/
|
||||
showCheckbox: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/**
|
||||
* 默认选中的节点,注意单选时为单个key,多选时为key的数组
|
||||
*/
|
||||
defaultCheckedKeys: {
|
||||
type: [Array, String, Number],
|
||||
default: null,
|
||||
},
|
||||
/**
|
||||
* 是否默认展开全部
|
||||
*/
|
||||
defaultExpandAll: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/**
|
||||
* 默认展开的节点
|
||||
*/
|
||||
defaultExpandedKeys: {
|
||||
type: Array,
|
||||
default: null,
|
||||
},
|
||||
/**
|
||||
* 筛选关键词
|
||||
*/
|
||||
filterValue: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
/**
|
||||
* 是否自动展开到选中的节点,默认不展开
|
||||
*/
|
||||
expandChecked: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
|
||||
/**
|
||||
* (旧)字段对应内容,默认为 {label: 'label',key: 'key', children: 'children', disabled: 'disabled', append: 'append'}
|
||||
* 注意:1.5.0版本后不再兼容
|
||||
*/
|
||||
field: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
/**
|
||||
* 标签字段(新,拆分了)
|
||||
*/
|
||||
labelField: {
|
||||
type: String,
|
||||
default: "label",
|
||||
},
|
||||
/**
|
||||
* 值字段(新,拆分了)
|
||||
*/
|
||||
valueField: {
|
||||
type: String,
|
||||
default: "value",
|
||||
},
|
||||
/**
|
||||
* 下级字段(新,拆分了)
|
||||
*/
|
||||
childrenField: {
|
||||
type: String,
|
||||
default: "children",
|
||||
},
|
||||
/**
|
||||
* 禁用字段(新,拆分了)
|
||||
*/
|
||||
disabledField: {
|
||||
type: String,
|
||||
default: "disabled",
|
||||
},
|
||||
/**
|
||||
* 末级节点字段(新,拆分了)
|
||||
*/
|
||||
leafField: {
|
||||
type: String,
|
||||
default: "leaf",
|
||||
},
|
||||
/**
|
||||
* 副标签字段(新,拆分了)
|
||||
*/
|
||||
appendField: {
|
||||
type: String,
|
||||
default: "append",
|
||||
},
|
||||
/**
|
||||
* 排序字段(新,拆分了)
|
||||
*/
|
||||
sortField: {
|
||||
type: String,
|
||||
default: "sort",
|
||||
},
|
||||
/**
|
||||
* Api数据返回后的结果路径,支持嵌套如`data.list`
|
||||
*/
|
||||
resultField: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
isLeafFn: {
|
||||
type: Function,
|
||||
default: null,
|
||||
},
|
||||
/**
|
||||
* 是否显示单选图标,默认显示
|
||||
*/
|
||||
showRadioIcon: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
/**
|
||||
* 单选时只允许选中末级,默认可随意选中
|
||||
*/
|
||||
onlyRadioLeaf: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/**
|
||||
* 多选时,是否执行父子不关联的任意勾选,默认父子关联
|
||||
*/
|
||||
checkStrictly: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/**
|
||||
* 为 true 时,空的 children 数组会显示展开图标
|
||||
*/
|
||||
loadMode: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/**
|
||||
* 异步加载接口
|
||||
*/
|
||||
loadApi: {
|
||||
type: Function,
|
||||
default: null,
|
||||
},
|
||||
/**
|
||||
* 是否总在首次的时候加载一下内容,来比对是否一致
|
||||
*/
|
||||
alwaysFirstLoad: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/**
|
||||
* 是否渲染(操作)禁用值
|
||||
*/
|
||||
checkedDisabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/**
|
||||
* 是否返回已禁用的但已选中的key
|
||||
*/
|
||||
packDisabledkey: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
/**
|
||||
* 选择框的位置,可选 left/right
|
||||
*/
|
||||
checkboxPlacement: {
|
||||
type: String,
|
||||
default: "left",
|
||||
},
|
||||
/**
|
||||
* 子项缩进距离,默认40,单位rpx
|
||||
*/
|
||||
indent: {
|
||||
type: Number,
|
||||
default: 40,
|
||||
},
|
||||
};
|
||||
@@ -1,310 +0,0 @@
|
||||
# da-tree
|
||||
|
||||
一个基于 Vue3 的 tree(树)组件,同时支持主题换色,可能是最适合你的 tree(树)组件
|
||||
|
||||
组件一直在更新,遇到问题可在下方讨论。
|
||||
|
||||
`同时更新 Vue2 版本,在此查看 ===>` **[Vue2 版](https://ext.dcloud.net.cn/plugin?id=12692)**
|
||||
|
||||
### 关于使用
|
||||
|
||||
可在右侧的`使用 HBuilderX 导入插件`或`下载示例项目ZIP`,方便快速上手。
|
||||
|
||||
可通过下方的示例及文档说明,进一步了解使用组件相关细节参数。
|
||||
|
||||
插件地址:https://ext.dcloud.net.cn/plugin?id=12384
|
||||
|
||||
### 组件示例
|
||||
|
||||
```jsx
|
||||
<template>
|
||||
<view>多选</view>
|
||||
<view><button @click="doCheckedTree(['2'],true)">全选</button></view>
|
||||
<view><button @click="doCheckedTree(['2'],false)">取消全选</button></view>
|
||||
<view><button @click="doCheckedTree(['211','222'],true)">选中指定节点</button></view>
|
||||
<view><button @click="doCheckedTree(['211','222'],false)">取消选中指定节点</button></view>
|
||||
<view><button @click="doExpandTree('all',true)">展开全部节点</button></view>
|
||||
<view><button @click="doExpandTree('all',false)">收起全部节点</button></view>
|
||||
<view><button @click="doExpandTree(['22','23'],true)">展开节点</button></view>
|
||||
<view><button @click="doExpandTree(['22','23'],false)">收起节点</button></view>
|
||||
<DaTree
|
||||
ref="DaTreeRef"
|
||||
:data="roomTreeData"
|
||||
labelField="name"
|
||||
valueField="id"
|
||||
defaultExpandAll
|
||||
showCheckbox
|
||||
:defaultCheckedKeys="defaultCheckedKeysValue"
|
||||
@change="handleTreeChange"
|
||||
@expand="handleExpandChange"></DaTree>
|
||||
<view>单选</view>
|
||||
<DaTree
|
||||
:data="roomTreeData"
|
||||
labelField="name"
|
||||
valueField="id"
|
||||
defaultExpandAll
|
||||
:defaultCheckedKeys="defaultCheckedKeysValue2"
|
||||
@change="handleTreeChange"
|
||||
@expand="handleExpandChange"></DaTree>
|
||||
<view>默认展开指定节点</view>
|
||||
<DaTree
|
||||
:data="roomTreeData"
|
||||
labelField="name"
|
||||
valueField="id"
|
||||
showCheckbox
|
||||
:defaultExpandedKeys="defaultExpandKeysValue3"
|
||||
@change="handleTreeChange"
|
||||
@expand="handleExpandChange"></DaTree>
|
||||
<view>异步加载数据</view>
|
||||
<DaTree
|
||||
:data="roomTreeData"
|
||||
labelField="name"
|
||||
valueField="id"
|
||||
showCheckbox
|
||||
loadMode
|
||||
:loadApi="GetApiData"
|
||||
defaultExpandAll
|
||||
@change="handleTreeChange"
|
||||
@expand="handleExpandChange"></DaTree>
|
||||
</template>
|
||||
```
|
||||
|
||||
```js
|
||||
import { defineComponent, ref } from "vue";
|
||||
|
||||
/**
|
||||
* 模拟创建一个接口数据
|
||||
*/
|
||||
function GetApiData(currentNode) {
|
||||
const { key } = currentNode;
|
||||
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
// 模拟返回空数据
|
||||
if (key.indexOf("-") > -1) {
|
||||
return resolve(null);
|
||||
// return resolve([])
|
||||
}
|
||||
|
||||
return resolve([
|
||||
{
|
||||
id: `${key}-1`,
|
||||
name: `行政部X${key}-1`,
|
||||
},
|
||||
{
|
||||
id: `${key}-2`,
|
||||
name: `财务部X${key}-2`,
|
||||
append: "定义了末项数据",
|
||||
leaf: true,
|
||||
},
|
||||
{
|
||||
id: `${key}-3`,
|
||||
name: `资源部X${key}-3`,
|
||||
},
|
||||
{
|
||||
id: `${key}-4`,
|
||||
name: `资源部X${key}-3`,
|
||||
append: "被禁用,无展开图标",
|
||||
disabled: true,
|
||||
},
|
||||
]);
|
||||
}, 2000);
|
||||
});
|
||||
}
|
||||
|
||||
import DaTree from "@/components/da-tree/index.vue";
|
||||
export default defineComponent({
|
||||
components: { DaTree },
|
||||
setup() {
|
||||
const DaTreeRef = ref();
|
||||
// key的类型必须对应树数据key的类型
|
||||
const defaultCheckedKeysValue = ref(["211", "222"]);
|
||||
const defaultCheckedKeysValue2 = ref("222");
|
||||
const defaultExpandKeysValue3 = ref(["212", "231"]);
|
||||
const roomTreeData = ref([
|
||||
{
|
||||
id: "2",
|
||||
name: "行政中心",
|
||||
children: [
|
||||
{
|
||||
id: "21",
|
||||
name: "行政部",
|
||||
children: [
|
||||
{
|
||||
id: "211",
|
||||
name: "行政一部",
|
||||
children: null,
|
||||
},
|
||||
{
|
||||
id: "212",
|
||||
name: "行政二部",
|
||||
children: [],
|
||||
disabled: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "22",
|
||||
name: "财务部",
|
||||
children: [
|
||||
{
|
||||
id: "221",
|
||||
name: "财务一部",
|
||||
children: [],
|
||||
disabled: true,
|
||||
},
|
||||
{
|
||||
id: "222",
|
||||
name: "财务二部",
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "23",
|
||||
name: "人力资源部",
|
||||
children: [
|
||||
{
|
||||
id: "231",
|
||||
name: "人力一部",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
id: "232",
|
||||
name: "人力二部",
|
||||
append: "更多示例,请下载示例项目查看",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
function doExpandTree(keys, expand) {
|
||||
DaTreeRef.value?.setExpandedKeys(keys, expand);
|
||||
|
||||
const gek = DaTreeRef.value?.getExpandedKeys();
|
||||
console.log("当前已展开的KEY ==>", gek);
|
||||
}
|
||||
function doCheckedTree(keys, checked) {
|
||||
DaTreeRef.value?.setCheckedKeys(keys, checked);
|
||||
|
||||
const gek = DaTreeRef.value?.getCheckedKeys();
|
||||
console.log("当前已选中的KEY ==>", gek);
|
||||
}
|
||||
function handleTreeChange(allSelectedKeys, currentItem) {
|
||||
console.log("handleTreeChange ==>", allSelectedKeys, currentItem);
|
||||
}
|
||||
function handleExpandChange(expand, currentItem) {
|
||||
console.log("handleExpandChange ==>", expand, currentItem);
|
||||
}
|
||||
return {
|
||||
DaTreeRef,
|
||||
roomTreeData,
|
||||
defaultCheckedKeysValue,
|
||||
defaultCheckedKeysValue2,
|
||||
defaultExpandKeysValue3,
|
||||
handleTreeChange,
|
||||
handleExpandChange,
|
||||
GetApiData,
|
||||
doExpandTree,
|
||||
doCheckedTree,
|
||||
};
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
** 更多示例请下载/导入示例项目 ZIP 查看 **
|
||||
|
||||
### 组件参数
|
||||
|
||||
| 属性 | 类型 | 默认值 | 必填 | 说明 |
|
||||
| :------------------ | :------------------------------ | :--------- | :--- | :--------------------------------------------------------------------------- |
|
||||
| data | `Array` | - | 是 | 树的数据 |
|
||||
| themeColor | `String` | `#007aff` | 否 | 主题色,十六进制 |
|
||||
| defaultCheckedKeys | `Array` \| `Number` \| `String` | - | 否 | 默认选中的节点,单选为单个 key,多选为 key 的数组 |
|
||||
| showCheckbox | `Boolean` | `false` | 否 | 是否开启多选,默认单选 |
|
||||
| checkStrictly | `Boolean` | `false` | 否 | 多选时,是否执行父子不关联的任意勾选,默认父子关联 |
|
||||
| showRadioIcon | `Boolean` | `true` | 否 | 是否显示单选图标,默认显示 |
|
||||
| onlyRadioLeaf | `Boolean` | `true` | 否 | 单选时只允许选中末级,默认可随意选中 |
|
||||
| defaultExpandAll | `Boolean` | `false` | 否 | 是否默认展开全部 |
|
||||
| defaultExpandedKeys | `Array` | - | 否 | 默认展开的节点 |
|
||||
| indent | `Number` | `40` | 否 | 子项缩进距离,单位 rpx |
|
||||
| checkboxPlacement | `String` | `left` | 否 | 选择框的位置,可选 left/right |
|
||||
| loadMode | `Boolean` | `false` | 否 | 为 true 时,空的 children 数组会显示展开图标 |
|
||||
| loadApi | `Function` | - | 否 | 选择框的位置,可选 left/right |
|
||||
| checkedDisabled | `Boolean` | `false` | 否 | 是否渲染禁用值,默认不渲染 |
|
||||
| packDisabledkey | `Boolean` | `true` | 否 | 是否返回已禁用的但已选中的 key,默认返回禁用已选值 |
|
||||
| expandChecked | `Boolean` | `false` | 否 | 是否自动展开到选中的节点,默认不展开 |
|
||||
| alwaysFirstLoad | `Boolean` | `false` | 否 | 是否总在首次的时候加载一下内容,默认不加载,否则只有展开末级节点才会加载数据 |
|
||||
| isLeafFn | `Function` | - | 否 | 自定义函数返回来控制数据项的末项 |
|
||||
| field | `Object` | - | 否 | 字段对应内容,格式参考下方(1.5.0 后移除,请用单独的字段匹配) |
|
||||
| labelField | `String` | `label` | 否 | 指定节点对象中某个属性为标签字段,默认`label` |
|
||||
| valueField | `String` | `value` | 否 | 指定节点对象中某个属性为值字段,默认`value` |
|
||||
| childrenField | `String` | `children` | 否 | 指定节点对象中某个属性为子树节点字段,默认`children` |
|
||||
| disabledField | `String` | `disabled` | 否 | 指定节点对象中某个属性为禁用字段,默认`disabled` |
|
||||
| appendField | `String` | `append` | 否 | 指定节点对象中某个属性为副标签字段,默认`append` |
|
||||
| leafField | `String` | `leaf` | 否 | 指定节点对象中某个属性为末级节点字段,默认`leaf` |
|
||||
| sortField | `String` | `sort` | 否 | 指定节点对象中某个属性为排序字段,默认`sort` |
|
||||
| filterValue | `String` | - | 否 | 搜索筛选的关键词,通过输入关键词筛选内容 |
|
||||
|
||||
**field 格式(1.5.0 后移除,请用单独的字段匹配)**
|
||||
|
||||
```js
|
||||
{
|
||||
label: 'label',
|
||||
key: 'key',
|
||||
children: 'children',
|
||||
disabled: 'disabled',
|
||||
append: 'append'
|
||||
}
|
||||
```
|
||||
|
||||
### 组件事件
|
||||
|
||||
| 事件名称 | 回调参数 | 说明 |
|
||||
| :------- | :-------------------------------------- | :-------------- |
|
||||
| change | `(allCheckedKeys, currentItem) => void` | 选中时回调 |
|
||||
| expand | `(expandState, currentItem) => void` | 展开/收起时回调 |
|
||||
|
||||
### 组件方法
|
||||
|
||||
| 方法名称 | 参数 | 说明 |
|
||||
| :------------------ | :--------------- | :------------------------------------------------------------------------------------------------ |
|
||||
| setCheckedKeys | `(keys,checked)` | 设置指定 key 的节点选中/取消选中的状态。注: keys 单选时为 key,多选时为 key 的数组 |
|
||||
| setExpandedKeys | `(keys,expand)` | 设置指定 key 的节点展开/收起的状态,当 keys 为 all 时即代表展开/收起全部。注:keys 为数组或 `all` |
|
||||
| getCheckedKeys | - | 返回已选的 key |
|
||||
| getHalfCheckedKeys | - | 返回半选的 key |
|
||||
| getUncheckedKeys | - | 返回未选的 key |
|
||||
| getCheckedNodes | - | 返回已选的节点 |
|
||||
| getUncheckedNodes | - | 返回未选的节点 |
|
||||
| getHalfCheckedNodes | - | 返回半选的节点 |
|
||||
| getExpandedKeys | - | 返回已展开的 key |
|
||||
| getUnexpandedKeys | - | 返回未展开的 key |
|
||||
| getExpandedNodes | - | 返回已展开的节点 |
|
||||
| getUnexpandedNodes | - | 返回未展开的节点 |
|
||||
|
||||
### 组件版本
|
||||
|
||||
v1.4.2
|
||||
|
||||
### 差异化
|
||||
|
||||
已通过测试
|
||||
|
||||
> - H5 页面
|
||||
> - 微信小程序
|
||||
> - 支付宝、钉钉小程序
|
||||
> - 字节跳动、抖音、今日头条小程序
|
||||
> - 百度小程序
|
||||
> - 飞书小程序
|
||||
> - QQ 小程序
|
||||
> - 京东小程序
|
||||
|
||||
未测试
|
||||
|
||||
> - 快手小程序由于非企业用户暂无演示
|
||||
> - 快应用、360 小程序因 Vue3 支持的原因暂无演示
|
||||
|
||||
### 开发组
|
||||
|
||||
[@CRLANG](https://crlang.com)
|
||||
@@ -1,153 +0,0 @@
|
||||
/** 未选 */
|
||||
export const unCheckedStatus = 0;
|
||||
/** 半选 */
|
||||
export const halfCheckedStatus = 1;
|
||||
/** 选中 */
|
||||
export const isCheckedStatus = 2;
|
||||
|
||||
/**
|
||||
* 深拷贝内容
|
||||
* @param originData 拷贝对象
|
||||
* @author crlang(https://crlang.com)
|
||||
*/
|
||||
export function deepClone(originData: any): any {
|
||||
const type = Object.prototype.toString.call(originData);
|
||||
let data: any;
|
||||
if (type === "[object Array]") {
|
||||
data = [];
|
||||
for (let i = 0; i < originData.length; i++) {
|
||||
data.push(deepClone(originData[i]));
|
||||
}
|
||||
} else if (type === "[object Object]") {
|
||||
data = {} as Record<string, any>;
|
||||
for (const prop in originData) {
|
||||
if (Object.prototype.hasOwnProperty.call(originData, prop)) {
|
||||
// 非继承属性
|
||||
data[prop] = deepClone(originData[prop]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
data = originData;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有指定的节点
|
||||
* @param list 列表
|
||||
* @param type 类型
|
||||
* @param value 值
|
||||
* @param packDisabledkey 是否包含禁用节点
|
||||
* @author crlang(https://crlang.com)
|
||||
*/
|
||||
export function getAllNodes(list: any[], type: string, value: any, packDisabledkey = true): any[] {
|
||||
if (!list || list.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const res = [];
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
const item = list[i];
|
||||
if (item[type] === value) {
|
||||
if ((packDisabledkey && item.disabled) || !item.disabled) {
|
||||
res.push(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有指定的key值
|
||||
* @param list 列表
|
||||
* @param type 类型
|
||||
* @param value 值
|
||||
* @param packDisabledkey 是否包含禁用节点
|
||||
* @author crlang(https://crlang.com)
|
||||
*/
|
||||
export function getAllNodeKeys(
|
||||
list: any[],
|
||||
type: string,
|
||||
value: any,
|
||||
packDisabledkey = true
|
||||
): string[] | null {
|
||||
if (!list || list.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const res: string[] = [];
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
const item = list[i];
|
||||
if (item[type] === value) {
|
||||
if ((packDisabledkey && item.disabled) || !item.disabled) {
|
||||
res.push(item.key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res.length ? res : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 错误输出
|
||||
* @param msg 错误消息
|
||||
* @param args 附加参数
|
||||
*/
|
||||
export function logError(msg: string, ...args: any[]): void {
|
||||
console.error(`DaTree: ${msg}`, ...args);
|
||||
}
|
||||
|
||||
const toString = Object.prototype.toString;
|
||||
|
||||
export function is(val: any, type: string): boolean {
|
||||
return toString.call(val) === `[object ${type}]`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否对象(Object)
|
||||
* @param val 值
|
||||
*/
|
||||
export function isObject(val: any): boolean {
|
||||
return val !== null && is(val, "Object");
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否数字(Number)
|
||||
* @param val 值
|
||||
*/
|
||||
export function isNumber(val: any): boolean {
|
||||
return is(val, "Number");
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否字符串(String)
|
||||
* @param val 值
|
||||
*/
|
||||
export function isString(val: any): boolean {
|
||||
return is(val, "String");
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否函数方法(Function)
|
||||
* @param val 值
|
||||
*/
|
||||
export function isFunction(val: any): boolean {
|
||||
return typeof val === "function";
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否布尔(Boolean)
|
||||
* @param val 值
|
||||
*/
|
||||
export function isBoolean(val: any): boolean {
|
||||
return is(val, "Boolean");
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否数组(Array)
|
||||
* @param val 值
|
||||
*/
|
||||
export function isArray(val: any): boolean {
|
||||
return val && Array.isArray(val);
|
||||
}
|
||||
@@ -1,59 +1,130 @@
|
||||
import { ref, computed } from "vue";
|
||||
import { ref, watch } from "vue";
|
||||
import type { ConfigProviderThemeVars } from "wot-design-uni";
|
||||
|
||||
/* 默认的主题list */
|
||||
/* 默认的主题色列表 */
|
||||
export const colorColumns = [
|
||||
{
|
||||
value: "#0055FE",
|
||||
label: "蓝色",
|
||||
},
|
||||
{
|
||||
value: "#CD5C5C",
|
||||
label: "红色",
|
||||
},
|
||||
{
|
||||
value: "#228B22",
|
||||
label: "绿色",
|
||||
},
|
||||
{ value: "#165DFF", label: "蓝色" },
|
||||
{ value: "#0FC6C2", label: "青绿色" },
|
||||
{ value: "#722ED1", label: "紫色" },
|
||||
{ value: "#F5222D", label: "红色" },
|
||||
{ value: "#FA8C16", label: "橙色" },
|
||||
{ value: "#FADB14", label: "黄色" },
|
||||
{ value: "#52C41A", label: "绿色" },
|
||||
{ value: "#EB2F96", label: "粉色" },
|
||||
{ value: "#13C2C2", label: "青色" },
|
||||
{ value: "#1890FF", label: "天蓝色" },
|
||||
{ value: "#CD5C5C", label: "经典红" },
|
||||
{ value: "#228B22", label: "自然绿" },
|
||||
];
|
||||
|
||||
/* 默认的主题 */
|
||||
export const initThemState = "light";
|
||||
/* 存储键名 */
|
||||
const THEME_STORAGE_KEY = "app_theme_mode";
|
||||
const THEME_COLOR_STORAGE_KEY = "app_theme_color";
|
||||
|
||||
/* 默认的主题变量 - 只使用wot-design-uni支持的变量 */
|
||||
export const initThemeVars: ConfigProviderThemeVars = {
|
||||
colorTheme: colorColumns[0].value,
|
||||
/* 从存储中获取主题模式 */
|
||||
const getStoredTheme = (): "light" | "dark" => {
|
||||
try {
|
||||
const stored = uni.getStorageSync(THEME_STORAGE_KEY);
|
||||
return stored === "dark" ? "dark" : "light";
|
||||
} catch {
|
||||
return "light";
|
||||
}
|
||||
};
|
||||
|
||||
/* 暗黑模式主题变量 */
|
||||
export const darkThemeVars: ConfigProviderThemeVars = {
|
||||
colorTheme: colorColumns[0].value,
|
||||
/* 从存储中获取主题色 */
|
||||
const getStoredThemeColor = (): string => {
|
||||
try {
|
||||
const stored = uni.getStorageSync(THEME_COLOR_STORAGE_KEY);
|
||||
return stored || colorColumns[0].value;
|
||||
} catch {
|
||||
return colorColumns[0].value;
|
||||
}
|
||||
};
|
||||
|
||||
/* 保存主题模式到存储 */
|
||||
const saveThemeToStorage = (theme: "light" | "dark") => {
|
||||
try {
|
||||
uni.setStorageSync(THEME_STORAGE_KEY, theme);
|
||||
} catch (error) {
|
||||
console.error("保存主题模式失败:", error);
|
||||
}
|
||||
};
|
||||
|
||||
/* 保存主题色到存储 */
|
||||
const saveThemeColorToStorage = (color: string) => {
|
||||
try {
|
||||
uni.setStorageSync(THEME_COLOR_STORAGE_KEY, color);
|
||||
} catch (error) {
|
||||
console.error("保存主题色失败:", error);
|
||||
}
|
||||
};
|
||||
|
||||
/* 应用暗黑模式的 body 样式 */
|
||||
const applyDarkModeBodyStyle = (isDark: boolean) => {
|
||||
// #ifdef H5
|
||||
if (typeof document !== "undefined") {
|
||||
const body = document.body;
|
||||
if (isDark) {
|
||||
body.style.backgroundColor = "#1a1a1a";
|
||||
body.style.color = "#f5f5f5";
|
||||
body.classList.add("wot-theme-dark");
|
||||
} else {
|
||||
body.style.backgroundColor = "#f8f8f8";
|
||||
body.style.color = "#333";
|
||||
body.classList.remove("wot-theme-dark");
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #ifdef MP
|
||||
// 小程序环境中设置页面样式
|
||||
try {
|
||||
const pages = getCurrentPages();
|
||||
if (pages.length > 0) {
|
||||
const currentPage = pages[pages.length - 1];
|
||||
if (currentPage && currentPage.$vm) {
|
||||
// 这里可以根据需要设置页面样式
|
||||
console.log("小程序暗黑模式:", isDark ? "开启" : "关闭");
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("设置小程序页面样式失败:", error);
|
||||
}
|
||||
// #endif
|
||||
};
|
||||
|
||||
/* 主题状态 */
|
||||
export const themeState = ref(initThemState);
|
||||
export const theme = ref<"light" | "dark">(getStoredTheme());
|
||||
|
||||
/* 主题变量 */
|
||||
export const themeVars = ref<ConfigProviderThemeVars>(initThemeVars);
|
||||
|
||||
/* 计算属性:根据主题状态返回对应的主题变量 */
|
||||
export const computedThemeVars = computed(() => {
|
||||
const baseVars = themeState.value === "dark" ? darkThemeVars : initThemeVars;
|
||||
return {
|
||||
...baseVars,
|
||||
...themeVars.value,
|
||||
};
|
||||
export const themeVars = ref<ConfigProviderThemeVars>({
|
||||
colorTheme: getStoredThemeColor(),
|
||||
});
|
||||
|
||||
/* 切换主题 */
|
||||
/* 监听主题模式变化,应用 body 样式 */
|
||||
watch(
|
||||
theme,
|
||||
(newTheme) => {
|
||||
saveThemeToStorage(newTheme);
|
||||
applyDarkModeBodyStyle(newTheme === "dark");
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
/* 监听主题色变化,保存到存储 */
|
||||
watch(
|
||||
() => themeVars.value.colorTheme,
|
||||
(newColor) => {
|
||||
if (newColor) {
|
||||
saveThemeColorToStorage(newColor);
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
/* 切换主题模式 */
|
||||
export const toggleTheme = () => {
|
||||
themeState.value = themeState.value === "light" ? "dark" : "light";
|
||||
// 更新主题变量
|
||||
const newBaseVars = themeState.value === "dark" ? darkThemeVars : initThemeVars;
|
||||
themeVars.value = {
|
||||
...newBaseVars,
|
||||
colorTheme: themeVars.value.colorTheme, // 保持用户选择的主题色
|
||||
};
|
||||
theme.value = theme.value === "light" ? "dark" : "light";
|
||||
};
|
||||
|
||||
/* 设置主题色 */
|
||||
@@ -64,13 +135,37 @@ export const setThemeColor = (color: string) => {
|
||||
};
|
||||
};
|
||||
|
||||
/* 重置主题 */
|
||||
export const resetTheme = () => {
|
||||
theme.value = "light";
|
||||
setThemeColor(colorColumns[0].value);
|
||||
};
|
||||
|
||||
/* 初始化主题 */
|
||||
export const initTheme = () => {
|
||||
// 应用当前主题的 body 样式
|
||||
applyDarkModeBodyStyle(theme.value === "dark");
|
||||
|
||||
// 确保主题变量已正确设置
|
||||
if (!themeVars.value.colorTheme) {
|
||||
themeVars.value.colorTheme = getStoredThemeColor();
|
||||
}
|
||||
|
||||
console.log("主题初始化完成:", {
|
||||
mode: theme.value,
|
||||
color: themeVars.value.colorTheme,
|
||||
});
|
||||
};
|
||||
|
||||
/* 导出主题相关的工具 */
|
||||
export const useTheme = () => {
|
||||
return {
|
||||
themeState,
|
||||
themeVars: computedThemeVars,
|
||||
theme,
|
||||
themeVars,
|
||||
toggleTheme,
|
||||
setThemeColor,
|
||||
resetTheme,
|
||||
initTheme,
|
||||
colorColumns,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import type { ConfigProviderThemeVars } from "wot-design-uni";
|
||||
import { useTheme } from "@/composables/useTheme";
|
||||
|
||||
const themeVars = reactive<ConfigProviderThemeVars>({
|
||||
colorTheme: "#FF5454",
|
||||
tabsNavLineBgColor: "red",
|
||||
navbarColor: "#ffffff",
|
||||
});
|
||||
const { theme, themeVars } = useTheme();
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
@@ -20,8 +16,10 @@ export default {
|
||||
|
||||
<template>
|
||||
<wd-config-provider
|
||||
:theme="theme"
|
||||
:theme-vars="themeVars"
|
||||
custom-style="background-color: #f5f5f5;min-height: 100vh"
|
||||
:class="{ 'wot-theme-dark': theme === 'dark' }"
|
||||
>
|
||||
<slot />
|
||||
<wd-notify />
|
||||
@@ -30,3 +28,11 @@ export default {
|
||||
<privacy-popup />
|
||||
</wd-config-provider>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/* 暗黑模式样式 */
|
||||
.wot-theme-dark {
|
||||
color: #f5f5f5 !important;
|
||||
background-color: #1a1a1a !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
* 记得注释
|
||||
-->
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, onMounted, nextTick } from "vue";
|
||||
import { ref, computed, onMounted, nextTick, onUnmounted } from "vue";
|
||||
import { onShow } from "@dcloudio/uni-app";
|
||||
import { useTheme } from "@/composables/useTheme";
|
||||
|
||||
// 定义 TabbarItem 接口
|
||||
@@ -26,7 +27,7 @@ const tabbarItems = ref<TabbarItem[]>([
|
||||
{ name: "mine", value: null, active: false, title: "我的", icon: "user" },
|
||||
]);
|
||||
|
||||
const { themeVars } = useTheme();
|
||||
const { theme, themeVars } = useTheme();
|
||||
|
||||
// 计算属性
|
||||
const tabbarList = computed(() => tabbarItems.value);
|
||||
@@ -43,6 +44,7 @@ const getTabbarItemValue = (name: string) => {
|
||||
};
|
||||
|
||||
const setTabbarItemActive = (name: string) => {
|
||||
console.log(`设置 tabbar 激活状态: ${name}`);
|
||||
tabbarItems.value.forEach((item) => {
|
||||
if (item.name === name) {
|
||||
item.active = true;
|
||||
@@ -52,7 +54,35 @@ const setTabbarItemActive = (name: string) => {
|
||||
});
|
||||
};
|
||||
|
||||
// 根据当前路由更新 tabbar 激活状态
|
||||
const updateTabbarByRoute = () => {
|
||||
const pages = getCurrentPages();
|
||||
if (pages.length > 0) {
|
||||
const currentPage = pages[pages.length - 1];
|
||||
const route = currentPage.route;
|
||||
|
||||
console.log("=== Tabbar 路由更新 ===");
|
||||
console.log("当前路由:", route);
|
||||
console.log("当前激活的 tabbar:", activeTabbar.value.name);
|
||||
|
||||
// 根据当前路由设置活跃的 tabbar
|
||||
if (route === "pages/index/index") {
|
||||
console.log("设置首页为激活状态");
|
||||
setTabbarItemActive("index");
|
||||
} else if (route === "pages/mine/index") {
|
||||
console.log("设置我的页面为激活状态");
|
||||
setTabbarItemActive("mine");
|
||||
} else {
|
||||
console.log("非 tabbar 页面,保持当前状态");
|
||||
}
|
||||
|
||||
console.log("更新后激活的 tabbar:", activeTabbar.value.name);
|
||||
console.log("=== 更新完成 ===");
|
||||
}
|
||||
};
|
||||
|
||||
function handleTabbarChange({ value }: { value: string }) {
|
||||
console.log(`用户点击 tabbar: ${value}`);
|
||||
setTabbarItemActive(value);
|
||||
|
||||
// 根据 tabbar 项目导航到对应页面
|
||||
@@ -67,29 +97,51 @@ function handleTabbarChange({ value }: { value: string }) {
|
||||
}
|
||||
}
|
||||
|
||||
// 监听页面栈变化
|
||||
const currentRoute = ref("");
|
||||
|
||||
const updateCurrentRoute = () => {
|
||||
const pages = getCurrentPages();
|
||||
if (pages.length > 0) {
|
||||
const currentPage = pages[pages.length - 1];
|
||||
const newRoute = currentPage.route || "";
|
||||
|
||||
if (newRoute !== currentRoute.value) {
|
||||
currentRoute.value = newRoute;
|
||||
console.log("页面路由发生变化:", newRoute);
|
||||
updateTabbarByRoute();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
// 获取当前页面路径
|
||||
const pages = getCurrentPages();
|
||||
if (pages.length > 0) {
|
||||
const currentPage = pages[pages.length - 1];
|
||||
const route = currentPage.route;
|
||||
updateTabbarByRoute();
|
||||
updateCurrentRoute();
|
||||
});
|
||||
|
||||
// 根据当前路由设置活跃的 tabbar
|
||||
if (route?.includes("pages/index/index")) {
|
||||
setTabbarItemActive("index");
|
||||
} else if (route?.includes("pages/mine/index")) {
|
||||
setTabbarItemActive("mine");
|
||||
}
|
||||
}
|
||||
// 监听页面发出的 tabbar 更新事件
|
||||
uni.$on("updateTabbar", (tabName: string) => {
|
||||
console.log("收到 tabbar 更新事件:", tabName);
|
||||
setTabbarItemActive(tabName);
|
||||
});
|
||||
});
|
||||
|
||||
// 页面显示时更新 tabbar 状态
|
||||
onShow(() => {
|
||||
nextTick(() => {
|
||||
updateCurrentRoute();
|
||||
});
|
||||
|
||||
// #ifdef APP-PLUS
|
||||
uni.hideTabBar();
|
||||
// #endif
|
||||
});
|
||||
|
||||
// 组件卸载时移除事件监听
|
||||
onUnmounted(() => {
|
||||
uni.$off("updateTabbar");
|
||||
});
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
@@ -103,7 +155,12 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<wd-config-provider :theme-vars="themeVars" custom-style="min-height: 100vh" theme="dark">
|
||||
<wd-config-provider
|
||||
:theme="theme"
|
||||
:theme-vars="themeVars"
|
||||
custom-style="min-height: 100vh"
|
||||
:class="{ 'wot-theme-dark': theme === 'dark' }"
|
||||
>
|
||||
<wd-navbar
|
||||
:title="activeTabbar.title"
|
||||
safe-area-inset-top
|
||||
@@ -135,3 +192,21 @@ export default {
|
||||
<wd-message-box />
|
||||
</wd-config-provider>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/* 暗黑模式样式 */
|
||||
.wot-theme-dark {
|
||||
color: #f5f5f5;
|
||||
background-color: #1a1a1a;
|
||||
|
||||
:deep(.wd-navbar) {
|
||||
color: #f5f5f5;
|
||||
background-color: #2a2a2a;
|
||||
}
|
||||
|
||||
:deep(.wd-tabbar) {
|
||||
background-color: #2a2a2a;
|
||||
border-top-color: #404040;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -3,6 +3,7 @@ import App from "./App.vue";
|
||||
|
||||
import "uno.css";
|
||||
import "@/styles/global.scss";
|
||||
import "@/styles/wot-theme.scss";
|
||||
|
||||
import { setupStore } from "@/store";
|
||||
|
||||
|
||||
@@ -252,6 +252,18 @@ onReady(() => {
|
||||
loadVisitStatsData();
|
||||
loadVisitTrendData();
|
||||
});
|
||||
|
||||
onShow(() => {
|
||||
// 确保 tabbar 状态正确
|
||||
const pages = getCurrentPages();
|
||||
if (pages.length > 0) {
|
||||
const currentPage = pages[pages.length - 1];
|
||||
if (currentPage.route === "pages/index/index") {
|
||||
// 通过事件通知 tabbar 布局更新状态
|
||||
uni.$emit("updateTabbar", "index");
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style setup lang="scss">
|
||||
|
||||
@@ -220,29 +220,25 @@ const handleQuestionFeedback = () => {
|
||||
|
||||
// 导航到各个板块
|
||||
const navigateToSection = (section: string, subSection?: string) => {
|
||||
if (!isLogin.value && section !== "services") {
|
||||
navigateToLoginPage();
|
||||
return;
|
||||
}
|
||||
|
||||
const sections: Record<string, string> = {
|
||||
messages: "消息中心",
|
||||
todos: "待办事项",
|
||||
favorites: "我的收藏",
|
||||
history: "浏览历史",
|
||||
wallet: "我的钱包",
|
||||
orders: "我的订单",
|
||||
address: "收货地址",
|
||||
services: "增值服务",
|
||||
};
|
||||
|
||||
let message = sections[section];
|
||||
if (subSection) {
|
||||
message += ` - ${subSection}`;
|
||||
}
|
||||
|
||||
toast.show(`${message}功能开发中...`);
|
||||
console.log(`导航到: ${section}${subSection ? ` - ${subSection}` : ""}`);
|
||||
// 这里可以根据需要实现具体的导航逻辑
|
||||
uni.showToast({
|
||||
title: "功能开发中",
|
||||
icon: "none",
|
||||
});
|
||||
};
|
||||
|
||||
onShow(() => {
|
||||
// 确保 tabbar 状态正确
|
||||
const pages = getCurrentPages();
|
||||
if (pages.length > 0) {
|
||||
const currentPage = pages[pages.length - 1];
|
||||
if (currentPage.route === "pages/mine/index") {
|
||||
// 通过事件通知 tabbar 布局更新状态
|
||||
uni.$emit("updateTabbar", "mine");
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import UserAPI, { type UserProfileVO, UserProfileForm } from "@/api/user";
|
||||
import FileAPI, { type FileInfo } from "@/api";
|
||||
import FileAPI, { type FileInfo } from "@/api/file";
|
||||
import { checkLogin } from "@/utils/auth";
|
||||
|
||||
const originalSrc = ref<string>(""); //选取的原图路径
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
import { useUserStore } from "@/store/modules/user.store";
|
||||
import { checkLogin } from "@/utils/auth";
|
||||
import { computed, ref } from "vue";
|
||||
import { onLoad } from "@dcloudio/uni-app";
|
||||
|
||||
const userStore = useUserStore();
|
||||
const isLogin = computed(() => !!userStore.userInfo);
|
||||
@@ -200,6 +201,39 @@ onLoad(() => {
|
||||
.settings-container {
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
color: var(--wot-color-text, #333);
|
||||
background-color: var(--wot-color-bg-light, #f8f8f8);
|
||||
|
||||
// 强制 Wot 组件应用暗黑模式样式
|
||||
:deep(.wd-cell-group) {
|
||||
overflow: hidden;
|
||||
background-color: var(--wot-card-bg-color, #fff);
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
|
||||
:deep(.wd-cell) {
|
||||
color: var(--wot-color-text, #333);
|
||||
background-color: var(--wot-card-bg-color, #fff);
|
||||
|
||||
.wd-cell__title {
|
||||
color: var(--wot-color-text, #333) !important;
|
||||
}
|
||||
|
||||
.wd-cell__value {
|
||||
color: var(--wot-color-text-secondary, #666) !important;
|
||||
}
|
||||
|
||||
.wd-cell__right-icon {
|
||||
color: var(--wot-color-text-secondary, #999) !important;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.wd-button) {
|
||||
&.logout-btn {
|
||||
color: #fff !important;
|
||||
background-color: var(--wot-color-theme, var(--primary-color)) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.loading-mask {
|
||||
position: fixed;
|
||||
@@ -216,7 +250,7 @@ onLoad(() => {
|
||||
.loading-content {
|
||||
padding: 30rpx 40rpx;
|
||||
text-align: center;
|
||||
background-color: rgba(255, 255, 255, 0.95);
|
||||
background-color: var(--wot-card-bg-color, rgba(255, 255, 255, 0.95));
|
||||
border-radius: 12rpx;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.15);
|
||||
|
||||
@@ -224,8 +258,8 @@ onLoad(() => {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
margin: 0 auto 20rpx;
|
||||
border: 4rpx solid #f3f3f3;
|
||||
border-top: 4rpx solid #409eff;
|
||||
border: 4rpx solid var(--wot-color-border, #f3f3f3);
|
||||
border-top: 4rpx solid var(--wot-color-theme, #409eff);
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
@@ -233,7 +267,7 @@ onLoad(() => {
|
||||
.loading-text {
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
color: var(--wot-color-text, #333);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -255,10 +289,10 @@ onLoad(() => {
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
background-color: var(--primary-color);
|
||||
background-color: var(--wot-color-theme, var(--primary-color));
|
||||
border: none;
|
||||
border-radius: 45rpx;
|
||||
box-shadow: 0 4rpx 12rpx rgba(var(--primary-color-rgb), 0.3);
|
||||
box-shadow: 0 4rpx 12rpx rgba(22, 93, 255, 0.3);
|
||||
transition: opacity 0.2s;
|
||||
|
||||
&:active {
|
||||
@@ -266,4 +300,40 @@ onLoad(() => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
// 全局暗黑模式适配(针对当前页面)
|
||||
:global([data-theme="dark"]) .settings-container {
|
||||
color: var(--wot-color-text, #fff) !important;
|
||||
background-color: var(--wot-color-bg, #1a1a1a) !important;
|
||||
|
||||
:deep(.wd-cell-group) {
|
||||
background-color: var(--wot-card-bg-color, #2a2a2a) !important;
|
||||
}
|
||||
|
||||
:deep(.wd-cell) {
|
||||
color: var(--wot-color-text, #fff) !important;
|
||||
background-color: var(--wot-card-bg-color, #2a2a2a) !important;
|
||||
|
||||
.wd-cell__title {
|
||||
color: var(--wot-color-text, #fff) !important;
|
||||
}
|
||||
|
||||
.wd-cell__value {
|
||||
color: var(--wot-color-text-secondary, #d1d5db) !important;
|
||||
}
|
||||
|
||||
.wd-cell__right-icon {
|
||||
color: var(--wot-color-text-secondary, #9ca3af) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -7,18 +7,18 @@
|
||||
</view>
|
||||
|
||||
<!-- 暗黑模式设置 -->
|
||||
<view class="setting-section">
|
||||
<wd-card class="setting-section">
|
||||
<view class="section-header">
|
||||
<wd-icon name="moon" size="20" :color="isDark ? '#FFD700' : '#666'" />
|
||||
<wd-icon name="moon" size="20" :color="theme === 'dark' ? '#FFD700' : '#666'" />
|
||||
<text class="section-title">外观模式</text>
|
||||
</view>
|
||||
<wd-cell title="暗黑模式" :value="isDark ? '已开启' : '已关闭'">
|
||||
<wd-switch v-model="isDark" @change="toggleDarkMode" />
|
||||
<wd-cell title="暗黑模式" :value="theme === 'dark' ? '已开启' : '已关闭'">
|
||||
<wd-switch :model-value="theme === 'dark'" @change="handleToggleDarkMode" />
|
||||
</wd-cell>
|
||||
</view>
|
||||
</wd-card>
|
||||
|
||||
<!-- 主题色设置 -->
|
||||
<view class="setting-section">
|
||||
<wd-card class="setting-section">
|
||||
<view class="section-header">
|
||||
<wd-icon name="palette" size="20" color="#666" />
|
||||
<text class="section-title">主题色彩</text>
|
||||
@@ -26,59 +26,78 @@
|
||||
|
||||
<!-- 预设颜色选择 -->
|
||||
<view class="color-section">
|
||||
<view class="color-label">预设主题色</view>
|
||||
<text class="color-label">预设主题色</text>
|
||||
<view class="color-grid">
|
||||
<view
|
||||
v-for="(color, index) in extendedThemeColors"
|
||||
v-for="(color, index) in colorColumns"
|
||||
:key="index"
|
||||
class="color-item"
|
||||
:class="{ active: currentThemeColor === color.value }"
|
||||
:style="{ backgroundColor: color.value }"
|
||||
@click="handleSelectColor(color.value)"
|
||||
>
|
||||
<wd-icon v-if="currentThemeColor === color.value" name="check" color="#fff" size="16" />
|
||||
<view
|
||||
class="color-preview"
|
||||
:style="{
|
||||
backgroundColor: color.value,
|
||||
border: currentThemeColor === color.value ? '3px solid #fff' : '1px solid #e0e0e0',
|
||||
}"
|
||||
>
|
||||
<text v-if="currentThemeColor === color.value" class="check-icon">✓</text>
|
||||
</view>
|
||||
<text class="color-name">{{ color.label }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 当前主题色显示 -->
|
||||
<wd-cell title="当前主题色" :value="currentThemeColor">
|
||||
<view class="current-color-preview" :style="{ backgroundColor: currentThemeColor }"></view>
|
||||
</wd-cell>
|
||||
<view class="current-theme-section">
|
||||
<view class="current-theme-item">
|
||||
<text class="current-theme-label">当前主题色</text>
|
||||
<view class="current-theme-value">
|
||||
<view
|
||||
class="current-color-preview"
|
||||
:style="{ backgroundColor: currentThemeColor }"
|
||||
></view>
|
||||
<text class="current-color-text">{{ currentThemeColor }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 自定义颜色 -->
|
||||
<wd-cell title="自定义颜色" is-link @click="showCustomInput">
|
||||
<wd-icon name="edit" size="16" color="#999" />
|
||||
</wd-cell>
|
||||
</view>
|
||||
</wd-card>
|
||||
|
||||
<!-- 预览区域 -->
|
||||
<view class="setting-section">
|
||||
<wd-card class="setting-section">
|
||||
<view class="section-header">
|
||||
<wd-icon name="eye" size="20" color="#666" />
|
||||
<text class="section-title">效果预览</text>
|
||||
</view>
|
||||
|
||||
<view class="preview-container">
|
||||
<view class="preview-item">
|
||||
<wd-divider />
|
||||
|
||||
<wd-grid :column="2" border>
|
||||
<wd-grid-item>
|
||||
<wd-button type="primary" size="small">主要按钮</wd-button>
|
||||
</view>
|
||||
<view class="preview-item">
|
||||
</wd-grid-item>
|
||||
<wd-grid-item>
|
||||
<text class="preview-text" :style="{ color: currentThemeColor }">主题色文本</text>
|
||||
</view>
|
||||
<view class="preview-item">
|
||||
</wd-grid-item>
|
||||
<wd-grid-item>
|
||||
<view class="preview-border" :style="{ borderColor: currentThemeColor }">主题色边框</view>
|
||||
</view>
|
||||
<view class="preview-item">
|
||||
</wd-grid-item>
|
||||
<wd-grid-item>
|
||||
<wd-tag type="primary" size="small">标签</wd-tag>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</wd-grid-item>
|
||||
</wd-grid>
|
||||
</wd-card>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<view class="action-section">
|
||||
<wd-button type="info" size="large" block @click="resetTheme">重置为默认主题</wd-button>
|
||||
</view>
|
||||
<wd-card class="action-section">
|
||||
<wd-button type="info" size="large" block @click="handleResetTheme">重置为默认主题</wd-button>
|
||||
</wd-card>
|
||||
|
||||
<!-- 自定义颜色输入弹窗 -->
|
||||
<wd-popup v-model="showCustomColorInput" position="bottom" :safe-area-inset-bottom="true">
|
||||
@@ -88,21 +107,24 @@
|
||||
<wd-icon name="close" size="20" color="#999" @click="showCustomColorInput = false" />
|
||||
</view>
|
||||
|
||||
<wd-divider />
|
||||
|
||||
<view class="color-input-section">
|
||||
<view class="input-label">请输入十六进制颜色值</view>
|
||||
<view class="input-container">
|
||||
<view class="color-preview-small" :style="{ backgroundColor: customColor }"></view>
|
||||
<input
|
||||
<wd-input
|
||||
v-model="customColor"
|
||||
type="text"
|
||||
placeholder="例如: #165DFF"
|
||||
:maxlength="7"
|
||||
class="color-input"
|
||||
maxlength="7"
|
||||
/>
|
||||
</view>
|
||||
<view class="input-tip">支持格式:#RGB 或 #RRGGBB</view>
|
||||
</view>
|
||||
|
||||
<wd-divider />
|
||||
|
||||
<view class="popup-actions">
|
||||
<wd-button type="info" size="large" @click="showCustomColorInput = false">取消</wd-button>
|
||||
<wd-button type="primary" size="large" @click="applyCustomColor">应用</wd-button>
|
||||
@@ -114,61 +136,23 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onLoad, onShow } from "@dcloudio/uni-app";
|
||||
import { useTheme } from "@/composables/useTheme";
|
||||
import { useThemeStore } from "@/store/modules/theme.store";
|
||||
import { applyThemeOnPageShow } from "@/utils/theme";
|
||||
import { ref, computed, watch, onMounted } from "vue";
|
||||
import { useTheme, colorColumns } from "@/composables/useTheme";
|
||||
import { ref, computed, onMounted, nextTick } from "vue";
|
||||
|
||||
const { toggleTheme, themeVars, themeState, setThemeColor } = useTheme();
|
||||
const themeStore = useThemeStore();
|
||||
|
||||
// 暗黑模式状态
|
||||
const isDark = ref(false);
|
||||
const { theme, themeVars, toggleTheme, setThemeColor, resetTheme } = useTheme();
|
||||
|
||||
// 自定义颜色输入
|
||||
const customColor = ref("");
|
||||
const showCustomColorInput = ref(false);
|
||||
|
||||
// 扩展的预设主题色
|
||||
const extendedThemeColors = [
|
||||
{ value: "#165DFF", label: "蓝色" },
|
||||
{ value: "#0FC6C2", label: "青绿色" },
|
||||
{ value: "#722ED1", label: "紫色" },
|
||||
{ value: "#F5222D", label: "红色" },
|
||||
{ value: "#FA8C16", label: "橙色" },
|
||||
{ value: "#FADB14", label: "黄色" },
|
||||
{ value: "#52C41A", label: "绿色" },
|
||||
{ value: "#EB2F96", label: "粉色" },
|
||||
{ value: "#13C2C2", label: "青色" },
|
||||
{ value: "#1890FF", label: "天蓝色" },
|
||||
{ value: "#CD5C5C", label: "经典红" },
|
||||
{ value: "#228B22", label: "自然绿" },
|
||||
];
|
||||
|
||||
// 当前选中的主题色
|
||||
const currentThemeColor = computed(() => {
|
||||
return themeVars.value.colorTheme || themeStore.primaryColor || extendedThemeColors[0].value;
|
||||
return themeVars.value.colorTheme || colorColumns[0].value;
|
||||
});
|
||||
|
||||
// 监听暗黑模式变化
|
||||
watch(themeState, (newTheme) => {
|
||||
isDark.value = newTheme === "dark";
|
||||
});
|
||||
|
||||
// 暗黑模式切换
|
||||
const toggleDarkMode = () => {
|
||||
toggleTheme();
|
||||
};
|
||||
|
||||
// 选择预设颜色
|
||||
const handleSelectColor = (color: string) => {
|
||||
// 同时更新两个store的主题色
|
||||
if (setThemeColor) {
|
||||
setThemeColor(color);
|
||||
} else {
|
||||
themeVars.value.colorTheme = color;
|
||||
}
|
||||
themeStore.setPrimaryColor(color);
|
||||
setThemeColor(color);
|
||||
customColor.value = color;
|
||||
|
||||
// 提示
|
||||
@@ -204,13 +188,7 @@ const applyCustomColor = () => {
|
||||
color = "#" + color[1] + color[1] + color[2] + color[2] + color[3] + color[3];
|
||||
}
|
||||
|
||||
// 同时更新两个store的主题色
|
||||
if (setThemeColor) {
|
||||
setThemeColor(color);
|
||||
} else {
|
||||
themeVars.value.colorTheme = color;
|
||||
}
|
||||
themeStore.setPrimaryColor(color);
|
||||
setThemeColor(color);
|
||||
showCustomColorInput.value = false;
|
||||
|
||||
// 提示
|
||||
@@ -222,27 +200,14 @@ const applyCustomColor = () => {
|
||||
};
|
||||
|
||||
// 重置为默认主题
|
||||
const resetTheme = () => {
|
||||
const handleResetTheme = () => {
|
||||
uni.showModal({
|
||||
title: "确认重置",
|
||||
content: "确定要重置为默认主题吗?",
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
const defaultColor = extendedThemeColors[0].value;
|
||||
|
||||
// 同时更新两个store的主题色
|
||||
if (setThemeColor) {
|
||||
setThemeColor(defaultColor);
|
||||
} else {
|
||||
themeVars.value.colorTheme = defaultColor;
|
||||
}
|
||||
themeStore.setPrimaryColor(defaultColor);
|
||||
customColor.value = defaultColor;
|
||||
|
||||
// 重置为浅色模式
|
||||
if (themeState.value === "dark") {
|
||||
toggleTheme();
|
||||
}
|
||||
resetTheme();
|
||||
customColor.value = colorColumns[0].value;
|
||||
|
||||
uni.showToast({
|
||||
title: "已重置为默认主题",
|
||||
@@ -254,31 +219,35 @@ const resetTheme = () => {
|
||||
});
|
||||
};
|
||||
|
||||
// 切换暗黑模式
|
||||
const handleToggleDarkMode = () => {
|
||||
toggleTheme();
|
||||
nextTick(() => {
|
||||
uni.showToast({
|
||||
title: `已切换到${theme.value === "dark" ? "暗黑" : "浅色"}模式`,
|
||||
icon: "success",
|
||||
duration: 1500,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
onLoad(() => {
|
||||
// 初始化自定义颜色输入框
|
||||
customColor.value = currentThemeColor.value;
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
// 初始化暗黑模式状态
|
||||
isDark.value = themeState.value === "dark";
|
||||
// 初始化自定义颜色输入框
|
||||
customColor.value = currentThemeColor.value;
|
||||
});
|
||||
|
||||
// 页面显示时重新应用主题(解决小程序环境问题)
|
||||
// 页面显示时确保主题色同步
|
||||
onShow(() => {
|
||||
// 在小程序环境中,页面显示时重新应用主题
|
||||
if (typeof document === "undefined") {
|
||||
applyThemeOnPageShow(currentThemeColor.value);
|
||||
|
||||
// 为了确保样式应用,我们可以在页面中设置内联样式
|
||||
// 这样可以绕过小程序的CSS变量限制
|
||||
const pages = getCurrentPages();
|
||||
const currentPage = pages[pages.length - 1];
|
||||
if (currentPage) {
|
||||
console.log("当前页面重新应用主题色");
|
||||
}
|
||||
}
|
||||
customColor.value = currentThemeColor.value;
|
||||
console.log("主题设置页面显示,当前主题:", {
|
||||
mode: theme.value,
|
||||
color: currentThemeColor.value,
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -286,15 +255,81 @@ onShow(() => {
|
||||
.theme-settings-container {
|
||||
min-height: 100vh;
|
||||
padding: 20rpx;
|
||||
background-color: #f8f9fa;
|
||||
background-color: var(--wot-color-bg-light, #f8f9fa);
|
||||
transition: background-color 0.3s ease;
|
||||
|
||||
// 强制 Wot 组件应用暗黑模式样式
|
||||
:deep(.wd-card) {
|
||||
background: var(--wot-card-bg-color, #fff);
|
||||
border-radius: 16rpx;
|
||||
box-shadow: var(--wot-card-shadow, 0 2rpx 12rpx rgba(0, 0, 0, 0.05));
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
:deep(.wd-cell) {
|
||||
color: var(--wot-color-text, #333);
|
||||
background-color: var(--wot-card-bg-color, #fff);
|
||||
|
||||
.wd-cell__title {
|
||||
color: var(--wot-color-text, #333) !important;
|
||||
}
|
||||
|
||||
.wd-cell__value {
|
||||
color: var(--wot-color-text-secondary, #666) !important;
|
||||
}
|
||||
|
||||
.wd-cell__right-icon {
|
||||
color: var(--wot-color-text-secondary, #999) !important;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.wd-grid-item) {
|
||||
color: var(--wot-color-text, #333) !important;
|
||||
background-color: var(--wot-card-bg-color, #fff) !important;
|
||||
}
|
||||
|
||||
// 专门为颜色预览块重置背景色
|
||||
:deep(.color-item) {
|
||||
background-color: transparent !important;
|
||||
|
||||
.color-preview {
|
||||
background-color: inherit !important;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.wd-button) {
|
||||
&[type="primary"] {
|
||||
color: #fff !important;
|
||||
background-color: var(--wot-color-theme, #165dff) !important;
|
||||
}
|
||||
|
||||
&[type="info"] {
|
||||
color: #fff !important;
|
||||
background-color: var(--wot-color-info, #909399) !important;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.wd-input) {
|
||||
color: var(--wot-color-text, #333) !important;
|
||||
background-color: var(--wot-card-bg-color, #fff) !important;
|
||||
}
|
||||
|
||||
:deep(.wd-popup) {
|
||||
background-color: var(--wot-popup-bg-color, #fff) !important;
|
||||
}
|
||||
|
||||
.custom-color-popup {
|
||||
padding: 40rpx 30rpx;
|
||||
background: var(--wot-popup-bg-color, #fff);
|
||||
border-radius: 20rpx 20rpx 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
.page-header {
|
||||
padding: 40rpx 20rpx;
|
||||
margin-bottom: 30rpx;
|
||||
text-align: center;
|
||||
background: linear-gradient(135deg, #165dff 0%, #667eea 100%);
|
||||
background: linear-gradient(135deg, var(--wot-color-theme, #165dff) 0%, #667eea 100%);
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
|
||||
@@ -313,25 +348,20 @@ onShow(() => {
|
||||
|
||||
.setting-section {
|
||||
margin-bottom: 30rpx;
|
||||
overflow: hidden;
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 30rpx 30rpx 20rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
border-bottom: 1rpx solid var(--wot-color-border, #f0f0f0);
|
||||
}
|
||||
|
||||
.section-title {
|
||||
margin-left: 12rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
color: var(--wot-color-text, #333);
|
||||
}
|
||||
|
||||
.color-section {
|
||||
@@ -341,58 +371,95 @@ onShow(() => {
|
||||
.color-label {
|
||||
margin-bottom: 20rpx;
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
color: var(--wot-color-text-secondary, #666);
|
||||
}
|
||||
|
||||
.color-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20rpx;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.color-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
width: calc(25% - 15rpx);
|
||||
padding: 10rpx;
|
||||
cursor: pointer;
|
||||
border-radius: 12rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
transition: all 0.3s ease;
|
||||
|
||||
.color-preview {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
margin-bottom: 8rpx;
|
||||
border-radius: 12rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.check-icon {
|
||||
font-size: 24rpx;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
text-shadow: 0 1rpx 2rpx rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.color-name {
|
||||
font-size: 22rpx;
|
||||
line-height: 1.2;
|
||||
color: var(--wot-color-text-secondary, #666);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&.active .color-preview {
|
||||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.2);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
&:active .color-preview {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
}
|
||||
|
||||
.color-item.active {
|
||||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.2);
|
||||
transform: scale(1.1);
|
||||
.current-theme-section {
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.color-item:active {
|
||||
transform: scale(0.95);
|
||||
.current-theme-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.current-theme-label {
|
||||
font-size: 28rpx;
|
||||
color: var(--wot-color-text-secondary, #666);
|
||||
}
|
||||
|
||||
.current-theme-value {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.current-color-preview {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
border: 2rpx solid #f0f0f0;
|
||||
border: 2rpx solid var(--wot-color-border, #f0f0f0);
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.preview-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20rpx;
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.preview-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20rpx;
|
||||
background: #f8f9fa;
|
||||
border-radius: 12rpx;
|
||||
.current-color-text {
|
||||
margin-left: 10rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.preview-text {
|
||||
@@ -407,22 +474,18 @@ onShow(() => {
|
||||
width: 200rpx;
|
||||
height: 60rpx;
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
color: var(--wot-color-text-secondary, #666);
|
||||
border: 2rpx solid;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.action-section {
|
||||
padding: 30rpx;
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.custom-color-popup {
|
||||
padding: 40rpx 30rpx;
|
||||
background: #fff;
|
||||
border-radius: 20rpx 20rpx 0 0;
|
||||
:deep(.wd-card) {
|
||||
padding: 30rpx;
|
||||
background: var(--wot-card-bg-color, #fff);
|
||||
border-radius: 16rpx;
|
||||
box-shadow: var(--wot-card-shadow, 0 2rpx 12rpx rgba(0, 0, 0, 0.05));
|
||||
}
|
||||
}
|
||||
|
||||
.popup-header {
|
||||
@@ -435,7 +498,7 @@ onShow(() => {
|
||||
.popup-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
color: var(--wot-color-text, #333);
|
||||
}
|
||||
|
||||
.color-input-section {
|
||||
@@ -445,7 +508,7 @@ onShow(() => {
|
||||
.input-label {
|
||||
margin-bottom: 20rpx;
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
color: var(--wot-color-text-secondary, #666);
|
||||
}
|
||||
|
||||
.input-container {
|
||||
@@ -459,28 +522,18 @@ onShow(() => {
|
||||
flex-shrink: 0;
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
border: 2rpx solid #f0f0f0;
|
||||
border: 2rpx solid var(--wot-color-border, #f0f0f0);
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.color-input {
|
||||
flex: 1;
|
||||
height: 60rpx;
|
||||
padding: 0 20rpx;
|
||||
font-size: 28rpx;
|
||||
background: #fff;
|
||||
border: 2rpx solid #e0e0e0;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.color-input:focus {
|
||||
border-color: #165dff;
|
||||
}
|
||||
|
||||
.input-tip {
|
||||
margin-left: 80rpx;
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
color: var(--wot-color-text-placeholder, #999);
|
||||
}
|
||||
|
||||
.popup-actions {
|
||||
@@ -501,52 +554,85 @@ onShow(() => {
|
||||
}
|
||||
}
|
||||
|
||||
/* 暗黑模式适配 */
|
||||
:deep(.wd-config-provider[data-theme="dark"]) {
|
||||
.theme-settings-container {
|
||||
background-color: #1a1a1a;
|
||||
// 全局暗黑模式适配(针对当前页面)
|
||||
:global([data-theme="dark"]) .theme-settings-container {
|
||||
color: var(--wot-color-text, #fff) !important;
|
||||
background-color: var(--wot-color-bg, #1a1a1a) !important;
|
||||
|
||||
.page-header {
|
||||
background: linear-gradient(135deg, var(--wot-color-theme, #165dff) 0%, #4a5568 100%);
|
||||
}
|
||||
|
||||
.setting-section {
|
||||
background: #2a2a2a;
|
||||
.section-title {
|
||||
color: var(--wot-color-text, #fff) !important;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
border-bottom-color: #404040;
|
||||
.color-label {
|
||||
color: var(--wot-color-text-secondary, #d1d5db) !important;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
color: #fff;
|
||||
}
|
||||
.preview-text {
|
||||
color: var(--wot-color-text, #fff) !important;
|
||||
}
|
||||
|
||||
.preview-border {
|
||||
color: var(--wot-color-text-secondary, #d1d5db) !important;
|
||||
}
|
||||
|
||||
.popup-title {
|
||||
color: var(--wot-color-text, #fff) !important;
|
||||
}
|
||||
|
||||
.input-label {
|
||||
color: var(--wot-color-text-secondary, #d1d5db) !important;
|
||||
}
|
||||
|
||||
.input-tip {
|
||||
color: var(--wot-color-text-placeholder, #9ca3af) !important;
|
||||
}
|
||||
|
||||
:deep(.wd-card) {
|
||||
background: var(--wot-card-bg-color, #2a2a2a) !important;
|
||||
}
|
||||
|
||||
:deep(.wd-cell) {
|
||||
color: var(--wot-color-text, #fff) !important;
|
||||
background-color: var(--wot-card-bg-color, #2a2a2a) !important;
|
||||
|
||||
.wd-cell__title {
|
||||
color: var(--wot-color-text, #fff) !important;
|
||||
}
|
||||
|
||||
.wd-cell__value {
|
||||
color: var(--wot-color-text-secondary, #d1d5db) !important;
|
||||
}
|
||||
|
||||
.wd-cell__right-icon {
|
||||
color: var(--wot-color-text-secondary, #9ca3af) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.preview-container .preview-item {
|
||||
background: #404040;
|
||||
:deep(.wd-grid-item) {
|
||||
color: var(--wot-color-text, #fff) !important;
|
||||
background-color: var(--wot-card-bg-color, #2a2a2a) !important;
|
||||
}
|
||||
|
||||
.action-section {
|
||||
background: #2a2a2a;
|
||||
// 专门为颜色预览块重置背景色
|
||||
:deep(.color-item) {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
:deep(.wd-input) {
|
||||
color: var(--wot-color-text, #fff) !important;
|
||||
background-color: var(--wot-card-bg-color, #2a2a2a) !important;
|
||||
}
|
||||
|
||||
:deep(.wd-popup) {
|
||||
background-color: var(--wot-popup-bg-color, #2a2a2a) !important;
|
||||
}
|
||||
|
||||
.custom-color-popup {
|
||||
background: #2a2a2a;
|
||||
|
||||
.popup-title {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.input-label {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.color-input {
|
||||
color: #fff;
|
||||
background: #404040;
|
||||
border-color: #606060;
|
||||
|
||||
&:focus {
|
||||
border-color: #165dff;
|
||||
}
|
||||
}
|
||||
background: var(--wot-popup-bg-color, #2a2a2a) !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
235
src/styles/wot-theme.scss
Normal file
235
src/styles/wot-theme.scss
Normal file
@@ -0,0 +1,235 @@
|
||||
/**
|
||||
* Wot Design Uni 主题变量定制
|
||||
* 基于 ConfigProvider 的 CSS 变量系统
|
||||
*/
|
||||
|
||||
/*
|
||||
* 全局 Wot 主题变量
|
||||
* 这些变量会被 ConfigProvider 自动应用到所有 Wot 组件
|
||||
*/
|
||||
:root,
|
||||
page {
|
||||
/* ===== 主题色系 ===== */
|
||||
--wot-color-theme: #165dff;
|
||||
--wot-color-success: #0fc6c2;
|
||||
--wot-color-warning: #ff7d00;
|
||||
--wot-color-danger: #f5222d;
|
||||
--wot-color-info: #86909c;
|
||||
|
||||
/* ===== 中性色系 ===== */
|
||||
--wot-color-white: #ffffff;
|
||||
--wot-color-black: #000000;
|
||||
--wot-color-gray-1: #f7f8fa;
|
||||
--wot-color-gray-2: #f2f3f5;
|
||||
--wot-color-gray-3: #e5e6eb;
|
||||
--wot-color-gray-4: #c9cdd4;
|
||||
--wot-color-gray-5: #86909c;
|
||||
--wot-color-gray-6: #4e5969;
|
||||
--wot-color-gray-7: #272e3b;
|
||||
--wot-color-gray-8: #1d2129;
|
||||
|
||||
/* ===== 文本颜色 ===== */
|
||||
--wot-color-text: #1d2129;
|
||||
--wot-color-text-secondary: #4e5969;
|
||||
--wot-color-text-placeholder: #86909c;
|
||||
--wot-color-text-disabled: #c9cdd4;
|
||||
|
||||
/* ===== 背景颜色 ===== */
|
||||
--wot-color-bg: #ffffff;
|
||||
--wot-color-bg-light: #f7f8fa;
|
||||
--wot-color-bg-dark: #f2f3f5;
|
||||
|
||||
/* ===== 边框颜色 ===== */
|
||||
--wot-color-border: #e5e6eb;
|
||||
--wot-color-border-light: #f2f3f5;
|
||||
|
||||
/* ===== 按钮相关变量 ===== */
|
||||
--wot-button-primary-bg-color: var(--wot-color-theme);
|
||||
--wot-button-primary-color: #ffffff;
|
||||
--wot-button-primary-border-color: var(--wot-color-theme);
|
||||
|
||||
--wot-button-success-bg-color: var(--wot-color-success);
|
||||
--wot-button-success-color: #ffffff;
|
||||
--wot-button-success-border-color: var(--wot-color-success);
|
||||
|
||||
--wot-button-warning-bg-color: var(--wot-color-warning);
|
||||
--wot-button-warning-color: #ffffff;
|
||||
--wot-button-warning-border-color: var(--wot-color-warning);
|
||||
|
||||
--wot-button-danger-bg-color: var(--wot-color-danger);
|
||||
--wot-button-danger-color: #ffffff;
|
||||
--wot-button-danger-border-color: var(--wot-color-danger);
|
||||
|
||||
--wot-button-info-bg-color: var(--wot-color-info);
|
||||
--wot-button-info-color: #ffffff;
|
||||
--wot-button-info-border-color: var(--wot-color-info);
|
||||
|
||||
/* ===== 输入框相关变量 ===== */
|
||||
--wot-input-border-color: var(--wot-color-border);
|
||||
--wot-input-focus-border-color: var(--wot-color-theme);
|
||||
--wot-input-placeholder-color: var(--wot-color-text-placeholder);
|
||||
--wot-input-disabled-bg-color: var(--wot-color-bg-light);
|
||||
|
||||
/* ===== 开关相关变量 ===== */
|
||||
--wot-switch-on-bg-color: var(--wot-color-theme);
|
||||
--wot-switch-off-bg-color: var(--wot-color-gray-3);
|
||||
|
||||
/* ===== 卡片相关变量 ===== */
|
||||
--wot-card-bg-color: #ffffff;
|
||||
--wot-card-border-color: var(--wot-color-border);
|
||||
--wot-card-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
|
||||
|
||||
/* ===== Cell 相关变量 ===== */
|
||||
--wot-cell-bg-color: #ffffff;
|
||||
--wot-cell-border-color: var(--wot-color-border);
|
||||
--wot-cell-title-color: var(--wot-color-text);
|
||||
--wot-cell-value-color: var(--wot-color-text-secondary);
|
||||
|
||||
/* ===== 标签相关变量 ===== */
|
||||
--wot-tag-primary-bg-color: var(--wot-color-theme);
|
||||
--wot-tag-primary-color: #ffffff;
|
||||
--wot-tag-success-bg-color: var(--wot-color-success);
|
||||
--wot-tag-success-color: #ffffff;
|
||||
--wot-tag-warning-bg-color: var(--wot-color-warning);
|
||||
--wot-tag-warning-color: #ffffff;
|
||||
--wot-tag-danger-bg-color: var(--wot-color-danger);
|
||||
--wot-tag-danger-color: #ffffff;
|
||||
|
||||
/* ===== 图标相关变量 ===== */
|
||||
--wot-icon-color: var(--wot-color-text-secondary);
|
||||
|
||||
/* ===== 分割线相关变量 ===== */
|
||||
--wot-divider-color: var(--wot-color-border);
|
||||
|
||||
/* ===== 弹窗相关变量 ===== */
|
||||
--wot-popup-bg-color: #ffffff;
|
||||
--wot-popup-border-radius: 16rpx;
|
||||
|
||||
/* ===== 网格相关变量 ===== */
|
||||
--wot-grid-border-color: var(--wot-color-border);
|
||||
}
|
||||
|
||||
/* ===== 暗黑模式变量 ===== */
|
||||
[data-theme="dark"],
|
||||
.wot-theme-dark {
|
||||
/* 主题色在暗黑模式下稍微调亮 */
|
||||
--wot-color-theme: #4080ff;
|
||||
--wot-color-success: #1dd1cc;
|
||||
--wot-color-warning: #ff8c1a;
|
||||
--wot-color-danger: #ff4757;
|
||||
--wot-color-info: #9ca3af;
|
||||
|
||||
/* 中性色系 - 暗黑模式 */
|
||||
--wot-color-white: #1a1a1a;
|
||||
--wot-color-black: #ffffff;
|
||||
--wot-color-gray-1: #2a2a2a;
|
||||
--wot-color-gray-2: #404040;
|
||||
--wot-color-gray-3: #606060;
|
||||
--wot-color-gray-4: #808080;
|
||||
--wot-color-gray-5: #9ca3af;
|
||||
--wot-color-gray-6: #d1d5db;
|
||||
--wot-color-gray-7: #e5e7eb;
|
||||
--wot-color-gray-8: #f3f4f6;
|
||||
|
||||
/* 文本颜色 - 暗黑模式 */
|
||||
--wot-color-text: #ffffff;
|
||||
--wot-color-text-secondary: #d1d5db;
|
||||
--wot-color-text-placeholder: #9ca3af;
|
||||
--wot-color-text-disabled: #6b7280;
|
||||
|
||||
/* 背景颜色 - 暗黑模式 */
|
||||
--wot-color-bg: #1a1a1a;
|
||||
--wot-color-bg-light: #2a2a2a;
|
||||
--wot-color-bg-dark: #404040;
|
||||
|
||||
/* 边框颜色 - 暗黑模式 */
|
||||
--wot-color-border: #404040;
|
||||
--wot-color-border-light: #606060;
|
||||
|
||||
/* 卡片相关变量 - 暗黑模式 */
|
||||
--wot-card-bg-color: #2a2a2a;
|
||||
--wot-card-border-color: var(--wot-color-border);
|
||||
--wot-card-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.3);
|
||||
|
||||
/* Cell 相关变量 - 暗黑模式 */
|
||||
--wot-cell-bg-color: #2a2a2a;
|
||||
|
||||
/* 弹窗相关变量 - 暗黑模式 */
|
||||
--wot-popup-bg-color: #2a2a2a;
|
||||
|
||||
/* 输入框相关变量 - 暗黑模式 */
|
||||
--wot-input-disabled-bg-color: var(--wot-color-bg-light);
|
||||
}
|
||||
|
||||
/* ===== 动态主题色支持 ===== */
|
||||
/* 这些变量会被 useTheme composable 动态设置 */
|
||||
.theme-blue {
|
||||
--wot-color-theme: #165dff;
|
||||
}
|
||||
|
||||
.theme-green {
|
||||
--wot-color-theme: #0fc6c2;
|
||||
}
|
||||
|
||||
.theme-orange {
|
||||
--wot-color-theme: #ff7d00;
|
||||
}
|
||||
|
||||
.theme-red {
|
||||
--wot-color-theme: #f5222d;
|
||||
}
|
||||
|
||||
.theme-purple {
|
||||
--wot-color-theme: #722ed1;
|
||||
}
|
||||
|
||||
.theme-pink {
|
||||
--wot-color-theme: #eb2f96;
|
||||
}
|
||||
|
||||
.theme-cyan {
|
||||
--wot-color-theme: #13c2c2;
|
||||
}
|
||||
|
||||
.theme-yellow {
|
||||
--wot-color-theme: #faad14;
|
||||
}
|
||||
|
||||
.theme-lime {
|
||||
--wot-color-theme: #a0d911;
|
||||
}
|
||||
|
||||
.theme-indigo {
|
||||
--wot-color-theme: #2f54eb;
|
||||
}
|
||||
|
||||
.theme-teal {
|
||||
--wot-color-theme: #08979c;
|
||||
}
|
||||
|
||||
.theme-brown {
|
||||
--wot-color-theme: #8c6239;
|
||||
}
|
||||
|
||||
/* ===== 全局样式增强 ===== */
|
||||
/* 确保暗黑模式下的全局样式 */
|
||||
[data-theme="dark"] {
|
||||
color: var(--wot-color-text);
|
||||
background-color: var(--wot-color-bg);
|
||||
}
|
||||
|
||||
/* H5 环境下的 body 样式 */
|
||||
/* #ifdef H5 */
|
||||
body.dark {
|
||||
color: #ffffff !important;
|
||||
background-color: #1a1a1a !important;
|
||||
}
|
||||
/* #endif */
|
||||
|
||||
/* 小程序环境下的 page 样式 */
|
||||
/* #ifndef H5 */
|
||||
page.dark {
|
||||
color: #ffffff !important;
|
||||
background-color: #1a1a1a !important;
|
||||
}
|
||||
/* #endif */
|
||||
5
src/types/env.d.ts
vendored
5
src/types/env.d.ts
vendored
@@ -12,6 +12,11 @@ interface ImportMetaEnv {
|
||||
* API 服务器的 URL
|
||||
*/
|
||||
VITE_APP_API_URL: string;
|
||||
|
||||
/**
|
||||
* WebSocket 端点
|
||||
*/
|
||||
VITE_APP_WS_ENDPOINT: string;
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
|
||||
66
src/uni.scss
66
src/uni.scss
@@ -74,3 +74,69 @@ $uni-color-subtitle: #555; // 二级标题颜色
|
||||
$uni-font-size-subtitle: 18px;
|
||||
$uni-color-paragraph: #3f536e; // 文章段落颜色
|
||||
$uni-font-size-paragraph: 15px;
|
||||
|
||||
/* 暗黑模式全局样式 */
|
||||
.wot-theme-dark {
|
||||
color: #f5f5f5 !important;
|
||||
background-color: #1a1a1a !important;
|
||||
|
||||
/* 页面背景 */
|
||||
page {
|
||||
color: #f5f5f5 !important;
|
||||
background-color: #1a1a1a !important;
|
||||
}
|
||||
|
||||
/* H5 环境 body 样式 */
|
||||
body {
|
||||
color: #f5f5f5 !important;
|
||||
background-color: #1a1a1a !important;
|
||||
}
|
||||
|
||||
/* 通用组件暗黑模式适配 */
|
||||
.uni-page-wrapper {
|
||||
color: #f5f5f5 !important;
|
||||
background-color: #1a1a1a !important;
|
||||
}
|
||||
|
||||
/* 导航栏暗黑模式 */
|
||||
.uni-navbar {
|
||||
color: #f5f5f5 !important;
|
||||
background-color: #2a2a2a !important;
|
||||
border-bottom-color: #404040 !important;
|
||||
}
|
||||
|
||||
/* 标签栏暗黑模式 */
|
||||
.uni-tabbar {
|
||||
background-color: #2a2a2a !important;
|
||||
border-top-color: #404040 !important;
|
||||
}
|
||||
|
||||
/* 卡片组件暗黑模式 */
|
||||
.uni-card {
|
||||
color: #f5f5f5 !important;
|
||||
background-color: #2a2a2a !important;
|
||||
}
|
||||
|
||||
/* 列表项暗黑模式 */
|
||||
.uni-list-item {
|
||||
color: #f5f5f5 !important;
|
||||
background-color: #2a2a2a !important;
|
||||
border-bottom-color: #404040 !important;
|
||||
}
|
||||
|
||||
/* 输入框暗黑模式 */
|
||||
.uni-input {
|
||||
color: #f5f5f5 !important;
|
||||
background-color: #404040 !important;
|
||||
border-color: #606060 !important;
|
||||
}
|
||||
|
||||
/* 按钮暗黑模式适配 */
|
||||
.uni-button {
|
||||
&.uni-button-default {
|
||||
color: #f5f5f5 !important;
|
||||
background-color: #404040 !important;
|
||||
border-color: #606060 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user