初次提交
This commit is contained in:
132
uni_modules/lime-echart/changelog.md
Normal file
132
uni_modules/lime-echart/changelog.md
Normal file
@ -0,0 +1,132 @@
|
||||
## 0.6.5(2022-11-03)
|
||||
- fix: 某些手机touches为对象,导致无法交互。
|
||||
## 0.6.4(2022-10-28)
|
||||
- fix: 优化点击事件的触发条件
|
||||
## 0.6.3(2022-10-26)
|
||||
- fix: 修复 dataZoom 拖动问题
|
||||
## 0.6.2(2022-10-23)
|
||||
- fix: 修复 飞书小程序 尺寸问题
|
||||
## 0.6.1(2022-10-19)
|
||||
- fix: 修复 PC mousewheel 事件 鼠标位置不准确的BUG,不兼容火狐!
|
||||
- feat: showLoading 增加传参
|
||||
## 0.6.0(2022-09-16)
|
||||
- feat: 增加PC的mousewheel事件
|
||||
## 0.5.4(2022-09-16)
|
||||
- fix: 修复 nvue 动态数据不显示问题
|
||||
## 0.5.3(2022-09-16)
|
||||
- feat: 增加enableHover属性, 在PC端时当鼠标进入显示tooltip,不必按下。
|
||||
- chore: 更新文档
|
||||
## 0.5.2(2022-09-16)
|
||||
- feat: 增加enableHover属性, 在PC端时当鼠标进入显示tooltip,不必按下。
|
||||
## 0.5.1(2022-09-16)
|
||||
- fix: 修复nvue报错
|
||||
## 0.5.0(2022-09-15)
|
||||
- feat: init(echarts, theme?:string, opts?:{}, callback: function(chart))
|
||||
## 0.4.8(2022-09-11)
|
||||
- feat: 增加 @finished
|
||||
## 0.4.7(2022-08-24)
|
||||
- chore: 去掉 stylus
|
||||
## 0.4.6(2022-08-24)
|
||||
- feat: 增加 beforeDelay
|
||||
## 0.4.5(2022-08-12)
|
||||
- chore: 更新文档
|
||||
## 0.4.4(2022-08-12)
|
||||
- fix: 修复 resize 无参数时报错
|
||||
## 0.4.3(2022-08-07)
|
||||
# 评论有说本插件对新手不友好,让我做不好就不要发出来。 还有的说跟官网一样,发出来做什么,给我整无语了。
|
||||
# 所以在此提醒一下准备要下载的你,如果你从未使用过 echarts 请不要下载 或 谨慎下载。
|
||||
# 如果你确认要下载,麻烦看完文档。还有请注意插件是让echarts在uniapp能运行,API 配置请自行去官网查阅!
|
||||
# 如果你不会echarts 但又需要图表,市场上有个很优秀的图表插件 uchart 你可以去使用这款插件,uchart的作者人很好,也热情。
|
||||
# 每个人都有自己的本职工作,如果你能力强可以自行兼容,如果使用了他人的插件也麻烦尊重他人的成果和劳动时间。谢谢。
|
||||
# 为了心情愉悦,本人已经使用插件屏蔽差评。
|
||||
- chore: 更新文档
|
||||
## 0.4.2(2022-07-20)
|
||||
- feat: 增加 resize
|
||||
## 0.4.1(2022-06-07)
|
||||
- fix: 修复 canvasToTempFilePath 不生效问题
|
||||
## 0.4.0(2022-06-04)
|
||||
- chore 为了词云 增加一个canvas 标签
|
||||
- 词云下载地址[echart-wordcloud](https://ext.dcloud.net.cn/plugin?id=8430)
|
||||
## 0.3.9(2022-06-02)
|
||||
- chore: 更新文档
|
||||
- tips: lines 不支持 `trailLength`
|
||||
## 0.3.8(2022-05-31)
|
||||
- fix: 修复 因mouse事件冲突tooltip跳动问题
|
||||
## 0.3.7(2022-05-26)
|
||||
- chore: 更新文档
|
||||
- chore: 设置默认宽高300px
|
||||
- fix: 修复 vue3 微信小程序 拖影BUG
|
||||
- chore: 支持PC
|
||||
## 0.3.5(2022-04-28)
|
||||
- chore: 更新使用方式
|
||||
- 🔔 必须使用hbuilderx 3.4.8-alpha以上
|
||||
## 0.3.4(2021-08-03)
|
||||
- chore: 增加 setOption的参数值
|
||||
## 0.3.3(2021-07-22)
|
||||
- fix: 修复 径向渐变报错的问题
|
||||
## 0.3.2(2021-07-09)
|
||||
- chore: 统一命名规范,无须主动引入组件
|
||||
## [代码示例站点1](https://limeui.qcoon.cn/#/echart-example)
|
||||
## [代码示例站点2](http://liangei.gitee.io/limeui/#/echart-example)
|
||||
## 0.3.1(2021-06-21)
|
||||
- fix: 修复 app-nvue ios is-enable 无效的问题
|
||||
## [代码示例站点1](https://limeui.qcoon.cn/#/echart-example)
|
||||
## [代码示例站点2](http://liangei.gitee.io/limeui/#/echart-example)
|
||||
## 0.3.0(2021-06-14)
|
||||
- fix: 修复 头条系小程序 2d 报 JSON.stringify 的问题
|
||||
- 目前 头条系小程序 2d 无法在开发工具上预览,划动图表页面无法滚动,axisLabel 字体颜色无法更改,建议使用非2d。
|
||||
## 0.2.9(2021-06-06)
|
||||
- fix: 修复 头条系小程序 2d 放大的BUG
|
||||
- 头条系小程序 2d 无法在开发工具上预览,也存在划动图表页面无法滚动的问题。
|
||||
## [代码示例:http://liangei.gitee.io/limeui/#/echart-example](http://liangei.gitee.io/limeui/#/echart-example)
|
||||
## 0.2.8(2021-05-19)
|
||||
- fix: 修复 微信小程序 PC 显示过大的问题
|
||||
## 0.2.7(2021-05-19)
|
||||
- fix: 修复 微信小程序 PC 不显示问题
|
||||
## [代码示例:http://liangei.gitee.io/limeui/#/echart-example](http://liangei.gitee.io/limeui/#/echart-example)
|
||||
## 0.2.6(2021-05-14)
|
||||
- feat: 支持 `image`
|
||||
- feat: props 增加 `ec.clear`,更新时是否先删除图表样式
|
||||
- feat: props 增加 `isDisableScroll` ,触摸图表时是否禁止页面滚动
|
||||
- feat: props 增加 `webviewStyles` ,webview 的样式, 仅nvue有效
|
||||
## 0.2.5(2021-05-13)
|
||||
- docs: 插件用到了css 预编译器 [stylus](https://ext.dcloud.net.cn/plugin?name=compile-stylus) 请安装它
|
||||
## 0.2.4(2021-05-12)
|
||||
- fix: 修复 百度平台 多个图表ctx 和 渐变色 bug
|
||||
- ## [代码示例:http://liangei.gitee.io/limeui/#/echart-example](http://liangei.gitee.io/limeui/#/echart-example)
|
||||
## 0.2.3(2021-05-10)
|
||||
- feat: 增加 `canvasToTempFilePath` 方法,用于生成图片
|
||||
```js
|
||||
this.$refs.chart.canvasToTempFilePath({success: (res) => {
|
||||
console.log('tempFilePath:', res.tempFilePath)
|
||||
}})
|
||||
```
|
||||
## 0.2.2(2021-05-10)
|
||||
- feat: 增加 `dispose` 方法,用于销毁实例
|
||||
- feat: 增加 `isClickable` 是否派发点击
|
||||
- feat: 实验性的支持 `nvue` 使用要慎重考虑
|
||||
- ## [代码示例:http://liangei.gitee.io/limeui/#/echart-example](http://liangei.gitee.io/limeui/#/echart-example)
|
||||
## 0.2.1(2021-05-06)
|
||||
- fix:修复 微信小程序 json 报错
|
||||
- chore: `reset` 更改为 `setChart`
|
||||
- feat: 增加 `isEnable` 开启初始化 启用这个后 无须再使用`init`方法
|
||||
```html
|
||||
<l-echart ref="chart" is-enable />
|
||||
```
|
||||
```js
|
||||
// 显示加载
|
||||
this.$refs.chart.showLoading()
|
||||
// 使用实例回调
|
||||
this.$refs.chart.setChart(chart => ...code)
|
||||
// 直接设置图表配置
|
||||
this.$refs.chart.setOption(data)
|
||||
```
|
||||
## 0.2.0(2021-05-05)
|
||||
- fix:修复 头条 百度 偏移的问题
|
||||
- docs: 更新文档
|
||||
## [代码示例:http://liangei.gitee.io/limeui/#/echart-example](http://liangei.gitee.io/limeui/#/echart-example)
|
||||
## 0.1.0(2021-05-02)
|
||||
- chore: 第一次上传,基本全端兼容,使用方法与官网一致。
|
||||
- 已知BUG:非2d 无法使用背景色,已反馈官方
|
||||
- 已知BUG:头条 百度 有许些偏移
|
||||
- 后期计划:兼容nvue
|
||||
372
uni_modules/lime-echart/components/l-echart/canvas.js
Normal file
372
uni_modules/lime-echart/components/l-echart/canvas.js
Normal file
@ -0,0 +1,372 @@
|
||||
const cacheChart = {}
|
||||
const fontSizeReg = /([\d\.]+)px/;
|
||||
class EventEmit {
|
||||
constructor() {
|
||||
this.__events = {};
|
||||
}
|
||||
on(type, listener) {
|
||||
if (!type || !listener) {
|
||||
return;
|
||||
}
|
||||
const events = this.__events[type] || [];
|
||||
events.push(listener);
|
||||
this.__events[type] = events;
|
||||
}
|
||||
emit(type, e) {
|
||||
if (type.constructor === Object) {
|
||||
e = type;
|
||||
type = e && e.type;
|
||||
}
|
||||
if (!type) {
|
||||
return;
|
||||
}
|
||||
const events = this.__events[type];
|
||||
if (!events || !events.length) {
|
||||
return;
|
||||
}
|
||||
events.forEach((listener) => {
|
||||
listener.call(this, e);
|
||||
});
|
||||
}
|
||||
off(type, listener) {
|
||||
const __events = this.__events;
|
||||
const events = __events[type];
|
||||
if (!events || !events.length) {
|
||||
return;
|
||||
}
|
||||
if (!listener) {
|
||||
delete __events[type];
|
||||
return;
|
||||
}
|
||||
for (let i = 0, len = events.length; i < len; i++) {
|
||||
if (events[i] === listener) {
|
||||
events.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
class Image {
|
||||
constructor() {
|
||||
this.currentSrc = null
|
||||
this.naturalHeight = 0
|
||||
this.naturalWidth = 0
|
||||
this.width = 0
|
||||
this.height = 0
|
||||
this.tagName = 'IMG'
|
||||
}
|
||||
set src(src) {
|
||||
this.currentSrc = src
|
||||
uni.getImageInfo({
|
||||
src,
|
||||
success: (res) => {
|
||||
this.naturalWidth = this.width = res.width
|
||||
this.naturalHeight = this.height = res.height
|
||||
this.onload()
|
||||
},
|
||||
fail: () => {
|
||||
this.onerror()
|
||||
}
|
||||
})
|
||||
}
|
||||
get src() {
|
||||
return this.currentSrc
|
||||
}
|
||||
}
|
||||
class OffscreenCanvas {
|
||||
constructor(ctx, com, canvasId) {
|
||||
this.tagName = 'canvas'
|
||||
this.com = com
|
||||
this.canvasId = canvasId
|
||||
this.ctx = ctx
|
||||
}
|
||||
set width(w) {
|
||||
this.com.offscreenWidth = w
|
||||
}
|
||||
set height(h) {
|
||||
this.com.offscreenHeight = h
|
||||
}
|
||||
get width() {
|
||||
return this.com.offscreenWidth || 0
|
||||
}
|
||||
get height() {
|
||||
return this.com.offscreenHeight || 0
|
||||
}
|
||||
getContext(type) {
|
||||
return this.ctx
|
||||
}
|
||||
getImageData() {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.com.$nextTick(() => {
|
||||
uni.canvasGetImageData({
|
||||
x:0,
|
||||
y:0,
|
||||
width: this.com.offscreenWidth,
|
||||
height: this.com.offscreenHeight,
|
||||
canvasId: this.canvasId,
|
||||
success: (res) => {
|
||||
resolve(res)
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err)
|
||||
},
|
||||
}, this.com)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
export class Canvas {
|
||||
constructor(ctx, com, isNew, canvasNode={}) {
|
||||
cacheChart[com.canvasId] = {ctx}
|
||||
this.canvasId = com.canvasId;
|
||||
this.chart = null;
|
||||
this.isNew = isNew
|
||||
this.tagName = 'canvas'
|
||||
this.canvasNode = canvasNode;
|
||||
this.com = com;
|
||||
if (!isNew) {this._initStyle(ctx)}
|
||||
this._initEvent();
|
||||
this._ee = new EventEmit()
|
||||
}
|
||||
getContext(type) {
|
||||
if (type === '2d') {
|
||||
return this.ctx;
|
||||
}
|
||||
}
|
||||
setChart(chart) {
|
||||
this.chart = chart;
|
||||
}
|
||||
createOffscreenCanvas(param){
|
||||
if(!this.children) {
|
||||
this.com.isOffscreenCanvas = true
|
||||
this.com.offscreenWidth = param.width||300
|
||||
this.com.offscreenHeight = param.height||300
|
||||
const com = this.com
|
||||
const canvasId = this.com.offscreenCanvasId
|
||||
const context = uni.createCanvasContext(canvasId, this.com)
|
||||
this._initStyle(context)
|
||||
this.children = new OffscreenCanvas(context, com, canvasId)
|
||||
}
|
||||
return this.children
|
||||
}
|
||||
appendChild(child) {
|
||||
console.log('child', child)
|
||||
}
|
||||
dispatchEvent(type, e) {
|
||||
if(typeof type == 'object') {
|
||||
this._ee.emit(type.type, type);
|
||||
} else {
|
||||
this._ee.emit(type, e);
|
||||
}
|
||||
return true
|
||||
}
|
||||
attachEvent() {
|
||||
}
|
||||
detachEvent() {
|
||||
}
|
||||
addEventListener(type, listener) {
|
||||
this._ee.on(type, listener)
|
||||
}
|
||||
removeEventListener(type, listener) {
|
||||
this._ee.off(type, listener)
|
||||
}
|
||||
_initCanvas(zrender, ctx) {
|
||||
zrender.util.getContext = function() {
|
||||
return ctx;
|
||||
};
|
||||
zrender.util.$override('measureText', function(text, font) {
|
||||
ctx.font = font || '12px sans-serif';
|
||||
return ctx.measureText(text, font);
|
||||
});
|
||||
}
|
||||
_initStyle(ctx, child) {
|
||||
const styles = [
|
||||
'fillStyle',
|
||||
'strokeStyle',
|
||||
'fontSize',
|
||||
'globalAlpha',
|
||||
'opacity',
|
||||
'textAlign',
|
||||
'textBaseline',
|
||||
'shadow',
|
||||
'lineWidth',
|
||||
'lineCap',
|
||||
'lineJoin',
|
||||
'lineDash',
|
||||
'miterLimit',
|
||||
'font'
|
||||
];
|
||||
const colorReg = /#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])\b/g;
|
||||
styles.forEach(style => {
|
||||
Object.defineProperty(ctx, style, {
|
||||
set: value => {
|
||||
if (style === 'font' && fontSizeReg.test(value)) {
|
||||
const match = fontSizeReg.exec(value);
|
||||
ctx.setFontSize(match[1]);
|
||||
return;
|
||||
}
|
||||
if (style === 'opacity') {
|
||||
ctx.setGlobalAlpha(value)
|
||||
return;
|
||||
}
|
||||
if (style !== 'fillStyle' && style !== 'strokeStyle' || value !== 'none' && value !== null) {
|
||||
// #ifdef H5 || APP-PLUS || MP-BAIDU
|
||||
if(typeof value == 'object') {
|
||||
if (value.hasOwnProperty('colorStop') || value.hasOwnProperty('colors')) {
|
||||
ctx['set' + style.charAt(0).toUpperCase() + style.slice(1)](value);
|
||||
}
|
||||
return
|
||||
}
|
||||
// #endif
|
||||
// #ifdef MP-TOUTIAO
|
||||
if(colorReg.test(value)) {
|
||||
value = value.replace(colorReg, '#$1$1$2$2$3$3')
|
||||
}
|
||||
// #endif
|
||||
ctx['set' + style.charAt(0).toUpperCase() + style.slice(1)](value);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
if(!this.isNew && !child) {
|
||||
ctx.uniDrawImage = ctx.drawImage
|
||||
ctx.drawImage = (...a) => {
|
||||
a[0] = a[0].src
|
||||
ctx.uniDrawImage(...a)
|
||||
}
|
||||
}
|
||||
if(!ctx.createRadialGradient) {
|
||||
ctx.createRadialGradient = function() {
|
||||
return ctx.createCircularGradient(...[...arguments].slice(-3))
|
||||
};
|
||||
}
|
||||
// 字节不支持
|
||||
if (!ctx.strokeText) {
|
||||
ctx.strokeText = (...a) => {
|
||||
ctx.fillText(...a)
|
||||
}
|
||||
}
|
||||
// 钉钉不支持
|
||||
if (!ctx.measureText) {
|
||||
const strLen = (str) => {
|
||||
let len = 0;
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
if (str.charCodeAt(i) > 0 && str.charCodeAt(i) < 128) {
|
||||
len++;
|
||||
} else {
|
||||
len += 2;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
ctx.measureText = (text, font) => {
|
||||
let fontSize = 12;
|
||||
if (font) {
|
||||
fontSize = parseInt(font.match(/([\d\.]+)px/)[1])
|
||||
}
|
||||
fontSize /= 2;
|
||||
return {
|
||||
width: strLen(text) * fontSize
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_initEvent(e) {
|
||||
this.event = {};
|
||||
const eventNames = [{
|
||||
wxName: 'touchStart',
|
||||
ecName: 'mousedown'
|
||||
}, {
|
||||
wxName: 'touchMove',
|
||||
ecName: 'mousemove'
|
||||
}, {
|
||||
wxName: 'touchEnd',
|
||||
ecName: 'mouseup'
|
||||
}, {
|
||||
wxName: 'touchEnd',
|
||||
ecName: 'click'
|
||||
}];
|
||||
|
||||
eventNames.forEach(name => {
|
||||
this.event[name.wxName] = e => {
|
||||
const touch = e.touches[0];
|
||||
this.chart.getZr().handler.dispatch(name.ecName, {
|
||||
zrX: name.wxName === 'tap' ? touch.clientX : touch.x,
|
||||
zrY: name.wxName === 'tap' ? touch.clientY : touch.y
|
||||
});
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
set width(w) {
|
||||
this.canvasNode.width = w
|
||||
}
|
||||
set height(h) {
|
||||
this.canvasNode.height = h
|
||||
}
|
||||
|
||||
get width() {
|
||||
return this.canvasNode.width || 0
|
||||
}
|
||||
get height() {
|
||||
return this.canvasNode.height || 0
|
||||
}
|
||||
get ctx() {
|
||||
return cacheChart[this.canvasId]['ctx'] || null
|
||||
}
|
||||
set chart(chart) {
|
||||
cacheChart[this.canvasId]['chart'] = chart
|
||||
}
|
||||
get chart() {
|
||||
return cacheChart[this.canvasId]['chart'] || null
|
||||
}
|
||||
}
|
||||
|
||||
export function dispatch(name, {x,y, wheelDelta}) {
|
||||
this.dispatch(name, {
|
||||
zrX: x,
|
||||
zrY: y,
|
||||
zrDelta: wheelDelta,
|
||||
preventDefault: () => {},
|
||||
stopPropagation: () =>{}
|
||||
});
|
||||
}
|
||||
export function setCanvasCreator(echarts, {canvas, node}) {
|
||||
// echarts.setCanvasCreator(() => canvas);
|
||||
echarts.registerPreprocessor(option => {
|
||||
if (option && option.series) {
|
||||
if (option.series.length > 0) {
|
||||
option.series.forEach(series => {
|
||||
series.progressive = 0;
|
||||
});
|
||||
} else if (typeof option.series === 'object') {
|
||||
option.series.progressive = 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
function loadImage(src, onload, onerror) {
|
||||
let img = null
|
||||
if(node && node.createImage) {
|
||||
img = node.createImage()
|
||||
img.onload = onload.bind(img);
|
||||
img.onerror = onerror.bind(img);
|
||||
img.src = src;
|
||||
return img
|
||||
} else {
|
||||
img = new Image()
|
||||
img.onload = onload.bind(img)
|
||||
img.onerror = onerror.bind(img);
|
||||
img.src = src
|
||||
return img
|
||||
}
|
||||
}
|
||||
if(echarts.setPlatformAPI) {
|
||||
echarts.setPlatformAPI({
|
||||
loadImage: canvas.setChart ? loadImage : null,
|
||||
createCanvas(){
|
||||
return canvas
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
516
uni_modules/lime-echart/components/l-echart/l-echart.vue
Normal file
516
uni_modules/lime-echart/components/l-echart/l-echart.vue
Normal file
@ -0,0 +1,516 @@
|
||||
<template>
|
||||
<view class="lime-echart" :style="customStyle" v-if="canvasId" ref="limeEchart">
|
||||
<!-- #ifndef APP-NVUE -->
|
||||
<canvas
|
||||
class="lime-echart__canvas"
|
||||
v-if="use2dCanvas"
|
||||
type="2d"
|
||||
:id="canvasId"
|
||||
:style="canvasStyle"
|
||||
:disable-scroll="isDisableScroll"
|
||||
@touchstart="touchStart"
|
||||
@touchmove="touchMove"
|
||||
@touchend="touchEnd"
|
||||
/>
|
||||
<canvas
|
||||
class="lime-echart__canvas"
|
||||
v-else-if="isPc"
|
||||
:style="canvasStyle"
|
||||
:id="canvasId"
|
||||
:canvas-id="canvasId"
|
||||
:disable-scroll="isDisableScroll"
|
||||
@mousedown="touchStart"
|
||||
@mousemove="touchMove"
|
||||
@mouseup="touchEnd"
|
||||
/>
|
||||
<canvas
|
||||
class="lime-echart__canvas"
|
||||
v-else
|
||||
:width="nodeWidth"
|
||||
:height="nodeHeight"
|
||||
:style="canvasStyle"
|
||||
:canvas-id="canvasId"
|
||||
:id="canvasId"
|
||||
:disable-scroll="isDisableScroll"
|
||||
@touchstart="touchStart"
|
||||
@touchmove="touchMove"
|
||||
@touchend="touchEnd"
|
||||
/>
|
||||
<canvas v-if="isOffscreenCanvas" :style="offscreenStyle" :canvas-id="offscreenCanvasId"></canvas>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef APP-NVUE -->
|
||||
<web-view
|
||||
class="lime-echart__canvas"
|
||||
:id="canvasId"
|
||||
:style="canvasStyle"
|
||||
:webview-styles="webviewStyles"
|
||||
ref="webview"
|
||||
src="/uni_modules/lime-echart/static/index.html"
|
||||
@pagefinish="finished = true"
|
||||
@onPostMessage="onMessage"
|
||||
></web-view>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// #ifdef VUE3
|
||||
// #ifdef APP-PLUS
|
||||
global = {}
|
||||
// #endif
|
||||
// #endif
|
||||
// #ifndef APP-NVUE
|
||||
import {Canvas, setCanvasCreator, dispatch} from './canvas';
|
||||
import { compareVersion, wrapTouch, devicePixelRatio ,sleep} from './utils';
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
import { base64ToPath, sleep } from './utils';
|
||||
// #endif
|
||||
const charts = {}
|
||||
const echartsObj = {}
|
||||
export default {
|
||||
name: 'lime-echart',
|
||||
props: {
|
||||
// #ifdef MP-WEIXIN || MP-TOUTIAO
|
||||
type: {
|
||||
type: String,
|
||||
default: '2d'
|
||||
},
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
webviewStyles: Object,
|
||||
// hybrid: Boolean,
|
||||
// #endif
|
||||
customStyle: String,
|
||||
isDisableScroll: Boolean,
|
||||
isClickable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
enableHover: Boolean,
|
||||
beforeDelay: {
|
||||
type: Number,
|
||||
default: 30
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// #ifdef MP-WEIXIN || MP-TOUTIAO || MP-ALIPAY
|
||||
use2dCanvas: true,
|
||||
// #endif
|
||||
// #ifndef MP-WEIXIN || MP-TOUTIAO || MP-ALIPAY
|
||||
use2dCanvas: false,
|
||||
// #endif
|
||||
width: null,
|
||||
height: null,
|
||||
nodeWidth: null,
|
||||
nodeHeight: null,
|
||||
canvasNode: null,
|
||||
config: {},
|
||||
inited: false,
|
||||
finished: false,
|
||||
file: '',
|
||||
platform: '',
|
||||
isPc: false,
|
||||
isDown: false,
|
||||
isOffscreenCanvas: false,
|
||||
offscreenWidth: 0,
|
||||
offscreenHeight: 0
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
canvasId() {
|
||||
return `lime-echart${this._ && this._.uid || this._uid}`
|
||||
},
|
||||
offscreenCanvasId() {
|
||||
return `${this.canvasId}_offscreen`
|
||||
},
|
||||
offscreenStyle() {
|
||||
return `width:${this.offscreenWidth}px;height: ${this.offscreenHeight}px; position: fixed; left: 99999px; background: red`
|
||||
},
|
||||
canvasStyle() {
|
||||
return this.width && this.height ? ('width:' + this.width + 'px;height:' + this.height + 'px') : ''
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.clear()
|
||||
this.dispose()
|
||||
// #ifdef H5
|
||||
if(this.isPc) {
|
||||
document.removeEventListener('mousewheel')
|
||||
}
|
||||
// #endif
|
||||
},
|
||||
created() {
|
||||
// #ifdef H5
|
||||
if(!('ontouchstart' in window)) {
|
||||
this.isPc = true
|
||||
document.addEventListener('mousewheel', (e) => {
|
||||
if(this.chart) {
|
||||
const touch = this.getTouch(e)
|
||||
const handler = this.chart.getZr().handler;
|
||||
dispatch.call(handler, 'mousewheel', touch)
|
||||
}
|
||||
})
|
||||
}
|
||||
// #endif
|
||||
// #ifdef MP-WEIXIN || MP-TOUTIAO || MP-ALIPAY
|
||||
const { SDKVersion, version, platform, environment } = uni.getSystemInfoSync();
|
||||
// #endif
|
||||
// #ifdef MP-WEIXIN
|
||||
this.isPC = /windows/i.test(platform)
|
||||
this.use2dCanvas = this.type === '2d' && compareVersion(SDKVersion, '2.9.2') >= 0 && !((/ios/i.test(platform) && /7.0.20/.test(version)) || /wxwork/i.test(environment)) && !this.isPC;
|
||||
// #endif
|
||||
// #ifdef MP-TOUTIAO
|
||||
this.isPC = /devtools/i.test(platform)
|
||||
this.use2dCanvas = this.type === '2d' && compareVersion(SDKVersion, '1.78.0') >= 0;
|
||||
// #endif
|
||||
// #ifdef MP-ALIPAY
|
||||
this.use2dCanvas = this.type === '2d' && compareVersion(my.SDKVersion, '2.7.0') >= 0;
|
||||
// #endif
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.$emit('finished')
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
// #ifdef APP-NVUE
|
||||
onMessage(e) {
|
||||
const res = e?.detail?.data[0] || null;
|
||||
if (res?.event) {
|
||||
if(res.event === 'inited') {
|
||||
this.inited = true
|
||||
}
|
||||
this.$emit(res.event, JSON.parse(res.data));
|
||||
} else if(res?.file){
|
||||
this.file = res.data
|
||||
} else if(!res[0] && JSON.stringify(res[0]) != '{}'){
|
||||
console.error(res);
|
||||
} else {
|
||||
console.log(...res)
|
||||
}
|
||||
},
|
||||
// #endif
|
||||
setChart(callback) {
|
||||
if(!this.chart) {
|
||||
console.warn(`组件还未初始化,请先使用 init`)
|
||||
return
|
||||
}
|
||||
if(typeof callback === 'function' && this.chart) {
|
||||
callback(this.chart);
|
||||
}
|
||||
// #ifdef APP-NVUE
|
||||
if(typeof callback === 'function') {
|
||||
this.$refs.webview.evalJs(`setChart(${JSON.stringify(callback.toString())}, ${JSON.stringify(this.roptions)})`);
|
||||
}
|
||||
// #endif
|
||||
},
|
||||
setOption() {
|
||||
if (!this.chart || !this.chart.setOption) {
|
||||
console.warn(`组件还未初始化,请先使用 init`)
|
||||
return
|
||||
}
|
||||
// #ifndef APP-NVUE
|
||||
this.chart.setOption(...arguments);
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
this.$refs.webview.evalJs(`setOption(${JSON.stringify(arguments)})`);
|
||||
// #endif
|
||||
},
|
||||
showLoading() {
|
||||
if(this.chart) {
|
||||
// #ifndef APP-NVUE
|
||||
this.chart.showLoading(...arguments)
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
this.$refs.webview.evalJs(`showLoading(${JSON.stringify(arguments)})`);
|
||||
// #endif
|
||||
}
|
||||
},
|
||||
hideLoading() {
|
||||
if(this.chart) {
|
||||
// #ifndef APP-NVUE
|
||||
this.chart.hideLoading()
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
this.$refs.webview.evalJs(`hideLoading()`);
|
||||
// #endif
|
||||
}
|
||||
},
|
||||
clear() {
|
||||
if(this.chart) {
|
||||
// #ifndef APP-NVUE
|
||||
this.chart.clear()
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
this.$refs.webview.evalJs(`clear()`);
|
||||
// #endif
|
||||
}
|
||||
},
|
||||
dispose() {
|
||||
if(this.chart) {
|
||||
// #ifndef APP-NVUE
|
||||
this.chart.dispose()
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
this.$refs.webview.evalJs(`dispose()`);
|
||||
// #endif
|
||||
}
|
||||
},
|
||||
resize(size) {
|
||||
if(size && size.width && size.height) {
|
||||
this.height = size.height
|
||||
this.width = size.width
|
||||
if(this.chart) {this.chart.resize(size)}
|
||||
// #ifdef APP-NVUE
|
||||
this.$refs.webview.evalJs(`resize(${size})`);
|
||||
// #endif
|
||||
} else {
|
||||
this.$nextTick(() => {
|
||||
// #ifndef APP-NVUE
|
||||
uni.createSelectorQuery()
|
||||
.in(this)
|
||||
.select(`.lime-echart`)
|
||||
.boundingClientRect()
|
||||
.exec(res => {
|
||||
if (res) {
|
||||
let { width, height } = res[0];
|
||||
this.width = width = width || 300;
|
||||
this.height = height = height || 300;
|
||||
this.chart.resize({width, height})
|
||||
}
|
||||
});
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
this.$refs.webview.evalJs(`resize()`);
|
||||
// #endif
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
canvasToTempFilePath(args = {}) {
|
||||
// #ifndef APP-NVUE
|
||||
const { use2dCanvas, canvasId, canvasNode } = this;
|
||||
return new Promise((resolve, reject) => {
|
||||
const copyArgs = Object.assign({
|
||||
canvasId,
|
||||
success: resolve,
|
||||
fail: reject
|
||||
}, args);
|
||||
if (use2dCanvas) {
|
||||
delete copyArgs.canvasId;
|
||||
copyArgs.canvas = canvasNode;
|
||||
}
|
||||
uni.canvasToTempFilePath(copyArgs, this);
|
||||
});
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
this.file = ''
|
||||
this.$refs.webview.evalJs(`canvasToTempFilePath()`);
|
||||
return new Promise((resolve, reject) => {
|
||||
this.$watch('file', async (file) => {
|
||||
if(file) {
|
||||
const tempFilePath = await base64ToPath(file)
|
||||
resolve(args.success({tempFilePath}))
|
||||
} else {
|
||||
reject(args.fail({error: ``}))
|
||||
}
|
||||
})
|
||||
})
|
||||
// #endif
|
||||
},
|
||||
async init(echarts, ...args) {
|
||||
// #ifdef APP-NVUE
|
||||
if(arguments && !arguments.length) {
|
||||
console.error('缺少参数:init(theme?:string, opts?: object, callback: function)')
|
||||
return
|
||||
}
|
||||
// #endif
|
||||
// #ifndef APP-NVUE
|
||||
if(arguments && arguments.length < 2) {
|
||||
console.error('缺少参数:init(echarts, theme?:string, opts?: object, callback: function)')
|
||||
return
|
||||
}
|
||||
// #endif
|
||||
let theme=null,opts={},callback;
|
||||
|
||||
Array.from(arguments).forEach(item => {
|
||||
if(typeof item === 'function') {
|
||||
callback = item
|
||||
}
|
||||
if(['string'].includes(typeof item)) {
|
||||
theme = item
|
||||
}
|
||||
if(typeof item === 'object') {
|
||||
opts = item
|
||||
}
|
||||
})
|
||||
|
||||
if(this.beforeDelay) {
|
||||
await sleep(this.beforeDelay)
|
||||
}
|
||||
let config = await this.getContext();
|
||||
// #ifndef APP-NVUE
|
||||
if(typeof callback === 'function') {
|
||||
setCanvasCreator(echarts, config)
|
||||
this.chart = echarts.init(config.canvas, theme, Object.assign({}, config, opts))
|
||||
callback(this.chart)
|
||||
} else {
|
||||
console.error('callback 非 function')
|
||||
}
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
if(callback) {
|
||||
this.chart = {
|
||||
setOption: (options) => {
|
||||
this.roptions = options
|
||||
}
|
||||
}
|
||||
callback(this.chart)
|
||||
this.$refs.webview.evalJs(`init(${JSON.stringify(callback.toString())}, ${JSON.stringify(this.roptions)}, ${JSON.stringify(opts)}, ${theme})`)
|
||||
} else {
|
||||
console.error('callback 非 function')
|
||||
}
|
||||
// #endif
|
||||
},
|
||||
getContext() {
|
||||
// #ifdef APP-NVUE
|
||||
if(this.finished) {
|
||||
return Promise.resolve(this.finished)
|
||||
}
|
||||
return new Promise(resolve => {
|
||||
this.$watch('finished', (val) => {
|
||||
if(val) {
|
||||
resolve(this.finished)
|
||||
}
|
||||
})
|
||||
})
|
||||
// #endif
|
||||
// #ifndef APP-NVUE
|
||||
const { use2dCanvas} = this;
|
||||
let dpr = devicePixelRatio
|
||||
if (use2dCanvas) {
|
||||
return new Promise(resolve => {
|
||||
uni.createSelectorQuery()
|
||||
.in(this)
|
||||
.select(`#${this.canvasId}`)
|
||||
.fields({
|
||||
node: true,
|
||||
size: true
|
||||
})
|
||||
.exec(res => {
|
||||
let { node, width, height } = res[0];
|
||||
this.width = width = width || 300;
|
||||
this.height = height = height || 300;
|
||||
const ctx = node.getContext('2d');
|
||||
const canvas = new Canvas(ctx, this, true, node);
|
||||
this.canvasNode = node
|
||||
resolve({ canvas, width, height, devicePixelRatio: dpr, node });
|
||||
});
|
||||
});
|
||||
}
|
||||
return new Promise(resolve => {
|
||||
uni.createSelectorQuery()
|
||||
.in(this)
|
||||
.select(`#${this.canvasId}`)
|
||||
.boundingClientRect()
|
||||
.exec(res => {
|
||||
if (res) {
|
||||
let { width, height } = res[0];
|
||||
this.width = width = width || 300;
|
||||
this.height = height = height || 300;
|
||||
// #ifdef MP-TOUTIAO
|
||||
dpr = !this.isPC ? devicePixelRatio : 1// 1.25
|
||||
// #endif
|
||||
// #ifndef MP-ALIPAY || MP-TOUTIAO
|
||||
dpr = this.isPC ? devicePixelRatio : 1
|
||||
// #endif
|
||||
// #ifdef MP-ALIPAY || MP-LARK
|
||||
dpr = devicePixelRatio
|
||||
// #endif
|
||||
this.rect = res[0]
|
||||
this.nodeWidth = width * dpr;
|
||||
this.nodeHeight = height * dpr;
|
||||
const ctx = uni.createCanvasContext(this.canvasId, this);
|
||||
const canvas = new Canvas(ctx, this, false);
|
||||
resolve({ canvas, width, height, devicePixelRatio: dpr });
|
||||
}
|
||||
});
|
||||
});
|
||||
// #endif
|
||||
},
|
||||
// #ifndef APP-NVUE
|
||||
getRelative(e) {
|
||||
return {x: e.pageX - this.rect.left, y: e.pageY - this.rect.top, wheelDelta: e.wheelDelta}
|
||||
},
|
||||
getTouch(e) {
|
||||
return e.touches && e.touches[0] && e.touches[0].x ? e.touches[0] : this.getRelative(e);
|
||||
},
|
||||
touchStart(e) {
|
||||
this.isDown = true
|
||||
if (this.chart && ((e.touches.length > 0 || e.touches['0']) && e.type != 'mousemove' || e.type == 'mousedown')) {
|
||||
const touch = this.getTouch(e)
|
||||
this.startX = touch.x
|
||||
this.startY = touch.y
|
||||
this.startT = new Date()
|
||||
const handler = this.chart.getZr().handler;
|
||||
dispatch.call(handler, 'mousedown', touch)
|
||||
dispatch.call(handler, 'mousemove', touch)
|
||||
handler.processGesture(wrapTouch(e), 'start');
|
||||
clearTimeout(this.endTimer);
|
||||
}
|
||||
},
|
||||
touchMove(e) {
|
||||
if(this.isPc && this.enableHover && !this.isDown) {this.isDown = true}
|
||||
if (this.chart && ((e.touches.length > 0 || e.touches['0']) && e.type != 'mousemove' || e.type == 'mousemove' && this.isDown)) {
|
||||
const handler = this.chart.getZr().handler;
|
||||
dispatch.call(handler, 'mousemove', this.getTouch(e))
|
||||
handler.processGesture(wrapTouch(e), 'change');
|
||||
}
|
||||
},
|
||||
touchEnd(e) {
|
||||
this.isDown = false
|
||||
if (this.chart) {
|
||||
const {x} = e.changedTouches && e.changedTouches[0] || {}
|
||||
const touch = (x ? e.changedTouches[0] : this.getRelative(e)) || {};
|
||||
const handler = this.chart.getZr().handler;
|
||||
const isClick = Math.abs(touch.x - this.startX) < 10 && new Date() - this.startT < 200;
|
||||
dispatch.call(handler, 'mouseup', touch)
|
||||
handler.processGesture(wrapTouch(e), 'end');
|
||||
if(isClick) {
|
||||
dispatch.call(handler, 'click', touch)
|
||||
} else {
|
||||
this.endTimer = setTimeout(() => {
|
||||
dispatch.call(handler, 'mousemove', {x: 999999999,y: 999999999});
|
||||
dispatch.call(handler, 'mouseup', {x: 999999999,y: 999999999});
|
||||
},50)
|
||||
}
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.lime-echart {
|
||||
position: relative;
|
||||
/* #ifndef APP-NVUE */
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
/* #endif */
|
||||
/* #ifdef APP-NVUE */
|
||||
flex: 1;
|
||||
/* #endif */
|
||||
}
|
||||
.lime-echart__canvas {
|
||||
/* #ifndef APP-NVUE */
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
/* #endif */
|
||||
/* #ifdef APP-NVUE */
|
||||
flex: 1;
|
||||
/* #endif */
|
||||
}
|
||||
</style>
|
||||
74
uni_modules/lime-echart/components/l-echart/utils.js
Normal file
74
uni_modules/lime-echart/components/l-echart/utils.js
Normal file
@ -0,0 +1,74 @@
|
||||
// #ifndef APP-NVUE
|
||||
// 计算版本
|
||||
export function compareVersion(v1, v2) {
|
||||
v1 = v1.split('.')
|
||||
v2 = v2.split('.')
|
||||
const len = Math.max(v1.length, v2.length)
|
||||
while (v1.length < len) {
|
||||
v1.push('0')
|
||||
}
|
||||
while (v2.length < len) {
|
||||
v2.push('0')
|
||||
}
|
||||
for (let i = 0; i < len; i++) {
|
||||
const num1 = parseInt(v1[i], 10)
|
||||
const num2 = parseInt(v2[i], 10)
|
||||
|
||||
if (num1 > num2) {
|
||||
return 1
|
||||
} else if (num1 < num2) {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
export function wrapTouch(event) {
|
||||
for (let i = 0; i < event.touches.length; ++i) {
|
||||
const touch = event.touches[i];
|
||||
touch.offsetX = touch.x;
|
||||
touch.offsetY = touch.y;
|
||||
}
|
||||
return event;
|
||||
}
|
||||
export const devicePixelRatio = wx.getSystemInfoSync().pixelRatio
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
export function base64ToPath(base64) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64) || [];
|
||||
const bitmap = new plus.nativeObj.Bitmap('bitmap' + Date.now())
|
||||
bitmap.loadBase64Data(base64, () => {
|
||||
if (!format) {
|
||||
reject(new Error('ERROR_BASE64SRC_PARSE'))
|
||||
}
|
||||
const time = new Date().getTime();
|
||||
const filePath = `_doc/uniapp_temp/${time}.${format}`
|
||||
|
||||
bitmap.save(filePath, {},
|
||||
() => {
|
||||
bitmap.clear()
|
||||
resolve(filePath)
|
||||
},
|
||||
(error) => {
|
||||
bitmap.clear()
|
||||
console.error(`${JSON.stringify(error)}`)
|
||||
reject(error)
|
||||
})
|
||||
}, (error) => {
|
||||
bitmap.clear()
|
||||
console.error(`${JSON.stringify(error)}`)
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
// #endif
|
||||
|
||||
|
||||
export function sleep(time) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(true)
|
||||
},time)
|
||||
})
|
||||
}
|
||||
84
uni_modules/lime-echart/package.json
Normal file
84
uni_modules/lime-echart/package.json
Normal file
@ -0,0 +1,84 @@
|
||||
{
|
||||
"id": "lime-echart",
|
||||
"displayName": "百度图表 echarts",
|
||||
"version": "0.6.5",
|
||||
"description": "echarts 全端兼容,一款使echarts图表能跑在uniapp各端中的插件",
|
||||
"keywords": [
|
||||
"echarts",
|
||||
"canvas",
|
||||
"图表",
|
||||
"可视化"
|
||||
],
|
||||
"repository": "https://gitee.com/liangei/lime-echart",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.6.4"
|
||||
},
|
||||
"dcloudext": {
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": "",
|
||||
"type": "component-vue"
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y"
|
||||
},
|
||||
"client": {
|
||||
"App": {
|
||||
"app-vue": "y",
|
||||
"app-nvue": "y"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "y",
|
||||
"Android Browser": "y",
|
||||
"微信浏览器(Android)": "y",
|
||||
"QQ浏览器(Android)": "y"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "u",
|
||||
"IE": "u",
|
||||
"Edge": "u",
|
||||
"Firefox": "u",
|
||||
"Safari": "u"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "y",
|
||||
"阿里": "y",
|
||||
"百度": "y",
|
||||
"字节跳动": "y",
|
||||
"QQ": "y",
|
||||
"钉钉": "u",
|
||||
"快手": "u",
|
||||
"飞书": "u",
|
||||
"京东": "u"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "u",
|
||||
"联盟": "u"
|
||||
},
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "y"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
245
uni_modules/lime-echart/readme.md
Normal file
245
uni_modules/lime-echart/readme.md
Normal file
@ -0,0 +1,245 @@
|
||||
# echarts 图表 <span style="font-size:16px;">👑👑👑👑👑 <span style="background:#ff9d00;padding:2px 4px;color:#fff;font-size:10px;border-radius: 3px;">全端</span></span>
|
||||
> 一个基于 JavaScript 的开源可视化图表库 [查看更多 站点1](https://limeui.qcoon.cn/#/echart) | [查看更多 站点2](http://liangei.gitee.io/limeui/#/echart) <br>
|
||||
> 基于 echarts 做了兼容处理,更多示例请访问 [uni示例 站点1](https://limeui.qcoon.cn/#/echart-example) | [uni示例 站点2](http://liangei.gitee.io/limeui/#/echart-example) | [官方示例](https://echarts.apache.org/examples/zh/index.html) <br>
|
||||
> Q群:1046793420 <br>
|
||||
|
||||
## 平台兼容
|
||||
|
||||
| H5 | 微信小程序 | 支付宝小程序 | 百度小程序 | 头条小程序 | QQ 小程序 | App |
|
||||
| --- | ---------- | ------------ | ---------- | ---------- | --------- | ---- |
|
||||
| √ | √ | √ | √ | √ | √ | √ |
|
||||
|
||||
|
||||
## 安装
|
||||
- 第一步、在uniapp 插件市场 找到 [百度图表](https://ext.dcloud.net.cn/plugin?id=4899) 导入
|
||||
- 第二步、安装 echarts 或者直接使用插件内的echarts.min文件
|
||||
```cmd
|
||||
pnpm add echarts
|
||||
-or-
|
||||
npm install echarts
|
||||
```
|
||||
|
||||
|
||||
**注意**
|
||||
* 🔔 必须使用hbuilderx 3.4.8-alpha及以上
|
||||
* 🔔 echarts 5.3.0及以上
|
||||
* 🔔 如果是 `cli` 项目需要主动 `import` 插件
|
||||
```js
|
||||
import LEchart from '@/uni_modules/lime-echart/components/l-echart/l-echart.vue';
|
||||
export default {
|
||||
components: {LEchart}
|
||||
}
|
||||
```
|
||||
|
||||
## 代码演示
|
||||
### 基础用法
|
||||
```html
|
||||
<view><l-echart ref="chart" @finished="init"></l-echart></view>
|
||||
```
|
||||
|
||||
```js
|
||||
// 如果你使用插件内提供的echarts.min
|
||||
// 也可以自行去官网下载自定义覆盖
|
||||
// 这种方式仅限于vue2
|
||||
import * as echarts from '@/uni_modules/lime-echart/static/echarts.min'
|
||||
//---or----------------------------------
|
||||
|
||||
// 如果你使用 npm 安装了 echarts --------- 使用以下方式
|
||||
// 引入全量包
|
||||
import * as echarts from 'echarts'
|
||||
//---or----------------------------------
|
||||
|
||||
// 按需引入 开始
|
||||
import * as echarts from 'echarts/core';
|
||||
import {LineChart, BarChart} from 'echarts/charts';
|
||||
import {TitleComponent,TooltipComponent,GridComponent, DatasetComponent, TransformComponent, LegendComponent } from 'echarts/components';
|
||||
// 标签自动布局,全局过渡动画等特性
|
||||
import {LabelLayout,UniversalTransition} from 'echarts/features';
|
||||
// 引入 Canvas 渲染器,注意引入 CanvasRenderer 是必须的一步
|
||||
import {CanvasRenderer} from 'echarts/renderers';
|
||||
|
||||
// 注册必须的组件
|
||||
echarts.use([
|
||||
LegendComponent,
|
||||
TitleComponent,
|
||||
TooltipComponent,
|
||||
GridComponent,
|
||||
DatasetComponent,
|
||||
TransformComponent,
|
||||
LineChart,
|
||||
BarChart,
|
||||
LabelLayout,
|
||||
UniversalTransition,
|
||||
CanvasRenderer
|
||||
]);
|
||||
//-------------按需引入结束------------------------
|
||||
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
option: {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow'
|
||||
},
|
||||
confine: true
|
||||
},
|
||||
legend: {
|
||||
data: ['热度', '正面', '负面']
|
||||
},
|
||||
grid: {
|
||||
left: 20,
|
||||
right: 20,
|
||||
bottom: 15,
|
||||
top: 40,
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#999999'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#666666'
|
||||
}
|
||||
}
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
axisTick: { show: false },
|
||||
data: ['汽车之家', '今日头条', '百度贴吧', '一点资讯', '微信', '微博', '知乎'],
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#999999'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#666666'
|
||||
}
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '热度',
|
||||
type: 'bar',
|
||||
label: {
|
||||
normal: {
|
||||
show: true,
|
||||
position: 'inside'
|
||||
}
|
||||
},
|
||||
data: [300, 270, 340, 344, 300, 320, 310],
|
||||
},
|
||||
{
|
||||
name: '正面',
|
||||
type: 'bar',
|
||||
stack: '总量',
|
||||
label: {
|
||||
normal: {
|
||||
show: true
|
||||
}
|
||||
},
|
||||
data: [120, 102, 141, 174, 190, 250, 220]
|
||||
},
|
||||
{
|
||||
name: '负面',
|
||||
type: 'bar',
|
||||
stack: '总量',
|
||||
label: {
|
||||
normal: {
|
||||
show: true,
|
||||
position: 'left'
|
||||
}
|
||||
},
|
||||
data: [-20, -32, -21, -34, -90, -130, -110]
|
||||
}
|
||||
]
|
||||
},
|
||||
};
|
||||
},
|
||||
// 组件能被调用必须是组件的节点已经被渲染到页面上
|
||||
// 1、在页面mounted里调用,有时候mounted 组件也未必渲染完成
|
||||
mounted() {
|
||||
// init(echarts, theme?:string, opts?:{}, chart => {})
|
||||
// echarts 必填, 非nvue必填,nvue不用填
|
||||
// theme 可选,应用的主题,目前只支持名称,如:'dark'
|
||||
// opts = { // 可选
|
||||
// locale?: string // 从 `5.0.0` 开始支持
|
||||
// }
|
||||
// chart => {} , callback 必填,返回图表实例
|
||||
this.$refs.chart.init(echarts, chart => {
|
||||
chart.setOption(this.option);
|
||||
});
|
||||
},
|
||||
// 2、或者使用组件的finished事件里调用
|
||||
methods: {
|
||||
init() {
|
||||
this.$refs.chart.init(echarts, chart => {
|
||||
chart.setOption(this.option);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 数据更新
|
||||
- 使用 `ref` 可获取`setOption`设置更新
|
||||
|
||||
```js
|
||||
this.$refs.chart.setOption(data)
|
||||
```
|
||||
|
||||
## 图表大小
|
||||
- 在有些场景下,我们希望当容器大小改变时,图表的大小也相应地改变。
|
||||
|
||||
```js
|
||||
// 默认获取容器尺寸
|
||||
this.$refs.chart.resize()
|
||||
// 指定尺寸
|
||||
this.$refs.chart.resize({width: 375, height: 375})
|
||||
```
|
||||
|
||||
|
||||
## 常见问题
|
||||
- 微信小程序 `2d` 只支持 真机调试2.0
|
||||
- 微信开发工具会出现canvas不跟随页面的情况,真机不影响
|
||||
- toolbox 不支持 `saveImage`
|
||||
- echarts 5.3.0 的 lines 不支持 trailLength,故需设置为 `0`
|
||||
- dataZoom H5不要设置 `showDetail`
|
||||
|
||||
|
||||
## Props
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --------------- | -------- | ------- | ------------ | ----- |
|
||||
| custom-style | 自定义样式 | `string` | - | - |
|
||||
| type | 指定 canvas 类型 | `string` | `2d` | |
|
||||
| is-disable-scroll | 触摸图表时是否禁止页面滚动 | `boolean` | `false` | |
|
||||
| beforeDelay | 延迟初始化 (毫秒) | `number` | `30` | |
|
||||
| enableHover | PC端使用鼠标悬浮 | `boolean` | `false` | |
|
||||
|
||||
## 事件
|
||||
|
||||
| 参数 | 说明 |
|
||||
| --------------- | --------------- |
|
||||
| init(echarts, chart => {}) | 初始化调用函数,第一个参数是传入`echarts`,第二个参数是回调函数,回调函数的参数是 `chart` 实例 |
|
||||
| setChart(chart => {}) | 已经初始化后,请使用这个方法,是个回调函数,参数是 `chart` 实例 |
|
||||
| setOption(data) | [图表配置项](https://echarts.apache.org/zh/option.html#title),用于更新 ,传递是数据 `option` |
|
||||
| clear() | 清空当前实例,会移除实例中所有的组件和图表。 |
|
||||
| dispose() | 销毁实例 |
|
||||
| showLoading() | 显示加载 |
|
||||
| hideLoading() | 隐藏加载 |
|
||||
| [canvasToTempFilePath](https://uniapp.dcloud.io/api/canvas/canvasToTempFilePath.html#canvastotempfilepath)(opt) | 用于生成图片,与官方使用方法一致,但不需要传`canvasId` |
|
||||
|
||||
|
||||
## 打赏
|
||||
如果你觉得本插件,解决了你的问题,赠人玫瑰,手留余香。
|
||||
|
||||

|
||||

|
||||
67
uni_modules/luyj-tree/changelog.md
Normal file
67
uni_modules/luyj-tree/changelog.md
Normal file
@ -0,0 +1,67 @@
|
||||
## 1.4.11(2021-10-13)
|
||||
当前选项是否选中的回显问题。
|
||||
## 1.4.10(2021-09-29)
|
||||
默认树的显示样式
|
||||
## 1.4.9(2021-09-13)
|
||||
1. luyj-tree参数中移除props.hasChildren , luyj-tree-item移除参数comparison.hasChilren。
|
||||
2. luyj-tree 参数nodes默认值改为false, luyj-tree-item 默认值改为false
|
||||
3. luyj-tree-item 修改选中框的默认大小。
|
||||
4. 修改luyj-tree-item 插槽 的默认样式
|
||||
5. 修改luyj-tree 插槽的默认样式
|
||||
6. 修改一些必要的说明
|
||||
## 1.4.8(2021-09-09)
|
||||
1. 修改了一些说明
|
||||
2. 不包含下一级时,点击页面部分,选中当前的项
|
||||
3. 修改默认选中事件bug
|
||||
4. 自定义slot 默认展示时与 单选框、复选框重叠问题
|
||||
## 1.4.7(2021-09-08)
|
||||
添加一些必要的说明。
|
||||
## 1.4.6(2021-09-03)
|
||||
展示和不显示搜索按钮时位置问题。
|
||||
## 1.4.5(2021-09-02)
|
||||
展示和不显示搜索按钮时位置问题。
|
||||
## 1.4.4(2021-09-01)
|
||||
区分"选项修改"和"确认"事件,分别对应@change 和 @sendValue。
|
||||
## 1.4.3(2021-09-01)
|
||||
变量tree_Stack的名称问题
|
||||
## 1.4.2(2021-08-27)
|
||||
为树添加导航栏事件
|
||||
## 1.4.1(2021-08-26)
|
||||
一些bug
|
||||
懒加载后重新加载数据,显示问题。
|
||||
## 1.4.0(2021-08-25)
|
||||
添加允许多次渲染item的方法(默认每次50条)。当数据量过大时使用
|
||||
## 1.3.2(2021-08-25)
|
||||
搜索时,没有显示名称列,中止报错问题。(改为提醒,跳过后继续执行)
|
||||
## 1.3.1(2021-08-24)
|
||||
添加一些简单的说明
|
||||
## 1.3.(2021-08-24)
|
||||
更新了一些bug。
|
||||
暂时令参数checkStrictly 关联失效。添加了一些参数。文档会后续陆续补充。
|
||||
独立出luyj-tree-item项。
|
||||
修复了(可能未完全修复)自定义插件的问题。
|
||||
移除了一些无效的参数,如max、scrollLeft。
|
||||
## 1.2.1(2021-08-20)
|
||||
解决。数据不包含数据,点击项报错问题。
|
||||
## 1.2.0(2021-08-20)
|
||||
将面包屑导航分开
|
||||
## 1.1.8(2021-08-19)
|
||||
更新不能检测传入数据变动(tree变动)问题
|
||||
## 1.1.7(2021-08-14)
|
||||
简单整理了一下代码,没有什么实质性的改变。
|
||||
## 1.1.6(2021-08-07)
|
||||
展示状态下显示确认
|
||||
## 1.1.5(2021-07-29)
|
||||
更新搜索框在微信开发者工具模拟器不能输入问题
|
||||
## 1.1.4(2021-07-27)
|
||||
read.md说明
|
||||
## 1.1.3(2021-07-27)
|
||||
read.md更新
|
||||
## 1.1.2(2021-07-27)
|
||||
更新说明文档
|
||||
## 1.1.1(2021-07-27)
|
||||
更新一些插件说明
|
||||
## 1.1.0(2021-07-27)
|
||||
为树的输入框,添加更多样式参数
|
||||
## 1.0.0(2021-07-25)
|
||||
无限树形结构组件。支持搜索、面包屑类型导航、选择。
|
||||
346
uni_modules/luyj-tree/components/luyj-tree-item/icon.css
Normal file
346
uni_modules/luyj-tree/components/luyj-tree-item/icon.css
Normal file
@ -0,0 +1,346 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 2009600 */
|
||||
src: url('https://at.alicdn.com/t/font_2009600_gpzp7pxtnw.woff2?t=1620633089023') format('woff2'),
|
||||
url('https://at.alicdn.com/t/font_2009600_gpzp7pxtnw.woff?t=1620633089023') format('woff'),
|
||||
url('https://at.alicdn.com/t/font_2009600_gpzp7pxtnw.ttf?t=1620633089023') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-family: "iconfont" !important;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
/* 清除图标 */
|
||||
.icon-clear:before{
|
||||
content: '\e606';
|
||||
}
|
||||
|
||||
.icon-banxuanzhongshousuo1-shi:before {
|
||||
content: "\e682";
|
||||
}
|
||||
|
||||
.icon-xuanzhong3:before {
|
||||
content: "\e6bb";
|
||||
}
|
||||
|
||||
.icon-weixuanzhong2:before {
|
||||
content: "\e62e";
|
||||
}
|
||||
|
||||
.icon-danxuanxuanzhong:before {
|
||||
content: "\e631";
|
||||
}
|
||||
|
||||
.icon-xuanzhong4:before {
|
||||
content: "\e63e";
|
||||
}
|
||||
|
||||
.icon-xuanzhong1:before {
|
||||
content: "\e62d";
|
||||
}
|
||||
.icon-xuanzhong2:before {
|
||||
content: "\e656";
|
||||
}
|
||||
|
||||
.icon-selected:before {
|
||||
content: "\e615";
|
||||
}
|
||||
|
||||
.icon-weixuanzhong1:before {
|
||||
content: "\e614";
|
||||
}
|
||||
|
||||
.icon-xingzhuang6kaobei3-copy-copy:before {
|
||||
content: "\e613";
|
||||
}
|
||||
|
||||
.icon-radio-checked:before {
|
||||
content: "\e63f";
|
||||
}
|
||||
|
||||
.icon-huifu:before {
|
||||
content: "\e619";
|
||||
}
|
||||
|
||||
.icon-dizhi:before {
|
||||
content: "\e64a";
|
||||
}
|
||||
|
||||
.icon-kuaijiecaidan:before {
|
||||
content: "\e60a";
|
||||
}
|
||||
|
||||
.icon-z043:before {
|
||||
content: "\e62f";
|
||||
}
|
||||
|
||||
.icon-guanbi:before {
|
||||
content: "\e607";
|
||||
}
|
||||
|
||||
.icon-xuanze:before {
|
||||
content: "\e623";
|
||||
}
|
||||
|
||||
.icon-caidanzhaolinggan:before {
|
||||
content: "\e616";
|
||||
}
|
||||
|
||||
.icon-xitongshezhi:before {
|
||||
content: "\e60c";
|
||||
}
|
||||
|
||||
.icon-xitongshezhi1:before {
|
||||
content: "\e633";
|
||||
}
|
||||
|
||||
.icon-lunbo:before {
|
||||
content: "\e692";
|
||||
}
|
||||
|
||||
.icon-shuping:before {
|
||||
content: "\e659";
|
||||
}
|
||||
|
||||
.icon-tongzhi:before {
|
||||
content: "\e641";
|
||||
}
|
||||
|
||||
.icon-pinglunguanlishezhi:before {
|
||||
content: "\e6ac";
|
||||
}
|
||||
|
||||
.icon-icon:before {
|
||||
content: "\e600";
|
||||
}
|
||||
|
||||
.icon-liuyanguanli:before {
|
||||
content: "\e61d";
|
||||
}
|
||||
|
||||
.icon-xuanzhong:before {
|
||||
content: "\e669";
|
||||
}
|
||||
|
||||
.icon--:before {
|
||||
content: "\e622";
|
||||
}
|
||||
|
||||
.icon-tushu:before {
|
||||
content: "\e604";
|
||||
}
|
||||
|
||||
.icon-huishouzhan:before {
|
||||
content: "\e61c";
|
||||
}
|
||||
|
||||
.icon-yonghutouxiang:before {
|
||||
content: "\e617";
|
||||
}
|
||||
|
||||
.icon-liebiao:before {
|
||||
content: "\e630";
|
||||
}
|
||||
|
||||
.icon-fenlei:before {
|
||||
content: "\e621";
|
||||
}
|
||||
|
||||
.icon-tushu1:before {
|
||||
content: "\e605";
|
||||
}
|
||||
|
||||
.icon-tubiao-:before {
|
||||
content: "\e620";
|
||||
}
|
||||
|
||||
.icon-weixuanze:before {
|
||||
content: "\e624";
|
||||
}
|
||||
|
||||
.icon-tushujieyue:before {
|
||||
content: "\e690";
|
||||
}
|
||||
|
||||
.icon-lunbo1:before {
|
||||
content: "\e6c5";
|
||||
}
|
||||
|
||||
.icon-shanchu:before {
|
||||
content: "\e67b";
|
||||
}
|
||||
|
||||
.icon-lunbo2:before {
|
||||
content: "\e61e";
|
||||
}
|
||||
|
||||
.icon-huaban:before {
|
||||
content: "\e663";
|
||||
}
|
||||
|
||||
.icon-kehuan:before {
|
||||
content: "\e608";
|
||||
}
|
||||
|
||||
.icon-icon02:before {
|
||||
content: "\e601";
|
||||
}
|
||||
|
||||
.icon-huishouzhan1:before {
|
||||
content: "\e612";
|
||||
}
|
||||
|
||||
.icon-huishouzhan2:before {
|
||||
content: "\e63d";
|
||||
}
|
||||
|
||||
.icon-sousuo:before {
|
||||
content: "\e62c";
|
||||
}
|
||||
|
||||
.icon-xingzhuang:before {
|
||||
content: "\e625";
|
||||
}
|
||||
|
||||
.icon-lunbobankuai:before {
|
||||
content: "\e61f";
|
||||
}
|
||||
|
||||
.icon-shangchuan:before {
|
||||
content: "\e602";
|
||||
}
|
||||
|
||||
.icon-yonghu:before {
|
||||
content: "\e761";
|
||||
}
|
||||
|
||||
.icon-tongzhi1:before {
|
||||
content: "\e603";
|
||||
}
|
||||
|
||||
.icon-jingsong:before {
|
||||
content: "\e65c";
|
||||
}
|
||||
|
||||
.icon-fenlei1:before {
|
||||
content: "\e6c6";
|
||||
}
|
||||
|
||||
.icon-xieshupingicon:before {
|
||||
content: "\e72d";
|
||||
}
|
||||
|
||||
.icon-liuyan:before {
|
||||
content: "\e626";
|
||||
}
|
||||
|
||||
.icon-weixuanzhong:before {
|
||||
content: "\e627";
|
||||
}
|
||||
|
||||
.icon-youxiang:before {
|
||||
content: "\e646";
|
||||
}
|
||||
|
||||
.icon-lunboguanggao:before {
|
||||
content: "\e6b3";
|
||||
}
|
||||
|
||||
.icon-xuanze1:before {
|
||||
content: "\e60d";
|
||||
}
|
||||
|
||||
.icon-chushaixuanxiang:before {
|
||||
content: "\e606";
|
||||
}
|
||||
|
||||
.icon-liuyanguanli1:before {
|
||||
content: "\e61a";
|
||||
}
|
||||
|
||||
.icon-shanchu1:before {
|
||||
content: "\e609";
|
||||
}
|
||||
|
||||
.icon-huishouzhan3:before {
|
||||
content: "\e642";
|
||||
}
|
||||
|
||||
.icon-shangchuan1:before {
|
||||
content: "\e823";
|
||||
}
|
||||
|
||||
.icon-huishouzhan4:before {
|
||||
content: "\e61b";
|
||||
}
|
||||
|
||||
.icon-chuangzuo:before {
|
||||
content: "\e8ad";
|
||||
}
|
||||
|
||||
.icon-dianzan:before {
|
||||
content: "\e8ae";
|
||||
}
|
||||
|
||||
.icon-paihangbang:before {
|
||||
content: "\e8b3";
|
||||
}
|
||||
|
||||
.icon-shouye:before {
|
||||
content: "\e8b9";
|
||||
}
|
||||
|
||||
.icon-shoucang:before {
|
||||
content: "\e8c6";
|
||||
}
|
||||
|
||||
.icon-addApp:before {
|
||||
content: "\e60b";
|
||||
}
|
||||
|
||||
.icon-huishouzhan5:before {
|
||||
content: "\e63a";
|
||||
}
|
||||
|
||||
.icon-add1:before {
|
||||
content: "\e60e";
|
||||
}
|
||||
|
||||
.icon-shoucang1:before {
|
||||
content: "\e60f";
|
||||
}
|
||||
|
||||
.icon-canshutongji:before {
|
||||
content: "\e618";
|
||||
}
|
||||
|
||||
.icon-rizhiguanli:before {
|
||||
content: "\e628";
|
||||
}
|
||||
|
||||
.icon-shanchu2:before {
|
||||
content: "\e629";
|
||||
}
|
||||
|
||||
.icon-xinzeng:before {
|
||||
content: "\e62a";
|
||||
}
|
||||
|
||||
.icon-zhankailiebiao:before {
|
||||
content: "\e62b";
|
||||
}
|
||||
|
||||
.icon-xiala-copy:before {
|
||||
content: "\e610";
|
||||
}
|
||||
|
||||
.icon-shangla:before {
|
||||
content: "\e64e";
|
||||
}
|
||||
|
||||
.icon-xianxingshezhi:before {
|
||||
content: "\e611";
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
.container-list-item {
|
||||
background-color: #fff;
|
||||
border-bottom: 1rpx solid #f4f4f4;
|
||||
border-radius: 20rpx;
|
||||
margin:0 30rpx 20rpx 30rpx;
|
||||
.content
|
||||
{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
// min-height: 60rpx;
|
||||
width: 100%;
|
||||
padding:30rpx 15rpx ;
|
||||
position: relative;
|
||||
font-size: 32rpx;
|
||||
// 默认文本显示内容(默认的slot)
|
||||
.slot {
|
||||
// position:absolute;
|
||||
right: 64rpx;
|
||||
font-size: 32rpx;
|
||||
color: #5b5757;
|
||||
.word {
|
||||
width:100%;
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
// 默认箭头显示样式
|
||||
.right {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
width: 80rpx;
|
||||
right: 30rpx;
|
||||
color: #babdc3;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
// 复选框
|
||||
.checkbox {
|
||||
position: relative;
|
||||
height: 36rpx;
|
||||
margin-left: 10rpx;
|
||||
margin-right: 0px;
|
||||
width: 36rpx;
|
||||
.txt {
|
||||
font-size: 35rpx;
|
||||
line-height: 36rpx;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.checkBorder {
|
||||
border: 1px solid #ecdee4;
|
||||
}
|
||||
|
||||
.text-cut{
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.value_box{
|
||||
display: flex;
|
||||
height: 100%;
|
||||
.index{
|
||||
color: #009C77;
|
||||
width: 70rpx;
|
||||
text-align: center;
|
||||
border-right: 1rpx solid #eeeeee;
|
||||
}
|
||||
.value{
|
||||
padding-left: 20rpx;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,312 @@
|
||||
<template>
|
||||
<view class="container-list-item" >
|
||||
<view class="content" @click="clickItem($event, item)">
|
||||
<!-- 复选框 -->
|
||||
<view class="checkbox" v-if="isCheckBox" @click.stop="clickBox($event , item)">
|
||||
<i v-if="curChecked " :style="{'color' :checkActiveColor}"
|
||||
class="iconfont icon-xuanzhong txt icon-selected" />
|
||||
<i v-else :style="{'color': checkNoneColor}" class="iconfont icon-weixuanzhong txt" />
|
||||
</view>
|
||||
<!-- 复选框 -->
|
||||
<!-- 单选框 -->
|
||||
<view class="checkbox" v-else-if="isRadio" @click.stop="clickBox($event, item)">
|
||||
<i v-if="curChecked" :style="{'color' :checkActiveColor}" class="txt iconfont icon-selected" />
|
||||
<i v-else :style="{'color': checkNoneColor}" class="txt iconfont icon-weixuanzhong1" />
|
||||
</view>
|
||||
<!-- 单选框 -->
|
||||
<!-- 自定义插槽body -->
|
||||
<view :style="isCheck ?'left: 56rpx':'left: 16rpx'" class="slot">
|
||||
<view v-if="item.name" class="value_box" style="height: 50rpx!important;display: flex;align-items: center;">
|
||||
<view class="index" style="height: 50rpx;">
|
||||
<image v-if="item.deviceType? item.deviceType.includes('pcs') : ''" :src="pcs" class="device-img"></image>
|
||||
<image v-else-if="item.deviceType? item.deviceType.includes('bms') : ''" :src="bms" class="device-img"></image>
|
||||
<image v-else-if="item.deviceType? item.deviceType.includes('stack') : ''" :src="cluster" class="device-img"></image>
|
||||
<image v-else-if="item.deviceType? item.deviceType.includes('storage_fire') : ''" :src="fire" class="device-img"></image>
|
||||
<image v-else-if="item.deviceType? item.deviceType.includes('pack') : ''" :src="pack" class="device-img"></image>
|
||||
<image v-else-if="item.deviceType? item.deviceType.includes('air_condition') : ''" :src="air" class="device-img"></image>
|
||||
<image v-else-if="item.deviceType? item.deviceType.includes('ele_meter') : ''" :src="unit" class="device-img"></image>
|
||||
<image v-else-if="item.deviceType? item.deviceType.includes('emu') : ''" :src="emu" class="device-img"></image>
|
||||
<image v-else :src="other" style="width: 50rpx;height: 50rpx;"></image>
|
||||
<!-- {{item.deviceType}} -->
|
||||
</view>
|
||||
<view class="value">
|
||||
{{item[sLabel]}}
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
<!-- 自定义插槽body -->
|
||||
<view v-if="hasChildren" class="right" @click.stop="clickItemRight($event,item)"><i class="iconfont icon-z043" ></i></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import pcs from '@/static/aidex/device/pcs.png'
|
||||
import bms from '@/static/aidex/device/bms.png'
|
||||
import cluster from '@/static/aidex/device/cluster.png'
|
||||
import air from '@/static/aidex/device/air.png'
|
||||
import fire from '@/static/aidex/device/fire.png'
|
||||
import emu from '@/static/aidex/device/emu.png'
|
||||
import pack from '@/static/aidex/device/pack.png'
|
||||
import unit from '@/static/aidex/device/unit.png'
|
||||
import other from '@/static/aidex/device/other.png'
|
||||
/**
|
||||
* 无限极树的单项 item
|
||||
* @description无限级数的单项item
|
||||
* @property {Object} item 单项的值(默认{})
|
||||
* @property {Boolean} isCheck 判断是否可选 (默认false)
|
||||
* @property {Boolean} 判断是否是否多选(默认false, isCheck为true时有效)。
|
||||
* @property {String} checkActiveColor 选中状态下单选框/复选框的颜色 (默认#00AAFF)
|
||||
* @property {String} checkNoneColor 未选中状态下单选框/复选框的颜色(默认#B8B8B8)
|
||||
* @property {Object} comparison 属性名称对照表
|
||||
* @param {String} value 选中值对应列名称(默认value)
|
||||
* @param {String} label 显示值对应列名称(默认label)
|
||||
* @param {String} children 子级列对应名称(默认children)
|
||||
* @return {Function} 点击当前项的执行方法
|
||||
* @param {Object} item 当前项的值
|
||||
* @return {Function} change 选中值变化时执行方法(event.detail = {value: 是否选中})
|
||||
*/
|
||||
export default {
|
||||
name: 'luyj-tree-item',
|
||||
props: {
|
||||
// 传入的数值
|
||||
item: {
|
||||
type: Object,
|
||||
default: {}
|
||||
},
|
||||
index: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
// 判断是否可选
|
||||
isCheck: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 是否多选
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 是否选中状态
|
||||
checked: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 是否只能选择叶子结点
|
||||
nodes: {
|
||||
type: false,
|
||||
default: false
|
||||
},
|
||||
// 选中状态下单选框/复选框的颜色
|
||||
checkActiveColor: {
|
||||
type: String,
|
||||
default: '#00AAFF'
|
||||
},
|
||||
// 未选中状态下单选框的颜色
|
||||
checkNoneColor: {
|
||||
type: String,
|
||||
default: '#B8B8B8'
|
||||
},
|
||||
// 列名称对照表
|
||||
comparison: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
value: 'value', // 选中值
|
||||
label: 'label', // 显示名称
|
||||
children: 'children', // 子级名称
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
sLabel: this.comparison.label ? this.comparison.label : 'label', // label值名称
|
||||
sChildren: this.comparison.children ? this.comparison.children : 'children', // children值名称
|
||||
curChecked: this.checked, //是否选中状态
|
||||
formModel: undefined,
|
||||
singleMinVolData: undefined,
|
||||
singleMaxVolData: undefined,
|
||||
pcs,
|
||||
bms,
|
||||
cluster,
|
||||
air,
|
||||
fire,emu,other,pack,unit
|
||||
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
/**
|
||||
* 是否包含子级
|
||||
*/
|
||||
hasChildren: function() {
|
||||
return Boolean(this.item) ? (Boolean(this.item[this.sChildren]) ? this.item[this.sChildren].length >
|
||||
0 : false) : false;
|
||||
},
|
||||
/**
|
||||
* 是否单选
|
||||
*/
|
||||
isRadio: function() {
|
||||
return this.isCheck && !this.multiple && (!this.nodes || !this.hasChildren);
|
||||
},
|
||||
/**
|
||||
* 是否多选
|
||||
*/
|
||||
isCheckBox: function() {
|
||||
return this.isCheck && this.multiple && (!this.nodes || !this.hasChildren);
|
||||
},
|
||||
|
||||
},
|
||||
watch: {
|
||||
// 监听列名对照表变化
|
||||
comparison: {
|
||||
handler: function(val) {
|
||||
this.sLabel = this.comparison.label ? this.comparison.label : 'label';
|
||||
this.sChildren = this.comparison.children ? this.comparison.children : 'children';
|
||||
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
// 是否选中状态
|
||||
checked: function(val) {
|
||||
this.curChecked = val;
|
||||
},
|
||||
item: {
|
||||
handler(val) {
|
||||
if (val) {
|
||||
// this.getStatus()
|
||||
this.$forceUpdate()
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// this.getStatus()
|
||||
},
|
||||
methods: {
|
||||
//获取状态
|
||||
getStatus() {
|
||||
if (this.item.deviceType) {
|
||||
let params = {
|
||||
colList: [],
|
||||
srcId: this.item.srcId,
|
||||
stationId: this.item.stationId
|
||||
}
|
||||
if (this.item.deviceType.includes('pcs')) { //舱
|
||||
params.colList = ['runState']
|
||||
} else if (this.item.deviceType.includes('emu')) {
|
||||
//emu 总有功功率 总无功功率
|
||||
params.colList = ['EMUPTotal', 'EMUQTotal']
|
||||
} else if (this.item.deviceType.includes('stack')) {
|
||||
// <!-- 簇 -->累计充电量,累计放电量
|
||||
params.colList = ['cTotalChargePower', 'cTotalDisChargePower']
|
||||
|
||||
} else if (this.item.deviceType.includes('bms')) {
|
||||
// 堆 累计充电量,累计放电量
|
||||
params.colList = ['totalCharge', 'totalDischarge']
|
||||
} else if (this.item.deviceType.includes('ele_meter')) {
|
||||
// 电表 正向有功总电量 反向有功总电量
|
||||
params.colList = ['totalCharge', 'totalDisCharge']
|
||||
} else if (this.item.deviceType.includes('air_condition')) {
|
||||
//空调 空调开关机:
|
||||
params.colList = ['airconditionSwitchYX']
|
||||
} else if (this.item.deviceType.includes('storage_fire')) {
|
||||
//消防
|
||||
} else if (this.item.deviceType.includes('pack')) { //组
|
||||
//组 最高电压 最低电压
|
||||
params.colList = ['singleMaxVolData', 'singleMinVolData']
|
||||
}
|
||||
if (params.colList.length > 0) {
|
||||
if (this.item.deviceType.includes('pack')) {
|
||||
this.GetPackTemperatureVoltageData(params)
|
||||
} else {
|
||||
this.GetNewValue(params)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
GetPackTemperatureVoltageData(params) {
|
||||
this.$u.api.deviceList.GetPackTemperatureVoltageData(params).then(res => {
|
||||
this.singleMaxVolData = res.data.packData.csingleMaxVolData
|
||||
this.singleMinVolData = res.data.packData.csingleMinVolData
|
||||
this.$forceUpdate()
|
||||
})
|
||||
},
|
||||
GetNewValue(params) {
|
||||
this.$u.api.deviceList.GetNewValue(params).then(res => {
|
||||
this.formModel = res.data
|
||||
this.$forceUpdate()
|
||||
})
|
||||
},
|
||||
/** 点击当前项右侧的执行方法
|
||||
* @param {Object} e
|
||||
* @param {Object} item
|
||||
*/
|
||||
clickItemRight: function(e, item) {
|
||||
this.$emit("clickItemRight", item, this.hasChildren);
|
||||
// 不包含下一级,修改check值事件
|
||||
if (!this.hasChildren && this.isCheck) {
|
||||
this.clickBox(e);
|
||||
}
|
||||
},
|
||||
/** 点击当前项的执行方法
|
||||
* @param {Object} e
|
||||
* @param {Object} item
|
||||
*/
|
||||
clickItem: function(e, item) {
|
||||
this.$emit("clickItem", item);
|
||||
},
|
||||
/**
|
||||
* 点击单选框或复选框
|
||||
* @param {Object} e 当前选中值
|
||||
* @param {Object} item 当前选中的项
|
||||
*/
|
||||
clickBox: function(e, item) {
|
||||
this.curChecked = !this.curChecked;
|
||||
e.detail.value = this.curChecked;
|
||||
this.$emit("change", e); // 切换单选框或复选框
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import 'luyj-tree-item.scss';
|
||||
@import "../../lib/css/icon.css";
|
||||
|
||||
.device-box {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin-top: 20rpx;
|
||||
|
||||
.device-img {
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
background: #f8f8f8;
|
||||
flex-shrink: 0;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
}
|
||||
.device-img{
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
}
|
||||
.runValue {
|
||||
flex: 1;
|
||||
color: #12ec0a;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.stopValue {
|
||||
flex: 1;
|
||||
color: #FFB800;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
</style>
|
||||
342
uni_modules/luyj-tree/components/luyj-tree-navigation/icon.css
Normal file
342
uni_modules/luyj-tree/components/luyj-tree-navigation/icon.css
Normal file
@ -0,0 +1,342 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 2009600 */
|
||||
src: url('https://at.alicdn.com/t/font_2009600_gpzp7pxtnw.woff2?t=1620633089023') format('woff2'),
|
||||
url('https://at.alicdn.com/t/font_2009600_gpzp7pxtnw.woff?t=1620633089023') format('woff'),
|
||||
url('https://at.alicdn.com/t/font_2009600_gpzp7pxtnw.ttf?t=1620633089023') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-family: "iconfont" !important;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-banxuanzhongshousuo1-shi:before {
|
||||
content: "\e682";
|
||||
}
|
||||
|
||||
.icon-xuanzhong3:before {
|
||||
content: "\e6bb";
|
||||
}
|
||||
|
||||
.icon-weixuanzhong2:before {
|
||||
content: "\e62e";
|
||||
}
|
||||
|
||||
.icon-danxuanxuanzhong:before {
|
||||
content: "\e631";
|
||||
}
|
||||
|
||||
.icon-xuanzhong4:before {
|
||||
content: "\e63e";
|
||||
}
|
||||
|
||||
.icon-xuanzhong1:before {
|
||||
content: "\e62d";
|
||||
}
|
||||
|
||||
.icon-xuanzhong2:before {
|
||||
content: "\e656";
|
||||
}
|
||||
|
||||
.icon-selected:before {
|
||||
content: "\e615";
|
||||
}
|
||||
|
||||
.icon-weixuanzhong1:before {
|
||||
content: "\e614";
|
||||
}
|
||||
|
||||
.icon-xingzhuang6kaobei3-copy-copy:before {
|
||||
content: "\e613";
|
||||
}
|
||||
|
||||
.icon-radio-checked:before {
|
||||
content: "\e63f";
|
||||
}
|
||||
|
||||
.icon-huifu:before {
|
||||
content: "\e619";
|
||||
}
|
||||
|
||||
.icon-dizhi:before {
|
||||
content: "\e64a";
|
||||
}
|
||||
|
||||
.icon-kuaijiecaidan:before {
|
||||
content: "\e60a";
|
||||
}
|
||||
|
||||
.icon-z043:before {
|
||||
content: "\e62f";
|
||||
}
|
||||
|
||||
.icon-guanbi:before {
|
||||
content: "\e607";
|
||||
}
|
||||
|
||||
.icon-xuanze:before {
|
||||
content: "\e623";
|
||||
}
|
||||
|
||||
.icon-caidanzhaolinggan:before {
|
||||
content: "\e616";
|
||||
}
|
||||
|
||||
.icon-xitongshezhi:before {
|
||||
content: "\e60c";
|
||||
}
|
||||
|
||||
.icon-xitongshezhi1:before {
|
||||
content: "\e633";
|
||||
}
|
||||
|
||||
.icon-lunbo:before {
|
||||
content: "\e692";
|
||||
}
|
||||
|
||||
.icon-shuping:before {
|
||||
content: "\e659";
|
||||
}
|
||||
|
||||
.icon-tongzhi:before {
|
||||
content: "\e641";
|
||||
}
|
||||
|
||||
.icon-pinglunguanlishezhi:before {
|
||||
content: "\e6ac";
|
||||
}
|
||||
|
||||
.icon-icon:before {
|
||||
content: "\e600";
|
||||
}
|
||||
|
||||
.icon-liuyanguanli:before {
|
||||
content: "\e61d";
|
||||
}
|
||||
|
||||
.icon-xuanzhong:before {
|
||||
content: "\e669";
|
||||
}
|
||||
|
||||
.icon--:before {
|
||||
content: "\e622";
|
||||
}
|
||||
|
||||
.icon-tushu:before {
|
||||
content: "\e604";
|
||||
}
|
||||
|
||||
.icon-huishouzhan:before {
|
||||
content: "\e61c";
|
||||
}
|
||||
|
||||
.icon-yonghutouxiang:before {
|
||||
content: "\e617";
|
||||
}
|
||||
|
||||
.icon-liebiao:before {
|
||||
content: "\e630";
|
||||
}
|
||||
|
||||
.icon-fenlei:before {
|
||||
content: "\e621";
|
||||
}
|
||||
|
||||
.icon-tushu1:before {
|
||||
content: "\e605";
|
||||
}
|
||||
|
||||
.icon-tubiao-:before {
|
||||
content: "\e620";
|
||||
}
|
||||
|
||||
.icon-weixuanze:before {
|
||||
content: "\e624";
|
||||
}
|
||||
|
||||
.icon-tushujieyue:before {
|
||||
content: "\e690";
|
||||
}
|
||||
|
||||
.icon-lunbo1:before {
|
||||
content: "\e6c5";
|
||||
}
|
||||
|
||||
.icon-shanchu:before {
|
||||
content: "\e67b";
|
||||
}
|
||||
|
||||
.icon-lunbo2:before {
|
||||
content: "\e61e";
|
||||
}
|
||||
|
||||
.icon-huaban:before {
|
||||
content: "\e663";
|
||||
}
|
||||
|
||||
.icon-kehuan:before {
|
||||
content: "\e608";
|
||||
}
|
||||
|
||||
.icon-icon02:before {
|
||||
content: "\e601";
|
||||
}
|
||||
|
||||
.icon-huishouzhan1:before {
|
||||
content: "\e612";
|
||||
}
|
||||
|
||||
.icon-huishouzhan2:before {
|
||||
content: "\e63d";
|
||||
}
|
||||
|
||||
.icon-sousuo:before {
|
||||
content: "\e62c";
|
||||
}
|
||||
|
||||
.icon-xingzhuang:before {
|
||||
content: "\e625";
|
||||
}
|
||||
|
||||
.icon-lunbobankuai:before {
|
||||
content: "\e61f";
|
||||
}
|
||||
|
||||
.icon-shangchuan:before {
|
||||
content: "\e602";
|
||||
}
|
||||
|
||||
.icon-yonghu:before {
|
||||
content: "\e761";
|
||||
}
|
||||
|
||||
.icon-tongzhi1:before {
|
||||
content: "\e603";
|
||||
}
|
||||
|
||||
.icon-jingsong:before {
|
||||
content: "\e65c";
|
||||
}
|
||||
|
||||
.icon-fenlei1:before {
|
||||
content: "\e6c6";
|
||||
}
|
||||
|
||||
.icon-xieshupingicon:before {
|
||||
content: "\e72d";
|
||||
}
|
||||
|
||||
.icon-liuyan:before {
|
||||
content: "\e626";
|
||||
}
|
||||
|
||||
.icon-weixuanzhong:before {
|
||||
content: "\e627";
|
||||
}
|
||||
|
||||
.icon-youxiang:before {
|
||||
content: "\e646";
|
||||
}
|
||||
|
||||
.icon-lunboguanggao:before {
|
||||
content: "\e6b3";
|
||||
}
|
||||
|
||||
.icon-xuanze1:before {
|
||||
content: "\e60d";
|
||||
}
|
||||
|
||||
.icon-chushaixuanxiang:before {
|
||||
content: "\e606";
|
||||
}
|
||||
|
||||
.icon-liuyanguanli1:before {
|
||||
content: "\e61a";
|
||||
}
|
||||
|
||||
.icon-shanchu1:before {
|
||||
content: "\e609";
|
||||
}
|
||||
|
||||
.icon-huishouzhan3:before {
|
||||
content: "\e642";
|
||||
}
|
||||
|
||||
.icon-shangchuan1:before {
|
||||
content: "\e823";
|
||||
}
|
||||
|
||||
.icon-huishouzhan4:before {
|
||||
content: "\e61b";
|
||||
}
|
||||
|
||||
.icon-chuangzuo:before {
|
||||
content: "\e8ad";
|
||||
}
|
||||
|
||||
.icon-dianzan:before {
|
||||
content: "\e8ae";
|
||||
}
|
||||
|
||||
.icon-paihangbang:before {
|
||||
content: "\e8b3";
|
||||
}
|
||||
|
||||
.icon-shouye:before {
|
||||
content: "\e8b9";
|
||||
}
|
||||
|
||||
.icon-shoucang:before {
|
||||
content: "\e8c6";
|
||||
}
|
||||
|
||||
.icon-addApp:before {
|
||||
content: "\e60b";
|
||||
}
|
||||
|
||||
.icon-huishouzhan5:before {
|
||||
content: "\e63a";
|
||||
}
|
||||
|
||||
.icon-add1:before {
|
||||
content: "\e60e";
|
||||
}
|
||||
|
||||
.icon-shoucang1:before {
|
||||
content: "\e60f";
|
||||
}
|
||||
|
||||
.icon-canshutongji:before {
|
||||
content: "\e618";
|
||||
}
|
||||
|
||||
.icon-rizhiguanli:before {
|
||||
content: "\e628";
|
||||
}
|
||||
|
||||
.icon-shanchu2:before {
|
||||
content: "\e629";
|
||||
}
|
||||
|
||||
.icon-xinzeng:before {
|
||||
content: "\e62a";
|
||||
}
|
||||
|
||||
.icon-zhankailiebiao:before {
|
||||
content: "\e62b";
|
||||
}
|
||||
|
||||
.icon-xiala-copy:before {
|
||||
content: "\e610";
|
||||
}
|
||||
|
||||
.icon-shangla:before {
|
||||
content: "\e64e";
|
||||
}
|
||||
|
||||
.icon-xianxingshezhi:before {
|
||||
content: "\e611";
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
// 导航栏标题
|
||||
.title {
|
||||
height: 90rpx;
|
||||
padding: 0 32rpx;
|
||||
line-height: 90rpx;
|
||||
font-size: 30rpx;
|
||||
background-color: #f5f5f5;
|
||||
color: #606064;
|
||||
// 导航栏图标样式
|
||||
.iconclass {
|
||||
display: inline-block;
|
||||
margin: 0 12rpx;
|
||||
color: #D0D4DB;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
// 导航栏项样式
|
||||
.inline-item {
|
||||
display: inline-block
|
||||
}
|
||||
// 导航栏项-启用状态
|
||||
.active {
|
||||
color: #666666 !important;
|
||||
}
|
||||
// 导航栏项-无状态
|
||||
.none {
|
||||
color: #009C77;
|
||||
}
|
||||
@ -0,0 +1,182 @@
|
||||
<template>
|
||||
<view class="title">
|
||||
<scroll-view ref="sea" scroll-x style="width: 100%;white-space: nowrap;">
|
||||
<!-- 全部 -->
|
||||
<view class="inline-item" @click="clickItem(null,-1)">
|
||||
<text v-if="!isre && treeStack.length == 0" class="none">{{ this.$t('homePage.device.all') }}</text>
|
||||
<text v-else class="active">{{ this.$t('homePage.device.all') }}</text>
|
||||
</view>
|
||||
<!-- 全部 -->
|
||||
<!-- 搜索结果 -->
|
||||
<view v-if="isre" @click="clickItem(null,-2)"
|
||||
:class="activeSearch?'active inline-item':' none inline-item'">
|
||||
<i class="iconfont icon-z043 iconclass" />
|
||||
{{ this.$t('homePage.device.queryResult') }}
|
||||
</view>
|
||||
<!-- 搜索结果 -->
|
||||
<!-- 当前树的层级值 -->
|
||||
<view v-for="(item,index) in treeStack" class="inline-item" :key="index">
|
||||
<view class="inline-item" @click="clickItem(item,index)">
|
||||
<i class="iconfont icon-z043 iconclass" />
|
||||
<text v-if="index== treeStack.length-1" class="none inline-item" style="color: #009C77;">
|
||||
{{item[slabel]}}
|
||||
</text>
|
||||
<text v-else class="active" >
|
||||
{{item[slabel]}}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 当前树的层级值 -->
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* 无限级树-面包屑导航
|
||||
* @description 无限级树的面包屑导航
|
||||
* @property {String} slabel 显示的label值
|
||||
* @return {Function} clickItem(item , index) 点击导航栏的索引
|
||||
* @item 表示导航项对应的值
|
||||
* @index 表示导航项的层级别索引
|
||||
* @value -1 全部
|
||||
* @value -2 表示层级
|
||||
* @value 其他 (从最外层开始,依次0,1,2,3……)
|
||||
* @return {Object} inF 导航条内部的方法
|
||||
* @param {Function} isIre 设置是否搜索状态
|
||||
* @param {Function} setTreeStack 设置导航树的值
|
||||
* @param {Function} pushTreeStack 为导航树添加项
|
||||
* @param {Function} clearTreeStack 清空导航树
|
||||
*/
|
||||
// scrollLeft : 暂时
|
||||
export default {
|
||||
name: "luyj-tree-navigation",
|
||||
props: {
|
||||
// 显示的label值
|
||||
slabel: {
|
||||
type: String,
|
||||
default: 'label'
|
||||
},
|
||||
},
|
||||
watch:{
|
||||
treeStack:{
|
||||
handler(val){
|
||||
uni.setStorage({
|
||||
key: 'deviceNavArr',//本地缓存中的指定的 key
|
||||
data: val
|
||||
})
|
||||
}
|
||||
},
|
||||
deep:true,
|
||||
immediate:true
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isre: false, // 是否进行了搜索(返回是否进行了搜索)
|
||||
treeStack: [], // 当前搜索值
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.clearTreeStack()
|
||||
},
|
||||
computed: {
|
||||
// 是否可点击搜索结果
|
||||
activeSearch: function() {
|
||||
return this.treeStack.length > 0;
|
||||
}
|
||||
},
|
||||
created: function() {
|
||||
// 浅拷贝导航列表的每一个对象(为了不改变item值,也不复制过多的数据)
|
||||
this.treeStack.forEach(item => {
|
||||
var tempItem = Object.assign(item);
|
||||
this.treeStack.push(tempItem);
|
||||
});
|
||||
var obj = {
|
||||
setIsre: this.setIsre,
|
||||
getIsre : this.getIsre,
|
||||
setTreeStack: this.setTreeStack,
|
||||
concatTreeStack : this.concatTreeStack,
|
||||
pushTreeStack: this.pushTreeStack,
|
||||
clearTreeStack: this.clearTreeStack,
|
||||
getTreeStack : this.getTreeStack
|
||||
};
|
||||
this.$emit("inF", obj); // 导出的导航栏调用方法
|
||||
},
|
||||
methods: {
|
||||
// ================================== 初始化时导出方法(用于外部调用内部结果) =========================================================
|
||||
/** 设置isre值(是否搜索)
|
||||
* @param {Boolean} isre 设置是否搜索
|
||||
*/
|
||||
setIsre: function(isre) {
|
||||
this.isre = isre;
|
||||
},
|
||||
/**
|
||||
* 获取isr值(获取是否搜索中)
|
||||
*/
|
||||
getIsre: function(){
|
||||
return this.isre;
|
||||
},
|
||||
/** 设置导航树
|
||||
* @param {Array} treeStack 导航树
|
||||
*/
|
||||
setTreeStack: function(treeStack) {
|
||||
this.treeStack = treeStack;
|
||||
},
|
||||
/** 拼接导航树
|
||||
* @param {Object} treeStack 导航树
|
||||
*/
|
||||
concatTreeStack : function(treeStack){
|
||||
this.treeStack = this.treeStack.concat(treeStack);
|
||||
},
|
||||
/** 为导航树添加项
|
||||
* @param {Object} item 待添加的对象
|
||||
*/
|
||||
pushTreeStack: function(item) {
|
||||
this.treeStack.push(item);
|
||||
},
|
||||
/**
|
||||
* 获取当前导航条
|
||||
*/
|
||||
getTreeStack : function(){
|
||||
return this.treeStack;
|
||||
},
|
||||
/**
|
||||
* 清空导航树
|
||||
*/
|
||||
clearTreeStack: function() {
|
||||
this.treeStack.splice(0);
|
||||
},
|
||||
// ================================== 监听事件 ===========================================================
|
||||
/** 点击导航栏索引
|
||||
* @param {Object} item 当前层的值
|
||||
* @param {Number} index 索引值
|
||||
*/
|
||||
clickItem(item, index) {
|
||||
if (index == -1) {
|
||||
// 点击全部
|
||||
this.isre = false;
|
||||
this.treeStack.splice(0);
|
||||
} else if (index == -2) {
|
||||
// 搜索结果
|
||||
if (this.activeSearch) {
|
||||
this.isre = true;
|
||||
this.treeStack.splice(0);
|
||||
}
|
||||
} else {
|
||||
// 点击某一层级树
|
||||
this.isre = false;
|
||||
if (this.treeStack.length - 1 > index) {
|
||||
this.treeStack.splice(index + 1);
|
||||
}
|
||||
}
|
||||
this.$emit("clickItem", item, index);
|
||||
},
|
||||
},
|
||||
// ============================================================================================================
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "luyj-tree-navigation.scss";
|
||||
@import "icon.css";
|
||||
</style>
|
||||
346
uni_modules/luyj-tree/components/luyj-tree-search/icon.css
Normal file
346
uni_modules/luyj-tree/components/luyj-tree-search/icon.css
Normal file
@ -0,0 +1,346 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 2009600 */
|
||||
src: url('https://at.alicdn.com/t/font_2009600_gpzp7pxtnw.woff2?t=1620633089023') format('woff2'),
|
||||
url('https://at.alicdn.com/t/font_2009600_gpzp7pxtnw.woff?t=1620633089023') format('woff'),
|
||||
url('https://at.alicdn.com/t/font_2009600_gpzp7pxtnw.ttf?t=1620633089023') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-family: "iconfont" !important;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
/* 清除图标 */
|
||||
.icon-clear:before{
|
||||
content: '\e606';
|
||||
}
|
||||
|
||||
.icon-banxuanzhongshousuo1-shi:before {
|
||||
content: "\e682";
|
||||
}
|
||||
|
||||
.icon-xuanzhong3:before {
|
||||
content: "\e6bb";
|
||||
}
|
||||
|
||||
.icon-weixuanzhong2:before {
|
||||
content: "\e62e";
|
||||
}
|
||||
|
||||
.icon-danxuanxuanzhong:before {
|
||||
content: "\e631";
|
||||
}
|
||||
|
||||
.icon-xuanzhong4:before {
|
||||
content: "\e63e";
|
||||
}
|
||||
|
||||
.icon-xuanzhong1:before {
|
||||
content: "\e62d";
|
||||
}
|
||||
.icon-xuanzhong2:before {
|
||||
content: "\e656";
|
||||
}
|
||||
|
||||
.icon-selected:before {
|
||||
content: "\e615";
|
||||
}
|
||||
|
||||
.icon-weixuanzhong1:before {
|
||||
content: "\e614";
|
||||
}
|
||||
|
||||
.icon-xingzhuang6kaobei3-copy-copy:before {
|
||||
content: "\e613";
|
||||
}
|
||||
|
||||
.icon-radio-checked:before {
|
||||
content: "\e63f";
|
||||
}
|
||||
|
||||
.icon-huifu:before {
|
||||
content: "\e619";
|
||||
}
|
||||
|
||||
.icon-dizhi:before {
|
||||
content: "\e64a";
|
||||
}
|
||||
|
||||
.icon-kuaijiecaidan:before {
|
||||
content: "\e60a";
|
||||
}
|
||||
|
||||
.icon-z043:before {
|
||||
content: "\e62f";
|
||||
}
|
||||
|
||||
.icon-guanbi:before {
|
||||
content: "\e607";
|
||||
}
|
||||
|
||||
.icon-xuanze:before {
|
||||
content: "\e623";
|
||||
}
|
||||
|
||||
.icon-caidanzhaolinggan:before {
|
||||
content: "\e616";
|
||||
}
|
||||
|
||||
.icon-xitongshezhi:before {
|
||||
content: "\e60c";
|
||||
}
|
||||
|
||||
.icon-xitongshezhi1:before {
|
||||
content: "\e633";
|
||||
}
|
||||
|
||||
.icon-lunbo:before {
|
||||
content: "\e692";
|
||||
}
|
||||
|
||||
.icon-shuping:before {
|
||||
content: "\e659";
|
||||
}
|
||||
|
||||
.icon-tongzhi:before {
|
||||
content: "\e641";
|
||||
}
|
||||
|
||||
.icon-pinglunguanlishezhi:before {
|
||||
content: "\e6ac";
|
||||
}
|
||||
|
||||
.icon-icon:before {
|
||||
content: "\e600";
|
||||
}
|
||||
|
||||
.icon-liuyanguanli:before {
|
||||
content: "\e61d";
|
||||
}
|
||||
|
||||
.icon-xuanzhong:before {
|
||||
content: "\e669";
|
||||
}
|
||||
|
||||
.icon--:before {
|
||||
content: "\e622";
|
||||
}
|
||||
|
||||
.icon-tushu:before {
|
||||
content: "\e604";
|
||||
}
|
||||
|
||||
.icon-huishouzhan:before {
|
||||
content: "\e61c";
|
||||
}
|
||||
|
||||
.icon-yonghutouxiang:before {
|
||||
content: "\e617";
|
||||
}
|
||||
|
||||
.icon-liebiao:before {
|
||||
content: "\e630";
|
||||
}
|
||||
|
||||
.icon-fenlei:before {
|
||||
content: "\e621";
|
||||
}
|
||||
|
||||
.icon-tushu1:before {
|
||||
content: "\e605";
|
||||
}
|
||||
|
||||
.icon-tubiao-:before {
|
||||
content: "\e620";
|
||||
}
|
||||
|
||||
.icon-weixuanze:before {
|
||||
content: "\e624";
|
||||
}
|
||||
|
||||
.icon-tushujieyue:before {
|
||||
content: "\e690";
|
||||
}
|
||||
|
||||
.icon-lunbo1:before {
|
||||
content: "\e6c5";
|
||||
}
|
||||
|
||||
.icon-shanchu:before {
|
||||
content: "\e67b";
|
||||
}
|
||||
|
||||
.icon-lunbo2:before {
|
||||
content: "\e61e";
|
||||
}
|
||||
|
||||
.icon-huaban:before {
|
||||
content: "\e663";
|
||||
}
|
||||
|
||||
.icon-kehuan:before {
|
||||
content: "\e608";
|
||||
}
|
||||
|
||||
.icon-icon02:before {
|
||||
content: "\e601";
|
||||
}
|
||||
|
||||
.icon-huishouzhan1:before {
|
||||
content: "\e612";
|
||||
}
|
||||
|
||||
.icon-huishouzhan2:before {
|
||||
content: "\e63d";
|
||||
}
|
||||
|
||||
.icon-sousuo:before {
|
||||
content: "\e62c";
|
||||
}
|
||||
|
||||
.icon-xingzhuang:before {
|
||||
content: "\e625";
|
||||
}
|
||||
|
||||
.icon-lunbobankuai:before {
|
||||
content: "\e61f";
|
||||
}
|
||||
|
||||
.icon-shangchuan:before {
|
||||
content: "\e602";
|
||||
}
|
||||
|
||||
.icon-yonghu:before {
|
||||
content: "\e761";
|
||||
}
|
||||
|
||||
.icon-tongzhi1:before {
|
||||
content: "\e603";
|
||||
}
|
||||
|
||||
.icon-jingsong:before {
|
||||
content: "\e65c";
|
||||
}
|
||||
|
||||
.icon-fenlei1:before {
|
||||
content: "\e6c6";
|
||||
}
|
||||
|
||||
.icon-xieshupingicon:before {
|
||||
content: "\e72d";
|
||||
}
|
||||
|
||||
.icon-liuyan:before {
|
||||
content: "\e626";
|
||||
}
|
||||
|
||||
.icon-weixuanzhong:before {
|
||||
content: "\e627";
|
||||
}
|
||||
|
||||
.icon-youxiang:before {
|
||||
content: "\e646";
|
||||
}
|
||||
|
||||
.icon-lunboguanggao:before {
|
||||
content: "\e6b3";
|
||||
}
|
||||
|
||||
.icon-xuanze1:before {
|
||||
content: "\e60d";
|
||||
}
|
||||
|
||||
.icon-chushaixuanxiang:before {
|
||||
content: "\e606";
|
||||
}
|
||||
|
||||
.icon-liuyanguanli1:before {
|
||||
content: "\e61a";
|
||||
}
|
||||
|
||||
.icon-shanchu1:before {
|
||||
content: "\e609";
|
||||
}
|
||||
|
||||
.icon-huishouzhan3:before {
|
||||
content: "\e642";
|
||||
}
|
||||
|
||||
.icon-shangchuan1:before {
|
||||
content: "\e823";
|
||||
}
|
||||
|
||||
.icon-huishouzhan4:before {
|
||||
content: "\e61b";
|
||||
}
|
||||
|
||||
.icon-chuangzuo:before {
|
||||
content: "\e8ad";
|
||||
}
|
||||
|
||||
.icon-dianzan:before {
|
||||
content: "\e8ae";
|
||||
}
|
||||
|
||||
.icon-paihangbang:before {
|
||||
content: "\e8b3";
|
||||
}
|
||||
|
||||
.icon-shouye:before {
|
||||
content: "\e8b9";
|
||||
}
|
||||
|
||||
.icon-shoucang:before {
|
||||
content: "\e8c6";
|
||||
}
|
||||
|
||||
.icon-addApp:before {
|
||||
content: "\e60b";
|
||||
}
|
||||
|
||||
.icon-huishouzhan5:before {
|
||||
content: "\e63a";
|
||||
}
|
||||
|
||||
.icon-add1:before {
|
||||
content: "\e60e";
|
||||
}
|
||||
|
||||
.icon-shoucang1:before {
|
||||
content: "\e60f";
|
||||
}
|
||||
|
||||
.icon-canshutongji:before {
|
||||
content: "\e618";
|
||||
}
|
||||
|
||||
.icon-rizhiguanli:before {
|
||||
content: "\e628";
|
||||
}
|
||||
|
||||
.icon-shanchu2:before {
|
||||
content: "\e629";
|
||||
}
|
||||
|
||||
.icon-xinzeng:before {
|
||||
content: "\e62a";
|
||||
}
|
||||
|
||||
.icon-zhankailiebiao:before {
|
||||
content: "\e62b";
|
||||
}
|
||||
|
||||
.icon-xiala-copy:before {
|
||||
content: "\e610";
|
||||
}
|
||||
|
||||
.icon-shangla:before {
|
||||
content: "\e64e";
|
||||
}
|
||||
|
||||
.icon-xianxingshezhi:before {
|
||||
content: "\e611";
|
||||
}
|
||||
@ -0,0 +1,165 @@
|
||||
<template>
|
||||
<view>
|
||||
<view class='filterBox' :style="{'background-color' : backgroundColor}">
|
||||
<view class='filter-input'
|
||||
:style="{'background-color' :inputBackgroundColor ,'border-radius':radius + 'rpx'}">
|
||||
<!-- 左侧搜索图标 -->
|
||||
<u-icon name="search" color="#009C77!important" size="40"></u-icon>
|
||||
<!-- 输入框内容 -->
|
||||
<input class="text" type='text' v-model="inputVal" confirm-type="搜索" :placeholder='placeholder'
|
||||
:placeholder-style="placeholderStyle" :maxlength="maxlength" @input="handleInput"
|
||||
@focus="handleFocus" @blur="handleBlur" @confirm='handleFllter'/>
|
||||
<!-- 清除按钮 -->
|
||||
<view v-if="clearable" class="padding-left-sm" @click="clears">
|
||||
<text :style="{'color':iconColor}" class="iconfont icon-clear filterImg"></text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* 无限级树的搜索框组件
|
||||
* @description 无限级树的搜索框组件
|
||||
* @property {String} backgroundColor 背景色(默认#FFFFFF)
|
||||
* @property {String} inputBackgroundColor 输入框背景色(默认#EEEFF0)
|
||||
* @property {Number} radius 输入框圆角,单位rpx(默认40)
|
||||
* @property {String} placeholder 输入框为空时占位符(默认'搜索')
|
||||
* @property {String} placeholderStyle placehoder的样式
|
||||
* @property {Number} maxlength 最大输入长度 ,设置为 -1 的时候不限制最大长度(默认值140)
|
||||
* @property {String} iconColor 图标颜色(默认#B8B8B8)
|
||||
* @property {Boolean} clearable 是否显示清除按钮 是否显示清除按钮(默认true)
|
||||
* @event {Function()} input 输入框内容编号时触发
|
||||
* @event {Function()} focus 输入框获得焦点时触发
|
||||
* @event {Function()} blur 输入框失去焦点时触发
|
||||
* @event {Function()} confirm 提交输入框内容是触发
|
||||
* @event {Function()} clear 清空输入框内容时触发
|
||||
*/
|
||||
export default {
|
||||
name: 'luyj-tree-search',
|
||||
props: {
|
||||
// 背景色
|
||||
backgroundColor: {
|
||||
type: String,
|
||||
default: '#FFFFFF'
|
||||
},
|
||||
// 输入框背景颜色
|
||||
inputBackgroundColor: {
|
||||
type: String,
|
||||
default: '#EEEFF0'
|
||||
},
|
||||
// 输入框圆角
|
||||
radius: {
|
||||
type: Number,
|
||||
default: 40
|
||||
},
|
||||
// 输入框为空时占位符
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '输入名称搜索'
|
||||
},
|
||||
// placeholder的样式
|
||||
placeholderStyle: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 最大输入长度 ,设置为 -1 的时候不限制最大长度
|
||||
maxlength: {
|
||||
type: Number,
|
||||
default: 140
|
||||
},
|
||||
// 图标的颜色
|
||||
iconColor: {
|
||||
type: String,
|
||||
default: '#009C77'
|
||||
},
|
||||
// 是否显示清除按钮
|
||||
clearable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
inputVal: "", // 输入内容
|
||||
};
|
||||
},
|
||||
components: {
|
||||
test: function() {
|
||||
return 120;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/** 输入框变化时方法
|
||||
* @param {Object} e
|
||||
*/
|
||||
handleInput: function(e) {
|
||||
this.$emit("input", e)
|
||||
},
|
||||
/** 输入框聚焦时触发
|
||||
* @param {Object} e
|
||||
*/
|
||||
handleFocus: function(e) {
|
||||
this.$emit("focus", e)
|
||||
},
|
||||
/** 输入框失去焦点时触发
|
||||
* @param {Object} e
|
||||
*/
|
||||
handleBlur: function(e) {
|
||||
this.$emit("blur", e)
|
||||
},
|
||||
/** 提交内容时触发
|
||||
* @param {Object} e
|
||||
*/
|
||||
handleFllter: function(e) {
|
||||
this.$emit("confirm", e)
|
||||
},
|
||||
/**
|
||||
* 清空输入框内容
|
||||
*/
|
||||
clears: function() {
|
||||
this.inputVal = "";
|
||||
this.$emit("clear", this.inputVal)
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.filterBox {
|
||||
padding: 15rpx 32rpx;
|
||||
|
||||
.filter-input {
|
||||
height: 80rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 40rpx;
|
||||
|
||||
.filterImg {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
margin-right: 20rpx;
|
||||
margin-bottom: 5rpx;
|
||||
}
|
||||
|
||||
.filterImgs {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
}
|
||||
|
||||
.text {
|
||||
width: 100%;
|
||||
font-size: 32rpx;
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 添加左侧padding(用于扩大图标范围)
|
||||
.padding-left-sm {
|
||||
padding-left: 20rpx;
|
||||
}
|
||||
|
||||
@import url("icon.css");
|
||||
</style>
|
||||
342
uni_modules/luyj-tree/components/luyj-tree/icon.css
Normal file
342
uni_modules/luyj-tree/components/luyj-tree/icon.css
Normal file
@ -0,0 +1,342 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 2009600 */
|
||||
src: url('https://at.alicdn.com/t/font_2009600_gpzp7pxtnw.woff2?t=1620633089023') format('woff2'),
|
||||
url('https://at.alicdn.com/t/font_2009600_gpzp7pxtnw.woff?t=1620633089023') format('woff'),
|
||||
url('https://at.alicdn.com/t/font_2009600_gpzp7pxtnw.ttf?t=1620633089023') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-family: "iconfont" !important;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-banxuanzhongshousuo1-shi:before {
|
||||
content: "\e682";
|
||||
}
|
||||
|
||||
.icon-xuanzhong3:before {
|
||||
content: "\e6bb";
|
||||
}
|
||||
|
||||
.icon-weixuanzhong2:before {
|
||||
content: "\e62e";
|
||||
}
|
||||
|
||||
.icon-danxuanxuanzhong:before {
|
||||
content: "\e631";
|
||||
}
|
||||
|
||||
.icon-xuanzhong4:before {
|
||||
content: "\e63e";
|
||||
}
|
||||
|
||||
.icon-xuanzhong1:before {
|
||||
content: "\e62d";
|
||||
}
|
||||
|
||||
.icon-xuanzhong2:before {
|
||||
content: "\e656";
|
||||
}
|
||||
|
||||
.icon-selected:before {
|
||||
content: "\e615";
|
||||
}
|
||||
|
||||
.icon-weixuanzhong1:before {
|
||||
content: "\e614";
|
||||
}
|
||||
|
||||
.icon-xingzhuang6kaobei3-copy-copy:before {
|
||||
content: "\e613";
|
||||
}
|
||||
|
||||
.icon-radio-checked:before {
|
||||
content: "\e63f";
|
||||
}
|
||||
|
||||
.icon-huifu:before {
|
||||
content: "\e619";
|
||||
}
|
||||
|
||||
.icon-dizhi:before {
|
||||
content: "\e64a";
|
||||
}
|
||||
|
||||
.icon-kuaijiecaidan:before {
|
||||
content: "\e60a";
|
||||
}
|
||||
|
||||
.icon-z043:before {
|
||||
content: "\e62f";
|
||||
}
|
||||
|
||||
.icon-guanbi:before {
|
||||
content: "\e607";
|
||||
}
|
||||
|
||||
.icon-xuanze:before {
|
||||
content: "\e623";
|
||||
}
|
||||
|
||||
.icon-caidanzhaolinggan:before {
|
||||
content: "\e616";
|
||||
}
|
||||
|
||||
.icon-xitongshezhi:before {
|
||||
content: "\e60c";
|
||||
}
|
||||
|
||||
.icon-xitongshezhi1:before {
|
||||
content: "\e633";
|
||||
}
|
||||
|
||||
.icon-lunbo:before {
|
||||
content: "\e692";
|
||||
}
|
||||
|
||||
.icon-shuping:before {
|
||||
content: "\e659";
|
||||
}
|
||||
|
||||
.icon-tongzhi:before {
|
||||
content: "\e641";
|
||||
}
|
||||
|
||||
.icon-pinglunguanlishezhi:before {
|
||||
content: "\e6ac";
|
||||
}
|
||||
|
||||
.icon-icon:before {
|
||||
content: "\e600";
|
||||
}
|
||||
|
||||
.icon-liuyanguanli:before {
|
||||
content: "\e61d";
|
||||
}
|
||||
|
||||
.icon-xuanzhong:before {
|
||||
content: "\e669";
|
||||
}
|
||||
|
||||
.icon--:before {
|
||||
content: "\e622";
|
||||
}
|
||||
|
||||
.icon-tushu:before {
|
||||
content: "\e604";
|
||||
}
|
||||
|
||||
.icon-huishouzhan:before {
|
||||
content: "\e61c";
|
||||
}
|
||||
|
||||
.icon-yonghutouxiang:before {
|
||||
content: "\e617";
|
||||
}
|
||||
|
||||
.icon-liebiao:before {
|
||||
content: "\e630";
|
||||
}
|
||||
|
||||
.icon-fenlei:before {
|
||||
content: "\e621";
|
||||
}
|
||||
|
||||
.icon-tushu1:before {
|
||||
content: "\e605";
|
||||
}
|
||||
|
||||
.icon-tubiao-:before {
|
||||
content: "\e620";
|
||||
}
|
||||
|
||||
.icon-weixuanze:before {
|
||||
content: "\e624";
|
||||
}
|
||||
|
||||
.icon-tushujieyue:before {
|
||||
content: "\e690";
|
||||
}
|
||||
|
||||
.icon-lunbo1:before {
|
||||
content: "\e6c5";
|
||||
}
|
||||
|
||||
.icon-shanchu:before {
|
||||
content: "\e67b";
|
||||
}
|
||||
|
||||
.icon-lunbo2:before {
|
||||
content: "\e61e";
|
||||
}
|
||||
|
||||
.icon-huaban:before {
|
||||
content: "\e663";
|
||||
}
|
||||
|
||||
.icon-kehuan:before {
|
||||
content: "\e608";
|
||||
}
|
||||
|
||||
.icon-icon02:before {
|
||||
content: "\e601";
|
||||
}
|
||||
|
||||
.icon-huishouzhan1:before {
|
||||
content: "\e612";
|
||||
}
|
||||
|
||||
.icon-huishouzhan2:before {
|
||||
content: "\e63d";
|
||||
}
|
||||
|
||||
.icon-sousuo:before {
|
||||
content: "\e62c";
|
||||
}
|
||||
|
||||
.icon-xingzhuang:before {
|
||||
content: "\e625";
|
||||
}
|
||||
|
||||
.icon-lunbobankuai:before {
|
||||
content: "\e61f";
|
||||
}
|
||||
|
||||
.icon-shangchuan:before {
|
||||
content: "\e602";
|
||||
}
|
||||
|
||||
.icon-yonghu:before {
|
||||
content: "\e761";
|
||||
}
|
||||
|
||||
.icon-tongzhi1:before {
|
||||
content: "\e603";
|
||||
}
|
||||
|
||||
.icon-jingsong:before {
|
||||
content: "\e65c";
|
||||
}
|
||||
|
||||
.icon-fenlei1:before {
|
||||
content: "\e6c6";
|
||||
}
|
||||
|
||||
.icon-xieshupingicon:before {
|
||||
content: "\e72d";
|
||||
}
|
||||
|
||||
.icon-liuyan:before {
|
||||
content: "\e626";
|
||||
}
|
||||
|
||||
.icon-weixuanzhong:before {
|
||||
content: "\e627";
|
||||
}
|
||||
|
||||
.icon-youxiang:before {
|
||||
content: "\e646";
|
||||
}
|
||||
|
||||
.icon-lunboguanggao:before {
|
||||
content: "\e6b3";
|
||||
}
|
||||
|
||||
.icon-xuanze1:before {
|
||||
content: "\e60d";
|
||||
}
|
||||
|
||||
.icon-chushaixuanxiang:before {
|
||||
content: "\e606";
|
||||
}
|
||||
|
||||
.icon-liuyanguanli1:before {
|
||||
content: "\e61a";
|
||||
}
|
||||
|
||||
.icon-shanchu1:before {
|
||||
content: "\e609";
|
||||
}
|
||||
|
||||
.icon-huishouzhan3:before {
|
||||
content: "\e642";
|
||||
}
|
||||
|
||||
.icon-shangchuan1:before {
|
||||
content: "\e823";
|
||||
}
|
||||
|
||||
.icon-huishouzhan4:before {
|
||||
content: "\e61b";
|
||||
}
|
||||
|
||||
.icon-chuangzuo:before {
|
||||
content: "\e8ad";
|
||||
}
|
||||
|
||||
.icon-dianzan:before {
|
||||
content: "\e8ae";
|
||||
}
|
||||
|
||||
.icon-paihangbang:before {
|
||||
content: "\e8b3";
|
||||
}
|
||||
|
||||
.icon-shouye:before {
|
||||
content: "\e8b9";
|
||||
}
|
||||
|
||||
.icon-shoucang:before {
|
||||
content: "\e8c6";
|
||||
}
|
||||
|
||||
.icon-addApp:before {
|
||||
content: "\e60b";
|
||||
}
|
||||
|
||||
.icon-huishouzhan5:before {
|
||||
content: "\e63a";
|
||||
}
|
||||
|
||||
.icon-add1:before {
|
||||
content: "\e60e";
|
||||
}
|
||||
|
||||
.icon-shoucang1:before {
|
||||
content: "\e60f";
|
||||
}
|
||||
|
||||
.icon-canshutongji:before {
|
||||
content: "\e618";
|
||||
}
|
||||
|
||||
.icon-rizhiguanli:before {
|
||||
content: "\e628";
|
||||
}
|
||||
|
||||
.icon-shanchu2:before {
|
||||
content: "\e629";
|
||||
}
|
||||
|
||||
.icon-xinzeng:before {
|
||||
content: "\e62a";
|
||||
}
|
||||
|
||||
.icon-zhankailiebiao:before {
|
||||
content: "\e62b";
|
||||
}
|
||||
|
||||
.icon-xiala-copy:before {
|
||||
content: "\e610";
|
||||
}
|
||||
|
||||
.icon-shangla:before {
|
||||
content: "\e64e";
|
||||
}
|
||||
|
||||
.icon-xianxingshezhi:before {
|
||||
content: "\e611";
|
||||
}
|
||||
121
uni_modules/luyj-tree/components/luyj-tree/luyj-tree.scss
Normal file
121
uni_modules/luyj-tree/components/luyj-tree/luyj-tree.scss
Normal file
@ -0,0 +1,121 @@
|
||||
.flex_between_center {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.checkbox {
|
||||
position: relative;
|
||||
height: 36rpx;
|
||||
margin-left: 10rpx;
|
||||
margin-right: 0px;
|
||||
width: 36rpx;
|
||||
.color {
|
||||
color: #00aaff;
|
||||
background-color: #00aaff;
|
||||
}
|
||||
.txt {
|
||||
// font-size: 30rpx;
|
||||
line-height: 36rpx;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
.checkBorder {
|
||||
border: 1px solid #ecdee4;
|
||||
}
|
||||
.header {
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
background-color: #fff;
|
||||
z-index: 99;
|
||||
.title {
|
||||
height: 90rpx;
|
||||
padding: 0 32rpx;
|
||||
line-height: 90rpx;
|
||||
font-size: 30rpx;
|
||||
background-color: #f5f5f5;
|
||||
color: #606064;
|
||||
.iconclass {
|
||||
display: inline-block;
|
||||
margin: 0 12rpx;
|
||||
color: #D0D4DB;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
.container-list {
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
.common {
|
||||
background-color: #fff;
|
||||
border-bottom: 1rpx solid #f4f4f4;
|
||||
padding-left: 10rpx;
|
||||
.content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: 60rpx;
|
||||
width: 100%;
|
||||
padding: 15rpx 0;
|
||||
position: relative;
|
||||
font-size: 32rpx;
|
||||
|
||||
.right {
|
||||
position: absolute;
|
||||
right: 30rpx;
|
||||
color: #babdc3;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
// item的数字样式
|
||||
.word {
|
||||
font-size: 30rpx;
|
||||
color: #5b5757;
|
||||
width: 500rpx;
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
.active {
|
||||
color: #4297ED !important;
|
||||
}
|
||||
.none {
|
||||
color: #666666;
|
||||
}
|
||||
.icon-selected{
|
||||
color: #0095F2!important;
|
||||
font-size: 40rpx!important;
|
||||
}
|
||||
.icons{
|
||||
color: #0095F2!important;
|
||||
font-size: 40rpx!important;
|
||||
}
|
||||
.inline-item {
|
||||
display: inline-block
|
||||
}
|
||||
|
||||
.content-item{
|
||||
display: flex;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.box_sizing {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.btn {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
padding: 10px;
|
||||
background-color: #fff;
|
||||
width: 100%;
|
||||
|
||||
.sureBtn {
|
||||
background-color: #0095F2;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
709
uni_modules/luyj-tree/components/luyj-tree/luyj-tree.vue
Normal file
709
uni_modules/luyj-tree/components/luyj-tree/luyj-tree.vue
Normal file
@ -0,0 +1,709 @@
|
||||
<template>
|
||||
<view style="width: 100%;height: 100%;">
|
||||
<!-- 搜索框 -->
|
||||
<view class="header">
|
||||
<!-- 搜索栏 -->
|
||||
<luyj-tree-search v-if="searchIf" :backgroundColor="searchBackgroundColor"
|
||||
:inputBackgroundColor="searchInputBackgroundColor" :radius="searchRadius" :iconColor="searchIconColor"
|
||||
:placeholder="searchPlaceholder" :placeholderStyle="searchPlaceholderStyle" :maxlength="searchMaxlength"
|
||||
:clearable="searchClearable" @confirm="confirmSearch"></luyj-tree-search>
|
||||
<!-- 面包屑导航 -->
|
||||
<luyj-tree-navigation :slabel="props.label" @inF="navigationInt" @clickItem="backTree" ref="treeNavigation">
|
||||
</luyj-tree-navigation>
|
||||
<!-- 面包屑导航 -->
|
||||
</view>
|
||||
<!-- 列表 -->
|
||||
<view style="height: 100%;">
|
||||
<view class="container-list" :style="{'padding-bottom' : isCheck ? '160rpx' : 0 , 'padding-top' :searchIf ? '200rpx' :'90rpx', height:'calc(100% - 90rpx)'}">
|
||||
<block v-for="(item , index) in tree" :key="index">
|
||||
<luyj-tree-item :item="item" :index='index' :isCheck="isCheck"
|
||||
:checkActiveColor="checkActiveColor" :checkNoneColor="checkNoneColor" :multiple="props.multiple" :checked="isChecked(item)"
|
||||
:nodes="props.nodes" :comparison="comparison" @clickItemRight="toChildren" @clickItem="toLookDetail"
|
||||
@change="checkbox($event , item , index)">
|
||||
</luyj-tree-item>
|
||||
</block>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 确定按钮 -->
|
||||
<view v-if="isCheck" class="btn box_sizing">
|
||||
<button class="sureBtn" type="primary" @click="backConfirm">确认</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* luyj-tree 无限树形结构树、支持搜索选择。
|
||||
* @description 无限树形结构组件。支持搜索、选择(包括单选、多选)。面包屑类型导航。原插件地址:https://ext.dcloud.net.cn/plugin?id=2423。
|
||||
* @tutorial url https://ext.dcloud.net.cn/plugin?name=luyj-tree
|
||||
* @property {Boolean} searchIf 是否开启搜索 (默认值true)
|
||||
* @property {String} searchBackgroundColor 搜索框背景色(默认#FFFFFF)
|
||||
* @property {String} searchInputBackgroundColor 搜索框的输入框背景色(默认#EEEFF0)
|
||||
* @property {Number} searchRadius 搜索框的圆角值,单位rpx(默认40)
|
||||
* @property {String} searchPlaceholder 搜索框的内容物空时提示内容
|
||||
* @property {String} searchPlaceholderStyle 搜索框的placehoder的样式
|
||||
* @property {Number} searchMaxlength 搜索框的最大输入长度 ,设置为 -1 的时候不限制最大长度
|
||||
* @property {String} searchIconColor 搜索框的图标颜色(默认#B8B8B8)
|
||||
* @property {Boolean} searchClearable 搜索框是否显示清除按钮
|
||||
* @property {Array} trees 传入的树形结构,每个对象必须包含唯一的id值(默认值【】)
|
||||
* @property {Boolean} isCheck 是否开启选择操作(默认值false)
|
||||
* @property {Object} slotObj 传入插槽的参数(因为插槽进行了循环,不能直接引用页面的参数,需要传递)
|
||||
* @property {Array} checkList 选中列表
|
||||
* @property {Boolean} parent 当子级全选时,是否选中父级数据(prop.checkStrictly为true时生效)(默认值false)
|
||||
* @property {Array} parentList 父级列表
|
||||
* @property {String} checkActiveColor 选中时单选框的颜色 (默认#00AAFF)
|
||||
* @property {String} checkNoneColor 未选中时单选框的颜色(默认#B8B8B8)
|
||||
* @property {Object} props 参数配置。
|
||||
* @property {String} id id列的属性名称
|
||||
* @param {String} label 指定选项标签为选项对象的某个属性值(默认值:name)
|
||||
* @param {String} children 指定选项的子选项为选项对象的某个属性名(默认值:children)
|
||||
* @param {Boolean} multiple 值为true时为多选,为false时是单选(默认值true)
|
||||
* @param {Boolean} checkStrictly(废弃) 需要在多选模式下才传该值,checkStrictly为false时,可让父子节点取消关联,选择任意一级选项。为true时关联子级,可以全选(默认值为false)
|
||||
* @param {Boolean} nodes 在单选模式下,nodes为false时,可以选择任意一级选项,nodes为true时,只能选择叶子节点(默认值为true)
|
||||
* @property {Boolean} stepReload 是否“分页加载”数据
|
||||
* @property {Number} pageSize 分步加载生效时(当条数过大时,反应时间很长)
|
||||
* @return {Function} clickItem 点击导航栏事件
|
||||
* @value item 当前选中的item值
|
||||
* @value realHasChildren 是否包含子级
|
||||
* @event {Function()} change 改变选择值时的方法
|
||||
* @event {Function()} sendValue 提交选择的方法
|
||||
* @event {Function()} backTree 选中导航栏时,返回其他层
|
||||
*/
|
||||
export default {
|
||||
name: "luyj-tree",
|
||||
props: {
|
||||
// 是否开启搜索
|
||||
searchIf: {
|
||||
type: Boolean,
|
||||
default: () => true
|
||||
},
|
||||
// 搜索框背景色
|
||||
searchBackgroundColor: {
|
||||
type: String,
|
||||
default: '#FFFFFF'
|
||||
},
|
||||
// 搜索框的输入框内背景颜色
|
||||
searchInputBackgroundColor: {
|
||||
type: String,
|
||||
default: '#EEEFF0'
|
||||
},
|
||||
// 搜索框的图标的颜色
|
||||
searchIconColor: {
|
||||
type: String,
|
||||
default: '#B8B8B8'
|
||||
},
|
||||
// 搜索框的圆角值,单位rpx
|
||||
searchRadius: {
|
||||
type: Number,
|
||||
default: 40
|
||||
},
|
||||
// 搜索框的提示placeholder内容
|
||||
searchPlaceholder: {
|
||||
type: String,
|
||||
default: '搜索'
|
||||
},
|
||||
// 搜索框的placeholder的样式
|
||||
searchPlaceholderStyle: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 搜索框最大输入长度 ,设置为 -1 的时候不限制最大长度
|
||||
searchMaxlength: {
|
||||
type: Number,
|
||||
default: 140
|
||||
},
|
||||
// 搜索框是否显示清除按钮
|
||||
searchClearable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 传入的树形结构数据,每个对象必须包含唯一的id值
|
||||
trees: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
},
|
||||
//是否开启选择操作,值为false时仅展示,无操作
|
||||
isCheck: {
|
||||
type: Boolean,
|
||||
default: () => {
|
||||
return false
|
||||
}
|
||||
},
|
||||
// 传入插槽的其他参数
|
||||
slotObj: {
|
||||
type: Object,
|
||||
default :() =>{
|
||||
return null;
|
||||
}
|
||||
},
|
||||
// 选中列表
|
||||
checkList: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
// 当子级全选时,是否选中父级数据(prop.checkStrictly为true时生效)
|
||||
parent: {
|
||||
type: Boolean,
|
||||
default: () => {
|
||||
return false
|
||||
}
|
||||
},
|
||||
// 父级列表
|
||||
parentList: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
// 选中时单选框的颜色
|
||||
checkActiveColor: {
|
||||
type: String,
|
||||
default: '#00AAFF'
|
||||
},
|
||||
// 未选中时单选框的颜色
|
||||
checkNoneColor: {
|
||||
type: String,
|
||||
default: '#B8B8B8'
|
||||
},
|
||||
// 树的属性参数
|
||||
props: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
id: 'id',
|
||||
label: 'name',
|
||||
children: 'children',
|
||||
multiple: false,
|
||||
checkStrictly: false, //不关联
|
||||
nodes: false, // nodes为false时,可以选择任意一级选项;nodes为true时只能选择叶子节点
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 是否懒加载树的值
|
||||
*/
|
||||
stepReload : {
|
||||
type:Boolean,
|
||||
default:false
|
||||
},
|
||||
// 每次循环加载的item的数据量
|
||||
pageSize : {
|
||||
type : Number,
|
||||
default:50
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 导航条
|
||||
setIsre: null, // 导航条方法 - 设置是否搜索中方法
|
||||
getIsre : null, // 获取是否搜索中
|
||||
setTreeStack: null, // 导航条 - 设置导航
|
||||
concatTreeStack: null, // 导航条 - 拼接当前导航对象
|
||||
clearTreeStack: null, // 导航条- 清空导航条
|
||||
getTreeStack: null, // 导航条 - 获取导航条
|
||||
|
||||
itemsLoading : false, // item是否在循环渲染中
|
||||
itemsStop : false, // 是否终止其他渲染
|
||||
tree: [], // 默认数组
|
||||
newNum: 0,
|
||||
oldNum: 0,
|
||||
allData: this.trees,
|
||||
storeData:undefined,
|
||||
parent_data: this.parentList || [], //选择父辈
|
||||
searchResult: [],
|
||||
newCheckList: this.checkList,
|
||||
nodePathArray: [], // 当前展示的路径
|
||||
// item名称对照表
|
||||
comparison: {
|
||||
value: this.props.id ? this.props.id : 'id', // 选中值名称
|
||||
label: this.props.label ? this.props.label : 'name', // 显示名称
|
||||
children: this.props.children ? this.props.children : 'children', // 子集名称
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// 监听数据值的变化
|
||||
trees: function(val, oldval) {
|
||||
if (val != oldval) {
|
||||
var tree_stack = val;
|
||||
this.allData = val; // 重新加载所有树
|
||||
this.storeData = JSON.parse(JSON.stringify(val))
|
||||
// 重新加载当前树
|
||||
this.$refs.treeNavigation.treeStack = val
|
||||
var length = tree_stack.length;
|
||||
if( length === 0){
|
||||
if(typeof(this.getIsre) === "function"){
|
||||
if(this.getIsre()){
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.loadTree(val);
|
||||
}else{
|
||||
let tempArray = val; // 存储当前值
|
||||
let children = this.props.children;
|
||||
for(var i = 0 ; i < length ; i ++){
|
||||
var tempObject = tempArray.find(item=>{
|
||||
return tree_stack[i].Value == item.Value;
|
||||
});
|
||||
if(Boolean(tempObject)){
|
||||
tempArray = tempObject[children];
|
||||
}else{
|
||||
// 跳转到全部
|
||||
break;
|
||||
}
|
||||
if(i == length -1){
|
||||
this.loadTree(tempArray);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// 树的属性对照参数
|
||||
props: {
|
||||
handler: function(val) {
|
||||
this.comparison.value = this.props.id ? this.props.id : 'id';
|
||||
this.comparison.label = this.props.label ? this.props.label : 'name';
|
||||
this.comparison.children = this.props.children ? this.props.children : [];
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
checkList: function(val , oldVal){
|
||||
if(val != oldVal){
|
||||
this.newCheckList = JSON.parse(JSON.stringify(val))
|
||||
return val;
|
||||
}
|
||||
}
|
||||
},
|
||||
created:function(){
|
||||
this.loadTree(this.trees);
|
||||
this.storeData = JSON.parse(JSON.stringify(this.trees))
|
||||
|
||||
},
|
||||
// 实例被挂载后调用
|
||||
mounted() {
|
||||
let id = this.props.id;
|
||||
let children = this.props.children;
|
||||
// 关联子级的验证,暂时不使用
|
||||
// if (this.props.multiple && this.props.checkStrictly) {
|
||||
// if (this.newCheckList.length != 0) {
|
||||
// this.checkAllChoose();
|
||||
// return;
|
||||
// }
|
||||
// for (let i = 0; i < this.tree.length; i++) {
|
||||
// this.$set(this.tree[i], 'bx', 0)
|
||||
// this.$set(this.tree[i], 'qx', 0)
|
||||
// }
|
||||
// }
|
||||
// 初始化选中项
|
||||
if (!this.props.multiple && this.newCheckList.length > 0) {
|
||||
this.getNodeRoute(this.allData, this.newCheckList[0][id]);
|
||||
let arr = this.nodePathArray.reverse();
|
||||
if (arr.length == 0) {
|
||||
return;
|
||||
}
|
||||
this.concatTreeStack(arr); // 获取导航条的值
|
||||
// 加载当前列对应的数据
|
||||
var tree_stack = this.trees;
|
||||
var data = Boolean(tree_stack[tree_stack.length -1][children]) ? tree_stack[tree_stack.length - 1][
|
||||
children
|
||||
] : [];
|
||||
this.loadTree(data);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// ========================================== 添加方法 =====================================================================
|
||||
/** 当前选项是否选中
|
||||
* @param {Object} item
|
||||
*/
|
||||
isChecked(item){
|
||||
if(Array.isArray(this.newCheckList)){
|
||||
let id = this.props.id;
|
||||
let temp = this.newCheckList.find(chcked=>{
|
||||
return chcked[id] == item.id;
|
||||
});
|
||||
return Boolean(temp);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
// =========================================== 初始化方法 ===================================================================
|
||||
/** 初始化导航条的方法
|
||||
* @param {Object} e
|
||||
*/
|
||||
navigationInt: function(e) {
|
||||
this.setIsre = e.setIsre;
|
||||
this.getIsre = e.getIsre;
|
||||
this.concatTreeStack = e.concatTreeStack;
|
||||
this.pushTreeStack = e.pushTreeStack;
|
||||
this.clearTreeStack = e.clearTreeStack;
|
||||
this.getTreeStack = e.getTreeStack;
|
||||
},
|
||||
// =========================================== 监听事件 =====================================================================
|
||||
/** 选中当前的值
|
||||
* @param {Object} e
|
||||
* @param {Object} item 当前项
|
||||
* @param {Object} index 低昂去索引
|
||||
*/
|
||||
checkbox(e, item, index) {
|
||||
var func = this.props.multiple ? this.checkboxChange : this.radioChange;
|
||||
func(e,item ,index); // 执行选择操作
|
||||
},
|
||||
/**单选
|
||||
* @param {Object} e 点击事件
|
||||
* @param {Object} item 当前项的值
|
||||
* @param {Object} index 索引
|
||||
*/
|
||||
radioChange :function( e,item ,index){
|
||||
var that = this;
|
||||
if(e.detail.value){
|
||||
// 选中当前对象
|
||||
that.newCheckList = [];
|
||||
that.newCheckList.push(that.tree[index]);
|
||||
}else{
|
||||
// 移除其他对象
|
||||
var nIndex = that.newCheckList.indexOf(item);
|
||||
that.newCheckList.splice(nIndex , 1);
|
||||
}
|
||||
that.$emit('change', that.newCheckList);
|
||||
},
|
||||
/**异步检查复选框值的改变
|
||||
* @param {Object} item
|
||||
* @param {Object} index
|
||||
* @param {Object} bx
|
||||
* @param {Object} qx
|
||||
*/
|
||||
async checkboxChange (e,item, index, bx, qx) {
|
||||
let that = this;
|
||||
let findIdex = that.newCheckList.indexOf(item);
|
||||
if(e.detail.value){
|
||||
// 点击选中
|
||||
if(findIdex == -1){
|
||||
that.newCheckList.push(that.tree[index]);
|
||||
}
|
||||
}else{
|
||||
// 点击不选
|
||||
that.newCheckList.splice(findIdex , 1);
|
||||
}
|
||||
that.$emit('change', that.newCheckList);
|
||||
|
||||
// if (findIdex > -1) { //反选
|
||||
// if (that.props.checkStrictly) { //关联子级
|
||||
// if (item[props.hasChilren]) { //用户
|
||||
// that.newCheckList.splice(findIdex, 1)
|
||||
// } else { //非用户,取消所有下一级
|
||||
// if (Boolean(item[props.children])) {
|
||||
// that.getIdBydelete(item[props.children]);
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// that.newCheckList.splice(findIdex, 1)
|
||||
// }
|
||||
// } else { //选中
|
||||
// if (!item[this.props.hasChilren] && that.props.checkStrictly) { //选中下一级
|
||||
// if (qx || bx) { //取消下级
|
||||
// if (Boolean(item[props.children])) {
|
||||
// await that.getIdBydelete(item[props.children]);
|
||||
// }
|
||||
// item.qx = 0;
|
||||
// item.bx = 0;
|
||||
// } else {
|
||||
// item.qx = 1;
|
||||
// item.bx = 0;
|
||||
// if (Boolean(item[props.children])) {
|
||||
// await that.chooseChild(item[props.children], item[this.props.id]);
|
||||
// }
|
||||
// }
|
||||
// that.$emit('change', that.newCheckList);
|
||||
// // that.$forceUpdate()
|
||||
// return;
|
||||
// }
|
||||
// // if(item[this.props.hasChilren]&&this.props.checkStrictly) this.getNodeRoute(this.allData,item[this.props.id]);
|
||||
// that.newCheckList.push({
|
||||
// ...item
|
||||
// });
|
||||
// }
|
||||
// that.$emit('change', that.newCheckList)
|
||||
},
|
||||
// 取消下一级的选中
|
||||
getIdBydelete(arr) {
|
||||
arr.forEach(e => {
|
||||
if (true) {
|
||||
for (var i = 0; i < this.newCheckList.length; i++) {
|
||||
// 包含下一级
|
||||
if (e[this.props.id] == this.newCheckList[i][this.props.id]) {
|
||||
this.newCheckList.splice(i, 1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
// 关联下一级,选中
|
||||
chooseChild(arr, pid) {
|
||||
let that = this;
|
||||
for (var i = 0, len = arr.length; i < len; i++) {
|
||||
let item = arr[i];
|
||||
if (true) {
|
||||
// 包含下一级
|
||||
that.newCheckList.push({
|
||||
...item,
|
||||
tree_stackId: pid
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Array} tree 目标树
|
||||
* @param {Object} targetId 为目标节点id
|
||||
*/
|
||||
getNodeRoute(tree, targetId) {
|
||||
let children = this.props.children;
|
||||
let id = this.props.id;
|
||||
for (let index = 0; index < tree.length; index++) {
|
||||
if (Boolean(tree[index][children]) ) {
|
||||
if (tree[index][children]) {
|
||||
let endRecursiveLoop = this.getNodeRoute(tree[index][children], targetId)
|
||||
if (endRecursiveLoop) {
|
||||
this.nodePathArray.push(tree[index]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tree[index][id] === targetId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**跳转到子级
|
||||
* @param {Object} item 选中的项
|
||||
* @param {Boolean} realHasChildren 是否包含子级
|
||||
*/
|
||||
toChildren(item, realHasChildren) {
|
||||
this.$emit("clickItem" , item , realHasChildren); // 点击导航栏事件
|
||||
// 不包含子级,不执行任何操作
|
||||
if (!realHasChildren) {
|
||||
return;
|
||||
}
|
||||
// 点击跳转下一级
|
||||
let id = this.props.id;
|
||||
let children = this.props.children; // 子级名称
|
||||
|
||||
// 将当前item加入到导航列表
|
||||
if (item[children].length > 0) {
|
||||
this.loadTree(item[children]);
|
||||
this.pushTreeStack(item); // 添加导航
|
||||
}
|
||||
// 关联数据 - 暂时不使用
|
||||
// if (this.props.checkStrictly) {
|
||||
// this.checkAllChoose();
|
||||
// }
|
||||
},
|
||||
/**查看详情 */
|
||||
toLookDetail(item, realHasChildren){
|
||||
this.$emit('lookDetail',item)
|
||||
},
|
||||
/** 搜索提交方法
|
||||
* @param {Object} e
|
||||
*/
|
||||
confirmSearch(e) {
|
||||
var val = e.detail.value;
|
||||
this.searchResult = [];
|
||||
if(val){
|
||||
// 查找
|
||||
uni.showLoading({
|
||||
title: '正在查找'
|
||||
});
|
||||
this.search(this.allData, val);
|
||||
|
||||
}else{
|
||||
return
|
||||
}
|
||||
// 返回搜索结果
|
||||
uni.hideLoading();
|
||||
this.setIsre(true); // 设置导航条为搜索状态
|
||||
this.clearTreeStack(); // 清空导航条
|
||||
this.loadTree(this.searchResult);
|
||||
},
|
||||
/**搜索方法
|
||||
* @param {Object} data 搜索数据
|
||||
* @param {Object} keyword 搜索关键字
|
||||
*/
|
||||
search(data, keyword) {
|
||||
var that = this;
|
||||
let children = that.props.children;
|
||||
for (var i = 0, len = data.length; i < len; i++) {
|
||||
// try-catch(try-catch) - 没有label列,跳过继续执行
|
||||
try{
|
||||
if ((data[i][that.props.label].toLowerCase()).indexOf(keyword.toLowerCase()) >= 0) {
|
||||
that.searchResult.push(data[i]);
|
||||
}
|
||||
if (Boolean(data[i][children])) {
|
||||
if (data[i][children].length > 0) {
|
||||
that.search(data[i][children], keyword);
|
||||
}
|
||||
}
|
||||
}catch(e){
|
||||
console.warn(e);
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 检查所有的选项
|
||||
*/
|
||||
checkAllChoose() {
|
||||
let o = false,
|
||||
t = true;
|
||||
this.tree.forEach((e, i) => {
|
||||
if (true) {
|
||||
// 包含下一级 !e[this.props.hasChilren]
|
||||
e.qx = o;
|
||||
e.bx = o;
|
||||
let num2 = this.computAllNumber(e[props.children]);
|
||||
// console.log(this.newNum,this.oldNum)
|
||||
if (this.newNum != 0 && this.oldNum != 0) {
|
||||
if (this.newNum == this.oldNum) {
|
||||
e.qx = t;
|
||||
e.bx = o;
|
||||
} else {
|
||||
e.qx = o;
|
||||
e.bx = t;
|
||||
}
|
||||
}
|
||||
if (this.newNum != 0 && this.oldNum == 0) {
|
||||
this.$set(this.tree[i], 'bx', o);
|
||||
this.$set(this.tree[i], 'qx', o);
|
||||
}
|
||||
// this.$forceUpdate()
|
||||
this.newNum = 0
|
||||
this.oldNum = 0
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 选中所选值
|
||||
computAllNumber(arr) {
|
||||
console.log("选中所选值");
|
||||
// for (let j = 0; j < arr.length; j++) {
|
||||
// var e = arr[j];
|
||||
// // if (arr[j][that.props.hasChilren]) {
|
||||
// this.newNum++;
|
||||
// // }
|
||||
// this.checkSum(e.id)
|
||||
// if (!e[that.props.hasChilren]) {
|
||||
// this.computAllNumber(e[props.children])
|
||||
// }
|
||||
// }
|
||||
},
|
||||
|
||||
// 选中事件累计
|
||||
checkSum(id) {
|
||||
for (let i = 0; i < this.newCheckList.length; i++) {
|
||||
if (id == this.newCheckList[i].id) {
|
||||
this.oldNum++;
|
||||
break
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/** 返回到其他树层
|
||||
* @param {Object} item 当前item值
|
||||
* @param {Object} index 返回到其他索引
|
||||
*/
|
||||
backTree(item, index) {
|
||||
this.$emit("backTree", item, index);
|
||||
let that = this;
|
||||
if (index == -1) {
|
||||
// 全部
|
||||
that.loadTree(that.storeData);
|
||||
} else if (index == -2) {
|
||||
// 搜索
|
||||
that.loadTree(that.searchResult); // 搜索结果
|
||||
} else {
|
||||
// 其他层级
|
||||
that.loadTree(item[that.props.children]); // tree的其他层级
|
||||
}
|
||||
// 关联数据
|
||||
// if (this.props.checkStrictly) {
|
||||
// this.checkAllChoose();
|
||||
// }
|
||||
},
|
||||
/**
|
||||
* 点击确认按钮执行事件
|
||||
*/
|
||||
backConfirm() {
|
||||
this.$emit('sendValue', this.newCheckList, 'back')
|
||||
},
|
||||
// ======================================== 公共方法 ===============================================================
|
||||
/**加载Tree值
|
||||
* @param {Array} datas 待复制的数组
|
||||
* @param {Number} start 起始位置
|
||||
* @description 加载tree值。当数据量大时,子项加载时间很长。可以多次渲染加载
|
||||
*/
|
||||
loadTree : function(datas , start = 0 ){
|
||||
let that = this;
|
||||
if(!this.stepReload){
|
||||
// 不进行多次渲染加载
|
||||
that.tree = datas;
|
||||
}else{
|
||||
// datas为null, 不进行渲染
|
||||
if(!Array.isArray(datas)){
|
||||
that.tree = datas;
|
||||
return;
|
||||
}else if(datas.length === 0){
|
||||
that.tree = datas;
|
||||
return;
|
||||
}
|
||||
// 进行多次渲染加载
|
||||
if(start === 0){
|
||||
// 终止其他渲染
|
||||
if(that.itemsLoading){
|
||||
that.itemsStop = true; //终止其他Item渲染
|
||||
}
|
||||
// 首次加载提醒
|
||||
uni.showLoading();
|
||||
that.tree = [];
|
||||
that.itemsLoading = true;
|
||||
}
|
||||
var length = datas.length ;
|
||||
var end = Math.min(start + that.pageSize , length);
|
||||
var tempArray = datas.slice(start , end);
|
||||
that.tree = that.tree.concat(tempArray);
|
||||
that.$nextTick(function(){
|
||||
if(start == 0){
|
||||
uni.hideLoading();
|
||||
that.itemsStop = false;
|
||||
}
|
||||
if(end < length && !that.itemsStop){
|
||||
that.loadTree(datas, end);
|
||||
}else{
|
||||
that.itemsLoading = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
// =================================================================================================================
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import "luyj-tree.scss";
|
||||
@import "icon.css";
|
||||
.device-box{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
.device-img{
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
background: #f8f8f8;
|
||||
flex-shrink: 0;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
346
uni_modules/luyj-tree/lib/css/icon.css
Normal file
346
uni_modules/luyj-tree/lib/css/icon.css
Normal file
@ -0,0 +1,346 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 2009600 */
|
||||
src: url('https://at.alicdn.com/t/font_2009600_gpzp7pxtnw.woff2?t=1620633089023') format('woff2'),
|
||||
url('https://at.alicdn.com/t/font_2009600_gpzp7pxtnw.woff?t=1620633089023') format('woff'),
|
||||
url('https://at.alicdn.com/t/font_2009600_gpzp7pxtnw.ttf?t=1620633089023') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-family: "iconfont" !important;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
/* 清除图标 */
|
||||
.icon-clear:before{
|
||||
content: '\e606';
|
||||
}
|
||||
|
||||
.icon-banxuanzhongshousuo1-shi:before {
|
||||
content: "\e682";
|
||||
}
|
||||
|
||||
.icon-xuanzhong3:before {
|
||||
content: "\e6bb";
|
||||
}
|
||||
|
||||
.icon-weixuanzhong2:before {
|
||||
content: "\e62e";
|
||||
}
|
||||
|
||||
.icon-danxuanxuanzhong:before {
|
||||
content: "\e631";
|
||||
}
|
||||
|
||||
.icon-xuanzhong4:before {
|
||||
content: "\e63e";
|
||||
}
|
||||
|
||||
.icon-xuanzhong1:before {
|
||||
content: "\e62d";
|
||||
}
|
||||
.icon-xuanzhong2:before {
|
||||
content: "\e656";
|
||||
}
|
||||
|
||||
.icon-selected:before {
|
||||
content: "\e615";
|
||||
}
|
||||
|
||||
.icon-weixuanzhong1:before {
|
||||
content: "\e614";
|
||||
}
|
||||
|
||||
.icon-xingzhuang6kaobei3-copy-copy:before {
|
||||
content: "\e613";
|
||||
}
|
||||
|
||||
.icon-radio-checked:before {
|
||||
content: "\e63f";
|
||||
}
|
||||
|
||||
.icon-huifu:before {
|
||||
content: "\e619";
|
||||
}
|
||||
|
||||
.icon-dizhi:before {
|
||||
content: "\e64a";
|
||||
}
|
||||
|
||||
.icon-kuaijiecaidan:before {
|
||||
content: "\e60a";
|
||||
}
|
||||
|
||||
.icon-z043:before {
|
||||
content: "\e62f";
|
||||
}
|
||||
|
||||
.icon-guanbi:before {
|
||||
content: "\e607";
|
||||
}
|
||||
|
||||
.icon-xuanze:before {
|
||||
content: "\e623";
|
||||
}
|
||||
|
||||
.icon-caidanzhaolinggan:before {
|
||||
content: "\e616";
|
||||
}
|
||||
|
||||
.icon-xitongshezhi:before {
|
||||
content: "\e60c";
|
||||
}
|
||||
|
||||
.icon-xitongshezhi1:before {
|
||||
content: "\e633";
|
||||
}
|
||||
|
||||
.icon-lunbo:before {
|
||||
content: "\e692";
|
||||
}
|
||||
|
||||
.icon-shuping:before {
|
||||
content: "\e659";
|
||||
}
|
||||
|
||||
.icon-tongzhi:before {
|
||||
content: "\e641";
|
||||
}
|
||||
|
||||
.icon-pinglunguanlishezhi:before {
|
||||
content: "\e6ac";
|
||||
}
|
||||
|
||||
.icon-icon:before {
|
||||
content: "\e600";
|
||||
}
|
||||
|
||||
.icon-liuyanguanli:before {
|
||||
content: "\e61d";
|
||||
}
|
||||
|
||||
.icon-xuanzhong:before {
|
||||
content: "\e669";
|
||||
}
|
||||
|
||||
.icon--:before {
|
||||
content: "\e622";
|
||||
}
|
||||
|
||||
.icon-tushu:before {
|
||||
content: "\e604";
|
||||
}
|
||||
|
||||
.icon-huishouzhan:before {
|
||||
content: "\e61c";
|
||||
}
|
||||
|
||||
.icon-yonghutouxiang:before {
|
||||
content: "\e617";
|
||||
}
|
||||
|
||||
.icon-liebiao:before {
|
||||
content: "\e630";
|
||||
}
|
||||
|
||||
.icon-fenlei:before {
|
||||
content: "\e621";
|
||||
}
|
||||
|
||||
.icon-tushu1:before {
|
||||
content: "\e605";
|
||||
}
|
||||
|
||||
.icon-tubiao-:before {
|
||||
content: "\e620";
|
||||
}
|
||||
|
||||
.icon-weixuanze:before {
|
||||
content: "\e624";
|
||||
}
|
||||
|
||||
.icon-tushujieyue:before {
|
||||
content: "\e690";
|
||||
}
|
||||
|
||||
.icon-lunbo1:before {
|
||||
content: "\e6c5";
|
||||
}
|
||||
|
||||
.icon-shanchu:before {
|
||||
content: "\e67b";
|
||||
}
|
||||
|
||||
.icon-lunbo2:before {
|
||||
content: "\e61e";
|
||||
}
|
||||
|
||||
.icon-huaban:before {
|
||||
content: "\e663";
|
||||
}
|
||||
|
||||
.icon-kehuan:before {
|
||||
content: "\e608";
|
||||
}
|
||||
|
||||
.icon-icon02:before {
|
||||
content: "\e601";
|
||||
}
|
||||
|
||||
.icon-huishouzhan1:before {
|
||||
content: "\e612";
|
||||
}
|
||||
|
||||
.icon-huishouzhan2:before {
|
||||
content: "\e63d";
|
||||
}
|
||||
|
||||
.icon-sousuo:before {
|
||||
content: "\e62c";
|
||||
}
|
||||
|
||||
.icon-xingzhuang:before {
|
||||
content: "\e625";
|
||||
}
|
||||
|
||||
.icon-lunbobankuai:before {
|
||||
content: "\e61f";
|
||||
}
|
||||
|
||||
.icon-shangchuan:before {
|
||||
content: "\e602";
|
||||
}
|
||||
|
||||
.icon-yonghu:before {
|
||||
content: "\e761";
|
||||
}
|
||||
|
||||
.icon-tongzhi1:before {
|
||||
content: "\e603";
|
||||
}
|
||||
|
||||
.icon-jingsong:before {
|
||||
content: "\e65c";
|
||||
}
|
||||
|
||||
.icon-fenlei1:before {
|
||||
content: "\e6c6";
|
||||
}
|
||||
|
||||
.icon-xieshupingicon:before {
|
||||
content: "\e72d";
|
||||
}
|
||||
|
||||
.icon-liuyan:before {
|
||||
content: "\e626";
|
||||
}
|
||||
|
||||
.icon-weixuanzhong:before {
|
||||
content: "\e627";
|
||||
}
|
||||
|
||||
.icon-youxiang:before {
|
||||
content: "\e646";
|
||||
}
|
||||
|
||||
.icon-lunboguanggao:before {
|
||||
content: "\e6b3";
|
||||
}
|
||||
|
||||
.icon-xuanze1:before {
|
||||
content: "\e60d";
|
||||
}
|
||||
|
||||
.icon-chushaixuanxiang:before {
|
||||
content: "\e606";
|
||||
}
|
||||
|
||||
.icon-liuyanguanli1:before {
|
||||
content: "\e61a";
|
||||
}
|
||||
|
||||
.icon-shanchu1:before {
|
||||
content: "\e609";
|
||||
}
|
||||
|
||||
.icon-huishouzhan3:before {
|
||||
content: "\e642";
|
||||
}
|
||||
|
||||
.icon-shangchuan1:before {
|
||||
content: "\e823";
|
||||
}
|
||||
|
||||
.icon-huishouzhan4:before {
|
||||
content: "\e61b";
|
||||
}
|
||||
|
||||
.icon-chuangzuo:before {
|
||||
content: "\e8ad";
|
||||
}
|
||||
|
||||
.icon-dianzan:before {
|
||||
content: "\e8ae";
|
||||
}
|
||||
|
||||
.icon-paihangbang:before {
|
||||
content: "\e8b3";
|
||||
}
|
||||
|
||||
.icon-shouye:before {
|
||||
content: "\e8b9";
|
||||
}
|
||||
|
||||
.icon-shoucang:before {
|
||||
content: "\e8c6";
|
||||
}
|
||||
|
||||
.icon-addApp:before {
|
||||
content: "\e60b";
|
||||
}
|
||||
|
||||
.icon-huishouzhan5:before {
|
||||
content: "\e63a";
|
||||
}
|
||||
|
||||
.icon-add1:before {
|
||||
content: "\e60e";
|
||||
}
|
||||
|
||||
.icon-shoucang1:before {
|
||||
content: "\e60f";
|
||||
}
|
||||
|
||||
.icon-canshutongji:before {
|
||||
content: "\e618";
|
||||
}
|
||||
|
||||
.icon-rizhiguanli:before {
|
||||
content: "\e628";
|
||||
}
|
||||
|
||||
.icon-shanchu2:before {
|
||||
content: "\e629";
|
||||
}
|
||||
|
||||
.icon-xinzeng:before {
|
||||
content: "\e62a";
|
||||
}
|
||||
|
||||
.icon-zhankailiebiao:before {
|
||||
content: "\e62b";
|
||||
}
|
||||
|
||||
.icon-xiala-copy:before {
|
||||
content: "\e610";
|
||||
}
|
||||
|
||||
.icon-shangla:before {
|
||||
content: "\e64e";
|
||||
}
|
||||
|
||||
.icon-xianxingshezhi:before {
|
||||
content: "\e611";
|
||||
}
|
||||
86
uni_modules/luyj-tree/package.json
Normal file
86
uni_modules/luyj-tree/package.json
Normal file
@ -0,0 +1,86 @@
|
||||
{
|
||||
"id": "luyj-tree",
|
||||
"displayName": "luyj-tree 无限级树形结构。",
|
||||
"version": "1.4.11",
|
||||
"description": "无限极树形结构。支持搜索、面包屑导航、单项选择、多项选择。",
|
||||
"keywords": [
|
||||
"uni-ui",
|
||||
"uniui",
|
||||
"",
|
||||
"tree",
|
||||
""
|
||||
],
|
||||
"repository": "https://github.com/luyanjie00436/luyj-tree-app",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.1.0"
|
||||
},
|
||||
"dcloudext": {
|
||||
"category": [
|
||||
"前端组件",
|
||||
"通用组件"
|
||||
],
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": ""
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y"
|
||||
},
|
||||
"client": {
|
||||
"App": {
|
||||
"app-vue": "y",
|
||||
"app-nvue": "y"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "u",
|
||||
"Android Browser": "u",
|
||||
"微信浏览器(Android)": "u",
|
||||
"QQ浏览器(Android)": "u"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "y",
|
||||
"IE": "u",
|
||||
"Edge": "u",
|
||||
"Firefox": "y",
|
||||
"Safari": "u"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": {
|
||||
"minVersion": "2.18.1"
|
||||
},
|
||||
"阿里": "u",
|
||||
"百度": "u",
|
||||
"字节跳动": "u",
|
||||
"QQ": "u"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "u",
|
||||
"联盟": "u"
|
||||
},
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "u"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
251
uni_modules/luyj-tree/readme.md
Normal file
251
uni_modules/luyj-tree/readme.md
Normal file
@ -0,0 +1,251 @@
|
||||
# luyj-tree
|
||||
> 代码块 `luyj-tree` 内包含`luyj-tree-search`、`luyj-tree-navigation`、`luyj-tree-item`
|
||||
|
||||
## 说明
|
||||
|
||||
* 本插件是基于[xiaolu-tree](https://ext.dcloud.net.cn/plugin?id=2423)进行了uni_modules模块化。并进行了一些修改。
|
||||
* 本人暂时只在微信小程序端和H5 使用Chrome浏览器测试。更改了一些内容,有可能会有一些错误 或说明与实际不一致,介意者慎用。本人会适当的抽出业余时间,把它完善,毕竟有一定的下载量了,而且自己也需要学习,再次感谢原作者。
|
||||
* 暂时,使用自定义插件渲染有问题,会出现``duplication is found under a single shadow root. The first one was accepted`` ,还未找到解决方案。
|
||||
|
||||
### 安装方式
|
||||
|
||||
本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
|
||||
|
||||
### 基本用法
|
||||
|
||||
在 ``template`` 中使用组件
|
||||
|
||||
```html
|
||||
<!-- 基础用法 -->
|
||||
<luyj-tree v-slot:default="{item}" :max="max" :trees="tree">
|
||||
<!-- 内容插槽 -->
|
||||
<view>
|
||||
<view class="content-item">
|
||||
<view class="word">{{item.name}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</luyj-tree>
|
||||
```
|
||||
|
||||
``` javascript
|
||||
import dataList from '@/common/data.js'; // 引用数据
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
tree: dataList,
|
||||
max: 5,
|
||||
}
|
||||
},
|
||||
}
|
||||
```
|
||||
### 功能说明
|
||||
|
||||
1. 树形结构展示。
|
||||
2. 包含搜索框。能够自定义搜索框的样式,能够直接搜索树形图、子文件的内容。
|
||||
3. 包含面包屑导航。
|
||||
4. 可以仅仅展示或选择树形的项内容。
|
||||
5. 可以显示选择改变,或确认选择的方法。
|
||||
6. 只需传checkList字段就可以回显默认选中。
|
||||
7. 支持自定义显示内容的插件(slot)。
|
||||
8. 支持懒加载。
|
||||
|
||||
### 属性
|
||||
|
||||
|属性名 |类型 |默认值 | 说明 |
|
||||
|:-: |:-: |:-: | :-: |
|
||||
|search-if |Boolean |true | 是否开启搜索 |
|
||||
|search-background-color |String |#FFFFFF | 搜索框背景色 |
|
||||
|search-input-background-color |String |#EEEFF0 | 搜索框的输入框背景色 |
|
||||
|search-radius |Number |40 | 搜索框的圆角值,单位rpx(默认40) |
|
||||
|search-placeholder |String |搜索 | 搜索框的内容物空时提示内容 |
|
||||
|search-placeholder-style |String | | 搜索框的placehoder的样式 |
|
||||
|search-maxlength |Number |140 | 搜索框的最大输入长度 ,设置为 -1 的时候不限制最大长度 |
|
||||
|search-iconColor |String | | 搜索框的图标颜色 |
|
||||
|search-clearable |Boolean |true | 搜索框是否显示清除按钮 |
|
||||
|trees |Array |[] | trees 传入的树形结构,每个对象必须包含唯一的id值 |
|
||||
|is-check |Boolean |false | 是否开启选择操作 |
|
||||
|slot-obj |Object |null | 传入插槽的参数(自定义的slot中不能引用页面的参数,否则样式会出错)|
|
||||
|check-list |Array |[] | 选中的列表 |
|
||||
|parent |Boolean |false | 当子级全选时,是否选中父级数据(prop.checkStrictly为true时生效)。此参数占时失效。 |
|
||||
|parent-list |Array |[] | 父级列表 |
|
||||
|check-active-color |String |#00AAFF | 选中时单选框/复选框的颜色 |
|
||||
|check-none-color |String |#B8B8B8 | 未选中时单选框/复选框的颜色 |
|
||||
|props |Object |{id: 'id',label:'name',children:'children',hasChilren: 'user',multiple: false,checkStrictly: false ,nodes: false} | 参数配置,详细见下表。 |
|
||||
|step-reload |Boolean |false | 是否懒加载数列 |
|
||||
|page-size |Number |50 | 每次加载的条数,stepReload = true时生效 |
|
||||
|
||||
#### props 参数说明
|
||||
|参数 |类型 |默认值 | 说明 |
|
||||
|:-: |:-: |:-: | :-: |
|
||||
|id |String |id | id列的属性名 |
|
||||
|label |String |name | 指定选项标签为选项对象的某个属性值 |
|
||||
|children |String |children | 指定选项的子选项为选项对象的某个属性值 |
|
||||
|multiple |Boolean |true | 值为true时为多选,为false时是单选 |
|
||||
|checkStrictly |Boolean |false | 需要在多选模式下才传该值,checkStrictly为false时,可让父子节点取消关联,选择任意一级选项。为true时关联子级,可以全选(暂时不可用) |
|
||||
|nodes |Boolean |true | 在单选模式下,nodes为false时,可以选择任意一级选项,nodes为true时,只能选择叶子节点 |
|
||||
|
||||
### 事件
|
||||
|
||||
|事件名 |说明 |返回值 |
|
||||
|:-: |:-: |:-: |
|
||||
|@clickItem |点击Item列事件 |(item : Object ,realHasChildren : Boolean) |
|
||||
|@change |选项改变时触发事件 当前选中的值 |
|
||||
|@sendValue |点击确认按钮时触发事件 | 参数(选中的项值) |
|
||||
|
||||
``@clickItem``,当点击item列时有效。返回值说明如下:
|
||||
|
||||
|返回值 |类型 | 说明 |
|
||||
|:-: |:-: |:-: |
|
||||
|item |Object | 当前选中的值 |
|
||||
|realHasChildren |Boolean| 是否包含子级 |
|
||||
|
||||
``@change`` ,``is-check``为```true```时,当选中的值改变时触发。返回值说明如下:
|
||||
|
||||
|参数 |类型 | 说明 |
|
||||
|:-: |:-: | :-: |
|
||||
|e.detail.value |Boolean | 当前项是否选中 |
|
||||
|item |Object | 当前的Item值 |
|
||||
|
||||
# luyj-tree-search
|
||||
|
||||
### 说明
|
||||
|
||||
``luyj-tree-search`` 是 ``luyj-tree``内的组件,作为搜索框,可以单独引用。
|
||||
|
||||

|
||||
|
||||
### 基本用法
|
||||
###
|
||||
在 ``template`` 中使用组件
|
||||
|
||||
``` html
|
||||
<luyj-tree-search></luyj-tree-search>
|
||||
```
|
||||
|
||||
### 属性
|
||||
|
||||
|属性名 |类型 |默认值 | 说明 |
|
||||
|:-: |:-: |:-: | :-: |
|
||||
|background-color |String |#FFFFFF | 背景色 |
|
||||
|input-background-color |String |#EEEFF0 | 输入框背景色 |
|
||||
|radius |Number |40 | 输入框圆角,单位rpx |
|
||||
|icon-color |String |#B8B8B8 | 图标颜色 |
|
||||
|placeholder |String |搜索 | 输入框为空时占位符 |
|
||||
|placeholder-style |String | | placeholder的样式 |
|
||||
|maxlength |Number |140 | 最大输入长度 ,设置为 -1 的时候不限制最大长度 |
|
||||
|
||||
### 事件
|
||||
|
||||
|事件名 |说明 |返回值 |
|
||||
|:-: |:-: |:-: |
|
||||
|@input |输入框内容变化时,触发事件 | event |
|
||||
|@focus |输入框获得焦点时,触发事件 | event |
|
||||
|@blur |输入框失去焦点时,触发事件 | event |
|
||||
|@confirm |输入框内容提交时,触发事件 | event |
|
||||
|@clear |清空输入框内容时,触发事件 | '' |
|
||||
|
||||
# luyj-tree-navigation
|
||||
|
||||
``luyj-tree-navigation`` 是 ``luyj-tree``内的组件,作为面包屑导航栏,可以单独引用。
|
||||
|
||||
# luyj-tree-item
|
||||
|
||||
``luyj-tree-item`` 是 ``luyj-tree``内的组件,是树的选择项。包含单选、多选的样式,可以单独引用。
|
||||
|
||||
### 基础用法
|
||||
|
||||
在``template``中使用组件
|
||||
|
||||
``` html
|
||||
<!-- 普通使用 -->
|
||||
<luyj-tree-item :item="item" :isCheck="ischecked" :multiple="multiple" :checked="ischecked" :comparison="comparison" @change="change" @clickItem="clickItem">
|
||||
</luyj-tree-item>
|
||||
<!-- 使用插件 -->
|
||||
<luyj-tree-item :item="item" :isCheck="isCheck" :multiple="multiple" :checked="ischecked" :comparison="comparison" @change="change" @clickItem="clickItem">
|
||||
<!-- 自定义插件内容 -->
|
||||
<template slot="body" >
|
||||
{{ item.label }}
|
||||
</template>
|
||||
<!-- 自定义插件内容 -->
|
||||
</luyj-tree-item>
|
||||
```
|
||||
|
||||
对应的数据及方法如下:
|
||||
|
||||
``` javascript
|
||||
import dataItem from '../../common/item-data.js';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
item : dataItem, // 当前item值
|
||||
isCheck : true, // 是否可选
|
||||
ischecked : true, // 是否选中
|
||||
multiple : false, // 是否多选
|
||||
comparison :{
|
||||
value : 'value', // 选中值
|
||||
label : 'label', // 显示名称
|
||||
children:'children', // 子级名称
|
||||
},
|
||||
test :124
|
||||
}
|
||||
},
|
||||
onLoad:function(){
|
||||
},
|
||||
methods: {
|
||||
// 修改change
|
||||
change : function(e , item){
|
||||
console.log("修改当前值=>" ,e , item);
|
||||
},
|
||||
// 点击当前项目
|
||||
clickItem : function(item , hasChildren){
|
||||
console.log("点击当前项目");
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 属性
|
||||
|
||||
|属性名 |类型 |默认值 | 说明 |
|
||||
|:-: |:-: |:-: | :-: |
|
||||
|item |Object |{} | 当前项的值 |
|
||||
|is-check |Boolean |false |判断是否可选择,与multiple组合使用。判断显示类型为展示、单选、多选|
|
||||
|multiple |Boolean |false |是否多选。当isCheck值为true时有效。multiple=false时为单选,multiple=true时多选|
|
||||
|checked |Boolean |false |当前项是否选中状态|
|
||||
|nodes |Boolean |false |是否只能选择叶子结点|
|
||||
|check-active-color |String |#00AAFF |选中状态下,单选框/复选框的颜色|
|
||||
|check-none-color |String |#B8B8B8 |未选中状态下,单选框/复选框的颜色|
|
||||
|comparison |Object |{value : 'value',label : 'label',children:'children'}; |当前项的列名称。 |
|
||||
|
||||
#### **comparison**的值
|
||||
|参数 |类型 |默认值 | 说明 |
|
||||
|:-: |:-: |:-: | :-: |
|
||||
|value |String |value | value值的列名,即选中时单选按钮或复选按钮的值 |
|
||||
|label |String |label | label值的列名,即当前item默认展示的名称 |
|
||||
|children |String |children | children对的列名,即当前item的下一级 |
|
||||
|
||||
### 事件
|
||||
|
||||
|事件名 |说明 |返回值 |
|
||||
|:-: |:-: |:-: |
|
||||
|@change |单选框/复选框值改变时执行方法 |(e , item) |
|
||||
|@clickItem |点击当前选项 |{item , hasChildren} |
|
||||
|
||||
#### **change** 的参数说明
|
||||
|
||||
|参数 |类型 | 说明 |
|
||||
|:-: |:-: | :-: |
|
||||
|e.detail.value |Boolean | 当前项是否选中 |
|
||||
|item |Object | 当前的Item值 |
|
||||
|
||||
#### **clickItem** 的参数说明
|
||||
|
||||
|参数 |类型 | 说明 |
|
||||
|:-: |:-: | :-: |
|
||||
|item |Object | 当前的Item值 |
|
||||
|hasChildren |Boolean | 是否包含子级,即children是否包含对象 |
|
||||
|
||||
### 源码地址
|
||||
|
||||
[代码csdn地址](https://codechina.csdn.net/qq_28624235/luyj-tree-app) <br>
|
||||
[代码github地址](https://github.com/luyanjie00436/luyj-tree-app)
|
||||
140
uni_modules/uni-datetime-picker/changelog.md
Normal file
140
uni_modules/uni-datetime-picker/changelog.md
Normal file
@ -0,0 +1,140 @@
|
||||
## 2.2.24(2023-06-02)
|
||||
- 修复 部分情况修改时间,开始、结束时间显示异常的Bug [详情](https://ask.dcloud.net.cn/question/171146)
|
||||
- 优化 当前月可以选择上月、下月的日期
|
||||
## 2.2.23(2023-05-02)
|
||||
- 修复 部分情况修改时间,开始时间未更新 [详情](https://github.com/dcloudio/uni-ui/issues/737)
|
||||
- 修复 部分平台及设备第一次点击无法显示弹框
|
||||
- 修复 ios 日期格式未补零显示及使用异常 [详情](https://ask.dcloud.net.cn/question/162979)
|
||||
## 2.2.22(2023-03-30)
|
||||
- 修复 日历 picker 修改年月后,自动选中当月1日 [详情](https://ask.dcloud.net.cn/question/165937)
|
||||
- 修复 小程序端 低版本 ios NaN [详情](https://ask.dcloud.net.cn/question/162979)
|
||||
## 2.2.21(2023-02-20)
|
||||
- 修复 firefox 浏览器显示区域点击无法拉起日历弹框的Bug [详情](https://ask.dcloud.net.cn/question/163362)
|
||||
## 2.2.20(2023-02-17)
|
||||
- 优化 值为空依然选中当天问题
|
||||
- 优化 提供 default-value 属性支持配置选择器打开时默认显示的时间
|
||||
- 优化 非范围选择未选择日期时间,点击确认按钮选中当前日期时间
|
||||
- 优化 字节小程序日期时间范围选择,底部日期换行问题
|
||||
## 2.2.19(2023-02-09)
|
||||
- 修复 2.2.18 引起范围选择配置 end 选择无效的Bug [详情](https://github.com/dcloudio/uni-ui/issues/686)
|
||||
## 2.2.18(2023-02-08)
|
||||
- 修复 移动端范围选择change事件触发异常的Bug [详情](https://github.com/dcloudio/uni-ui/issues/684)
|
||||
- 优化 PC端输入日期格式错误时返回当前日期时间
|
||||
- 优化 PC端输入日期时间超出 start、end 限制的Bug
|
||||
- 优化 移动端日期时间范围用法时间展示不完整问题
|
||||
## 2.2.17(2023-02-04)
|
||||
- 修复 小程序端绑定 Date 类型报错的Bug [详情](https://github.com/dcloudio/uni-ui/issues/679)
|
||||
- 修复 vue3 time-picker 无法显示绑定时分秒的Bug
|
||||
## 2.2.16(2023-02-02)
|
||||
- 修复 字节小程序报错的Bug
|
||||
## 2.2.15(2023-02-02)
|
||||
- 修复 某些情况切换月份错误的Bug
|
||||
## 2.2.14(2023-01-30)
|
||||
- 修复 某些情况切换月份错误的Bug [详情](https://ask.dcloud.net.cn/question/162033)
|
||||
## 2.2.13(2023-01-10)
|
||||
- 修复 多次加载组件造成内存占用的Bug
|
||||
## 2.2.12(2022-12-01)
|
||||
- 修复 vue3 下 i18n 国际化初始值不正确的Bug
|
||||
## 2.2.11(2022-09-19)
|
||||
- 修复 支付宝小程序样式错乱的Bug [详情](https://github.com/dcloudio/uni-app/issues/3861)
|
||||
## 2.2.10(2022-09-19)
|
||||
- 修复 反向选择日期范围,日期显示异常的Bug [详情](https://ask.dcloud.net.cn/question/153401?item_id=212892&rf=false)
|
||||
## 2.2.9(2022-09-16)
|
||||
- 可以使用 uni-scss 控制主题色
|
||||
## 2.2.8(2022-09-08)
|
||||
- 修复 close事件无效的Bug
|
||||
## 2.2.7(2022-09-05)
|
||||
- 修复 移动端 maskClick 无效的Bug [详情](https://ask.dcloud.net.cn/question/140824)
|
||||
## 2.2.6(2022-06-30)
|
||||
- 优化 组件样式,调整了组件图标大小、高度、颜色等,与uni-ui风格保持一致
|
||||
## 2.2.5(2022-06-24)
|
||||
- 修复 日历顶部年月及底部确认未国际化的Bug
|
||||
## 2.2.4(2022-03-31)
|
||||
- 修复 Vue3 下动态赋值,单选类型未响应的Bug
|
||||
## 2.2.3(2022-03-28)
|
||||
- 修复 Vue3 下动态赋值未响应的Bug
|
||||
## 2.2.2(2021-12-10)
|
||||
- 修复 clear-icon 属性在小程序平台不生效的Bug
|
||||
## 2.2.1(2021-12-10)
|
||||
- 修复 日期范围选在小程序平台,必须多点击一次才能取消选中状态的Bug
|
||||
## 2.2.0(2021-11-19)
|
||||
- 优化 组件UI,并提供设计资源 [详情](https://uniapp.dcloud.io/component/uniui/resource)
|
||||
- 文档迁移 [https://uniapp.dcloud.io/component/uniui/uni-datetime-picker](https://uniapp.dcloud.io/component/uniui/uni-datetime-picker)
|
||||
## 2.1.5(2021-11-09)
|
||||
- 新增 提供组件设计资源,组件样式调整
|
||||
## 2.1.4(2021-09-10)
|
||||
- 修复 hide-second 在移动端的Bug
|
||||
- 修复 单选赋默认值时,赋值日期未高亮的Bug
|
||||
- 修复 赋默认值时,移动端未正确显示时间的Bug
|
||||
## 2.1.3(2021-09-09)
|
||||
- 新增 hide-second 属性,支持只使用时分,隐藏秒
|
||||
## 2.1.2(2021-09-03)
|
||||
- 优化 取消选中时(范围选)直接开始下一次选择, 避免多点一次
|
||||
- 优化 移动端支持清除按钮,同时支持通过 ref 调用组件的 clear 方法
|
||||
- 优化 调整字号大小,美化日历界面
|
||||
- 修复 因国际化导致的 placeholder 失效的Bug
|
||||
## 2.1.1(2021-08-24)
|
||||
- 新增 支持国际化
|
||||
- 优化 范围选择器在 pc 端过宽的问题
|
||||
## 2.1.0(2021-08-09)
|
||||
- 新增 适配 vue3
|
||||
## 2.0.19(2021-08-09)
|
||||
- 新增 支持作为 uni-forms 子组件相关功能
|
||||
- 修复 在 uni-forms 中使用时,选择时间报 NAN 错误的Bug
|
||||
## 2.0.18(2021-08-05)
|
||||
- 修复 type 属性动态赋值无效的Bug
|
||||
- 修复 ‘确认’按钮被 tabbar 遮盖 bug
|
||||
- 修复 组件未赋值时范围选左、右日历相同的Bug
|
||||
## 2.0.17(2021-08-04)
|
||||
- 修复 范围选未正确显示当前值的Bug
|
||||
- 修复 h5 平台(移动端)报错 'cale' of undefined 的Bug
|
||||
## 2.0.16(2021-07-21)
|
||||
- 新增 return-type 属性支持返回 date 日期对象
|
||||
## 2.0.15(2021-07-14)
|
||||
- 修复 单选日期类型,初始赋值后不在当前日历的Bug
|
||||
- 新增 clearIcon 属性,显示框的清空按钮可配置显示隐藏(仅 pc 有效)
|
||||
- 优化 移动端移除显示框的清空按钮,无实际用途
|
||||
## 2.0.14(2021-07-14)
|
||||
- 修复 组件赋值为空,界面未更新的Bug
|
||||
- 修复 start 和 end 不能动态赋值的Bug
|
||||
- 修复 范围选类型,用户选择后再次选择右侧日历(结束日期)显示不正确的Bug
|
||||
## 2.0.13(2021-07-08)
|
||||
- 修复 范围选择不能动态赋值的Bug
|
||||
## 2.0.12(2021-07-08)
|
||||
- 修复 范围选择的初始时间在一个月内时,造成无法选择的bug
|
||||
## 2.0.11(2021-07-08)
|
||||
- 优化 弹出层在超出视窗边缘定位不准确的问题
|
||||
## 2.0.10(2021-07-08)
|
||||
- 修复 范围起始点样式的背景色与今日样式的字体前景色融合,导致日期字体看不清的Bug
|
||||
- 优化 弹出层在超出视窗边缘被遮盖的问题
|
||||
## 2.0.9(2021-07-07)
|
||||
- 新增 maskClick 事件
|
||||
- 修复 特殊情况日历 rpx 布局错误的Bug,rpx -> px
|
||||
- 修复 范围选择时清空返回值不合理的bug,['', ''] -> []
|
||||
## 2.0.8(2021-07-07)
|
||||
- 新增 日期时间显示框支持插槽
|
||||
## 2.0.7(2021-07-01)
|
||||
- 优化 添加 uni-icons 依赖
|
||||
## 2.0.6(2021-05-22)
|
||||
- 修复 图标在小程序上不显示的Bug
|
||||
- 优化 重命名引用组件,避免潜在组件命名冲突
|
||||
## 2.0.5(2021-05-20)
|
||||
- 优化 代码目录扁平化
|
||||
## 2.0.4(2021-05-12)
|
||||
- 新增 组件示例地址
|
||||
## 2.0.3(2021-05-10)
|
||||
- 修复 ios 下不识别 '-' 日期格式的Bug
|
||||
- 优化 pc 下弹出层添加边框和阴影
|
||||
## 2.0.2(2021-05-08)
|
||||
- 修复 在 admin 中获取弹出层定位错误的bug
|
||||
## 2.0.1(2021-05-08)
|
||||
- 修复 type 属性向下兼容,默认值从 date 变更为 datetime
|
||||
## 2.0.0(2021-04-30)
|
||||
- 支持日历形式的日期+时间的范围选择
|
||||
> 注意:此版本不向后兼容,不再支持单独时间选择(type=time)及相关的 hide-second 属性(时间选可使用内置组件 picker)
|
||||
## 1.0.6(2021-03-18)
|
||||
- 新增 hide-second 属性,时间支持仅选择时、分
|
||||
- 修复 选择跟显示的日期不一样的Bug
|
||||
- 修复 chang事件触发2次的Bug
|
||||
- 修复 分、秒 end 范围错误的Bug
|
||||
- 优化 更好的 nvue 适配
|
||||
@ -0,0 +1,177 @@
|
||||
<template>
|
||||
<view class="uni-calendar-item__weeks-box" :class="{
|
||||
'uni-calendar-item--disable':weeks.disable,
|
||||
'uni-calendar-item--before-checked-x':weeks.beforeMultiple,
|
||||
'uni-calendar-item--multiple': weeks.multiple,
|
||||
'uni-calendar-item--after-checked-x':weeks.afterMultiple,
|
||||
}" @click="choiceDate(weeks)" @mouseenter="handleMousemove(weeks)">
|
||||
<view class="uni-calendar-item__weeks-box-item" :class="{
|
||||
'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && (calendar.userChecked || !checkHover),
|
||||
'uni-calendar-item--checked-range-text': checkHover,
|
||||
'uni-calendar-item--before-checked':weeks.beforeMultiple,
|
||||
'uni-calendar-item--multiple': weeks.multiple,
|
||||
'uni-calendar-item--after-checked':weeks.afterMultiple,
|
||||
'uni-calendar-item--disable':weeks.disable,
|
||||
}">
|
||||
<text v-if="selected && weeks.extraInfo" class="uni-calendar-item__weeks-box-circle"></text>
|
||||
<text class="uni-calendar-item__weeks-box-text uni-calendar-item__weeks-box-text-disable uni-calendar-item--checked-text">{{weeks.date}}</text>
|
||||
</view>
|
||||
<view :class="{'uni-calendar-item--today': weeks.isToday}"></view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
weeks: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
calendar: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
selected: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
},
|
||||
checkHover: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
choiceDate(weeks) {
|
||||
this.$emit('change', weeks)
|
||||
},
|
||||
handleMousemove(weeks) {
|
||||
this.$emit('handleMouse', weeks)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" >
|
||||
$uni-primary: #009C77 !default;
|
||||
|
||||
.uni-calendar-item__weeks-box {
|
||||
flex: 1;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 1px 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.uni-calendar-item__weeks-box-text {
|
||||
font-size: 14px;
|
||||
// font-family: Lato-Bold, Lato;
|
||||
font-weight: bold;
|
||||
color: darken($color: $uni-primary, $amount: 40%);
|
||||
}
|
||||
|
||||
.uni-calendar-item__weeks-box-item {
|
||||
position: relative;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
/* #ifdef H5 */
|
||||
cursor: pointer;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
|
||||
.uni-calendar-item__weeks-box-circle {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 8px;
|
||||
background-color: #dd524d;
|
||||
|
||||
}
|
||||
|
||||
.uni-calendar-item__weeks-box .uni-calendar-item--disable {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.uni-calendar-item--disable .uni-calendar-item__weeks-box-text-disable {
|
||||
color: #D1D1D1;
|
||||
}
|
||||
|
||||
.uni-calendar-item--today {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 17%;
|
||||
background-color: #dd524d;
|
||||
width:6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.uni-calendar-item--extra {
|
||||
color: #dd524d;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.uni-calendar-item__weeks-box .uni-calendar-item--checked {
|
||||
background-color: $uni-primary;
|
||||
border-radius: 50%;
|
||||
box-sizing: border-box;
|
||||
border: 3px solid #fff;
|
||||
}
|
||||
|
||||
.uni-calendar-item--checked .uni-calendar-item--checked-text {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.uni-calendar-item--multiple .uni-calendar-item--checked-range-text {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.uni-calendar-item--multiple {
|
||||
background-color: #F6F7FC;
|
||||
// color: #fff;
|
||||
}
|
||||
|
||||
.uni-calendar-item--multiple .uni-calendar-item--before-checked,
|
||||
.uni-calendar-item--multiple .uni-calendar-item--after-checked {
|
||||
background-color: $uni-primary;
|
||||
border-radius: 50%;
|
||||
box-sizing: border-box;
|
||||
border: 3px solid #F6F7FC;
|
||||
}
|
||||
|
||||
.uni-calendar-item--before-checked .uni-calendar-item--checked-text,
|
||||
.uni-calendar-item--after-checked .uni-calendar-item--checked-text {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.uni-calendar-item--before-checked-x {
|
||||
border-top-left-radius: 50px;
|
||||
border-bottom-left-radius: 50px;
|
||||
box-sizing: border-box;
|
||||
background-color: #F6F7FC;
|
||||
}
|
||||
|
||||
.uni-calendar-item--after-checked-x {
|
||||
border-top-right-radius: 50px;
|
||||
border-bottom-right-radius: 50px;
|
||||
background-color: #F6F7FC;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,931 @@
|
||||
<template>
|
||||
<view class="uni-calendar" @mouseleave="leaveCale">
|
||||
|
||||
<view v-if="!insert && show" class="uni-calendar__mask" :class="{'uni-calendar--mask-show':aniMaskShow}"
|
||||
@click="maskClick"></view>
|
||||
|
||||
<view v-if="insert || show" class="uni-calendar__content"
|
||||
:class="{'uni-calendar--fixed':!insert,'uni-calendar--ani-show':aniMaskShow, 'uni-calendar__content-mobile': aniMaskShow}">
|
||||
<view class="uni-calendar__header" :class="{'uni-calendar__header-mobile' :!insert}">
|
||||
|
||||
<view class="uni-calendar__header-btn-box" @click.stop="changeMonth('pre')">
|
||||
<view class="uni-calendar__header-btn uni-calendar--left"></view>
|
||||
</view>
|
||||
|
||||
<picker mode="date" :value="date" fields="month" @change="bindDateChange">
|
||||
<text
|
||||
class="uni-calendar__header-text">{{ (nowDate.year||'') + yearText + ( nowDate.month||'') + monthText}}</text>
|
||||
</picker>
|
||||
|
||||
<view class="uni-calendar__header-btn-box" @click.stop="changeMonth('next')">
|
||||
<view class="uni-calendar__header-btn uni-calendar--right"></view>
|
||||
</view>
|
||||
|
||||
<view v-if="!insert" class="dialog-close" @click="close">
|
||||
<view class="dialog-close-plus" data-id="close"></view>
|
||||
<view class="dialog-close-plus dialog-close-rotate" data-id="close"></view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="uni-calendar__box">
|
||||
|
||||
<view v-if="showMonth" class="uni-calendar__box-bg">
|
||||
<text class="uni-calendar__box-bg-text">{{nowDate.month}}</text>
|
||||
</view>
|
||||
|
||||
<view class="uni-calendar__weeks" style="padding-bottom: 7px;">
|
||||
<view class="uni-calendar__weeks-day">
|
||||
<text class="uni-calendar__weeks-day-text">{{SUNText}}</text>
|
||||
</view>
|
||||
<view class="uni-calendar__weeks-day">
|
||||
<text class="uni-calendar__weeks-day-text">{{MONText}}</text>
|
||||
</view>
|
||||
<view class="uni-calendar__weeks-day">
|
||||
<text class="uni-calendar__weeks-day-text">{{TUEText}}</text>
|
||||
</view>
|
||||
<view class="uni-calendar__weeks-day">
|
||||
<text class="uni-calendar__weeks-day-text">{{WEDText}}</text>
|
||||
</view>
|
||||
<view class="uni-calendar__weeks-day">
|
||||
<text class="uni-calendar__weeks-day-text">{{THUText}}</text>
|
||||
</view>
|
||||
<view class="uni-calendar__weeks-day">
|
||||
<text class="uni-calendar__weeks-day-text">{{FRIText}}</text>
|
||||
</view>
|
||||
<view class="uni-calendar__weeks-day">
|
||||
<text class="uni-calendar__weeks-day-text">{{SATText}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="uni-calendar__weeks" v-for="(item,weekIndex) in weeks" :key="weekIndex">
|
||||
<view class="uni-calendar__weeks-item" v-for="(weeks,weeksIndex) in item" :key="weeksIndex">
|
||||
<calendar-item class="uni-calendar-item--hook" :weeks="weeks" :calendar="calendar"
|
||||
:selected="selected" :checkHover="range" @change="choiceDate"
|
||||
@handleMouse="handleMouse">
|
||||
</calendar-item>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="!insert && !range && hasTime" class="uni-date-changed uni-calendar--fixed-top"
|
||||
style="padding: 0 80px;">
|
||||
<view class="uni-date-changed--time-date">{{tempSingleDate ? tempSingleDate : selectDateText}}</view>
|
||||
<time-picker type="time" :start="timepickerStartTime" :end="timepickerEndTime" v-model="time"
|
||||
:disabled="!tempSingleDate" :border="false" :hide-second="hideSecond" class="time-picker-style">
|
||||
</time-picker>
|
||||
</view>
|
||||
|
||||
<view v-if="!insert && range && hasTime" class="uni-date-changed uni-calendar--fixed-top">
|
||||
<view class="uni-date-changed--time-start">
|
||||
<view class="uni-date-changed--time-date">{{tempRange.before ? tempRange.before : startDateText}}
|
||||
</view>
|
||||
<time-picker type="time" :start="timepickerStartTime" v-model="timeRange.startTime" :border="false"
|
||||
:hide-second="hideSecond" :disabled="!tempRange.before" class="time-picker-style">
|
||||
</time-picker>
|
||||
</view>
|
||||
<view style="line-height: 50px;">
|
||||
<!-- <uni-icons type="arrowthinright" color="#999"></uni-icons> -->
|
||||
<u-icon name="arrow-right" color="#999!important" ></u-icon>
|
||||
</view>
|
||||
<view class="uni-date-changed--time-end">
|
||||
<view class="uni-date-changed--time-date">{{tempRange.after ? tempRange.after : endDateText}}</view>
|
||||
<time-picker type="time" :end="timepickerEndTime" v-model="timeRange.endTime" :border="false"
|
||||
:hide-second="hideSecond" :disabled="!tempRange.after" class="time-picker-style">
|
||||
</time-picker>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="!insert" class="uni-date-changed uni-date-btn--ok">
|
||||
<view class="uni-datetime-picker--btn" @click="confirm">{{confirmText}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Calendar, getDate, getTime } from './util.js';
|
||||
import calendarItem from './calendar-item.vue'
|
||||
import timePicker from './time-picker.vue'
|
||||
|
||||
import { initVueI18n } from '@dcloudio/uni-i18n'
|
||||
import i18nMessages from './i18n/index.js'
|
||||
const { t } = initVueI18n(i18nMessages)
|
||||
|
||||
/**
|
||||
* Calendar 日历
|
||||
* @description 日历组件可以查看日期,选择任意范围内的日期,打点操作。常用场景如:酒店日期预订、火车机票选择购买日期、上下班打卡等
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=56
|
||||
* @property {String} date 自定义当前时间,默认为今天
|
||||
* @property {String} startDate 日期选择范围-开始日期
|
||||
* @property {String} endDate 日期选择范围-结束日期
|
||||
* @property {Boolean} range 范围选择
|
||||
* @property {Boolean} insert = [true|false] 插入模式,默认为false
|
||||
* @value true 弹窗模式
|
||||
* @value false 插入模式
|
||||
* @property {Boolean} clearDate = [true|false] 弹窗模式是否清空上次选择内容
|
||||
* @property {Array} selected 打点,期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}]
|
||||
* @property {Boolean} showMonth 是否选择月份为背景
|
||||
* @property {[String} defaultValue 选择器打开时默认显示的时间
|
||||
* @event {Function} change 日期改变,`insert :ture` 时生效
|
||||
* @event {Function} confirm 确认选择`insert :false` 时生效
|
||||
* @event {Function} monthSwitch 切换月份时触发
|
||||
* @example <uni-calendar :insert="true" :start-date="'2019-3-2'":end-date="'2019-5-20'"@change="change" />
|
||||
*/
|
||||
export default {
|
||||
components: {
|
||||
calendarItem,
|
||||
timePicker
|
||||
},
|
||||
props: {
|
||||
date: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
defTime: {
|
||||
type: [String, Object],
|
||||
default: ''
|
||||
},
|
||||
selectableTimes: {
|
||||
type: [Object],
|
||||
default () {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
selected: {
|
||||
type: Array,
|
||||
default () {
|
||||
return []
|
||||
}
|
||||
},
|
||||
startDate: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
endDate: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
startPlaceholder: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
endPlaceholder: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
range: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
hasTime: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
insert: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
showMonth: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
clearDate: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
checkHover: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
hideSecond: {
|
||||
type: [Boolean],
|
||||
default: false
|
||||
},
|
||||
pleStatus: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {
|
||||
before: '',
|
||||
after: '',
|
||||
data: [],
|
||||
fulldate: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
defaultValue: {
|
||||
type: [String, Object, Array],
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
show: false,
|
||||
weeks: [],
|
||||
calendar: {},
|
||||
nowDate: {},
|
||||
aniMaskShow: false,
|
||||
firstEnter: true,
|
||||
time: '',
|
||||
timeRange: {
|
||||
startTime: '',
|
||||
endTime: ''
|
||||
},
|
||||
tempSingleDate: '',
|
||||
tempRange: {
|
||||
before: '',
|
||||
after: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
date: {
|
||||
immediate: true,
|
||||
handler(newVal) {
|
||||
if (!this.range) {
|
||||
this.tempSingleDate = newVal
|
||||
setTimeout(() => {
|
||||
this.init(newVal)
|
||||
}, 100)
|
||||
}
|
||||
}
|
||||
},
|
||||
defTime: {
|
||||
immediate: true,
|
||||
handler(newVal) {
|
||||
if (!this.range) {
|
||||
this.time = newVal
|
||||
} else {
|
||||
this.timeRange.startTime = newVal.start
|
||||
this.timeRange.endTime = newVal.end
|
||||
}
|
||||
}
|
||||
},
|
||||
startDate(val) {
|
||||
// 字节小程序 watch 早于 created
|
||||
if(!this.cale){
|
||||
return
|
||||
}
|
||||
this.cale.setStartDate(val)
|
||||
this.cale.setDate(this.nowDate.fullDate)
|
||||
this.weeks = this.cale.weeks
|
||||
},
|
||||
endDate(val) {
|
||||
// 字节小程序 watch 早于 created
|
||||
if(!this.cale){
|
||||
return
|
||||
}
|
||||
this.cale.setEndDate(val)
|
||||
this.cale.setDate(this.nowDate.fullDate)
|
||||
this.weeks = this.cale.weeks
|
||||
},
|
||||
selected(newVal) {
|
||||
// 字节小程序 watch 早于 created
|
||||
if(!this.cale){
|
||||
return
|
||||
}
|
||||
this.cale.setSelectInfo(this.nowDate.fullDate, newVal)
|
||||
this.weeks = this.cale.weeks
|
||||
},
|
||||
pleStatus: {
|
||||
immediate: true,
|
||||
handler(newVal) {
|
||||
const {
|
||||
before,
|
||||
after,
|
||||
fulldate,
|
||||
which
|
||||
} = newVal
|
||||
this.tempRange.before = before
|
||||
this.tempRange.after = after
|
||||
setTimeout(() => {
|
||||
if (fulldate) {
|
||||
this.cale.setHoverMultiple(fulldate)
|
||||
if (before && after) {
|
||||
this.cale.lastHover = true
|
||||
if (this.rangeWithinMonth(after, before)) return
|
||||
this.setDate(before)
|
||||
} else {
|
||||
this.cale.setMultiple(fulldate)
|
||||
this.setDate(this.nowDate.fullDate)
|
||||
this.calendar.fullDate = ''
|
||||
this.cale.lastHover = false
|
||||
}
|
||||
} else {
|
||||
// 字节小程序 watch 早于 created
|
||||
if(!this.cale){
|
||||
return
|
||||
}
|
||||
|
||||
this.cale.setDefaultMultiple(before, after)
|
||||
if (which === 'left' && before) {
|
||||
this.setDate(before)
|
||||
this.weeks = this.cale.weeks
|
||||
} else if(after) {
|
||||
this.setDate(after)
|
||||
this.weeks = this.cale.weeks
|
||||
}
|
||||
this.cale.lastHover = true
|
||||
}
|
||||
}, 16)
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
timepickerStartTime() {
|
||||
const activeDate = this.range ? this.tempRange.before : this.calendar.fullDate
|
||||
return activeDate === this.startDate ? this.selectableTimes.start : ''
|
||||
},
|
||||
timepickerEndTime() {
|
||||
const activeDate = this.range ? this.tempRange.after : this.calendar.fullDate
|
||||
return activeDate === this.endDate ? this.selectableTimes.end : ''
|
||||
},
|
||||
/**
|
||||
* for i18n
|
||||
*/
|
||||
selectDateText() {
|
||||
return t("uni-datetime-picker.selectDate")
|
||||
},
|
||||
startDateText() {
|
||||
return this.startPlaceholder || t("uni-datetime-picker.startDate")
|
||||
},
|
||||
endDateText() {
|
||||
return this.endPlaceholder || t("uni-datetime-picker.endDate")
|
||||
},
|
||||
okText() {
|
||||
return t("uni-datetime-picker.ok")
|
||||
},
|
||||
yearText() {
|
||||
return t("uni-datetime-picker.year")
|
||||
},
|
||||
monthText() {
|
||||
return t("uni-datetime-picker.month")
|
||||
},
|
||||
MONText() {
|
||||
return t("uni-calender.MON")
|
||||
},
|
||||
TUEText() {
|
||||
return t("uni-calender.TUE")
|
||||
},
|
||||
WEDText() {
|
||||
return t("uni-calender.WED")
|
||||
},
|
||||
THUText() {
|
||||
return t("uni-calender.THU")
|
||||
},
|
||||
FRIText() {
|
||||
return t("uni-calender.FRI")
|
||||
},
|
||||
SATText() {
|
||||
return t("uni-calender.SAT")
|
||||
},
|
||||
SUNText() {
|
||||
return t("uni-calender.SUN")
|
||||
},
|
||||
confirmText() {
|
||||
return t("uni-calender.confirm")
|
||||
},
|
||||
},
|
||||
created() {
|
||||
// 获取日历方法实例
|
||||
this.cale = new Calendar({
|
||||
selected: this.selected,
|
||||
startDate: this.startDate,
|
||||
endDate: this.endDate,
|
||||
range: this.range,
|
||||
})
|
||||
// 选中某一天
|
||||
this.init(this.date)
|
||||
},
|
||||
methods: {
|
||||
leaveCale() {
|
||||
this.firstEnter = true
|
||||
},
|
||||
handleMouse(weeks) {
|
||||
if (weeks.disable) return
|
||||
if (this.cale.lastHover) return
|
||||
let {
|
||||
before,
|
||||
after
|
||||
} = this.cale.multipleStatus
|
||||
if (!before) return
|
||||
this.calendar = weeks
|
||||
// 设置范围选
|
||||
this.cale.setHoverMultiple(this.calendar.fullDate)
|
||||
this.weeks = this.cale.weeks
|
||||
// hover时,进入一个日历,更新另一个
|
||||
if (this.firstEnter) {
|
||||
this.$emit('firstEnterCale', this.cale.multipleStatus)
|
||||
this.firstEnter = false
|
||||
}
|
||||
},
|
||||
rangeWithinMonth(A, B) {
|
||||
const [yearA, monthA] = A.split('-')
|
||||
const [yearB, monthB] = B.split('-')
|
||||
return yearA === yearB && monthA === monthB
|
||||
},
|
||||
// 蒙版点击事件
|
||||
maskClick() {
|
||||
this.close()
|
||||
this.$emit('maskClose')
|
||||
},
|
||||
|
||||
clearCalender() {
|
||||
if (this.range) {
|
||||
this.timeRange.startTime = ''
|
||||
this.timeRange.endTime = ''
|
||||
this.tempRange.before = ''
|
||||
this.tempRange.after = ''
|
||||
this.cale.multipleStatus.before = ''
|
||||
this.cale.multipleStatus.after = ''
|
||||
this.cale.multipleStatus.data = []
|
||||
this.cale.lastHover = false
|
||||
} else {
|
||||
this.time = ''
|
||||
this.tempSingleDate = ''
|
||||
}
|
||||
this.calendar.fullDate = ''
|
||||
this.setDate(new Date())
|
||||
},
|
||||
|
||||
bindDateChange(e) {
|
||||
const value = e.detail.value + '-1'
|
||||
this.setDate(value)
|
||||
},
|
||||
/**
|
||||
* 初始化日期显示
|
||||
* @param {Object} date
|
||||
*/
|
||||
init(date) {
|
||||
// 字节小程序 watch 早于 created
|
||||
if(!this.cale){
|
||||
return
|
||||
}
|
||||
this.cale.setDate(date || new Date())
|
||||
this.weeks = this.cale.weeks
|
||||
this.nowDate = this.cale.getInfo(date)
|
||||
this.calendar = {...this.nowDate}
|
||||
if(!date){
|
||||
// 优化date为空默认不选中今天
|
||||
this.calendar.fullDate = ''
|
||||
if(this.defaultValue && !this.range){
|
||||
// 暂时只支持移动端非范围选择
|
||||
const defaultDate = new Date(this.defaultValue)
|
||||
const fullDate = getDate(defaultDate)
|
||||
const year = defaultDate.getFullYear()
|
||||
const month = defaultDate.getMonth()+1
|
||||
const date = defaultDate.getDate()
|
||||
const day = defaultDate.getDay()
|
||||
this.calendar = {
|
||||
fullDate,
|
||||
year,
|
||||
month,
|
||||
date,
|
||||
day
|
||||
},
|
||||
this.tempSingleDate = fullDate
|
||||
this.time = getTime(defaultDate, this.hideSecond)
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 打开日历弹窗
|
||||
*/
|
||||
open() {
|
||||
// 弹窗模式并且清理数据
|
||||
if (this.clearDate && !this.insert) {
|
||||
this.cale.cleanMultipleStatus()
|
||||
this.init(this.date)
|
||||
}
|
||||
this.show = true
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.aniMaskShow = true
|
||||
}, 50)
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 关闭日历弹窗
|
||||
*/
|
||||
close() {
|
||||
this.aniMaskShow = false
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.show = false
|
||||
this.$emit('close')
|
||||
}, 300)
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
confirm() {
|
||||
this.setEmit('confirm')
|
||||
this.close()
|
||||
},
|
||||
/**
|
||||
* 变化触发
|
||||
*/
|
||||
change() {
|
||||
if (!this.insert) return
|
||||
this.setEmit('change')
|
||||
},
|
||||
/**
|
||||
* 选择月份触发
|
||||
*/
|
||||
monthSwitch() {
|
||||
let {
|
||||
year,
|
||||
month
|
||||
} = this.nowDate
|
||||
this.$emit('monthSwitch', {
|
||||
year,
|
||||
month: Number(month)
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 派发事件
|
||||
* @param {Object} name
|
||||
*/
|
||||
setEmit(name) {
|
||||
if(!this.range){
|
||||
if(!this.calendar.fullDate){
|
||||
this.calendar = this.cale.getInfo(new Date())
|
||||
this.tempSingleDate = this.calendar.fullDate
|
||||
}
|
||||
if(this.hasTime && !this.time) {
|
||||
this.time = getTime(new Date(), this.hideSecond)
|
||||
}
|
||||
}
|
||||
let {
|
||||
year,
|
||||
month,
|
||||
date,
|
||||
fullDate,
|
||||
extraInfo
|
||||
} = this.calendar
|
||||
this.$emit(name, {
|
||||
range: this.cale.multipleStatus,
|
||||
year,
|
||||
month,
|
||||
date,
|
||||
time: this.time,
|
||||
timeRange: this.timeRange,
|
||||
fulldate: fullDate,
|
||||
extraInfo: extraInfo || {}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 选择天触发
|
||||
* @param {Object} weeks
|
||||
*/
|
||||
choiceDate(weeks) {
|
||||
if (weeks.disable) return
|
||||
this.calendar = weeks
|
||||
this.calendar.userChecked = true
|
||||
// 设置多选
|
||||
this.cale.setMultiple(this.calendar.fullDate, true)
|
||||
this.weeks = this.cale.weeks
|
||||
this.tempSingleDate = this.calendar.fullDate
|
||||
const beforeDate = new Date(this.cale.multipleStatus.before).getTime()
|
||||
const afterDate = new Date(this.cale.multipleStatus.after).getTime()
|
||||
// 如果先选择结束日期,后选择开始日期,需要交换
|
||||
if (beforeDate > afterDate && afterDate) {
|
||||
this.tempRange.before = this.cale.multipleStatus.after
|
||||
this.tempRange.after = this.cale.multipleStatus.before
|
||||
} else {
|
||||
this.tempRange.before = this.cale.multipleStatus.before
|
||||
this.tempRange.after = this.cale.multipleStatus.after
|
||||
}
|
||||
this.change()
|
||||
},
|
||||
changeMonth(type) {
|
||||
let newDate
|
||||
if(type === 'pre') {
|
||||
newDate = this.cale.getPreMonthObj(this.nowDate.fullDate).fullDate
|
||||
} else if(type === 'next') {
|
||||
newDate = this.cale.getNextMonthObj(this.nowDate.fullDate).fullDate
|
||||
}
|
||||
|
||||
this.setDate(newDate)
|
||||
this.monthSwitch()
|
||||
},
|
||||
/**
|
||||
* 设置日期
|
||||
* @param {Object} date
|
||||
*/
|
||||
setDate(date) {
|
||||
this.cale.setDate(date)
|
||||
this.weeks = this.cale.weeks
|
||||
this.nowDate = this.cale.getInfo(date)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" >
|
||||
$uni-primary: #009C77 !default;
|
||||
|
||||
.uni-calendar {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.uni-calendar__mask {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
transition-property: opacity;
|
||||
transition-duration: 0.3s;
|
||||
opacity: 0;
|
||||
/* #ifndef APP-NVUE */
|
||||
z-index: 99;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-calendar--mask-show {
|
||||
opacity: 1
|
||||
}
|
||||
|
||||
.uni-calendar--fixed {
|
||||
position: fixed;
|
||||
bottom: calc(var(--window-bottom));
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom:0;
|
||||
transition-property: transform;
|
||||
transition-duration: 0.3s;
|
||||
transform: translateY(460px);
|
||||
/* #ifndef APP-NVUE */
|
||||
z-index: 99;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-calendar--ani-show {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.uni-calendar__content {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.uni-calendar__content-mobile {
|
||||
border-top-left-radius: 10px;
|
||||
border-top-right-radius: 10px;
|
||||
box-shadow: 0px 0px 5px 3px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.uni-calendar__header {
|
||||
position: relative;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.uni-calendar__header-mobile {
|
||||
padding: 10px;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.uni-calendar--fixed-top {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
border-top-color: rgba(0, 0, 0, 0.4);
|
||||
border-top-style: solid;
|
||||
border-top-width: 1px;
|
||||
}
|
||||
|
||||
.uni-calendar--fixed-width {
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.uni-calendar__backtoday {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 25rpx;
|
||||
padding: 0 5px;
|
||||
padding-left: 10px;
|
||||
height: 25px;
|
||||
line-height: 25px;
|
||||
font-size: 12px;
|
||||
border-top-left-radius: 25px;
|
||||
border-bottom-left-radius: 25px;
|
||||
color: #fff;
|
||||
background-color: #f1f1f1;
|
||||
}
|
||||
|
||||
.uni-calendar__header-text {
|
||||
text-align: center;
|
||||
width: 100px;
|
||||
font-size: 15px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.uni-calendar__button-text {
|
||||
text-align: center;
|
||||
width: 100px;
|
||||
font-size: 14px;
|
||||
color: $uni-primary;
|
||||
/* #ifndef APP-NVUE */
|
||||
letter-spacing: 3px;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-calendar__header-btn-box {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.uni-calendar__header-btn {
|
||||
width: 9px;
|
||||
height: 9px;
|
||||
border-left-color: #808080;
|
||||
border-left-style: solid;
|
||||
border-left-width: 1px;
|
||||
border-top-color: #555555;
|
||||
border-top-style: solid;
|
||||
border-top-width: 1px;
|
||||
}
|
||||
|
||||
.uni-calendar--left {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.uni-calendar--right {
|
||||
transform: rotate(135deg);
|
||||
}
|
||||
|
||||
|
||||
.uni-calendar__weeks {
|
||||
position: relative;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.uni-calendar__weeks-item {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.uni-calendar__weeks-day {
|
||||
flex: 1;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 40px;
|
||||
border-bottom-color: #F5F5F5;
|
||||
border-bottom-style: solid;
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
|
||||
.uni-calendar__weeks-day-text {
|
||||
font-size: 12px;
|
||||
color: #B2B2B2;
|
||||
}
|
||||
|
||||
.uni-calendar__box {
|
||||
position: relative;
|
||||
// padding: 0 10px;
|
||||
padding-bottom: 7px;
|
||||
}
|
||||
|
||||
.uni-calendar__box-bg {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.uni-calendar__box-bg-text {
|
||||
font-size: 200px;
|
||||
font-weight: bold;
|
||||
color: #999;
|
||||
opacity: 0.1;
|
||||
text-align: center;
|
||||
/* #ifndef APP-NVUE */
|
||||
line-height: 1;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-date-changed {
|
||||
padding: 0 10px;
|
||||
// line-height: 50px;
|
||||
text-align: center;
|
||||
color: #333;
|
||||
border-top-color: #DCDCDC;
|
||||
;
|
||||
border-top-style: solid;
|
||||
border-top-width: 1px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.uni-date-btn--ok {
|
||||
padding: 20px 15px;
|
||||
}
|
||||
|
||||
.uni-date-changed--time-start {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.uni-date-changed--time-end {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.uni-date-changed--time-date {
|
||||
color: #999;
|
||||
line-height: 50px;
|
||||
/* #ifdef MP-TOUTIAO */
|
||||
font-size: 16px;
|
||||
/* #endif */
|
||||
margin-right: 5px;
|
||||
// opacity: 0.6;
|
||||
}
|
||||
|
||||
.time-picker-style {
|
||||
// width: 62px;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
justify-content: center;
|
||||
align-items: center
|
||||
}
|
||||
|
||||
.mr-10 {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.dialog-close {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 0 25px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.dialog-close-plus {
|
||||
width: 16px;
|
||||
height: 2px;
|
||||
background-color: #737987;
|
||||
border-radius: 2px;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.dialog-close-rotate {
|
||||
position: absolute;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.uni-datetime-picker--btn {
|
||||
border-radius: 100px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
background-color: $uni-primary;
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
|
||||
/* #ifndef APP-NVUE */
|
||||
.uni-datetime-picker--btn:active {
|
||||
opacity: 0.7;
|
||||
}
|
||||
/* #endif */
|
||||
</style>
|
||||
@ -0,0 +1,22 @@
|
||||
{
|
||||
"uni-datetime-picker.selectDate": "select date",
|
||||
"uni-datetime-picker.selectTime": "select time",
|
||||
"uni-datetime-picker.selectDateTime": "select date and time",
|
||||
"uni-datetime-picker.startDate": "start date",
|
||||
"uni-datetime-picker.endDate": "end date",
|
||||
"uni-datetime-picker.startTime": "start time",
|
||||
"uni-datetime-picker.endTime": "end time",
|
||||
"uni-datetime-picker.ok": "ok",
|
||||
"uni-datetime-picker.clear": "clear",
|
||||
"uni-datetime-picker.cancel": "cancel",
|
||||
"uni-datetime-picker.year": "-",
|
||||
"uni-datetime-picker.month": "",
|
||||
"uni-calender.MON": "MON",
|
||||
"uni-calender.TUE": "TUE",
|
||||
"uni-calender.WED": "WED",
|
||||
"uni-calender.THU": "THU",
|
||||
"uni-calender.FRI": "FRI",
|
||||
"uni-calender.SAT": "SAT",
|
||||
"uni-calender.SUN": "SUN",
|
||||
"uni-calender.confirm": "confirm"
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
import en from './en.json'
|
||||
import zhHans from './zh-Hans.json'
|
||||
import zhHant from './zh-Hant.json'
|
||||
export default {
|
||||
en,
|
||||
'zh-Hans': zhHans,
|
||||
'zh-Hant': zhHant
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
{
|
||||
"uni-datetime-picker.selectDate": "选择日期",
|
||||
"uni-datetime-picker.selectTime": "选择时间",
|
||||
"uni-datetime-picker.selectDateTime": "选择日期时间",
|
||||
"uni-datetime-picker.startDate": "开始日期",
|
||||
"uni-datetime-picker.endDate": "结束日期",
|
||||
"uni-datetime-picker.startTime": "开始时间",
|
||||
"uni-datetime-picker.endTime": "结束时间",
|
||||
"uni-datetime-picker.ok": "确定",
|
||||
"uni-datetime-picker.clear": "清除",
|
||||
"uni-datetime-picker.cancel": "取消",
|
||||
"uni-datetime-picker.year": "年",
|
||||
"uni-datetime-picker.month": "月",
|
||||
"uni-calender.SUN": "日",
|
||||
"uni-calender.MON": "一",
|
||||
"uni-calender.TUE": "二",
|
||||
"uni-calender.WED": "三",
|
||||
"uni-calender.THU": "四",
|
||||
"uni-calender.FRI": "五",
|
||||
"uni-calender.SAT": "六",
|
||||
"uni-calender.confirm": "确认"
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
{
|
||||
"uni-datetime-picker.selectDate": "選擇日期",
|
||||
"uni-datetime-picker.selectTime": "選擇時間",
|
||||
"uni-datetime-picker.selectDateTime": "選擇日期時間",
|
||||
"uni-datetime-picker.startDate": "開始日期",
|
||||
"uni-datetime-picker.endDate": "結束日期",
|
||||
"uni-datetime-picker.startTime": "開始时间",
|
||||
"uni-datetime-picker.endTime": "結束时间",
|
||||
"uni-datetime-picker.ok": "確定",
|
||||
"uni-datetime-picker.clear": "清除",
|
||||
"uni-datetime-picker.cancel": "取消",
|
||||
"uni-datetime-picker.year": "年",
|
||||
"uni-datetime-picker.month": "月",
|
||||
"uni-calender.SUN": "日",
|
||||
"uni-calender.MON": "一",
|
||||
"uni-calender.TUE": "二",
|
||||
"uni-calender.WED": "三",
|
||||
"uni-calender.THU": "四",
|
||||
"uni-calender.FRI": "五",
|
||||
"uni-calender.SAT": "六",
|
||||
"uni-calender.confirm": "確認"
|
||||
}
|
||||
@ -0,0 +1,934 @@
|
||||
<template>
|
||||
<view class="uni-datetime-picker">
|
||||
<view @click="initTimePicker">
|
||||
<slot>
|
||||
<view class="uni-datetime-picker-timebox-pointer"
|
||||
:class="{'uni-datetime-picker-disabled': disabled, 'uni-datetime-picker-timebox': border}">
|
||||
<text class="uni-datetime-picker-text">{{time}}</text>
|
||||
<view v-if="!time" class="uni-datetime-picker-time">
|
||||
<text class="uni-datetime-picker-text">{{selectTimeText}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</slot>
|
||||
</view>
|
||||
<view v-if="visible" id="mask" class="uni-datetime-picker-mask" @click="tiggerTimePicker"></view>
|
||||
<view v-if="visible" class="uni-datetime-picker-popup" :class="[dateShow && timeShow ? '' : 'fix-nvue-height']"
|
||||
:style="fixNvueBug">
|
||||
<view class="uni-title">
|
||||
<text class="uni-datetime-picker-text">{{selectTimeText}}</text>
|
||||
</view>
|
||||
<view v-if="dateShow" class="uni-datetime-picker__container-box">
|
||||
<picker-view class="uni-datetime-picker-view" :indicator-style="indicatorStyle" :value="ymd"
|
||||
@change="bindDateChange">
|
||||
<picker-view-column>
|
||||
<view class="uni-datetime-picker-item" v-for="(item,index) in years" :key="index">
|
||||
<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
|
||||
</view>
|
||||
</picker-view-column>
|
||||
<picker-view-column>
|
||||
<view class="uni-datetime-picker-item" v-for="(item,index) in months" :key="index">
|
||||
<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
|
||||
</view>
|
||||
</picker-view-column>
|
||||
<picker-view-column>
|
||||
<view class="uni-datetime-picker-item" v-for="(item,index) in days" :key="index">
|
||||
<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
|
||||
</view>
|
||||
</picker-view-column>
|
||||
</picker-view>
|
||||
<!-- 兼容 nvue 不支持伪类 -->
|
||||
<text class="uni-datetime-picker-sign sign-left">-</text>
|
||||
<text class="uni-datetime-picker-sign sign-right">-</text>
|
||||
</view>
|
||||
<view v-if="timeShow" class="uni-datetime-picker__container-box">
|
||||
<picker-view class="uni-datetime-picker-view" :class="[hideSecond ? 'time-hide-second' : '']"
|
||||
:indicator-style="indicatorStyle" :value="hms" @change="bindTimeChange">
|
||||
<picker-view-column>
|
||||
<view class="uni-datetime-picker-item" v-for="(item,index) in hours" :key="index">
|
||||
<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
|
||||
</view>
|
||||
</picker-view-column>
|
||||
<picker-view-column>
|
||||
<view class="uni-datetime-picker-item" v-for="(item,index) in minutes" :key="index">
|
||||
<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
|
||||
</view>
|
||||
</picker-view-column>
|
||||
<picker-view-column v-if="!hideSecond">
|
||||
<view class="uni-datetime-picker-item" v-for="(item,index) in seconds" :key="index">
|
||||
<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
|
||||
</view>
|
||||
</picker-view-column>
|
||||
</picker-view>
|
||||
<!-- 兼容 nvue 不支持伪类 -->
|
||||
<text class="uni-datetime-picker-sign" :class="[hideSecond ? 'sign-center' : 'sign-left']">:</text>
|
||||
<text v-if="!hideSecond" class="uni-datetime-picker-sign sign-right">:</text>
|
||||
</view>
|
||||
<view class="uni-datetime-picker-btn">
|
||||
<view @click="clearTime">
|
||||
<text class="uni-datetime-picker-btn-text">{{clearText}}</text>
|
||||
</view>
|
||||
<view class="uni-datetime-picker-btn-group">
|
||||
<view class="uni-datetime-picker-cancel" @click="tiggerTimePicker">
|
||||
<text class="uni-datetime-picker-btn-text">{{cancelText}}</text>
|
||||
</view>
|
||||
<view @click="setTime">
|
||||
<text class="uni-datetime-picker-btn-text">{{okText}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { initVueI18n } from '@dcloudio/uni-i18n'
|
||||
import i18nMessages from './i18n/index.js'
|
||||
const { t } = initVueI18n(i18nMessages)
|
||||
import { fixIosDateFormat } from './util'
|
||||
|
||||
/**
|
||||
* DatetimePicker 时间选择器
|
||||
* @description 可以同时选择日期和时间的选择器
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=xxx
|
||||
* @property {String} type = [datetime | date | time] 显示模式
|
||||
* @property {Boolean} multiple = [true|false] 是否多选
|
||||
* @property {String|Number} value 默认值
|
||||
* @property {String|Number} start 起始日期或时间
|
||||
* @property {String|Number} end 起始日期或时间
|
||||
* @property {String} return-type = [timestamp | string]
|
||||
* @event {Function} change 选中发生变化触发
|
||||
*/
|
||||
|
||||
export default {
|
||||
name: 'UniDatetimePicker',
|
||||
data() {
|
||||
return {
|
||||
indicatorStyle: `height: 50px;`,
|
||||
visible: false,
|
||||
fixNvueBug: {},
|
||||
dateShow: true,
|
||||
timeShow: true,
|
||||
title: '日期和时间',
|
||||
// 输入框当前时间
|
||||
time: '',
|
||||
// 当前的年月日时分秒
|
||||
year: 1920,
|
||||
month: 0,
|
||||
day: 0,
|
||||
hour: 0,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
// 起始时间
|
||||
startYear: 1920,
|
||||
startMonth: 1,
|
||||
startDay: 1,
|
||||
startHour: 0,
|
||||
startMinute: 0,
|
||||
startSecond: 0,
|
||||
// 结束时间
|
||||
endYear: 2120,
|
||||
endMonth: 12,
|
||||
endDay: 31,
|
||||
endHour: 23,
|
||||
endMinute: 59,
|
||||
endSecond: 59,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: 'datetime'
|
||||
},
|
||||
value: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
modelValue: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
start: {
|
||||
type: [Number, String],
|
||||
default: ''
|
||||
},
|
||||
end: {
|
||||
type: [Number, String],
|
||||
default: ''
|
||||
},
|
||||
returnType: {
|
||||
type: String,
|
||||
default: 'string'
|
||||
},
|
||||
disabled: {
|
||||
type: [Boolean, String],
|
||||
default: false
|
||||
},
|
||||
border: {
|
||||
type: [Boolean, String],
|
||||
default: true
|
||||
},
|
||||
hideSecond: {
|
||||
type: [Boolean, String],
|
||||
default: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// #ifndef VUE3
|
||||
value: {
|
||||
handler(newVal) {
|
||||
if (newVal) {
|
||||
this.parseValue(fixIosDateFormat(newVal))
|
||||
this.initTime(false)
|
||||
} else {
|
||||
this.time = ''
|
||||
this.parseValue(Date.now())
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
// #endif
|
||||
// #ifdef VUE3
|
||||
modelValue: {
|
||||
handler(newVal) {
|
||||
if (newVal) {
|
||||
this.parseValue(fixIosDateFormat(newVal))
|
||||
this.initTime(false)
|
||||
} else {
|
||||
this.time = ''
|
||||
this.parseValue(Date.now())
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
// #endif
|
||||
type: {
|
||||
handler(newValue) {
|
||||
if (newValue === 'date') {
|
||||
this.dateShow = true
|
||||
this.timeShow = false
|
||||
this.title = '日期'
|
||||
} else if (newValue === 'time') {
|
||||
this.dateShow = false
|
||||
this.timeShow = true
|
||||
this.title = '时间'
|
||||
} else {
|
||||
this.dateShow = true
|
||||
this.timeShow = true
|
||||
this.title = '日期和时间'
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
start: {
|
||||
handler(newVal) {
|
||||
this.parseDatetimeRange(fixIosDateFormat(newVal), 'start')
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
end: {
|
||||
handler(newVal) {
|
||||
this.parseDatetimeRange(fixIosDateFormat(newVal), 'end')
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
|
||||
// 月、日、时、分、秒可选范围变化后,检查当前值是否在范围内,不在则当前值重置为可选范围第一项
|
||||
months(newVal) {
|
||||
this.checkValue('month', this.month, newVal)
|
||||
},
|
||||
days(newVal) {
|
||||
this.checkValue('day', this.day, newVal)
|
||||
},
|
||||
hours(newVal) {
|
||||
this.checkValue('hour', this.hour, newVal)
|
||||
},
|
||||
minutes(newVal) {
|
||||
this.checkValue('minute', this.minute, newVal)
|
||||
},
|
||||
seconds(newVal) {
|
||||
this.checkValue('second', this.second, newVal)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 当前年、月、日、时、分、秒选择范围
|
||||
years() {
|
||||
return this.getCurrentRange('year')
|
||||
},
|
||||
|
||||
months() {
|
||||
return this.getCurrentRange('month')
|
||||
},
|
||||
|
||||
days() {
|
||||
return this.getCurrentRange('day')
|
||||
},
|
||||
|
||||
hours() {
|
||||
return this.getCurrentRange('hour')
|
||||
},
|
||||
|
||||
minutes() {
|
||||
return this.getCurrentRange('minute')
|
||||
},
|
||||
|
||||
seconds() {
|
||||
return this.getCurrentRange('second')
|
||||
},
|
||||
|
||||
// picker 当前值数组
|
||||
ymd() {
|
||||
return [this.year - this.minYear, this.month - this.minMonth, this.day - this.minDay]
|
||||
},
|
||||
hms() {
|
||||
return [this.hour - this.minHour, this.minute - this.minMinute, this.second - this.minSecond]
|
||||
},
|
||||
|
||||
// 当前 date 是 start
|
||||
currentDateIsStart() {
|
||||
return this.year === this.startYear && this.month === this.startMonth && this.day === this.startDay
|
||||
},
|
||||
|
||||
// 当前 date 是 end
|
||||
currentDateIsEnd() {
|
||||
return this.year === this.endYear && this.month === this.endMonth && this.day === this.endDay
|
||||
},
|
||||
|
||||
// 当前年、月、日、时、分、秒的最小值和最大值
|
||||
minYear() {
|
||||
return this.startYear
|
||||
},
|
||||
maxYear() {
|
||||
return this.endYear
|
||||
},
|
||||
minMonth() {
|
||||
if (this.year === this.startYear) {
|
||||
return this.startMonth
|
||||
} else {
|
||||
return 1
|
||||
}
|
||||
},
|
||||
maxMonth() {
|
||||
if (this.year === this.endYear) {
|
||||
return this.endMonth
|
||||
} else {
|
||||
return 12
|
||||
}
|
||||
},
|
||||
minDay() {
|
||||
if (this.year === this.startYear && this.month === this.startMonth) {
|
||||
return this.startDay
|
||||
} else {
|
||||
return 1
|
||||
}
|
||||
},
|
||||
maxDay() {
|
||||
if (this.year === this.endYear && this.month === this.endMonth) {
|
||||
return this.endDay
|
||||
} else {
|
||||
return this.daysInMonth(this.year, this.month)
|
||||
}
|
||||
},
|
||||
minHour() {
|
||||
if (this.type === 'datetime') {
|
||||
if (this.currentDateIsStart) {
|
||||
return this.startHour
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
if (this.type === 'time') {
|
||||
return this.startHour
|
||||
}
|
||||
},
|
||||
maxHour() {
|
||||
if (this.type === 'datetime') {
|
||||
if (this.currentDateIsEnd) {
|
||||
return this.endHour
|
||||
} else {
|
||||
return 23
|
||||
}
|
||||
}
|
||||
if (this.type === 'time') {
|
||||
return this.endHour
|
||||
}
|
||||
},
|
||||
minMinute() {
|
||||
if (this.type === 'datetime') {
|
||||
if (this.currentDateIsStart && this.hour === this.startHour) {
|
||||
return this.startMinute
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
if (this.type === 'time') {
|
||||
if (this.hour === this.startHour) {
|
||||
return this.startMinute
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
},
|
||||
maxMinute() {
|
||||
if (this.type === 'datetime') {
|
||||
if (this.currentDateIsEnd && this.hour === this.endHour) {
|
||||
return this.endMinute
|
||||
} else {
|
||||
return 59
|
||||
}
|
||||
}
|
||||
if (this.type === 'time') {
|
||||
if (this.hour === this.endHour) {
|
||||
return this.endMinute
|
||||
} else {
|
||||
return 59
|
||||
}
|
||||
}
|
||||
},
|
||||
minSecond() {
|
||||
if (this.type === 'datetime') {
|
||||
if (this.currentDateIsStart && this.hour === this.startHour && this.minute === this.startMinute) {
|
||||
return this.startSecond
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
if (this.type === 'time') {
|
||||
if (this.hour === this.startHour && this.minute === this.startMinute) {
|
||||
return this.startSecond
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
},
|
||||
maxSecond() {
|
||||
if (this.type === 'datetime') {
|
||||
if (this.currentDateIsEnd && this.hour === this.endHour && this.minute === this.endMinute) {
|
||||
return this.endSecond
|
||||
} else {
|
||||
return 59
|
||||
}
|
||||
}
|
||||
if (this.type === 'time') {
|
||||
if (this.hour === this.endHour && this.minute === this.endMinute) {
|
||||
return this.endSecond
|
||||
} else {
|
||||
return 59
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* for i18n
|
||||
*/
|
||||
selectTimeText() {
|
||||
return t("uni-datetime-picker.selectTime")
|
||||
},
|
||||
okText() {
|
||||
return t("uni-datetime-picker.ok")
|
||||
},
|
||||
clearText() {
|
||||
return t("uni-datetime-picker.clear")
|
||||
},
|
||||
cancelText() {
|
||||
return t("uni-datetime-picker.cancel")
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
// #ifdef APP-NVUE
|
||||
const res = uni.getSystemInfoSync();
|
||||
this.fixNvueBug = {
|
||||
top: res.windowHeight / 2,
|
||||
left: res.windowWidth / 2
|
||||
}
|
||||
// #endif
|
||||
},
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* @param {Object} item
|
||||
* 小于 10 在前面加个 0
|
||||
*/
|
||||
|
||||
lessThanTen(item) {
|
||||
return item < 10 ? '0' + item : item
|
||||
},
|
||||
|
||||
/**
|
||||
* 解析时分秒字符串,例如:00:00:00
|
||||
* @param {String} timeString
|
||||
*/
|
||||
parseTimeType(timeString) {
|
||||
if (timeString) {
|
||||
let timeArr = timeString.split(':')
|
||||
this.hour = Number(timeArr[0])
|
||||
this.minute = Number(timeArr[1])
|
||||
this.second = Number(timeArr[2])
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 解析选择器初始值,类型可以是字符串、时间戳,例如:2000-10-02、'08:30:00'、 1610695109000
|
||||
* @param {String | Number} datetime
|
||||
*/
|
||||
initPickerValue(datetime) {
|
||||
let defaultValue = null
|
||||
if (datetime) {
|
||||
defaultValue = this.compareValueWithStartAndEnd(datetime, this.start, this.end)
|
||||
} else {
|
||||
defaultValue = Date.now()
|
||||
defaultValue = this.compareValueWithStartAndEnd(defaultValue, this.start, this.end)
|
||||
}
|
||||
this.parseValue(defaultValue)
|
||||
},
|
||||
|
||||
/**
|
||||
* 初始值规则:
|
||||
* - 用户设置初始值 value
|
||||
* - 设置了起始时间 start、终止时间 end,并 start < value < end,初始值为 value, 否则初始值为 start
|
||||
* - 只设置了起始时间 start,并 start < value,初始值为 value,否则初始值为 start
|
||||
* - 只设置了终止时间 end,并 value < end,初始值为 value,否则初始值为 end
|
||||
* - 无起始终止时间,则初始值为 value
|
||||
* - 无初始值 value,则初始值为当前本地时间 Date.now()
|
||||
* @param {Object} value
|
||||
* @param {Object} dateBase
|
||||
*/
|
||||
compareValueWithStartAndEnd(value, start, end) {
|
||||
let winner = null
|
||||
value = this.superTimeStamp(value)
|
||||
start = this.superTimeStamp(start)
|
||||
end = this.superTimeStamp(end)
|
||||
|
||||
if (start && end) {
|
||||
if (value < start) {
|
||||
winner = new Date(start)
|
||||
} else if (value > end) {
|
||||
winner = new Date(end)
|
||||
} else {
|
||||
winner = new Date(value)
|
||||
}
|
||||
} else if (start && !end) {
|
||||
winner = start <= value ? new Date(value) : new Date(start)
|
||||
} else if (!start && end) {
|
||||
winner = value <= end ? new Date(value) : new Date(end)
|
||||
} else {
|
||||
winner = new Date(value)
|
||||
}
|
||||
|
||||
return winner
|
||||
},
|
||||
|
||||
/**
|
||||
* 转换为可比较的时间戳,接受日期、时分秒、时间戳
|
||||
* @param {Object} value
|
||||
*/
|
||||
superTimeStamp(value) {
|
||||
let dateBase = ''
|
||||
if (this.type === 'time' && value && typeof value === 'string') {
|
||||
const now = new Date()
|
||||
const year = now.getFullYear()
|
||||
const month = now.getMonth() + 1
|
||||
const day = now.getDate()
|
||||
dateBase = year + '/' + month + '/' + day + ' '
|
||||
}
|
||||
if (Number(value)) {
|
||||
value = parseInt(value)
|
||||
dateBase = 0
|
||||
}
|
||||
return this.createTimeStamp(dateBase + value)
|
||||
},
|
||||
|
||||
/**
|
||||
* 解析默认值 value,字符串、时间戳
|
||||
* @param {Object} defaultTime
|
||||
*/
|
||||
parseValue(value) {
|
||||
if (!value) {
|
||||
return
|
||||
}
|
||||
if (this.type === 'time' && typeof value === "string") {
|
||||
this.parseTimeType(value)
|
||||
} else {
|
||||
let defaultDate = null
|
||||
defaultDate = new Date(value)
|
||||
if (this.type !== 'time') {
|
||||
this.year = defaultDate.getFullYear()
|
||||
this.month = defaultDate.getMonth() + 1
|
||||
this.day = defaultDate.getDate()
|
||||
}
|
||||
if (this.type !== 'date') {
|
||||
this.hour = defaultDate.getHours()
|
||||
this.minute = defaultDate.getMinutes()
|
||||
this.second = defaultDate.getSeconds()
|
||||
}
|
||||
}
|
||||
if (this.hideSecond) {
|
||||
this.second = 0
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 解析可选择时间范围 start、end,年月日字符串、时间戳
|
||||
* @param {Object} defaultTime
|
||||
*/
|
||||
parseDatetimeRange(point, pointType) {
|
||||
// 时间为空,则重置为初始值
|
||||
if (!point) {
|
||||
if (pointType === 'start') {
|
||||
this.startYear = 1920
|
||||
this.startMonth = 1
|
||||
this.startDay = 1
|
||||
this.startHour = 0
|
||||
this.startMinute = 0
|
||||
this.startSecond = 0
|
||||
}
|
||||
if (pointType === 'end') {
|
||||
this.endYear = 2120
|
||||
this.endMonth = 12
|
||||
this.endDay = 31
|
||||
this.endHour = 23
|
||||
this.endMinute = 59
|
||||
this.endSecond = 59
|
||||
}
|
||||
return
|
||||
}
|
||||
if (this.type === 'time') {
|
||||
const pointArr = point.split(':')
|
||||
this[pointType + 'Hour'] = Number(pointArr[0])
|
||||
this[pointType + 'Minute'] = Number(pointArr[1])
|
||||
this[pointType + 'Second'] = Number(pointArr[2])
|
||||
} else {
|
||||
if (!point) {
|
||||
pointType === 'start' ? this.startYear = this.year - 60 : this.endYear = this.year + 60
|
||||
return
|
||||
}
|
||||
if (Number(point)) {
|
||||
point = parseInt(point)
|
||||
}
|
||||
// datetime 的 end 没有时分秒, 则不限制
|
||||
const hasTime = /[0-9]:[0-9]/
|
||||
if (this.type === 'datetime' && pointType === 'end' && typeof point === 'string' && !hasTime.test(
|
||||
point)) {
|
||||
point = point + ' 23:59:59'
|
||||
}
|
||||
const pointDate = new Date(point)
|
||||
this[pointType + 'Year'] = pointDate.getFullYear()
|
||||
this[pointType + 'Month'] = pointDate.getMonth() + 1
|
||||
this[pointType + 'Day'] = pointDate.getDate()
|
||||
if (this.type === 'datetime') {
|
||||
this[pointType + 'Hour'] = pointDate.getHours()
|
||||
this[pointType + 'Minute'] = pointDate.getMinutes()
|
||||
this[pointType + 'Second'] = pointDate.getSeconds()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 获取 年、月、日、时、分、秒 当前可选范围
|
||||
getCurrentRange(value) {
|
||||
const range = []
|
||||
for (let i = this['min' + this.capitalize(value)]; i <= this['max' + this.capitalize(value)]; i++) {
|
||||
range.push(i)
|
||||
}
|
||||
return range
|
||||
},
|
||||
|
||||
// 字符串首字母大写
|
||||
capitalize(str) {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1)
|
||||
},
|
||||
|
||||
// 检查当前值是否在范围内,不在则当前值重置为可选范围第一项
|
||||
checkValue(name, value, values) {
|
||||
if (values.indexOf(value) === -1) {
|
||||
this[name] = values[0]
|
||||
}
|
||||
},
|
||||
|
||||
// 每个月的实际天数
|
||||
daysInMonth(year, month) { // Use 1 for January, 2 for February, etc.
|
||||
return new Date(year, month, 0).getDate();
|
||||
},
|
||||
|
||||
//兼容 iOS、safari 日期格式
|
||||
fixIosDateFormat(value) {
|
||||
if (typeof value === 'string') {
|
||||
value = value.replace(/-/g, '/')
|
||||
}
|
||||
return value
|
||||
},
|
||||
|
||||
/**
|
||||
* 生成时间戳
|
||||
* @param {Object} time
|
||||
*/
|
||||
createTimeStamp(time) {
|
||||
if (!time) return
|
||||
if (typeof time === "number") {
|
||||
return time
|
||||
} else {
|
||||
time = time.replace(/-/g, '/')
|
||||
if (this.type === 'date') {
|
||||
time = time + ' ' + '00:00:00'
|
||||
}
|
||||
return Date.parse(time)
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 生成日期或时间的字符串
|
||||
*/
|
||||
createDomSting() {
|
||||
const yymmdd = this.year +
|
||||
'-' +
|
||||
this.lessThanTen(this.month) +
|
||||
'-' +
|
||||
this.lessThanTen(this.day)
|
||||
|
||||
let hhmmss = this.lessThanTen(this.hour) +
|
||||
':' +
|
||||
this.lessThanTen(this.minute)
|
||||
|
||||
if (!this.hideSecond) {
|
||||
hhmmss = hhmmss + ':' + this.lessThanTen(this.second)
|
||||
}
|
||||
|
||||
if (this.type === 'date') {
|
||||
return yymmdd
|
||||
} else if (this.type === 'time') {
|
||||
return hhmmss
|
||||
} else {
|
||||
return yymmdd + ' ' + hhmmss
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 初始化返回值,并抛出 change 事件
|
||||
*/
|
||||
initTime(emit = true) {
|
||||
this.time = this.createDomSting()
|
||||
if (!emit) return
|
||||
if (this.returnType === 'timestamp' && this.type !== 'time') {
|
||||
this.$emit('change', this.createTimeStamp(this.time))
|
||||
this.$emit('input', this.createTimeStamp(this.time))
|
||||
this.$emit('update:modelValue', this.createTimeStamp(this.time))
|
||||
} else {
|
||||
this.$emit('change', this.time)
|
||||
this.$emit('input', this.time)
|
||||
this.$emit('update:modelValue', this.time)
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 用户选择日期或时间更新 data
|
||||
* @param {Object} e
|
||||
*/
|
||||
bindDateChange(e) {
|
||||
const val = e.detail.value
|
||||
this.year = this.years[val[0]]
|
||||
this.month = this.months[val[1]]
|
||||
this.day = this.days[val[2]]
|
||||
},
|
||||
bindTimeChange(e) {
|
||||
const val = e.detail.value
|
||||
this.hour = this.hours[val[0]]
|
||||
this.minute = this.minutes[val[1]]
|
||||
this.second = this.seconds[val[2]]
|
||||
},
|
||||
|
||||
/**
|
||||
* 初始化弹出层
|
||||
*/
|
||||
initTimePicker() {
|
||||
if (this.disabled) return
|
||||
const value = fixIosDateFormat(this.time)
|
||||
this.initPickerValue(value)
|
||||
this.visible = !this.visible
|
||||
},
|
||||
|
||||
/**
|
||||
* 触发或关闭弹框
|
||||
*/
|
||||
tiggerTimePicker(e) {
|
||||
this.visible = !this.visible
|
||||
},
|
||||
|
||||
/**
|
||||
* 用户点击“清空”按钮,清空当前值
|
||||
*/
|
||||
clearTime() {
|
||||
this.time = ''
|
||||
this.$emit('change', this.time)
|
||||
this.$emit('input', this.time)
|
||||
this.$emit('update:modelValue', this.time)
|
||||
this.tiggerTimePicker()
|
||||
},
|
||||
|
||||
/**
|
||||
* 用户点击“确定”按钮
|
||||
*/
|
||||
setTime() {
|
||||
this.initTime()
|
||||
this.tiggerTimePicker()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
$uni-primary: #007aff !default;
|
||||
|
||||
.uni-datetime-picker {
|
||||
/* #ifndef APP-NVUE */
|
||||
/* width: 100%; */
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-datetime-picker-view {
|
||||
height: 130px;
|
||||
width: 270px;
|
||||
/* #ifndef APP-NVUE */
|
||||
cursor: pointer;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-datetime-picker-item {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.uni-datetime-picker-btn {
|
||||
margin-top: 60px;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.uni-datetime-picker-btn-text {
|
||||
font-size: 14px;
|
||||
color: $uni-primary;
|
||||
}
|
||||
|
||||
.uni-datetime-picker-btn-group {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.uni-datetime-picker-cancel {
|
||||
margin-right: 30px;
|
||||
}
|
||||
|
||||
.uni-datetime-picker-mask {
|
||||
position: fixed;
|
||||
bottom: 0px;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
transition-duration: 0.3s;
|
||||
z-index: 998;
|
||||
}
|
||||
|
||||
.uni-datetime-picker-popup {
|
||||
border-radius: 8px;
|
||||
padding: 30px;
|
||||
width: 270px;
|
||||
/* #ifdef APP-NVUE */
|
||||
height: 500px;
|
||||
/* #endif */
|
||||
/* #ifdef APP-NVUE */
|
||||
width: 330px;
|
||||
/* #endif */
|
||||
background-color: #fff;
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
transition-duration: 0.3s;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.fix-nvue-height {
|
||||
/* #ifdef APP-NVUE */
|
||||
height: 330px;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-datetime-picker-time {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
.uni-datetime-picker-column {
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.uni-datetime-picker-timebox {
|
||||
|
||||
border: 1px solid #E5E5E5;
|
||||
border-radius: 5px;
|
||||
padding: 7px 10px;
|
||||
/* #ifndef APP-NVUE */
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-datetime-picker-timebox-pointer {
|
||||
/* #ifndef APP-NVUE */
|
||||
cursor: pointer;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
|
||||
.uni-datetime-picker-disabled {
|
||||
opacity: 0.4;
|
||||
/* #ifdef H5 */
|
||||
cursor: not-allowed !important;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-datetime-picker-text {
|
||||
font-size: 14px;
|
||||
line-height: 50px
|
||||
}
|
||||
|
||||
.uni-datetime-picker-sign {
|
||||
position: absolute;
|
||||
top: 53px;
|
||||
/* 减掉 10px 的元素高度,兼容nvue */
|
||||
color: #999;
|
||||
/* #ifdef APP-NVUE */
|
||||
font-size: 16px;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.sign-left {
|
||||
left: 86px;
|
||||
}
|
||||
|
||||
.sign-right {
|
||||
right: 86px;
|
||||
}
|
||||
|
||||
.sign-center {
|
||||
left: 135px;
|
||||
}
|
||||
|
||||
.uni-datetime-picker__container-box {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.time-hide-second {
|
||||
width: 180px;
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,453 @@
|
||||
class Calendar {
|
||||
constructor({
|
||||
selected,
|
||||
startDate,
|
||||
endDate,
|
||||
range,
|
||||
} = {}) {
|
||||
// 当前日期
|
||||
this.date = this.getDateObj(new Date()) // 当前初入日期
|
||||
// 打点信息
|
||||
this.selected = selected || [];
|
||||
// 起始时间
|
||||
this.startDate = startDate
|
||||
// 终止时间
|
||||
this.endDate = endDate
|
||||
// 是否范围选择
|
||||
this.range = range
|
||||
// 多选状态
|
||||
this.cleanMultipleStatus()
|
||||
// 每周日期
|
||||
this.weeks = {}
|
||||
this.lastHover = false
|
||||
}
|
||||
/**
|
||||
* 设置日期
|
||||
* @param {Object} date
|
||||
*/
|
||||
setDate(date) {
|
||||
const selectDate = this.getDateObj(date)
|
||||
this.getWeeks(selectDate.fullDate)
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理多选状态
|
||||
*/
|
||||
cleanMultipleStatus() {
|
||||
this.multipleStatus = {
|
||||
before: '',
|
||||
after: '',
|
||||
data: []
|
||||
}
|
||||
}
|
||||
|
||||
setStartDate(startDate) {
|
||||
this.startDate = startDate
|
||||
}
|
||||
|
||||
setEndDate(endDate) {
|
||||
this.endDate = endDate
|
||||
}
|
||||
|
||||
getPreMonthObj(date){
|
||||
date = fixIosDateFormat(date)
|
||||
date = new Date(date)
|
||||
|
||||
const oldMonth = date.getMonth()
|
||||
date.setMonth(oldMonth - 1)
|
||||
const newMonth = date.getMonth()
|
||||
if(oldMonth !== 0 && newMonth - oldMonth === 0){
|
||||
date.setMonth(newMonth - 1)
|
||||
}
|
||||
return this.getDateObj(date)
|
||||
}
|
||||
getNextMonthObj(date){
|
||||
date = fixIosDateFormat(date)
|
||||
date = new Date(date)
|
||||
|
||||
const oldMonth = date.getMonth()
|
||||
date.setMonth(oldMonth + 1)
|
||||
const newMonth = date.getMonth()
|
||||
if(newMonth - oldMonth > 1){
|
||||
date.setMonth(newMonth - 1)
|
||||
}
|
||||
return this.getDateObj(date)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定格式Date对象
|
||||
*/
|
||||
getDateObj(date) {
|
||||
date = fixIosDateFormat(date)
|
||||
date = new Date(date)
|
||||
|
||||
return {
|
||||
fullDate: getDate(date),
|
||||
year: date.getFullYear(),
|
||||
month: addZero(date.getMonth() + 1),
|
||||
date: addZero(date.getDate()),
|
||||
day: date.getDay()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上一个月日期集合
|
||||
*/
|
||||
getPreMonthDays(amount, dateObj) {
|
||||
const result = []
|
||||
for (let i = amount - 1; i >= 0; i--) {
|
||||
const month = dateObj.month > 1 ? dateObj.month -1 : 12
|
||||
const year = month === 12 ? dateObj.year - 1 : dateObj.year
|
||||
const date = new Date(year,month,-i).getDate()
|
||||
const fullDate = `${year}-${addZero(month)}-${addZero(date)}`
|
||||
let multiples = this.multipleStatus.data
|
||||
let multiplesStatus = -1
|
||||
if (this.range && multiples) {
|
||||
multiplesStatus = multiples.findIndex((item) => {
|
||||
return this.dateEqual(item, fullDate)
|
||||
})
|
||||
}
|
||||
const checked = multiplesStatus !== -1
|
||||
// 获取打点信息
|
||||
const extraInfo = this.selected && this.selected.find((item) => {
|
||||
if (this.dateEqual(fullDate, item.date)) {
|
||||
return item
|
||||
}
|
||||
})
|
||||
result.push({
|
||||
fullDate,
|
||||
year,
|
||||
month,
|
||||
date,
|
||||
multiple: this.range ? checked : false,
|
||||
beforeMultiple: this.isLogicBefore(fullDate, this.multipleStatus.before, this.multipleStatus.after),
|
||||
afterMultiple: this.isLogicAfter(fullDate, this.multipleStatus.before, this.multipleStatus.after),
|
||||
disable: (this.startDate && !dateCompare(this.startDate, fullDate)) || (this.endDate && !dateCompare(fullDate,this.endDate)),
|
||||
isToday: fullDate === this.date.fullDate,
|
||||
userChecked: false,
|
||||
extraInfo
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
/**
|
||||
* 获取本月日期集合
|
||||
*/
|
||||
getCurrentMonthDays(amount, dateObj) {
|
||||
const result = []
|
||||
const fullDate = this.date.fullDate
|
||||
for (let i = 1; i <= amount; i++) {
|
||||
const currentDate = `${dateObj.year}-${dateObj.month}-${addZero(i)}`
|
||||
const isToday = fullDate === currentDate
|
||||
// 获取打点信息
|
||||
const extraInfo = this.selected && this.selected.find((item) => {
|
||||
if (this.dateEqual(currentDate, item.date)) {
|
||||
return item
|
||||
}
|
||||
})
|
||||
|
||||
// 日期禁用
|
||||
let disableBefore = true
|
||||
let disableAfter = true
|
||||
if (this.startDate) {
|
||||
disableBefore = dateCompare(this.startDate, currentDate)
|
||||
}
|
||||
|
||||
if (this.endDate) {
|
||||
disableAfter = dateCompare(currentDate, this.endDate)
|
||||
}
|
||||
|
||||
let multiples = this.multipleStatus.data
|
||||
let multiplesStatus = -1
|
||||
if (this.range && multiples) {
|
||||
multiplesStatus = multiples.findIndex((item) => {
|
||||
return this.dateEqual(item, currentDate)
|
||||
})
|
||||
}
|
||||
const checked = multiplesStatus !== -1
|
||||
|
||||
result.push({
|
||||
fullDate: currentDate,
|
||||
year: dateObj.year,
|
||||
month: dateObj.month,
|
||||
date: i,
|
||||
multiple: this.range ? checked : false,
|
||||
beforeMultiple: this.isLogicBefore(currentDate, this.multipleStatus.before, this.multipleStatus.after),
|
||||
afterMultiple: this.isLogicAfter(currentDate, this.multipleStatus.before, this.multipleStatus.after),
|
||||
disable: (this.startDate && !dateCompare(this.startDate, currentDate)) || (this.endDate && !dateCompare(currentDate,this.endDate)),
|
||||
isToday,
|
||||
userChecked: false,
|
||||
extraInfo
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
/**
|
||||
* 获取下一个月日期集合
|
||||
*/
|
||||
_getNextMonthDays(amount, dateObj) {
|
||||
const result = []
|
||||
const month = dateObj.month + 1
|
||||
for (let i = 1; i <= amount; i++) {
|
||||
const month = dateObj.month === 12 ? 1 : dateObj.month*1 + 1
|
||||
const year = month === 1 ? dateObj.year + 1 : dateObj.year
|
||||
const fullDate = `${year}-${addZero(month)}-${addZero(i)}`
|
||||
let multiples = this.multipleStatus.data
|
||||
let multiplesStatus = -1
|
||||
if (this.range && multiples) {
|
||||
multiplesStatus = multiples.findIndex((item) => {
|
||||
return this.dateEqual(item, fullDate)
|
||||
})
|
||||
}
|
||||
const checked = multiplesStatus !== -1
|
||||
// 获取打点信息
|
||||
const extraInfo = this.selected && this.selected.find((item) => {
|
||||
if (this.dateEqual(fullDate, item.date)) {
|
||||
return item
|
||||
}
|
||||
})
|
||||
result.push({
|
||||
fullDate,
|
||||
year,
|
||||
date: i,
|
||||
month,
|
||||
multiple: this.range ? checked : false,
|
||||
beforeMultiple: this.isLogicBefore(fullDate, this.multipleStatus.before, this.multipleStatus.after),
|
||||
afterMultiple: this.isLogicAfter(fullDate, this.multipleStatus.before, this.multipleStatus.after),
|
||||
disable: (this.startDate && !dateCompare(this.startDate, fullDate)) || (this.endDate && !dateCompare(fullDate,this.endDate)),
|
||||
isToday: fullDate === this.date.fullDate,
|
||||
userChecked: false,
|
||||
extraInfo
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前日期详情
|
||||
* @param {Object} date
|
||||
*/
|
||||
getInfo(date) {
|
||||
if (!date) {
|
||||
date = new Date()
|
||||
}
|
||||
|
||||
return this.calendar.find(item => item.fullDate === this.getDateObj(date).fullDate)
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较时间是否相等
|
||||
*/
|
||||
dateEqual(before, after) {
|
||||
before = new Date(fixIosDateFormat(before))
|
||||
after = new Date(fixIosDateFormat(after))
|
||||
return before.valueOf() === after.valueOf()
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较真实起始日期
|
||||
*/
|
||||
|
||||
isLogicBefore(currentDate, before, after) {
|
||||
let logicBefore = before
|
||||
if (before && after) {
|
||||
logicBefore = dateCompare(before, after) ? before : after
|
||||
}
|
||||
return this.dateEqual(logicBefore, currentDate)
|
||||
}
|
||||
|
||||
isLogicAfter(currentDate, before, after) {
|
||||
let logicAfter = after
|
||||
if (before && after) {
|
||||
logicAfter = dateCompare(before, after) ? after : before
|
||||
}
|
||||
return this.dateEqual(logicAfter, currentDate)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取日期范围内所有日期
|
||||
* @param {Object} begin
|
||||
* @param {Object} end
|
||||
*/
|
||||
geDateAll(begin, end) {
|
||||
var arr = []
|
||||
var ab = begin.split('-')
|
||||
var ae = end.split('-')
|
||||
var db = new Date()
|
||||
db.setFullYear(ab[0], ab[1] - 1, ab[2])
|
||||
var de = new Date()
|
||||
de.setFullYear(ae[0], ae[1] - 1, ae[2])
|
||||
var unixDb = db.getTime() - 24 * 60 * 60 * 1000
|
||||
var unixDe = de.getTime() - 24 * 60 * 60 * 1000
|
||||
for (var k = unixDb; k <= unixDe;) {
|
||||
k = k + 24 * 60 * 60 * 1000
|
||||
arr.push(this.getDateObj(new Date(parseInt(k))).fullDate)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取多选状态
|
||||
*/
|
||||
setMultiple(fullDate) {
|
||||
if (!this.range) return
|
||||
|
||||
let {
|
||||
before,
|
||||
after
|
||||
} = this.multipleStatus
|
||||
if (before && after) {
|
||||
if (!this.lastHover) {
|
||||
this.lastHover = true
|
||||
return
|
||||
}
|
||||
this.multipleStatus.before = fullDate
|
||||
this.multipleStatus.after = ''
|
||||
this.multipleStatus.data = []
|
||||
this.multipleStatus.fulldate = ''
|
||||
this.lastHover = false
|
||||
} else {
|
||||
if (!before) {
|
||||
this.multipleStatus.before = fullDate
|
||||
this.lastHover = false
|
||||
} else {
|
||||
this.multipleStatus.after = fullDate
|
||||
if (dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
|
||||
this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus
|
||||
.after);
|
||||
} else {
|
||||
this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus
|
||||
.before);
|
||||
}
|
||||
this.lastHover = true
|
||||
}
|
||||
}
|
||||
this.getWeeks(fullDate)
|
||||
}
|
||||
|
||||
/**
|
||||
* 鼠标 hover 更新多选状态
|
||||
*/
|
||||
setHoverMultiple(fullDate) {
|
||||
if (!this.range || this.lastHover) return
|
||||
|
||||
const { before } = this.multipleStatus
|
||||
|
||||
if (!before) {
|
||||
this.multipleStatus.before = fullDate
|
||||
} else {
|
||||
this.multipleStatus.after = fullDate
|
||||
if (dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
|
||||
this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus.after);
|
||||
} else {
|
||||
this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus.before);
|
||||
}
|
||||
}
|
||||
this.getWeeks(fullDate)
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新默认值多选状态
|
||||
*/
|
||||
setDefaultMultiple(before, after) {
|
||||
this.multipleStatus.before = before
|
||||
this.multipleStatus.after = after
|
||||
if (before && after) {
|
||||
if (dateCompare(before, after)) {
|
||||
this.multipleStatus.data = this.geDateAll(before, after);
|
||||
this.getWeeks(after)
|
||||
} else {
|
||||
this.multipleStatus.data = this.geDateAll(after, before);
|
||||
this.getWeeks(before)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取每周数据
|
||||
* @param {Object} dateData
|
||||
*/
|
||||
getWeeks(dateData) {
|
||||
const {
|
||||
year,
|
||||
month,
|
||||
} = this.getDateObj(dateData)
|
||||
|
||||
const preMonthDayAmount = new Date(year, month - 1, 1).getDay()
|
||||
const preMonthDays = this.getPreMonthDays(preMonthDayAmount, this.getDateObj(dateData))
|
||||
|
||||
const currentMonthDayAmount = new Date(year, month, 0).getDate()
|
||||
const currentMonthDays = this.getCurrentMonthDays(currentMonthDayAmount, this.getDateObj(dateData))
|
||||
|
||||
const nextMonthDayAmount = 42 - preMonthDayAmount - currentMonthDayAmount
|
||||
const nextMonthDays = this._getNextMonthDays(nextMonthDayAmount, this.getDateObj(dateData))
|
||||
|
||||
const calendarDays = [...preMonthDays, ...currentMonthDays, ...nextMonthDays]
|
||||
|
||||
const weeks = new Array(6)
|
||||
for (let i = 0; i < calendarDays.length; i++) {
|
||||
const index = Math.floor(i / 7)
|
||||
if(!weeks[index]){
|
||||
weeks[index] = new Array(7)
|
||||
}
|
||||
weeks[index][i % 7] = calendarDays[i]
|
||||
}
|
||||
|
||||
this.calendar = calendarDays
|
||||
this.weeks = weeks
|
||||
}
|
||||
}
|
||||
|
||||
function getDateTime(date, hideSecond){
|
||||
return `${getDate(date)} ${getTime(date, hideSecond)}`
|
||||
}
|
||||
|
||||
function getDate(date) {
|
||||
date = fixIosDateFormat(date)
|
||||
date = new Date(date)
|
||||
const year = date.getFullYear()
|
||||
const month = date.getMonth()+1
|
||||
const day = date.getDate()
|
||||
return `${year}-${addZero(month)}-${addZero(day)}`
|
||||
}
|
||||
|
||||
function getTime(date, hideSecond){
|
||||
date = fixIosDateFormat(date)
|
||||
date = new Date(date)
|
||||
const hour = date.getHours()
|
||||
const minute = date.getMinutes()
|
||||
const second = date.getSeconds()
|
||||
return hideSecond ? `${addZero(hour)}:${addZero(minute)}` : `${addZero(hour)}:${addZero(minute)}:${addZero(second)}`
|
||||
}
|
||||
|
||||
function addZero(num) {
|
||||
if(num < 10){
|
||||
num = `0${num}`
|
||||
}
|
||||
return num
|
||||
}
|
||||
|
||||
function getDefaultSecond(hideSecond) {
|
||||
return hideSecond ? '00:00' : '00:00:00'
|
||||
}
|
||||
|
||||
function dateCompare(startDate, endDate) {
|
||||
startDate = new Date(fixIosDateFormat(startDate))
|
||||
endDate = new Date(fixIosDateFormat(endDate))
|
||||
return startDate <= endDate
|
||||
}
|
||||
|
||||
function checkDate(date){
|
||||
const dateReg = /((19|20)\d{2})(-|\/)\d{1,2}(-|\/)\d{1,2}/g
|
||||
return date.match(dateReg)
|
||||
}
|
||||
|
||||
const dateTimeReg = /^\d{4}-(0?[1-9]|1[012])-(0?[1-9]|[12][0-9]|3[01])( [0-5]?[0-9]:[0-5]?[0-9]:[0-5]?[0-9])?$/
|
||||
function fixIosDateFormat(value) {
|
||||
if (typeof value === 'string' && dateTimeReg.test(value)) {
|
||||
value = value.replace(/-/g, '/')
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
export {Calendar, getDateTime, getDate, getTime, addZero, getDefaultSecond, dateCompare, checkDate, fixIosDateFormat}
|
||||
87
uni_modules/uni-datetime-picker/package.json
Normal file
87
uni_modules/uni-datetime-picker/package.json
Normal file
@ -0,0 +1,87 @@
|
||||
{
|
||||
"id": "uni-datetime-picker",
|
||||
"displayName": "uni-datetime-picker 日期选择器",
|
||||
"version": "2.2.24",
|
||||
"description": "uni-datetime-picker 日期时间选择器,支持日历,支持范围选择",
|
||||
"keywords": [
|
||||
"uni-datetime-picker",
|
||||
"uni-ui",
|
||||
"uniui",
|
||||
"日期时间选择器",
|
||||
"日期时间"
|
||||
],
|
||||
"repository": "https://github.com/dcloudio/uni-ui",
|
||||
"engines": {
|
||||
"HBuilderX": ""
|
||||
},
|
||||
"directories": {
|
||||
"example": "../../temps/example_temps"
|
||||
},
|
||||
"dcloudext": {
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
|
||||
"type": "component-vue"
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [
|
||||
"uni-scss",
|
||||
"uni-icons"
|
||||
],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y"
|
||||
},
|
||||
"client": {
|
||||
"App": {
|
||||
"app-vue": "y",
|
||||
"app-nvue": "n"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "y",
|
||||
"Android Browser": "y",
|
||||
"微信浏览器(Android)": "y",
|
||||
"QQ浏览器(Android)": "y"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "y",
|
||||
"IE": "y",
|
||||
"Edge": "y",
|
||||
"Firefox": "y",
|
||||
"Safari": "y"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "y",
|
||||
"阿里": "y",
|
||||
"百度": "y",
|
||||
"字节跳动": "y",
|
||||
"QQ": "y"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "u",
|
||||
"联盟": "u"
|
||||
},
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "y"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
21
uni_modules/uni-datetime-picker/readme.md
Normal file
21
uni_modules/uni-datetime-picker/readme.md
Normal file
@ -0,0 +1,21 @@
|
||||
|
||||
|
||||
> `重要通知:组件升级更新 2.0.0 后,支持日期+时间范围选择,组件 ui 将使用日历选择日期,ui 变化较大,同时支持 PC 和 移动端。此版本不向后兼容,不再支持单独的时间选择(type=time)及相关的 hide-second 属性(时间选可使用内置组件 picker)。若仍需使用旧版本,可在插件市场下载*非uni_modules版本*,旧版本将不再维护`
|
||||
|
||||
## DatetimePicker 时间选择器
|
||||
|
||||
> **组件名:uni-datetime-picker**
|
||||
> 代码块: `uDatetimePicker`
|
||||
|
||||
|
||||
该组件的优势是,支持**时间戳**输入和输出(起始时间、终止时间也支持时间戳),可**同时选择**日期和时间。
|
||||
|
||||
若只是需要单独选择日期和时间,不需要时间戳输入和输出,可使用原生的 picker 组件。
|
||||
|
||||
**_点击 picker 默认值规则:_**
|
||||
|
||||
- 若设置初始值 value, 会显示在 picker 显示框中
|
||||
- 若无初始值 value,则初始值 value 为当前本地时间 Date.now(), 但不会显示在 picker 显示框中
|
||||
|
||||
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-datetime-picker)
|
||||
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
|
||||
8
uni_modules/uni-scss/changelog.md
Normal file
8
uni_modules/uni-scss/changelog.md
Normal file
@ -0,0 +1,8 @@
|
||||
## 1.0.3(2022-01-21)
|
||||
- 优化 组件示例
|
||||
## 1.0.2(2021-11-22)
|
||||
- 修复 / 符号在 vue 不同版本兼容问题引起的报错问题
|
||||
## 1.0.1(2021-11-22)
|
||||
- 修复 vue3中scss语法兼容问题
|
||||
## 1.0.0(2021-11-18)
|
||||
- init
|
||||
1
uni_modules/uni-scss/index.scss
Normal file
1
uni_modules/uni-scss/index.scss
Normal file
@ -0,0 +1 @@
|
||||
@import './styles/index.scss';
|
||||
82
uni_modules/uni-scss/package.json
Normal file
82
uni_modules/uni-scss/package.json
Normal file
@ -0,0 +1,82 @@
|
||||
{
|
||||
"id": "uni-scss",
|
||||
"displayName": "uni-scss 辅助样式",
|
||||
"version": "1.0.3",
|
||||
"description": "uni-sass是uni-ui提供的一套全局样式 ,通过一些简单的类名和sass变量,实现简单的页面布局操作,比如颜色、边距、圆角等。",
|
||||
"keywords": [
|
||||
"uni-scss",
|
||||
"uni-ui",
|
||||
"辅助样式"
|
||||
],
|
||||
"repository": "https://github.com/dcloudio/uni-ui",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.1.0"
|
||||
},
|
||||
"dcloudext": {
|
||||
"category": [
|
||||
"JS SDK",
|
||||
"通用 SDK"
|
||||
],
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y"
|
||||
},
|
||||
"client": {
|
||||
"App": {
|
||||
"app-vue": "y",
|
||||
"app-nvue": "u"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "y",
|
||||
"Android Browser": "y",
|
||||
"微信浏览器(Android)": "y",
|
||||
"QQ浏览器(Android)": "y"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "y",
|
||||
"IE": "y",
|
||||
"Edge": "y",
|
||||
"Firefox": "y",
|
||||
"Safari": "y"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "y",
|
||||
"阿里": "y",
|
||||
"百度": "y",
|
||||
"字节跳动": "y",
|
||||
"QQ": "y"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "n",
|
||||
"联盟": "n"
|
||||
},
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "y"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
4
uni_modules/uni-scss/readme.md
Normal file
4
uni_modules/uni-scss/readme.md
Normal file
@ -0,0 +1,4 @@
|
||||
`uni-sass` 是 `uni-ui`提供的一套全局样式 ,通过一些简单的类名和`sass`变量,实现简单的页面布局操作,比如颜色、边距、圆角等。
|
||||
|
||||
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-sass)
|
||||
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
|
||||
7
uni_modules/uni-scss/styles/index.scss
Normal file
7
uni_modules/uni-scss/styles/index.scss
Normal file
@ -0,0 +1,7 @@
|
||||
@import './setting/_variables.scss';
|
||||
@import './setting/_border.scss';
|
||||
@import './setting/_color.scss';
|
||||
@import './setting/_space.scss';
|
||||
@import './setting/_radius.scss';
|
||||
@import './setting/_text.scss';
|
||||
@import './setting/_styles.scss';
|
||||
3
uni_modules/uni-scss/styles/setting/_border.scss
Normal file
3
uni_modules/uni-scss/styles/setting/_border.scss
Normal file
@ -0,0 +1,3 @@
|
||||
.uni-border {
|
||||
border: 1px $uni-border-1 solid;
|
||||
}
|
||||
66
uni_modules/uni-scss/styles/setting/_color.scss
Normal file
66
uni_modules/uni-scss/styles/setting/_color.scss
Normal file
@ -0,0 +1,66 @@
|
||||
|
||||
// TODO 暂时不需要 class ,需要用户使用变量实现 ,如果使用类名其实并不推荐
|
||||
// @mixin get-styles($k,$c) {
|
||||
// @if $k == size or $k == weight{
|
||||
// font-#{$k}:#{$c}
|
||||
// }@else{
|
||||
// #{$k}:#{$c}
|
||||
// }
|
||||
// }
|
||||
$uni-ui-color:(
|
||||
// 主色
|
||||
primary: $uni-primary,
|
||||
primary-disable: $uni-primary-disable,
|
||||
primary-light: $uni-primary-light,
|
||||
// 辅助色
|
||||
success: $uni-success,
|
||||
success-disable: $uni-success-disable,
|
||||
success-light: $uni-success-light,
|
||||
warning: $uni-warning,
|
||||
warning-disable: $uni-warning-disable,
|
||||
warning-light: $uni-warning-light,
|
||||
error: $uni-error,
|
||||
error-disable: $uni-error-disable,
|
||||
error-light: $uni-error-light,
|
||||
info: $uni-info,
|
||||
info-disable: $uni-info-disable,
|
||||
info-light: $uni-info-light,
|
||||
// 中性色
|
||||
main-color: $uni-main-color,
|
||||
base-color: $uni-base-color,
|
||||
secondary-color: $uni-secondary-color,
|
||||
extra-color: $uni-extra-color,
|
||||
// 背景色
|
||||
bg-color: $uni-bg-color,
|
||||
// 边框颜色
|
||||
border-1: $uni-border-1,
|
||||
border-2: $uni-border-2,
|
||||
border-3: $uni-border-3,
|
||||
border-4: $uni-border-4,
|
||||
// 黑色
|
||||
black:$uni-black,
|
||||
// 白色
|
||||
white:$uni-white,
|
||||
// 透明
|
||||
transparent:$uni-transparent
|
||||
) !default;
|
||||
@each $key, $child in $uni-ui-color {
|
||||
.uni-#{"" + $key} {
|
||||
color: $child;
|
||||
}
|
||||
.uni-#{"" + $key}-bg {
|
||||
background-color: $child;
|
||||
}
|
||||
}
|
||||
.uni-shadow-sm {
|
||||
box-shadow: $uni-shadow-sm;
|
||||
}
|
||||
.uni-shadow-base {
|
||||
box-shadow: $uni-shadow-base;
|
||||
}
|
||||
.uni-shadow-lg {
|
||||
box-shadow: $uni-shadow-lg;
|
||||
}
|
||||
.uni-mask {
|
||||
background-color:$uni-mask;
|
||||
}
|
||||
55
uni_modules/uni-scss/styles/setting/_radius.scss
Normal file
55
uni_modules/uni-scss/styles/setting/_radius.scss
Normal file
@ -0,0 +1,55 @@
|
||||
@mixin radius($r,$d:null ,$important: false){
|
||||
$radius-value:map-get($uni-radius, $r) if($important, !important, null);
|
||||
// Key exists within the $uni-radius variable
|
||||
@if (map-has-key($uni-radius, $r) and $d){
|
||||
@if $d == t {
|
||||
border-top-left-radius:$radius-value;
|
||||
border-top-right-radius:$radius-value;
|
||||
}@else if $d == r {
|
||||
border-top-right-radius:$radius-value;
|
||||
border-bottom-right-radius:$radius-value;
|
||||
}@else if $d == b {
|
||||
border-bottom-left-radius:$radius-value;
|
||||
border-bottom-right-radius:$radius-value;
|
||||
}@else if $d == l {
|
||||
border-top-left-radius:$radius-value;
|
||||
border-bottom-left-radius:$radius-value;
|
||||
}@else if $d == tl {
|
||||
border-top-left-radius:$radius-value;
|
||||
}@else if $d == tr {
|
||||
border-top-right-radius:$radius-value;
|
||||
}@else if $d == br {
|
||||
border-bottom-right-radius:$radius-value;
|
||||
}@else if $d == bl {
|
||||
border-bottom-left-radius:$radius-value;
|
||||
}
|
||||
}@else{
|
||||
border-radius:$radius-value;
|
||||
}
|
||||
}
|
||||
|
||||
@each $key, $child in $uni-radius {
|
||||
@if($key){
|
||||
.uni-radius-#{"" + $key} {
|
||||
@include radius($key)
|
||||
}
|
||||
}@else{
|
||||
.uni-radius {
|
||||
@include radius($key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@each $direction in t, r, b, l,tl, tr, br, bl {
|
||||
@each $key, $child in $uni-radius {
|
||||
@if($key){
|
||||
.uni-radius-#{"" + $direction}-#{"" + $key} {
|
||||
@include radius($key,$direction,false)
|
||||
}
|
||||
}@else{
|
||||
.uni-radius-#{$direction} {
|
||||
@include radius($key,$direction,false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
56
uni_modules/uni-scss/styles/setting/_space.scss
Normal file
56
uni_modules/uni-scss/styles/setting/_space.scss
Normal file
@ -0,0 +1,56 @@
|
||||
|
||||
@mixin fn($space,$direction,$size,$n) {
|
||||
@if $n {
|
||||
#{$space}-#{$direction}: #{$size*$uni-space-root}px
|
||||
} @else {
|
||||
#{$space}-#{$direction}: #{-$size*$uni-space-root}px
|
||||
}
|
||||
}
|
||||
@mixin get-styles($direction,$i,$space,$n){
|
||||
@if $direction == t {
|
||||
@include fn($space, top,$i,$n);
|
||||
}
|
||||
@if $direction == r {
|
||||
@include fn($space, right,$i,$n);
|
||||
}
|
||||
@if $direction == b {
|
||||
@include fn($space, bottom,$i,$n);
|
||||
}
|
||||
@if $direction == l {
|
||||
@include fn($space, left,$i,$n);
|
||||
}
|
||||
@if $direction == x {
|
||||
@include fn($space, left,$i,$n);
|
||||
@include fn($space, right,$i,$n);
|
||||
}
|
||||
@if $direction == y {
|
||||
@include fn($space, top,$i,$n);
|
||||
@include fn($space, bottom,$i,$n);
|
||||
}
|
||||
@if $direction == a {
|
||||
@if $n {
|
||||
#{$space}:#{$i*$uni-space-root}px;
|
||||
} @else {
|
||||
#{$space}:#{-$i*$uni-space-root}px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@each $orientation in m,p {
|
||||
$space: margin;
|
||||
@if $orientation == m {
|
||||
$space: margin;
|
||||
} @else {
|
||||
$space: padding;
|
||||
}
|
||||
@for $i from 0 through 16 {
|
||||
@each $direction in t, r, b, l, x, y, a {
|
||||
.uni-#{$orientation}#{$direction}-#{$i} {
|
||||
@include get-styles($direction,$i,$space,true);
|
||||
}
|
||||
.uni-#{$orientation}#{$direction}-n#{$i} {
|
||||
@include get-styles($direction,$i,$space,false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
167
uni_modules/uni-scss/styles/setting/_styles.scss
Normal file
167
uni_modules/uni-scss/styles/setting/_styles.scss
Normal file
@ -0,0 +1,167 @@
|
||||
/* #ifndef APP-NVUE */
|
||||
|
||||
$-color-white:#fff;
|
||||
$-color-black:#000;
|
||||
@mixin base-style($color) {
|
||||
color: #fff;
|
||||
background-color: $color;
|
||||
border-color: mix($-color-black, $color, 8%);
|
||||
&:not([hover-class]):active {
|
||||
background: mix($-color-black, $color, 10%);
|
||||
border-color: mix($-color-black, $color, 20%);
|
||||
color: $-color-white;
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
@mixin is-color($color) {
|
||||
@include base-style($color);
|
||||
&[loading] {
|
||||
@include base-style($color);
|
||||
&::before {
|
||||
margin-right:5px;
|
||||
}
|
||||
}
|
||||
&[disabled] {
|
||||
&,
|
||||
&[loading],
|
||||
&:not([hover-class]):active {
|
||||
color: $-color-white;
|
||||
border-color: mix(darken($color,10%), $-color-white);
|
||||
background-color: mix($color, $-color-white);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@mixin base-plain-style($color) {
|
||||
color:$color;
|
||||
background-color: mix($-color-white, $color, 90%);
|
||||
border-color: mix($-color-white, $color, 70%);
|
||||
&:not([hover-class]):active {
|
||||
background: mix($-color-white, $color, 80%);
|
||||
color: $color;
|
||||
outline: none;
|
||||
border-color: mix($-color-white, $color, 50%);
|
||||
}
|
||||
}
|
||||
@mixin is-plain($color){
|
||||
&[plain] {
|
||||
@include base-plain-style($color);
|
||||
&[loading] {
|
||||
@include base-plain-style($color);
|
||||
&::before {
|
||||
margin-right:5px;
|
||||
}
|
||||
}
|
||||
&[disabled] {
|
||||
&,
|
||||
&:active {
|
||||
color: mix($-color-white, $color, 40%);
|
||||
background-color: mix($-color-white, $color, 90%);
|
||||
border-color: mix($-color-white, $color, 80%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.uni-btn {
|
||||
margin: 5px;
|
||||
color: #393939;
|
||||
border:1px solid #ccc;
|
||||
font-size: 16px;
|
||||
font-weight: 200;
|
||||
background-color: #F9F9F9;
|
||||
// TODO 暂时处理边框隐藏一边的问题
|
||||
overflow: visible;
|
||||
&::after{
|
||||
border: none;
|
||||
}
|
||||
|
||||
&:not([type]),&[type=default] {
|
||||
color: #999;
|
||||
&[loading] {
|
||||
background: none;
|
||||
&::before {
|
||||
margin-right:5px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
&[disabled]{
|
||||
color: mix($-color-white, #999, 60%);
|
||||
&,
|
||||
&[loading],
|
||||
&:active {
|
||||
color: mix($-color-white, #999, 60%);
|
||||
background-color: mix($-color-white,$-color-black , 98%);
|
||||
border-color: mix($-color-white, #999, 85%);
|
||||
}
|
||||
}
|
||||
|
||||
&[plain] {
|
||||
color: #999;
|
||||
background: none;
|
||||
border-color: $uni-border-1;
|
||||
&:not([hover-class]):active {
|
||||
background: none;
|
||||
color: mix($-color-white, $-color-black, 80%);
|
||||
border-color: mix($-color-white, $-color-black, 90%);
|
||||
outline: none;
|
||||
}
|
||||
&[disabled]{
|
||||
&,
|
||||
&[loading],
|
||||
&:active {
|
||||
background: none;
|
||||
color: mix($-color-white, #999, 60%);
|
||||
border-color: mix($-color-white, #999, 85%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:not([hover-class]):active {
|
||||
color: mix($-color-white, $-color-black, 50%);
|
||||
}
|
||||
|
||||
&[size=mini] {
|
||||
font-size: 16px;
|
||||
font-weight: 200;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
&.uni-btn-small {
|
||||
font-size: 14px;
|
||||
}
|
||||
&.uni-btn-mini {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
&.uni-btn-radius {
|
||||
border-radius: 999px;
|
||||
}
|
||||
&[type=primary] {
|
||||
@include is-color($uni-primary);
|
||||
@include is-plain($uni-primary)
|
||||
}
|
||||
&[type=success] {
|
||||
@include is-color($uni-success);
|
||||
@include is-plain($uni-success)
|
||||
}
|
||||
&[type=error] {
|
||||
@include is-color($uni-error);
|
||||
@include is-plain($uni-error)
|
||||
}
|
||||
&[type=warning] {
|
||||
@include is-color($uni-warning);
|
||||
@include is-plain($uni-warning)
|
||||
}
|
||||
&[type=info] {
|
||||
@include is-color($uni-info);
|
||||
@include is-plain($uni-info)
|
||||
}
|
||||
}
|
||||
/* #endif */
|
||||
24
uni_modules/uni-scss/styles/setting/_text.scss
Normal file
24
uni_modules/uni-scss/styles/setting/_text.scss
Normal file
@ -0,0 +1,24 @@
|
||||
@mixin get-styles($k,$c) {
|
||||
@if $k == size or $k == weight{
|
||||
font-#{$k}:#{$c}
|
||||
}@else{
|
||||
#{$k}:#{$c}
|
||||
}
|
||||
}
|
||||
|
||||
@each $key, $child in $uni-headings {
|
||||
/* #ifndef APP-NVUE */
|
||||
.uni-#{$key} {
|
||||
@each $k, $c in $child {
|
||||
@include get-styles($k,$c)
|
||||
}
|
||||
}
|
||||
/* #endif */
|
||||
/* #ifdef APP-NVUE */
|
||||
.container .uni-#{$key} {
|
||||
@each $k, $c in $child {
|
||||
@include get-styles($k,$c)
|
||||
}
|
||||
}
|
||||
/* #endif */
|
||||
}
|
||||
146
uni_modules/uni-scss/styles/setting/_variables.scss
Normal file
146
uni_modules/uni-scss/styles/setting/_variables.scss
Normal file
@ -0,0 +1,146 @@
|
||||
// @use "sass:math";
|
||||
@import '../tools/functions.scss';
|
||||
// 间距基础倍数
|
||||
$uni-space-root: 2 !default;
|
||||
// 边框半径默认值
|
||||
$uni-radius-root:5px !default;
|
||||
$uni-radius: () !default;
|
||||
// 边框半径断点
|
||||
$uni-radius: map-deep-merge(
|
||||
(
|
||||
0: 0,
|
||||
// TODO 当前版本暂时不支持 sm 属性
|
||||
// 'sm': math.div($uni-radius-root, 2),
|
||||
null: $uni-radius-root,
|
||||
'lg': $uni-radius-root * 2,
|
||||
'xl': $uni-radius-root * 6,
|
||||
'pill': 9999px,
|
||||
'circle': 50%
|
||||
),
|
||||
$uni-radius
|
||||
);
|
||||
// 字体家族
|
||||
$body-font-family: 'Roboto', sans-serif !default;
|
||||
// 文本
|
||||
$heading-font-family: $body-font-family !default;
|
||||
$uni-headings: () !default;
|
||||
$letterSpacing: -0.01562em;
|
||||
$uni-headings: map-deep-merge(
|
||||
(
|
||||
'h1': (
|
||||
size: 32px,
|
||||
weight: 300,
|
||||
line-height: 50px,
|
||||
// letter-spacing:-0.01562em
|
||||
),
|
||||
'h2': (
|
||||
size: 28px,
|
||||
weight: 300,
|
||||
line-height: 40px,
|
||||
// letter-spacing: -0.00833em
|
||||
),
|
||||
'h3': (
|
||||
size: 24px,
|
||||
weight: 400,
|
||||
line-height: 32px,
|
||||
// letter-spacing: normal
|
||||
),
|
||||
'h4': (
|
||||
size: 20px,
|
||||
weight: 400,
|
||||
line-height: 30px,
|
||||
// letter-spacing: 0.00735em
|
||||
),
|
||||
'h5': (
|
||||
size: 16px,
|
||||
weight: 400,
|
||||
line-height: 24px,
|
||||
// letter-spacing: normal
|
||||
),
|
||||
'h6': (
|
||||
size: 14px,
|
||||
weight: 500,
|
||||
line-height: 18px,
|
||||
// letter-spacing: 0.0125em
|
||||
),
|
||||
'subtitle': (
|
||||
size: 12px,
|
||||
weight: 400,
|
||||
line-height: 20px,
|
||||
// letter-spacing: 0.00937em
|
||||
),
|
||||
'body': (
|
||||
font-size: 14px,
|
||||
font-weight: 400,
|
||||
line-height: 22px,
|
||||
// letter-spacing: 0.03125em
|
||||
),
|
||||
'caption': (
|
||||
'size': 12px,
|
||||
'weight': 400,
|
||||
'line-height': 20px,
|
||||
// 'letter-spacing': 0.03333em,
|
||||
// 'text-transform': false
|
||||
)
|
||||
),
|
||||
$uni-headings
|
||||
);
|
||||
|
||||
|
||||
|
||||
// 主色
|
||||
$uni-primary: #2979ff !default;
|
||||
$uni-primary-disable:lighten($uni-primary,20%) !default;
|
||||
$uni-primary-light: lighten($uni-primary,25%) !default;
|
||||
|
||||
// 辅助色
|
||||
// 除了主色外的场景色,需要在不同的场景中使用(例如危险色表示危险的操作)。
|
||||
$uni-success: #18bc37 !default;
|
||||
$uni-success-disable:lighten($uni-success,20%) !default;
|
||||
$uni-success-light: lighten($uni-success,25%) !default;
|
||||
|
||||
$uni-warning: #f3a73f !default;
|
||||
$uni-warning-disable:lighten($uni-warning,20%) !default;
|
||||
$uni-warning-light: lighten($uni-warning,25%) !default;
|
||||
|
||||
$uni-error: #e43d33 !default;
|
||||
$uni-error-disable:lighten($uni-error,20%) !default;
|
||||
$uni-error-light: lighten($uni-error,25%) !default;
|
||||
|
||||
$uni-info: #8f939c !default;
|
||||
$uni-info-disable:lighten($uni-info,20%) !default;
|
||||
$uni-info-light: lighten($uni-info,25%) !default;
|
||||
|
||||
// 中性色
|
||||
// 中性色用于文本、背景和边框颜色。通过运用不同的中性色,来表现层次结构。
|
||||
$uni-main-color: #3a3a3a !default; // 主要文字
|
||||
$uni-base-color: #6a6a6a !default; // 常规文字
|
||||
$uni-secondary-color: #909399 !default; // 次要文字
|
||||
$uni-extra-color: #c7c7c7 !default; // 辅助说明
|
||||
|
||||
// 边框颜色
|
||||
$uni-border-1: #F0F0F0 !default;
|
||||
$uni-border-2: #EDEDED !default;
|
||||
$uni-border-3: #DCDCDC !default;
|
||||
$uni-border-4: #B9B9B9 !default;
|
||||
|
||||
// 常规色
|
||||
$uni-black: #000000 !default;
|
||||
$uni-white: #ffffff !default;
|
||||
$uni-transparent: rgba($color: #000000, $alpha: 0) !default;
|
||||
|
||||
// 背景色
|
||||
$uni-bg-color: #f7f7f7 !default;
|
||||
|
||||
/* 水平间距 */
|
||||
$uni-spacing-sm: 8px !default;
|
||||
$uni-spacing-base: 15px !default;
|
||||
$uni-spacing-lg: 30px !default;
|
||||
|
||||
// 阴影
|
||||
$uni-shadow-sm:0 0 5px rgba($color: #d8d8d8, $alpha: 0.5) !default;
|
||||
$uni-shadow-base:0 1px 8px 1px rgba($color: #a5a5a5, $alpha: 0.2) !default;
|
||||
$uni-shadow-lg:0px 1px 10px 2px rgba($color: #a5a4a4, $alpha: 0.5) !default;
|
||||
|
||||
// 蒙版
|
||||
$uni-mask: rgba($color: #000000, $alpha: 0.4) !default;
|
||||
19
uni_modules/uni-scss/styles/tools/functions.scss
Normal file
19
uni_modules/uni-scss/styles/tools/functions.scss
Normal file
@ -0,0 +1,19 @@
|
||||
// 合并 map
|
||||
@function map-deep-merge($parent-map, $child-map){
|
||||
$result: $parent-map;
|
||||
@each $key, $child in $child-map {
|
||||
$parent-has-key: map-has-key($result, $key);
|
||||
$parent-value: map-get($result, $key);
|
||||
$parent-type: type-of($parent-value);
|
||||
$child-type: type-of($child);
|
||||
$parent-is-map: $parent-type == map;
|
||||
$child-is-map: $child-type == map;
|
||||
|
||||
@if (not $parent-has-key) or ($parent-type != $child-type) or (not ($parent-is-map and $child-is-map)){
|
||||
$result: map-merge($result, ( $key: $child ));
|
||||
}@else {
|
||||
$result: map-merge($result, ( $key: map-deep-merge($parent-value, $child) ));
|
||||
}
|
||||
}
|
||||
@return $result;
|
||||
};
|
||||
31
uni_modules/uni-scss/theme.scss
Normal file
31
uni_modules/uni-scss/theme.scss
Normal file
@ -0,0 +1,31 @@
|
||||
// 间距基础倍数
|
||||
$uni-space-root: 2;
|
||||
// 边框半径默认值
|
||||
$uni-radius-root:5px;
|
||||
// 主色
|
||||
$uni-primary: #2979ff;
|
||||
// 辅助色
|
||||
$uni-success: #4cd964;
|
||||
// 警告色
|
||||
$uni-warning: #f0ad4e;
|
||||
// 错误色
|
||||
$uni-error: #dd524d;
|
||||
// 描述色
|
||||
$uni-info: #909399;
|
||||
// 中性色
|
||||
$uni-main-color: #303133;
|
||||
$uni-base-color: #606266;
|
||||
$uni-secondary-color: #909399;
|
||||
$uni-extra-color: #C0C4CC;
|
||||
// 背景色
|
||||
$uni-bg-color: #f5f5f5;
|
||||
// 边框颜色
|
||||
$uni-border-1: #DCDFE6;
|
||||
$uni-border-2: #E4E7ED;
|
||||
$uni-border-3: #EBEEF5;
|
||||
$uni-border-4: #F2F6FC;
|
||||
|
||||
// 常规色
|
||||
$uni-black: #000000;
|
||||
$uni-white: #ffffff;
|
||||
$uni-transparent: rgba($color: #000000, $alpha: 0);
|
||||
62
uni_modules/uni-scss/variables.scss
Normal file
62
uni_modules/uni-scss/variables.scss
Normal file
@ -0,0 +1,62 @@
|
||||
@import './styles/setting/_variables.scss';
|
||||
// 间距基础倍数
|
||||
$uni-space-root: 2;
|
||||
// 边框半径默认值
|
||||
$uni-radius-root:5px;
|
||||
|
||||
// 主色
|
||||
$uni-primary: #2979ff;
|
||||
$uni-primary-disable:mix(#fff,$uni-primary,50%);
|
||||
$uni-primary-light: mix(#fff,$uni-primary,80%);
|
||||
|
||||
// 辅助色
|
||||
// 除了主色外的场景色,需要在不同的场景中使用(例如危险色表示危险的操作)。
|
||||
$uni-success: #18bc37;
|
||||
$uni-success-disable:mix(#fff,$uni-success,50%);
|
||||
$uni-success-light: mix(#fff,$uni-success,80%);
|
||||
|
||||
$uni-warning: #f3a73f;
|
||||
$uni-warning-disable:mix(#fff,$uni-warning,50%);
|
||||
$uni-warning-light: mix(#fff,$uni-warning,80%);
|
||||
|
||||
$uni-error: #e43d33;
|
||||
$uni-error-disable:mix(#fff,$uni-error,50%);
|
||||
$uni-error-light: mix(#fff,$uni-error,80%);
|
||||
|
||||
$uni-info: #8f939c;
|
||||
$uni-info-disable:mix(#fff,$uni-info,50%);
|
||||
$uni-info-light: mix(#fff,$uni-info,80%);
|
||||
|
||||
// 中性色
|
||||
// 中性色用于文本、背景和边框颜色。通过运用不同的中性色,来表现层次结构。
|
||||
$uni-main-color: #3a3a3a; // 主要文字
|
||||
$uni-base-color: #6a6a6a; // 常规文字
|
||||
$uni-secondary-color: #909399; // 次要文字
|
||||
$uni-extra-color: #c7c7c7; // 辅助说明
|
||||
|
||||
// 边框颜色
|
||||
$uni-border-1: #F0F0F0;
|
||||
$uni-border-2: #EDEDED;
|
||||
$uni-border-3: #DCDCDC;
|
||||
$uni-border-4: #B9B9B9;
|
||||
|
||||
// 常规色
|
||||
$uni-black: #000000;
|
||||
$uni-white: #ffffff;
|
||||
$uni-transparent: rgba($color: #000000, $alpha: 0);
|
||||
|
||||
// 背景色
|
||||
$uni-bg-color: #f7f7f7;
|
||||
|
||||
/* 水平间距 */
|
||||
$uni-spacing-sm: 8px;
|
||||
$uni-spacing-base: 15px;
|
||||
$uni-spacing-lg: 30px;
|
||||
|
||||
// 阴影
|
||||
$uni-shadow-sm:0 0 5px rgba($color: #d8d8d8, $alpha: 0.5);
|
||||
$uni-shadow-base:0 1px 8px 1px rgba($color: #a5a5a5, $alpha: 0.2);
|
||||
$uni-shadow-lg:0px 1px 10px 2px rgba($color: #a5a4a4, $alpha: 0.5);
|
||||
|
||||
// 蒙版
|
||||
$uni-mask: rgba($color: #000000, $alpha: 0.4);
|
||||
29
uni_modules/uni-table/changelog.md
Normal file
29
uni_modules/uni-table/changelog.md
Normal file
@ -0,0 +1,29 @@
|
||||
## 1.2.4(2023-12-19)
|
||||
- 修复 uni-tr只有一列时minWidth计算错误,列变化实时计算更新
|
||||
## 1.2.3(2023-03-28)
|
||||
- 修复 在vue3模式下可能会出现错误的问题
|
||||
## 1.2.2(2022-11-29)
|
||||
- 优化 主题样式
|
||||
## 1.2.1(2022-06-06)
|
||||
- 修复 微信小程序存在无使用组件的问题
|
||||
## 1.2.0(2021-11-19)
|
||||
- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
|
||||
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-table](https://uniapp.dcloud.io/component/uniui/uni-table)
|
||||
## 1.1.0(2021-07-30)
|
||||
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
|
||||
## 1.0.7(2021-07-08)
|
||||
- 新增 uni-th 支持 date 日期筛选范围
|
||||
## 1.0.6(2021-07-05)
|
||||
- 新增 uni-th 支持 range 筛选范围
|
||||
## 1.0.5(2021-06-28)
|
||||
- 新增 uni-th 筛选功能
|
||||
## 1.0.4(2021-05-12)
|
||||
- 新增 示例地址
|
||||
- 修复 示例项目缺少组件的Bug
|
||||
## 1.0.3(2021-04-16)
|
||||
- 新增 sortable 属性,是否开启单列排序
|
||||
- 优化 表格多选逻辑
|
||||
## 1.0.2(2021-03-22)
|
||||
- uni-tr 添加 disabled 属性,用于 type=selection 时,设置某行是否可由全选按钮控制
|
||||
## 1.0.1(2021-02-05)
|
||||
- 调整为uni_modules目录规范
|
||||
455
uni_modules/uni-table/components/uni-table/uni-table.vue
Normal file
455
uni_modules/uni-table/components/uni-table/uni-table.vue
Normal file
@ -0,0 +1,455 @@
|
||||
<template>
|
||||
<view class="uni-table-scroll" :class="{ 'table--border': border, 'border-none': !noData }" style="height: 100%;padding-top: 20rpx;">
|
||||
<!-- #ifdef H5 -->
|
||||
<table class="uni-table" border="0" cellpadding="0" cellspacing="0" :class="{ 'table--stripe': stripe }" :style="{ 'min-width': minWidth + 'px' }">
|
||||
<slot></slot>
|
||||
<tr v-if="noData" class="uni-table-loading">
|
||||
<td class="uni-table-text" :class="{ 'empty-border': border }">{{ emptyText }}</td>
|
||||
</tr>
|
||||
<view v-if="loading" class="uni-table-mask" :class="{ 'empty-border': border }"><div class="uni-table--loader"></div></view>
|
||||
</table>
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef H5 -->
|
||||
<view class="uni-table" :style="{ 'min-width': minWidth + 'px' }" :class="{ 'table--stripe': stripe }">
|
||||
<slot></slot>
|
||||
<view v-if="noData" class="uni-table-loading">
|
||||
<view class="uni-table-text" :class="{ 'empty-border': border }">{{ emptyText }}</view>
|
||||
</view>
|
||||
<view v-if="loading" class="uni-table-mask" :class="{ 'empty-border': border }"><div class="uni-table--loader"></div></view>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* Table 表格
|
||||
* @description 用于展示多条结构类似的数据
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=3270
|
||||
* @property {Boolean} border 是否带有纵向边框
|
||||
* @property {Boolean} stripe 是否显示斑马线
|
||||
* @property {Boolean} type 是否开启多选
|
||||
* @property {String} emptyText 空数据时显示的文本内容
|
||||
* @property {Boolean} loading 显示加载中
|
||||
* @event {Function} selection-change 开启多选时,当选择项发生变化时会触发该事件
|
||||
*/
|
||||
export default {
|
||||
name: 'uniTable',
|
||||
options: {
|
||||
virtualHost: true
|
||||
},
|
||||
emits:['selection-change'],
|
||||
props: {
|
||||
data: {
|
||||
type: Array,
|
||||
default() {
|
||||
return []
|
||||
}
|
||||
},
|
||||
// 是否有竖线
|
||||
border: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 是否显示斑马线
|
||||
stripe: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 多选
|
||||
type: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 没有更多数据
|
||||
emptyText: {
|
||||
type: String,
|
||||
default: '没有更多数据'
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
rowKey: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
noData: true,
|
||||
minWidth: 0,
|
||||
multiTableHeads: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
loading(val) {},
|
||||
data(newVal) {
|
||||
let theadChildren = this.theadChildren
|
||||
let rowspan = 1
|
||||
if (this.theadChildren) {
|
||||
rowspan = this.theadChildren.rowspan
|
||||
}
|
||||
|
||||
// this.trChildren.length - rowspan
|
||||
this.noData = false
|
||||
// this.noData = newVal.length === 0
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 定义tr的实例数组
|
||||
this.trChildren = []
|
||||
this.thChildren = []
|
||||
this.theadChildren = null
|
||||
this.backData = []
|
||||
this.backIndexData = []
|
||||
},
|
||||
|
||||
methods: {
|
||||
isNodata() {
|
||||
let theadChildren = this.theadChildren
|
||||
let rowspan = 1
|
||||
if (this.theadChildren) {
|
||||
rowspan = this.theadChildren.rowspan
|
||||
}
|
||||
this.noData = this.trChildren.length - rowspan <= 0
|
||||
},
|
||||
/**
|
||||
* 选中所有
|
||||
*/
|
||||
selectionAll() {
|
||||
let startIndex = 1
|
||||
let theadChildren = this.theadChildren
|
||||
if (!this.theadChildren) {
|
||||
theadChildren = this.trChildren[0]
|
||||
} else {
|
||||
startIndex = theadChildren.rowspan - 1
|
||||
}
|
||||
let isHaveData = this.data && this.data.length > 0
|
||||
theadChildren.checked = true
|
||||
theadChildren.indeterminate = false
|
||||
this.trChildren.forEach((item, index) => {
|
||||
if (!item.disabled) {
|
||||
item.checked = true
|
||||
if (isHaveData && item.keyValue) {
|
||||
const row = this.data.find(v => v[this.rowKey] === item.keyValue)
|
||||
if (!this.backData.find(v => v[this.rowKey] === row[this.rowKey])) {
|
||||
this.backData.push(row)
|
||||
}
|
||||
}
|
||||
if (index > (startIndex - 1) && this.backIndexData.indexOf(index - startIndex) === -1) {
|
||||
this.backIndexData.push(index - startIndex)
|
||||
}
|
||||
}
|
||||
})
|
||||
// this.backData = JSON.parse(JSON.stringify(this.data))
|
||||
this.$emit('selection-change', {
|
||||
detail: {
|
||||
value: this.backData,
|
||||
index: this.backIndexData
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 用于多选表格,切换某一行的选中状态,如果使用了第二个参数,则是设置这一行选中与否(selected 为 true 则选中)
|
||||
*/
|
||||
toggleRowSelection(row, selected) {
|
||||
// if (!this.theadChildren) return
|
||||
row = [].concat(row)
|
||||
|
||||
this.trChildren.forEach((item, index) => {
|
||||
// if (item.keyValue) {
|
||||
|
||||
const select = row.findIndex(v => {
|
||||
//
|
||||
if (typeof v === 'number') {
|
||||
return v === index - 1
|
||||
} else {
|
||||
return v[this.rowKey] === item.keyValue
|
||||
}
|
||||
})
|
||||
let ischeck = item.checked
|
||||
if (select !== -1) {
|
||||
if (typeof selected === 'boolean') {
|
||||
item.checked = selected
|
||||
} else {
|
||||
item.checked = !item.checked
|
||||
}
|
||||
if (ischeck !== item.checked) {
|
||||
this.check(item.rowData||item, item.checked, item.rowData?item.keyValue:null, true)
|
||||
}
|
||||
}
|
||||
// }
|
||||
})
|
||||
this.$emit('selection-change', {
|
||||
detail: {
|
||||
value: this.backData,
|
||||
index:this.backIndexData
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 用于多选表格,清空用户的选择
|
||||
*/
|
||||
clearSelection() {
|
||||
let theadChildren = this.theadChildren
|
||||
if (!this.theadChildren) {
|
||||
theadChildren = this.trChildren[0]
|
||||
}
|
||||
// if (!this.theadChildren) return
|
||||
theadChildren.checked = false
|
||||
theadChildren.indeterminate = false
|
||||
this.trChildren.forEach(item => {
|
||||
// if (item.keyValue) {
|
||||
item.checked = false
|
||||
// }
|
||||
})
|
||||
this.backData = []
|
||||
this.backIndexData = []
|
||||
this.$emit('selection-change', {
|
||||
detail: {
|
||||
value: [],
|
||||
index: []
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 用于多选表格,切换所有行的选中状态
|
||||
*/
|
||||
toggleAllSelection() {
|
||||
let list = []
|
||||
let startIndex = 1
|
||||
let theadChildren = this.theadChildren
|
||||
if (!this.theadChildren) {
|
||||
theadChildren = this.trChildren[0]
|
||||
} else {
|
||||
startIndex = theadChildren.rowspan - 1
|
||||
}
|
||||
this.trChildren.forEach((item, index) => {
|
||||
if (!item.disabled) {
|
||||
if (index > (startIndex - 1) ) {
|
||||
list.push(index-startIndex)
|
||||
}
|
||||
}
|
||||
})
|
||||
this.toggleRowSelection(list)
|
||||
},
|
||||
|
||||
/**
|
||||
* 选中\取消选中
|
||||
* @param {Object} child
|
||||
* @param {Object} check
|
||||
* @param {Object} rowValue
|
||||
*/
|
||||
check(child, check, keyValue, emit) {
|
||||
let theadChildren = this.theadChildren
|
||||
if (!this.theadChildren) {
|
||||
theadChildren = this.trChildren[0]
|
||||
}
|
||||
|
||||
|
||||
|
||||
let childDomIndex = this.trChildren.findIndex((item, index) => child === item)
|
||||
if(childDomIndex < 0){
|
||||
childDomIndex = this.data.findIndex(v=>v[this.rowKey] === keyValue) + 1
|
||||
}
|
||||
const dataLen = this.trChildren.filter(v => !v.disabled && v.keyValue).length
|
||||
if (childDomIndex === 0) {
|
||||
check ? this.selectionAll() : this.clearSelection()
|
||||
return
|
||||
}
|
||||
|
||||
if (check) {
|
||||
if (keyValue) {
|
||||
this.backData.push(child)
|
||||
}
|
||||
this.backIndexData.push(childDomIndex - 1)
|
||||
} else {
|
||||
const index = this.backData.findIndex(v => v[this.rowKey] === keyValue)
|
||||
const idx = this.backIndexData.findIndex(item => item === childDomIndex - 1)
|
||||
if (keyValue) {
|
||||
this.backData.splice(index, 1)
|
||||
}
|
||||
this.backIndexData.splice(idx, 1)
|
||||
}
|
||||
|
||||
const domCheckAll = this.trChildren.find((item, index) => index > 0 && !item.checked && !item.disabled)
|
||||
if (!domCheckAll) {
|
||||
theadChildren.indeterminate = false
|
||||
theadChildren.checked = true
|
||||
} else {
|
||||
theadChildren.indeterminate = true
|
||||
theadChildren.checked = false
|
||||
}
|
||||
|
||||
if (this.backIndexData.length === 0) {
|
||||
theadChildren.indeterminate = false
|
||||
}
|
||||
|
||||
if (!emit) {
|
||||
this.$emit('selection-change', {
|
||||
detail: {
|
||||
value: this.backData,
|
||||
index: this.backIndexData
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
$border-color: #ebeef5;
|
||||
|
||||
.uni-table-scroll {
|
||||
width: 100%;
|
||||
/* #ifndef APP-NVUE */
|
||||
overflow-x: auto;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-table {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
border-radius: 5px;
|
||||
// box-shadow: 0px 0px 3px 1px rgba(0, 0, 0, 0.1);
|
||||
background-color: #fff;
|
||||
/* #ifndef APP-NVUE */
|
||||
box-sizing: border-box;
|
||||
display: table;
|
||||
overflow-x: auto;
|
||||
::v-deep .uni-table-tr:nth-child(n + 2) {
|
||||
&:hover {
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
}
|
||||
::v-deep .uni-table-thead {
|
||||
.uni-table-tr {
|
||||
// background-color: #f5f7fa;
|
||||
&:hover {
|
||||
background-color:#fafafa;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.table--border {
|
||||
border: 1px $border-color solid;
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.border-none {
|
||||
/* #ifndef APP-NVUE */
|
||||
border-bottom: none;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.table--stripe {
|
||||
/* #ifndef APP-NVUE */
|
||||
::v-deep .uni-table-tr:nth-child(2n + 3) {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
/* 表格加载、无数据样式 */
|
||||
.uni-table-loading {
|
||||
position: relative;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: table-row;
|
||||
/* #endif */
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.empty-border {
|
||||
border-right: 1px $border-color solid;
|
||||
}
|
||||
.uni-table-text {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: 0;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.uni-table-mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
z-index: 99;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
margin: auto;
|
||||
transition: all 0.5s;
|
||||
/* #endif */
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.uni-table--loader {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border: 2px solid #aaa;
|
||||
// border-bottom-color: transparent;
|
||||
border-radius: 50%;
|
||||
/* #ifndef APP-NVUE */
|
||||
animation: 2s uni-table--loader linear infinite;
|
||||
/* #endif */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@keyframes uni-table--loader {
|
||||
0% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
|
||||
10% {
|
||||
border-left-color: transparent;
|
||||
}
|
||||
|
||||
20% {
|
||||
border-bottom-color: transparent;
|
||||
}
|
||||
|
||||
30% {
|
||||
border-right-color: transparent;
|
||||
}
|
||||
|
||||
40% {
|
||||
border-top-color: transparent;
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
60% {
|
||||
border-top-color: transparent;
|
||||
}
|
||||
|
||||
70% {
|
||||
border-left-color: transparent;
|
||||
}
|
||||
|
||||
80% {
|
||||
border-bottom-color: transparent;
|
||||
}
|
||||
|
||||
90% {
|
||||
border-right-color: transparent;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate(-360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
29
uni_modules/uni-table/components/uni-tbody/uni-tbody.vue
Normal file
29
uni_modules/uni-table/components/uni-tbody/uni-tbody.vue
Normal file
@ -0,0 +1,29 @@
|
||||
<template>
|
||||
<!-- #ifdef H5 -->
|
||||
<tbody>
|
||||
<slot></slot>
|
||||
</tbody>
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef H5 -->
|
||||
<view><slot></slot></view>
|
||||
<!-- #endif -->
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'uniBody',
|
||||
options: {
|
||||
virtualHost: true
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
}
|
||||
},
|
||||
created() {},
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
90
uni_modules/uni-table/components/uni-td/uni-td.vue
Normal file
90
uni_modules/uni-table/components/uni-td/uni-td.vue
Normal file
@ -0,0 +1,90 @@
|
||||
<template>
|
||||
<!-- #ifdef H5 -->
|
||||
<td class="uni-table-td" :rowspan="rowspan" :colspan="colspan" :class="{'table--border':border}" :style="{width:width + 'px','text-align':align}">
|
||||
<slot></slot>
|
||||
</td>
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef H5 -->
|
||||
<!-- :class="{'table--border':border}" -->
|
||||
<view class="uni-table-td" :class="{'table--border':border}" :style="{width:width + 'px','text-align':align}">
|
||||
<slot></slot>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* Td 单元格
|
||||
* @description 表格中的标准单元格组件
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=3270
|
||||
* @property {Number} align = [left|center|right] 单元格对齐方式
|
||||
*/
|
||||
export default {
|
||||
name: 'uniTd',
|
||||
options: {
|
||||
virtualHost: true
|
||||
},
|
||||
props: {
|
||||
width: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
align: {
|
||||
type: String,
|
||||
default: 'left'
|
||||
},
|
||||
rowspan: {
|
||||
type: [Number,String],
|
||||
default: 1
|
||||
},
|
||||
colspan: {
|
||||
type: [Number,String],
|
||||
default: 1
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
border: false
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.root = this.getTable()
|
||||
this.border = this.root.border
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 获取父元素实例
|
||||
*/
|
||||
getTable() {
|
||||
let parent = this.$parent;
|
||||
let parentName = parent.$options.name;
|
||||
while (parentName !== 'uniTable') {
|
||||
parent = parent.$parent;
|
||||
if (!parent) return false;
|
||||
parentName = parent.$options.name;
|
||||
}
|
||||
return parent;
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
$border-color:#EBEEF5;
|
||||
|
||||
.uni-table-td {
|
||||
display: table-cell;
|
||||
padding: 8px 10px;
|
||||
font-size: 14px;
|
||||
border-bottom: 1px $border-color solid;
|
||||
font-weight: 400;
|
||||
color: #606266;
|
||||
line-height: 23px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.table--border {
|
||||
border-right: 1px $border-color solid;
|
||||
}
|
||||
</style>
|
||||
511
uni_modules/uni-table/components/uni-th/filter-dropdown.vue
Normal file
511
uni_modules/uni-table/components/uni-th/filter-dropdown.vue
Normal file
@ -0,0 +1,511 @@
|
||||
<template>
|
||||
<view class="uni-filter-dropdown">
|
||||
<view class="dropdown-btn" @click="onDropdown">
|
||||
<view class="icon-select" :class="{active: canReset}" v-if="isSelect || isRange"></view>
|
||||
<view class="icon-search" :class="{active: canReset}" v-if="isSearch">
|
||||
<view class="icon-search-0"></view>
|
||||
<view class="icon-search-1"></view>
|
||||
</view>
|
||||
<view class="icon-calendar" :class="{active: canReset}" v-if="isDate">
|
||||
<view class="icon-calendar-0"></view>
|
||||
<view class="icon-calendar-1"></view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="uni-dropdown-cover" v-if="isOpened" @click="handleClose"></view>
|
||||
<view class="dropdown-popup dropdown-popup-right" v-if="isOpened" @click.stop>
|
||||
<!-- select-->
|
||||
<view v-if="isSelect" class="list">
|
||||
<label class="flex-r a-i-c list-item" v-for="(item,index) in dataList" :key="index"
|
||||
@click="onItemClick($event, index)">
|
||||
<check-box class="check" :checked="item.checked" />
|
||||
<view class="checklist-content">
|
||||
<text class="checklist-text" :style="item.styleIconText">{{item[map.text]}}</text>
|
||||
</view>
|
||||
</label>
|
||||
</view>
|
||||
<view v-if="isSelect" class="flex-r opera-area">
|
||||
<view class="flex-f btn btn-default" :class="{disable: !canReset}" @click="handleSelectReset">
|
||||
{{resource.reset}}</view>
|
||||
<view class="flex-f btn btn-submit" @click="handleSelectSubmit">{{resource.submit}}</view>
|
||||
</view>
|
||||
<!-- search -->
|
||||
<view v-if="isSearch" class="search-area">
|
||||
<input class="search-input" v-model="filterValue" />
|
||||
</view>
|
||||
<view v-if="isSearch" class="flex-r opera-area">
|
||||
<view class="flex-f btn btn-submit" @click="handleSearchSubmit">{{resource.search}}</view>
|
||||
<view class="flex-f btn btn-default" :class="{disable: !canReset}" @click="handleSearchReset">
|
||||
{{resource.reset}}</view>
|
||||
</view>
|
||||
<!-- range -->
|
||||
<view v-if="isRange">
|
||||
<view class="input-label">{{resource.gt}}</view>
|
||||
<input class="input" v-model="gtValue" />
|
||||
<view class="input-label">{{resource.lt}}</view>
|
||||
<input class="input" v-model="ltValue" />
|
||||
</view>
|
||||
<view v-if="isRange" class="flex-r opera-area">
|
||||
<view class="flex-f btn btn-default" :class="{disable: !canReset}" @click="handleRangeReset">
|
||||
{{resource.reset}}</view>
|
||||
<view class="flex-f btn btn-submit" @click="handleRangeSubmit">{{resource.submit}}</view>
|
||||
</view>
|
||||
<!-- date -->
|
||||
<view v-if="isDate">
|
||||
<uni-datetime-picker ref="datetimepicker" :value="dateRange" type="datetimerange" return-type="timestamp" @change="datetimechange" @maskClick="timepickerclose">
|
||||
<view></view>
|
||||
</uni-datetime-picker>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import checkBox from '../uni-tr/table-checkbox.vue'
|
||||
|
||||
const resource = {
|
||||
"reset": "重置",
|
||||
"search": "搜索",
|
||||
"submit": "确定",
|
||||
"filter": "筛选",
|
||||
"gt": "大于等于",
|
||||
"lt": "小于等于",
|
||||
"date": "日期范围"
|
||||
}
|
||||
|
||||
const DropdownType = {
|
||||
Select: "select",
|
||||
Search: "search",
|
||||
Range: "range",
|
||||
Date: "date",
|
||||
Timestamp: "timestamp"
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'FilterDropdown',
|
||||
emits:['change'],
|
||||
components: {
|
||||
checkBox
|
||||
},
|
||||
options: {
|
||||
virtualHost: true
|
||||
},
|
||||
props: {
|
||||
filterType: {
|
||||
type: String,
|
||||
default: DropdownType.Select
|
||||
},
|
||||
filterData: {
|
||||
type: Array,
|
||||
default () {
|
||||
return []
|
||||
}
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'default'
|
||||
},
|
||||
map: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {
|
||||
text: 'text',
|
||||
value: 'value'
|
||||
}
|
||||
}
|
||||
},
|
||||
filterDefaultValue: {
|
||||
type: [Array,String],
|
||||
default () {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
canReset() {
|
||||
if (this.isSearch) {
|
||||
return this.filterValue.length > 0
|
||||
}
|
||||
if (this.isSelect) {
|
||||
return this.checkedValues.length > 0
|
||||
}
|
||||
if (this.isRange) {
|
||||
return (this.gtValue.length > 0 && this.ltValue.length > 0)
|
||||
}
|
||||
if (this.isDate) {
|
||||
return this.dateSelect.length > 0
|
||||
}
|
||||
return false
|
||||
},
|
||||
isSelect() {
|
||||
return this.filterType === DropdownType.Select
|
||||
},
|
||||
isSearch() {
|
||||
return this.filterType === DropdownType.Search
|
||||
},
|
||||
isRange() {
|
||||
return this.filterType === DropdownType.Range
|
||||
},
|
||||
isDate() {
|
||||
return (this.filterType === DropdownType.Date || this.filterType === DropdownType.Timestamp)
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
filterData(newVal) {
|
||||
this._copyFilters()
|
||||
},
|
||||
indeterminate(newVal) {
|
||||
this.isIndeterminate = newVal
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
resource,
|
||||
enabled: true,
|
||||
isOpened: false,
|
||||
dataList: [],
|
||||
filterValue: this.filterDefaultValue,
|
||||
checkedValues: [],
|
||||
gtValue: '',
|
||||
ltValue: '',
|
||||
dateRange: [],
|
||||
dateSelect: []
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this._copyFilters()
|
||||
},
|
||||
methods: {
|
||||
_copyFilters() {
|
||||
let dl = JSON.parse(JSON.stringify(this.filterData))
|
||||
for (let i = 0; i < dl.length; i++) {
|
||||
if (dl[i].checked === undefined) {
|
||||
dl[i].checked = false
|
||||
}
|
||||
}
|
||||
this.dataList = dl
|
||||
},
|
||||
openPopup() {
|
||||
this.isOpened = true
|
||||
if (this.isDate) {
|
||||
this.$nextTick(() => {
|
||||
if (!this.dateRange.length) {
|
||||
this.resetDate()
|
||||
}
|
||||
this.$refs.datetimepicker.show()
|
||||
})
|
||||
}
|
||||
},
|
||||
closePopup() {
|
||||
this.isOpened = false
|
||||
},
|
||||
handleClose(e) {
|
||||
this.closePopup()
|
||||
},
|
||||
resetDate() {
|
||||
let date = new Date()
|
||||
let dateText = date.toISOString().split('T')[0]
|
||||
this.dateRange = [dateText + ' 0:00:00', dateText + ' 23:59:59']
|
||||
},
|
||||
onDropdown(e) {
|
||||
this.openPopup()
|
||||
},
|
||||
onItemClick(e, index) {
|
||||
let items = this.dataList
|
||||
let listItem = items[index]
|
||||
if (listItem.checked === undefined) {
|
||||
items[index].checked = true
|
||||
} else {
|
||||
items[index].checked = !listItem.checked
|
||||
}
|
||||
|
||||
let checkvalues = []
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const item = items[i]
|
||||
if (item.checked) {
|
||||
checkvalues.push(item.value)
|
||||
}
|
||||
}
|
||||
this.checkedValues = checkvalues
|
||||
},
|
||||
datetimechange(e) {
|
||||
this.closePopup()
|
||||
this.dateRange = e
|
||||
this.dateSelect = e
|
||||
this.$emit('change', {
|
||||
filterType: this.filterType,
|
||||
filter: e
|
||||
})
|
||||
},
|
||||
timepickerclose(e) {
|
||||
this.closePopup()
|
||||
},
|
||||
handleSelectSubmit() {
|
||||
this.closePopup()
|
||||
this.$emit('change', {
|
||||
filterType: this.filterType,
|
||||
filter: this.checkedValues
|
||||
})
|
||||
},
|
||||
handleSelectReset() {
|
||||
if (!this.canReset) {
|
||||
return;
|
||||
}
|
||||
var items = this.dataList
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
let item = items[i]
|
||||
this.$set(item, 'checked', false)
|
||||
}
|
||||
this.checkedValues = []
|
||||
this.handleSelectSubmit()
|
||||
},
|
||||
handleSearchSubmit() {
|
||||
this.closePopup()
|
||||
this.$emit('change', {
|
||||
filterType: this.filterType,
|
||||
filter: this.filterValue
|
||||
})
|
||||
},
|
||||
handleSearchReset() {
|
||||
if (!this.canReset) {
|
||||
return;
|
||||
}
|
||||
this.filterValue = ''
|
||||
this.handleSearchSubmit()
|
||||
},
|
||||
handleRangeSubmit(isReset) {
|
||||
this.closePopup()
|
||||
this.$emit('change', {
|
||||
filterType: this.filterType,
|
||||
filter: isReset === true ? [] : [parseInt(this.gtValue), parseInt(this.ltValue)]
|
||||
})
|
||||
},
|
||||
handleRangeReset() {
|
||||
if (!this.canReset) {
|
||||
return;
|
||||
}
|
||||
this.gtValue = ''
|
||||
this.ltValue = ''
|
||||
this.handleRangeSubmit(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
$uni-primary: #1890ff !default;
|
||||
|
||||
.flex-r {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.flex-f {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.a-i-c {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.j-c-c {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.icon-select {
|
||||
width: 14px;
|
||||
height: 16px;
|
||||
border: solid 6px transparent;
|
||||
border-top: solid 6px #ddd;
|
||||
border-bottom: none;
|
||||
background-color: #ddd;
|
||||
background-clip: content-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.icon-select.active {
|
||||
background-color: $uni-primary;
|
||||
border-top-color: $uni-primary;
|
||||
}
|
||||
|
||||
.icon-search {
|
||||
width: 12px;
|
||||
height: 16px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.icon-search-0 {
|
||||
border: 2px solid #ddd;
|
||||
border-radius: 8px;
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
}
|
||||
|
||||
.icon-search-1 {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 0;
|
||||
width: 1px;
|
||||
height: 7px;
|
||||
background-color: #ddd;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.icon-search.active .icon-search-0 {
|
||||
border-color: $uni-primary;
|
||||
}
|
||||
|
||||
.icon-search.active .icon-search-1 {
|
||||
background-color: $uni-primary;
|
||||
}
|
||||
|
||||
.icon-calendar {
|
||||
color: #ddd;
|
||||
width: 14px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.icon-calendar-0 {
|
||||
height: 4px;
|
||||
margin-top: 3px;
|
||||
margin-bottom: 1px;
|
||||
background-color: #ddd;
|
||||
border-radius: 2px 2px 1px 1px;
|
||||
position: relative;
|
||||
}
|
||||
.icon-calendar-0:before, .icon-calendar-0:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -3px;
|
||||
width: 4px;
|
||||
height: 3px;
|
||||
border-radius: 1px;
|
||||
background-color: #ddd;
|
||||
}
|
||||
.icon-calendar-0:before {
|
||||
left: 2px;
|
||||
}
|
||||
.icon-calendar-0:after {
|
||||
right: 2px;
|
||||
}
|
||||
|
||||
.icon-calendar-1 {
|
||||
height: 9px;
|
||||
background-color: #ddd;
|
||||
border-radius: 1px 1px 2px 2px;
|
||||
}
|
||||
|
||||
.icon-calendar.active {
|
||||
color: $uni-primary;
|
||||
}
|
||||
|
||||
.icon-calendar.active .icon-calendar-0,
|
||||
.icon-calendar.active .icon-calendar-1,
|
||||
.icon-calendar.active .icon-calendar-0:before,
|
||||
.icon-calendar.active .icon-calendar-0:after {
|
||||
background-color: $uni-primary;
|
||||
}
|
||||
|
||||
.uni-filter-dropdown {
|
||||
position: relative;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.dropdown-popup {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 3px 6px -4px #0000001f, 0 6px 16px #00000014, 0 9px 28px 8px #0000000d;
|
||||
min-width: 150px;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.dropdown-popup-left {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.dropdown-popup-right {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.uni-dropdown-cover {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: transparent;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.list {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.list-item {
|
||||
padding: 5px 10px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.list-item:hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.check {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.search-area {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
font-size: 12px;
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 3px;
|
||||
padding: 2px 5px;
|
||||
min-width: 150px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.input-label {
|
||||
margin: 10px 10px 5px 10px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.input {
|
||||
font-size: 12px;
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 3px;
|
||||
margin: 10px;
|
||||
padding: 2px 5px;
|
||||
min-width: 150px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.opera-area {
|
||||
cursor: default;
|
||||
border-top: 1px solid #ddd;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.opera-area .btn {
|
||||
font-size: 12px;
|
||||
border-radius: 3px;
|
||||
margin: 5px;
|
||||
padding: 4px 4px;
|
||||
}
|
||||
|
||||
.btn-default {
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.btn-default.disable {
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.btn-submit {
|
||||
background-color: $uni-primary;
|
||||
color: #ffffff;
|
||||
}
|
||||
</style>
|
||||
285
uni_modules/uni-table/components/uni-th/uni-th.vue
Normal file
285
uni_modules/uni-table/components/uni-th/uni-th.vue
Normal file
@ -0,0 +1,285 @@
|
||||
<template>
|
||||
<!-- #ifdef H5 -->
|
||||
<th :rowspan="rowspan" :colspan="colspan" class="uni-table-th" :class="{ 'table--border': border }" :style="{ width: customWidth + 'px', 'text-align': align }">
|
||||
<view class="uni-table-th-row">
|
||||
<view class="uni-table-th-content" :style="{ 'justify-content': contentAlign }" @click="sort">
|
||||
<slot></slot>
|
||||
<view v-if="sortable" class="arrow-box">
|
||||
<text class="arrow up" :class="{ active: ascending }" @click.stop="ascendingFn"></text>
|
||||
<text class="arrow down" :class="{ active: descending }" @click.stop="descendingFn"></text>
|
||||
</view>
|
||||
</view>
|
||||
<dropdown v-if="filterType || filterData.length" :filterDefaultValue="filterDefaultValue" :filterData="filterData" :filterType="filterType" @change="ondropdown"></dropdown>
|
||||
</view>
|
||||
</th>
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef H5 -->
|
||||
<view class="uni-table-th" :class="{ 'table--border': border }" :style="{ width: customWidth + 'px', 'text-align': align }"><slot></slot></view>
|
||||
<!-- #endif -->
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// #ifdef H5
|
||||
import dropdown from './filter-dropdown.vue'
|
||||
// #endif
|
||||
/**
|
||||
* Th 表头
|
||||
* @description 表格内的表头单元格组件
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=3270
|
||||
* @property {Number | String} width 单元格宽度(支持纯数字、携带单位px或rpx)
|
||||
* @property {Boolean} sortable 是否启用排序
|
||||
* @property {Number} align = [left|center|right] 单元格对齐方式
|
||||
* @value left 单元格文字左侧对齐
|
||||
* @value center 单元格文字居中
|
||||
* @value right 单元格文字右侧对齐
|
||||
* @property {Array} filterData 筛选数据
|
||||
* @property {String} filterType [search|select] 筛选类型
|
||||
* @value search 关键字搜素
|
||||
* @value select 条件选择
|
||||
* @event {Function} sort-change 排序触发事件
|
||||
*/
|
||||
export default {
|
||||
name: 'uniTh',
|
||||
options: {
|
||||
virtualHost: true
|
||||
},
|
||||
components: {
|
||||
// #ifdef H5
|
||||
dropdown
|
||||
// #endif
|
||||
},
|
||||
emits:['sort-change','filter-change'],
|
||||
props: {
|
||||
width: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
align: {
|
||||
type: String,
|
||||
default: 'left'
|
||||
},
|
||||
rowspan: {
|
||||
type: [Number, String],
|
||||
default: 1
|
||||
},
|
||||
colspan: {
|
||||
type: [Number, String],
|
||||
default: 1
|
||||
},
|
||||
sortable: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
filterType: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
filterData: {
|
||||
type: Array,
|
||||
default () {
|
||||
return []
|
||||
}
|
||||
},
|
||||
filterDefaultValue: {
|
||||
type: [Array,String],
|
||||
default () {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
border: false,
|
||||
ascending: false,
|
||||
descending: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 根据props中的width属性 自动匹配当前th的宽度(px)
|
||||
customWidth(){
|
||||
if(typeof this.width === 'number'){
|
||||
return this.width
|
||||
} else if(typeof this.width === 'string') {
|
||||
let regexHaveUnitPx = new RegExp(/^[1-9][0-9]*px$/g)
|
||||
let regexHaveUnitRpx = new RegExp(/^[1-9][0-9]*rpx$/g)
|
||||
let regexHaveNotUnit = new RegExp(/^[1-9][0-9]*$/g)
|
||||
if (this.width.match(regexHaveUnitPx) !== null) { // 携带了 px
|
||||
return this.width.replace('px', '')
|
||||
} else if (this.width.match(regexHaveUnitRpx) !== null) { // 携带了 rpx
|
||||
let numberRpx = Number(this.width.replace('rpx', ''))
|
||||
let widthCoe = uni.getSystemInfoSync().screenWidth / 750
|
||||
return Math.round(numberRpx * widthCoe)
|
||||
} else if (this.width.match(regexHaveNotUnit) !== null) { // 未携带 rpx或px 的纯数字 String
|
||||
return this.width
|
||||
} else { // 不符合格式
|
||||
return ''
|
||||
}
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
},
|
||||
contentAlign() {
|
||||
let align = 'left'
|
||||
switch (this.align) {
|
||||
case 'left':
|
||||
align = 'flex-start'
|
||||
break
|
||||
case 'center':
|
||||
align = 'center'
|
||||
break
|
||||
case 'right':
|
||||
align = 'flex-end'
|
||||
break
|
||||
}
|
||||
return align
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.root = this.getTable('uniTable')
|
||||
this.rootTr = this.getTable('uniTr')
|
||||
this.rootTr.minWidthUpdate(this.customWidth ? this.customWidth : 140)
|
||||
this.border = this.root.border
|
||||
this.root.thChildren.push(this)
|
||||
},
|
||||
methods: {
|
||||
sort() {
|
||||
if (!this.sortable) return
|
||||
this.clearOther()
|
||||
if (!this.ascending && !this.descending) {
|
||||
this.ascending = true
|
||||
this.$emit('sort-change', { order: 'ascending' })
|
||||
return
|
||||
}
|
||||
if (this.ascending && !this.descending) {
|
||||
this.ascending = false
|
||||
this.descending = true
|
||||
this.$emit('sort-change', { order: 'descending' })
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.ascending && this.descending) {
|
||||
this.ascending = false
|
||||
this.descending = false
|
||||
this.$emit('sort-change', { order: null })
|
||||
}
|
||||
},
|
||||
ascendingFn() {
|
||||
this.clearOther()
|
||||
this.ascending = !this.ascending
|
||||
this.descending = false
|
||||
this.$emit('sort-change', { order: this.ascending ? 'ascending' : null })
|
||||
},
|
||||
descendingFn() {
|
||||
this.clearOther()
|
||||
this.descending = !this.descending
|
||||
this.ascending = false
|
||||
this.$emit('sort-change', { order: this.descending ? 'descending' : null })
|
||||
},
|
||||
clearOther() {
|
||||
this.root.thChildren.map(item => {
|
||||
if (item !== this) {
|
||||
item.ascending = false
|
||||
item.descending = false
|
||||
}
|
||||
return item
|
||||
})
|
||||
},
|
||||
ondropdown(e) {
|
||||
this.$emit("filter-change", e)
|
||||
},
|
||||
/**
|
||||
* 获取父元素实例
|
||||
*/
|
||||
getTable(name) {
|
||||
let parent = this.$parent
|
||||
let parentName = parent.$options.name
|
||||
while (parentName !== name) {
|
||||
parent = parent.$parent
|
||||
if (!parent) return false
|
||||
parentName = parent.$options.name
|
||||
}
|
||||
return parent
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
$border-color: #ebeef5;
|
||||
$uni-primary: #007aff !default;
|
||||
|
||||
.uni-table-th {
|
||||
padding: 12px 10px;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: table-cell;
|
||||
box-sizing: border-box;
|
||||
/* #endif */
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
color: #909399;
|
||||
border-bottom: 1px $border-color solid;
|
||||
}
|
||||
|
||||
.uni-table-th-row {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.table--border {
|
||||
border-right: 1px $border-color solid;
|
||||
}
|
||||
.uni-table-th-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
}
|
||||
.arrow-box {
|
||||
}
|
||||
.arrow {
|
||||
display: block;
|
||||
position: relative;
|
||||
width: 10px;
|
||||
height: 8px;
|
||||
// border: 1px red solid;
|
||||
left: 5px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
}
|
||||
.down {
|
||||
top: 3px;
|
||||
::after {
|
||||
content: '';
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
position: absolute;
|
||||
left: 2px;
|
||||
top: -5px;
|
||||
transform: rotate(45deg);
|
||||
background-color: #ccc;
|
||||
}
|
||||
&.active {
|
||||
::after {
|
||||
background-color: $uni-primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
.up {
|
||||
::after {
|
||||
content: '';
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
position: absolute;
|
||||
left: 2px;
|
||||
top: 5px;
|
||||
transform: rotate(45deg);
|
||||
background-color: #ccc;
|
||||
}
|
||||
&.active {
|
||||
::after {
|
||||
background-color: $uni-primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
129
uni_modules/uni-table/components/uni-thead/uni-thead.vue
Normal file
129
uni_modules/uni-table/components/uni-thead/uni-thead.vue
Normal file
@ -0,0 +1,129 @@
|
||||
<template>
|
||||
<!-- #ifdef H5 -->
|
||||
<thead class="uni-table-thead">
|
||||
<tr class="uni-table-tr">
|
||||
<th :rowspan="rowspan" colspan="1" class="checkbox" :class="{ 'tr-table--border': border }">
|
||||
<table-checkbox :indeterminate="indeterminate" :checked="checked" @checkboxSelected="checkboxSelected"></table-checkbox>
|
||||
</th>
|
||||
</tr>
|
||||
<slot></slot>
|
||||
</thead>
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef H5 -->
|
||||
<view class="uni-table-thead"><slot></slot></view>
|
||||
<!-- #endif -->
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import tableCheckbox from '../uni-tr/table-checkbox.vue'
|
||||
export default {
|
||||
name: 'uniThead',
|
||||
components: {
|
||||
tableCheckbox
|
||||
},
|
||||
options: {
|
||||
virtualHost: true
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
border: false,
|
||||
selection: false,
|
||||
rowspan: 1,
|
||||
indeterminate: false,
|
||||
checked: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.root = this.getTable()
|
||||
// #ifdef H5
|
||||
this.root.theadChildren = this
|
||||
// #endif
|
||||
this.border = this.root.border
|
||||
this.selection = this.root.type
|
||||
},
|
||||
methods: {
|
||||
init(self) {
|
||||
this.rowspan++
|
||||
},
|
||||
checkboxSelected(e) {
|
||||
this.indeterminate = false
|
||||
const backIndexData = this.root.backIndexData
|
||||
const data = this.root.trChildren.filter(v => !v.disabled && v.keyValue)
|
||||
if (backIndexData.length === data.length) {
|
||||
this.checked = false
|
||||
this.root.clearSelection()
|
||||
} else {
|
||||
this.checked = true
|
||||
this.root.selectionAll()
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 获取父元素实例
|
||||
*/
|
||||
getTable(name = 'uniTable') {
|
||||
let parent = this.$parent
|
||||
let parentName = parent.$options.name
|
||||
while (parentName !== name) {
|
||||
parent = parent.$parent
|
||||
if (!parent) return false
|
||||
parentName = parent.$options.name
|
||||
}
|
||||
return parent
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
$border-color: #ebeef5;
|
||||
|
||||
.uni-table-thead {
|
||||
display: table-header-group;
|
||||
}
|
||||
|
||||
.uni-table-tr {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: table-row;
|
||||
transition: all 0.3s;
|
||||
box-sizing: border-box;
|
||||
/* #endif */
|
||||
border: 1px red solid;
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
.checkbox {
|
||||
padding: 0 8px;
|
||||
width: 26px;
|
||||
padding-left: 12px;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
/* #endif */
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
border-bottom: 1px $border-color solid;
|
||||
font-size: 14px;
|
||||
// text-align: center;
|
||||
}
|
||||
|
||||
.tr-table--border {
|
||||
border-right: 1px $border-color solid;
|
||||
}
|
||||
|
||||
/* #ifndef APP-NVUE */
|
||||
.uni-table-tr {
|
||||
::v-deep .uni-table-th {
|
||||
&.table--border:last-child {
|
||||
// border-right: none;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .uni-table-td {
|
||||
&.table--border:last-child {
|
||||
// border-right: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
</style>
|
||||
179
uni_modules/uni-table/components/uni-tr/table-checkbox.vue
Normal file
179
uni_modules/uni-table/components/uni-tr/table-checkbox.vue
Normal file
@ -0,0 +1,179 @@
|
||||
<template>
|
||||
<view class="uni-table-checkbox" @click="selected">
|
||||
<view v-if="!indeterminate" class="checkbox__inner" :class="{'is-checked':isChecked,'is-disable':isDisabled}">
|
||||
<view class="checkbox__inner-icon"></view>
|
||||
</view>
|
||||
<view v-else class="checkbox__inner checkbox--indeterminate">
|
||||
<view class="checkbox__inner-icon"></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'TableCheckbox',
|
||||
emits:['checkboxSelected'],
|
||||
props: {
|
||||
indeterminate: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
checked: {
|
||||
type: [Boolean,String],
|
||||
default: false
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
index: {
|
||||
type: Number,
|
||||
default: -1
|
||||
},
|
||||
cellData: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
watch:{
|
||||
checked(newVal){
|
||||
if(typeof this.checked === 'boolean'){
|
||||
this.isChecked = newVal
|
||||
}else{
|
||||
this.isChecked = true
|
||||
}
|
||||
},
|
||||
indeterminate(newVal){
|
||||
this.isIndeterminate = newVal
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isChecked: false,
|
||||
isDisabled: false,
|
||||
isIndeterminate:false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if(typeof this.checked === 'boolean'){
|
||||
this.isChecked = this.checked
|
||||
}
|
||||
this.isDisabled = this.disabled
|
||||
},
|
||||
methods: {
|
||||
selected() {
|
||||
if (this.isDisabled) return
|
||||
this.isIndeterminate = false
|
||||
this.isChecked = !this.isChecked
|
||||
this.$emit('checkboxSelected', {
|
||||
checked: this.isChecked,
|
||||
data: this.cellData
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
$uni-primary: #007aff !default;
|
||||
$border-color: #DCDFE6;
|
||||
$disable:0.4;
|
||||
|
||||
.uni-table-checkbox {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
margin: 5px 0;
|
||||
cursor: pointer;
|
||||
|
||||
// 多选样式
|
||||
.checkbox__inner {
|
||||
/* #ifndef APP-NVUE */
|
||||
flex-shrink: 0;
|
||||
box-sizing: border-box;
|
||||
/* #endif */
|
||||
position: relative;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 1px solid $border-color;
|
||||
border-radius: 2px;
|
||||
background-color: #fff;
|
||||
z-index: 1;
|
||||
|
||||
.checkbox__inner-icon {
|
||||
position: absolute;
|
||||
/* #ifdef APP-NVUE */
|
||||
top: 2px;
|
||||
/* #endif */
|
||||
/* #ifndef APP-NVUE */
|
||||
top: 2px;
|
||||
/* #endif */
|
||||
left: 5px;
|
||||
height: 7px;
|
||||
width: 3px;
|
||||
border: 1px solid #fff;
|
||||
border-left: 0;
|
||||
border-top: 0;
|
||||
opacity: 0;
|
||||
transform-origin: center;
|
||||
transform: rotate(45deg);
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
&.checkbox--indeterminate {
|
||||
border-color: $uni-primary;
|
||||
background-color: $uni-primary;
|
||||
|
||||
.checkbox__inner-icon {
|
||||
position: absolute;
|
||||
opacity: 1;
|
||||
transform: rotate(0deg);
|
||||
height: 2px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
bottom: 0;
|
||||
width: auto;
|
||||
border: none;
|
||||
border-radius: 2px;
|
||||
transform: scale(0.5);
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
&:hover{
|
||||
border-color: $uni-primary;
|
||||
}
|
||||
// 禁用
|
||||
&.is-disable {
|
||||
/* #ifdef H5 */
|
||||
cursor: not-allowed;
|
||||
/* #endif */
|
||||
background-color: #F2F6FC;
|
||||
border-color: $border-color;
|
||||
}
|
||||
|
||||
// 选中
|
||||
&.is-checked {
|
||||
border-color: $uni-primary;
|
||||
background-color: $uni-primary;
|
||||
|
||||
.checkbox__inner-icon {
|
||||
opacity: 1;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
// 选中禁用
|
||||
&.is-disable {
|
||||
opacity: $disable;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</style>
|
||||
175
uni_modules/uni-table/components/uni-tr/uni-tr.vue
Normal file
175
uni_modules/uni-table/components/uni-tr/uni-tr.vue
Normal file
@ -0,0 +1,175 @@
|
||||
<template>
|
||||
<!-- #ifdef H5 -->
|
||||
<tr class="uni-table-tr">
|
||||
<th v-if="selection === 'selection' && ishead" class="checkbox" :class="{ 'tr-table--border': border }">
|
||||
<table-checkbox :checked="checked" :indeterminate="indeterminate" :disabled="disabled" @checkboxSelected="checkboxSelected"></table-checkbox>
|
||||
</th>
|
||||
<slot></slot>
|
||||
<!-- <uni-th class="th-fixed">123</uni-th> -->
|
||||
</tr>
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef H5 -->
|
||||
<view class="uni-table-tr">
|
||||
<view v-if="selection === 'selection' " class="checkbox" :class="{ 'tr-table--border': border }">
|
||||
<table-checkbox :checked="checked" :indeterminate="indeterminate" :disabled="disabled" @checkboxSelected="checkboxSelected"></table-checkbox>
|
||||
</view>
|
||||
<slot></slot>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import tableCheckbox from './table-checkbox.vue'
|
||||
/**
|
||||
* Tr 表格行组件
|
||||
* @description 表格行组件 仅包含 th,td 组件
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=
|
||||
*/
|
||||
export default {
|
||||
name: 'uniTr',
|
||||
components: { tableCheckbox },
|
||||
props: {
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
keyValue: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
options: {
|
||||
virtualHost: true
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
value: false,
|
||||
border: false,
|
||||
selection: false,
|
||||
widthThArr: [],
|
||||
ishead: true,
|
||||
checked: false,
|
||||
indeterminate:false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.root = this.getTable()
|
||||
this.head = this.getTable('uniThead')
|
||||
if (this.head) {
|
||||
this.ishead = false
|
||||
this.head.init(this)
|
||||
}
|
||||
this.border = this.root.border
|
||||
this.selection = this.root.type
|
||||
this.root.trChildren.push(this)
|
||||
const rowData = this.root.data.find(v => v[this.root.rowKey] === this.keyValue)
|
||||
if(rowData){
|
||||
this.rowData = rowData
|
||||
}
|
||||
this.root.isNodata()
|
||||
},
|
||||
mounted() {
|
||||
if (this.widthThArr.length > 0) {
|
||||
const selectionWidth = this.selection === 'selection' ? 50 : 0
|
||||
this.root.minWidth = Number(this.widthThArr.reduce((a, b) => Number(a) + Number(b))) + selectionWidth;
|
||||
}
|
||||
},
|
||||
// #ifndef VUE3
|
||||
destroyed() {
|
||||
const index = this.root.trChildren.findIndex(i => i === this)
|
||||
this.root.trChildren.splice(index, 1)
|
||||
this.root.isNodata()
|
||||
},
|
||||
// #endif
|
||||
// #ifdef VUE3
|
||||
unmounted() {
|
||||
const index = this.root.trChildren.findIndex(i => i === this)
|
||||
this.root.trChildren.splice(index, 1)
|
||||
this.root.isNodata()
|
||||
},
|
||||
// #endif
|
||||
methods: {
|
||||
minWidthUpdate(width) {
|
||||
this.widthThArr.push(width)
|
||||
if (this.widthThArr.length > 0) {
|
||||
const selectionWidth = this.selection === 'selection' ? 50 : 0;
|
||||
this.root.minWidth = Number(this.widthThArr.reduce((a, b) => Number(a) + Number(b))) + selectionWidth;
|
||||
}
|
||||
},
|
||||
// 选中
|
||||
checkboxSelected(e) {
|
||||
let rootData = this.root.data.find(v => v[this.root.rowKey] === this.keyValue)
|
||||
this.checked = e.checked
|
||||
this.root.check(rootData||this, e.checked,rootData? this.keyValue:null)
|
||||
},
|
||||
change(e) {
|
||||
this.root.trChildren.forEach(item => {
|
||||
if (item === this) {
|
||||
this.root.check(this, e.detail.value.length > 0 ? true : false)
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 获取父元素实例
|
||||
*/
|
||||
getTable(name = 'uniTable') {
|
||||
let parent = this.$parent
|
||||
let parentName = parent.$options.name
|
||||
while (parentName !== name) {
|
||||
parent = parent.$parent
|
||||
if (!parent) return false
|
||||
parentName = parent.$options.name
|
||||
}
|
||||
return parent
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
$border-color: #ebeef5;
|
||||
|
||||
.uni-table-tr {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: table-row;
|
||||
transition: all 0.3s;
|
||||
box-sizing: border-box;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.checkbox {
|
||||
padding: 0 8px;
|
||||
width: 26px;
|
||||
padding-left: 12px;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
/* #endif */
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
border-bottom: 1px $border-color solid;
|
||||
font-size: 14px;
|
||||
// text-align: center;
|
||||
}
|
||||
|
||||
.tr-table--border {
|
||||
border-right: 1px $border-color solid;
|
||||
}
|
||||
|
||||
/* #ifndef APP-NVUE */
|
||||
.uni-table-tr {
|
||||
::v-deep .uni-table-th {
|
||||
&.table--border:last-child {
|
||||
// border-right: none;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .uni-table-td {
|
||||
&.table--border:last-child {
|
||||
// border-right: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
</style>
|
||||
9
uni_modules/uni-table/i18n/en.json
Normal file
9
uni_modules/uni-table/i18n/en.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"filter-dropdown.reset": "Reset",
|
||||
"filter-dropdown.search": "Search",
|
||||
"filter-dropdown.submit": "Submit",
|
||||
"filter-dropdown.filter": "Filter",
|
||||
"filter-dropdown.gt": "Greater or equal to",
|
||||
"filter-dropdown.lt": "Less than or equal to",
|
||||
"filter-dropdown.date": "Date"
|
||||
}
|
||||
9
uni_modules/uni-table/i18n/es.json
Normal file
9
uni_modules/uni-table/i18n/es.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"filter-dropdown.reset": "Reiniciar",
|
||||
"filter-dropdown.search": "Búsqueda",
|
||||
"filter-dropdown.submit": "Entregar",
|
||||
"filter-dropdown.filter": "Filtrar",
|
||||
"filter-dropdown.gt": "Mayor o igual a",
|
||||
"filter-dropdown.lt": "Menos que o igual a",
|
||||
"filter-dropdown.date": "Fecha"
|
||||
}
|
||||
9
uni_modules/uni-table/i18n/fr.json
Normal file
9
uni_modules/uni-table/i18n/fr.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"filter-dropdown.reset": "Réinitialiser",
|
||||
"filter-dropdown.search": "Chercher",
|
||||
"filter-dropdown.submit": "Soumettre",
|
||||
"filter-dropdown.filter": "Filtre",
|
||||
"filter-dropdown.gt": "Supérieur ou égal à",
|
||||
"filter-dropdown.lt": "Inférieur ou égal à",
|
||||
"filter-dropdown.date": "Date"
|
||||
}
|
||||
12
uni_modules/uni-table/i18n/index.js
Normal file
12
uni_modules/uni-table/i18n/index.js
Normal file
@ -0,0 +1,12 @@
|
||||
import en from './en.json'
|
||||
import es from './es.json'
|
||||
import fr from './fr.json'
|
||||
import zhHans from './zh-Hans.json'
|
||||
import zhHant from './zh-Hant.json'
|
||||
export default {
|
||||
en,
|
||||
es,
|
||||
fr,
|
||||
'zh-Hans': zhHans,
|
||||
'zh-Hant': zhHant
|
||||
}
|
||||
9
uni_modules/uni-table/i18n/zh-Hans.json
Normal file
9
uni_modules/uni-table/i18n/zh-Hans.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"filter-dropdown.reset": "重置",
|
||||
"filter-dropdown.search": "搜索",
|
||||
"filter-dropdown.submit": "确定",
|
||||
"filter-dropdown.filter": "筛选",
|
||||
"filter-dropdown.gt": "大于等于",
|
||||
"filter-dropdown.lt": "小于等于",
|
||||
"filter-dropdown.date": "日期范围"
|
||||
}
|
||||
9
uni_modules/uni-table/i18n/zh-Hant.json
Normal file
9
uni_modules/uni-table/i18n/zh-Hant.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"filter-dropdown.reset": "重置",
|
||||
"filter-dropdown.search": "搜索",
|
||||
"filter-dropdown.submit": "確定",
|
||||
"filter-dropdown.filter": "篩選",
|
||||
"filter-dropdown.gt": "大於等於",
|
||||
"filter-dropdown.lt": "小於等於",
|
||||
"filter-dropdown.date": "日期範圍"
|
||||
}
|
||||
83
uni_modules/uni-table/package.json
Normal file
83
uni_modules/uni-table/package.json
Normal file
@ -0,0 +1,83 @@
|
||||
{
|
||||
"id": "uni-table",
|
||||
"displayName": "uni-table 表格",
|
||||
"version": "1.2.4",
|
||||
"description": "表格组件,多用于展示多条结构类似的数据,如",
|
||||
"keywords": [
|
||||
"uni-ui",
|
||||
"uniui",
|
||||
"table",
|
||||
"表格"
|
||||
],
|
||||
"repository": "https://github.com/dcloudio/uni-ui",
|
||||
"engines": {
|
||||
"HBuilderX": ""
|
||||
},
|
||||
"directories": {
|
||||
"example": "../../temps/example_temps"
|
||||
},
|
||||
"dcloudext": {
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
|
||||
"type": "component-vue"
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": ["uni-scss","uni-datetime-picker"],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y"
|
||||
},
|
||||
"client": {
|
||||
"App": {
|
||||
"app-vue": "y",
|
||||
"app-nvue": "n"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "y",
|
||||
"Android Browser": "y",
|
||||
"微信浏览器(Android)": "y",
|
||||
"QQ浏览器(Android)": "y"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "y",
|
||||
"IE": "y",
|
||||
"Edge": "y",
|
||||
"Firefox": "y",
|
||||
"Safari": "y"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "y",
|
||||
"阿里": "y",
|
||||
"百度": "y",
|
||||
"字节跳动": "n",
|
||||
"QQ": "y"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "n",
|
||||
"联盟": "n"
|
||||
},
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "y"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
13
uni_modules/uni-table/readme.md
Normal file
13
uni_modules/uni-table/readme.md
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
|
||||
## Table 表单
|
||||
> 组件名:``uni-table``,代码块: `uTable`。
|
||||
|
||||
用于展示多条结构类似的数据
|
||||
|
||||
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-table)
|
||||
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
|
||||
|
||||
|
||||
|
||||
|
||||
12
uni_modules/zero-loading/changelog.md
Normal file
12
uni_modules/zero-loading/changelog.md
Normal file
@ -0,0 +1,12 @@
|
||||
## 1.2.1(2022-09-09)
|
||||
增加齿轮动画 type=gear
|
||||
## 1.2.0(2022-05-27)
|
||||
1. 增加加载类型-剑气(sword),原子(atom)
|
||||
2. 默认类型改为 atom
|
||||
3. 遮罩透明度调整
|
||||
## 1.1.1(2022-04-02)
|
||||
更新使用说明
|
||||
## 1.1.0(2022-02-23)
|
||||
增加 type="love" 的心形加载动画
|
||||
## 1.0.0(2022-01-28)
|
||||
首次发布
|
||||
@ -0,0 +1,109 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<view class="box">
|
||||
<view class="atom"></view>
|
||||
<view class="atom"></view>
|
||||
<view class="atom"></view>
|
||||
<view class="dot"></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'loading-atom',
|
||||
data() {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.container {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
.box {
|
||||
position: relative;
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
}
|
||||
.dot{
|
||||
position: absolute;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background-color: #0396FF;
|
||||
animation: dotbreath 2s linear infinite;
|
||||
}
|
||||
.atom {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
border-left-width: 6rpx;
|
||||
border-top-width: 6rpx;
|
||||
border-left-color: #0396FF;
|
||||
border-left-style: solid;
|
||||
border-top-style: solid;
|
||||
border-top-color: transparent;
|
||||
|
||||
}
|
||||
.atom:nth-of-type(1) {
|
||||
left: 0%;
|
||||
top: 0%;
|
||||
animation: atom1 1s linear infinite;
|
||||
}
|
||||
.atom:nth-of-type(2) {
|
||||
right: 0%;
|
||||
top: 0%;
|
||||
animation: atom2 1s linear infinite;
|
||||
}
|
||||
.atom:nth-of-type(3) {
|
||||
right: 0%;
|
||||
bottom: 0%;
|
||||
animation: atom3 1s linear infinite;
|
||||
}
|
||||
@keyframes dotbreath {
|
||||
0% {
|
||||
opacity:1;
|
||||
}
|
||||
|
||||
50%{
|
||||
opacity:0.5;
|
||||
}
|
||||
100%{
|
||||
opacity:1;
|
||||
}
|
||||
}
|
||||
@keyframes atom1 {
|
||||
0% {
|
||||
transform: rotateZ(120deg) rotateX(66deg) rotateZ(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotateZ(120deg) rotateX(66deg) rotateZ(360deg);
|
||||
}
|
||||
}
|
||||
@keyframes atom2 {
|
||||
0% {
|
||||
transform: rotateZ(240deg) rotateX(66deg) rotateZ(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotateZ(240deg) rotateX(66deg) rotateZ(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes atom3 {
|
||||
0% {
|
||||
transform: rotateZ(360deg) rotateX(66deg) rotateZ(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotateZ(360deg) rotateX(66deg) rotateZ(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,76 @@
|
||||
<template>
|
||||
<!-- -->
|
||||
<view :style="{'position': position,'z-index':zIndex}" class="container" :class="mask?'mask':''" @click.prevent="handleClick">
|
||||
<view>
|
||||
<view class="main">
|
||||
<loading8 v-if="type=='atom'"></loading8>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import loading8 from "./static/loading-atom.vue"
|
||||
|
||||
|
||||
export default {
|
||||
name: "zero-loading",
|
||||
components: {
|
||||
loading8,
|
||||
},
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: "atom"
|
||||
},
|
||||
position: {
|
||||
type: String,
|
||||
default: "fixed"
|
||||
},
|
||||
zIndex: {
|
||||
type: Number,
|
||||
default: 9,
|
||||
},
|
||||
mask: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleClick() {
|
||||
this.$emit('click')
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.container {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.mask {
|
||||
z-index: 999 !important;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
background: rgba(7, 17, 27, .3);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
</style>
|
||||
80
uni_modules/zero-loading/package.json
Normal file
80
uni_modules/zero-loading/package.json
Normal file
@ -0,0 +1,80 @@
|
||||
{
|
||||
"id": "zero-loading",
|
||||
"displayName": "zero-loading(加载动画)",
|
||||
"version": "1.2.1",
|
||||
"description": "纯css加载动画, 一个标签元素即可实现炫酷的全屏loading效果",
|
||||
"keywords": [
|
||||
"loading",
|
||||
"加载动画",
|
||||
"css动画",
|
||||
"加载"
|
||||
],
|
||||
"repository": "",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.1.0"
|
||||
},
|
||||
"dcloudext": {
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "插件不采集任何数据",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": "",
|
||||
"type": "component-vue"
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y"
|
||||
},
|
||||
"client": {
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "u"
|
||||
},
|
||||
"App": {
|
||||
"app-vue": "u",
|
||||
"app-nvue": "u"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "y",
|
||||
"Android Browser": "u",
|
||||
"微信浏览器(Android)": "y",
|
||||
"QQ浏览器(Android)": "u"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "y",
|
||||
"IE": "u",
|
||||
"Edge": "u",
|
||||
"Firefox": "u",
|
||||
"Safari": "u"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "y",
|
||||
"阿里": "u",
|
||||
"百度": "u",
|
||||
"字节跳动": "u",
|
||||
"QQ": "u"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "u",
|
||||
"联盟": "u"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
50
uni_modules/zero-loading/readme.md
Normal file
50
uni_modules/zero-loading/readme.md
Normal file
@ -0,0 +1,50 @@
|
||||
# zero-loading
|
||||
|
||||
## 使用方法
|
||||
|
||||
导入 `uni_modules` 后直接使用即可
|
||||
|
||||
提供多种加载动画类型,传入 type 改变 loading 样式,不传默认 circle
|
||||
|
||||
### 全屏使用
|
||||
|
||||
```html
|
||||
<zero-loading v-if="loading"></zero-loading>
|
||||
```
|
||||
|
||||
### 局部使用
|
||||
|
||||
**父元素的 `position` 记得改为 `relative` 哦**
|
||||
|
||||
```html
|
||||
<zero-loading type="pulse" position="absolute"></zero-loading>
|
||||
```
|
||||
|
||||
## 参数说明
|
||||
|
||||
| 参数 | 类型 | 默认值 | 描述 |
|
||||
| -------- | ------- | ------ | ------------ |
|
||||
| type | String | atom | 样式 |
|
||||
| position | String | fixed | 定位方式 |
|
||||
| zIndex | Number | 9 | |
|
||||
| mask | Boolean | false | 是否需要遮罩 |
|
||||
|
||||
### type 可选值:
|
||||
|
||||
| type 值 | 描述 |
|
||||
| -------- | ---- |
|
||||
| gear | 齿轮 |
|
||||
| sword | 剑气 |
|
||||
| atom | 原子 |
|
||||
| circle | 圆环 |
|
||||
| love | 爱心 |
|
||||
| pulse | 脉冲 |
|
||||
| sun | 太阳 |
|
||||
| eyes | 眼睛 |
|
||||
| triangle | 三角 |
|
||||
| bounce | 弹跳 |
|
||||
|
||||
插件预览:
|
||||

|
||||
|
||||
> 预览的小程序不一定能及时更新当前插件
|
||||
Reference in New Issue
Block a user