提交 cc2e5a53 编写于 作者: W wanganxp

初始化

上级
<script>
import {
mapGetters,
mapActions
} from 'vuex'
import config from '@/admin.config.js'
import { version } from './package.json'
export default {
computed: {
...mapGetters({
isTokenValid: 'user/isTokenValid'
})
},
methods: {
...mapActions({
init: 'app/init'
})
},
onPageNotFound(msg) {
uni.redirectTo({
url: config.error.url
})
},
onLaunch: function() {
console.log('App Launch')
console.log('uniCloud admin 当前版本号:', version)
if (!this.isTokenValid) {
uni.redirectTo({
url: config.login.url
})
} else {
this.init()
}
},
onShow: function() {
console.log('App Show')
},
onHide: function() {
console.log('App Hide')
}
}
</script>
<style>
@import '@/common/uni.css';
@import '@/common/uni-icons.css';
</style>
MIT License
Copyright (c) 2020 DCloud
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# uniCloud-admin
> 基于 uni-app,uniCloud 的 admin 管理项目模板。[文档](https://uniapp.dcloud.io/uniCloud/admin)
export default {
login: {
url: '/pages/login/login' // 登录页面路径
},
index: {
url: '/pages/index/index' // 登录后跳转的第一个页面
},
error: {
url: '/pages/error/404' // 404 Not Found 错误页面路径
},
navBar: { // 顶部导航
logo: '/static/logo.png', // 左侧 Logo
links: [{ // 右侧链接
text: 'Admin框架文档',
url: 'https://uniapp.dcloud.net.cn/uniCloud/admin'
}, {
text: '浏览更多Admin插件',
url: 'https://ext.dcloud.net.cn/?cat1=7&cat2=74'
}],
debug: {
enable: process.env.NODE_ENV !== 'production', //是否显示错误信息
engine: [{ // 搜索引擎配置(每条错误信息后,会自动生成搜索链接,点击后跳转至搜索引擎)
name: '百度',
url: 'https://www.baidu.com/baidu?wd=ERR_MSG'
}, {
name: '谷歌',
url: 'https://www.google.com/search?q=ERR_MSG'
}]
}
},
sideBar: { // 左侧菜单
// 配置静态菜单列表(放置在用户被授权的菜单列表下边)
staticMenu: [{
menu_id: "demo",
name: '静态功能演示',
icon: 'uni-icons-list',
url: "",
children: [{
menu_id: "icons",
name: '图标',
icon: '',
url: '/pages/demo/icons/icons',
}, {
menu_id: "table",
name: '表格',
icon: '',
url: '/pages/demo/table/table',
}]
}]
}
}
@font-face {
font-family: uni-icons;
src: url('~@/components/uni-icons/uni.ttf') format('truetype');
font-weight: 400;
font-display: "auto";
font-style: normal
}
[class*=" uni-icons-"],
[class^=uni-icons-] {
font-family: uni-icons !important;
speak: none;
font-style: normal;
font-weight: 400;
font-variant: normal;
text-transform: none;
line-height: 1;
vertical-align: baseline;
display: inline-block;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale
}
.uni-icons-shop:before {
content: "\e609";
}
.uni-icons-headphones:before {
content: "\e8bf";
}
.uni-icons-pulldown:before {
content: "\e588";
}
.uni-icons-scan:before {
content: "\e612";
}
.uni-icons-back:before {
content: "\e471";
}
.uni-icons-forward:before {
content: "\e470";
}
.uni-icons-refreshempty:before {
content: "\e461";
}
.uni-icons-checkbox-filled:before {
content: "\e442";
}
.uni-icons-checkbox:before {
content: "\e7fa";
}
.uni-icons-loop:before {
content: "\e565";
}
.uni-icons-arrowthindown:before {
content: "\e585";
}
.uni-icons-arrowthinleft:before {
content: "\e586";
}
.uni-icons-arrowthinright:before {
content: "\e587";
}
.uni-icons-arrowthinup:before {
content: "\e584";
}
.uni-icons-bars:before {
content: "\e563";
}
.uni-icons-cart-filled:before {
content: "\e7f4";
}
.uni-icons-cart:before {
content: "\e7f5";
}
.uni-icons-arrowleft:before {
content: "\e582";
}
.uni-icons-arrowdown:before {
content: "\e581";
}
.uni-icons-arrowright:before {
content: "\e583";
}
.uni-icons-arrowup:before {
content: "\e580";
}
.uni-icons-eye-filled:before {
content: "\e568";
}
.uni-icons-eye-slash-filled:before {
content: "\e822";
}
.uni-icons-eye-slash:before {
content: "\e823";
}
.uni-icons-eye:before {
content: "\e824";
}
.uni-icons-reload:before {
content: "\e462";
}
.uni-icons-hand-thumbsdown-filled:before {
content: "\e83b";
}
.uni-icons-hand-thumbsdown:before {
content: "\e83c";
}
.uni-icons-hand-thumbsup-filled:before {
content: "\e83d";
}
.uni-icons-heart-filled:before {
content: "\e83e";
}
.uni-icons-hand-thumbsup:before {
content: "\e83f";
}
.uni-icons-heart:before {
content: "\e840";
}
.uni-icons-mail-open-filled:before {
content: "\e84d";
}
.uni-icons-mail-open:before {
content: "\e84e";
}
.uni-icons-list:before {
content: "\e562";
}
.uni-icons-map-pin:before {
content: "\e85e";
}
.uni-icons-map-pin-ellipse:before {
content: "\e864";
}
.uni-icons-paperclip:before {
content: "\e567";
}
.uni-icons-images-filled:before {
content: "\e87a";
}
.uni-icons-images:before {
content: "\e87b";
}
.uni-icons-search:before {
content: "\e466";
}
.uni-icons-settings:before {
content: "\e560";
}
.uni-icons-cloud-download:before {
content: "\e8e4";
}
.uni-icons-cloud-upload-filled:before {
content: "\e8e5";
}
.uni-icons-cloud-upload:before {
content: "\e8e6";
}
.uni-icons-cloud-download-filled:before {
content: "\e8e9";
}
.uni-icons-more:before {
content: "\e507";
}
.uni-icons-more-filled:before {
content: "\e537";
}
.uni-icons-refresh:before {
content: "\e407";
}
.uni-icons-refresh-filled:before {
content: "\e437";
}
.uni-icons-undo-filled:before {
content: "\e7d6";
}
.uni-icons-undo:before {
content: "\e406";
}
.uni-icons-redo:before {
content: "\e405";
}
.uni-icons-redo-filled:before {
content: "\e7d9";
}
.uni-icons-camera:before {
content: "\e301";
}
.uni-icons-camera-filled:before {
content: "\e7ef";
}
.uni-icons-smallcircle-filled:before {
content: "\e801";
}
.uni-icons-circle:before {
content: "\e411";
}
.uni-icons-flag-filled:before {
content: "\e825";
}
.uni-icons-flag:before {
content: "\e508";
}
.uni-icons-gear-filled:before {
content: "\e532";
}
.uni-icons-gear:before {
content: "\e502";
}
.uni-icons-home:before {
content: "\e500";
}
.uni-icons-info:before {
content: "\e504";
}
.uni-icons-home-filled:before {
content: "\e530";
}
.uni-icons-info-filled:before {
content: "\e534";
}
.uni-icons-circle-filled:before {
content: "\e441";
}
.uni-icons-chat-filled:before {
content: "\e847";
}
.uni-icons-chat:before {
content: "\e263";
}
.uni-icons-checkmarkempty:before {
content: "\e472";
}
.uni-icons-locked-filled:before {
content: "\e856";
}
.uni-icons-locked:before {
content: "\e506";
}
.uni-icons-map-filled:before {
content: "\e85c";
}
.uni-icons-map:before {
content: "\e364";
}
.uni-icons-minus-filled:before {
content: "\e440";
}
.uni-icons-mic-filled:before {
content: "\e332";
}
.uni-icons-minus:before {
content: "\e410";
}
.uni-icons-micoff:before {
content: "\e360";
}
.uni-icons-mic:before {
content: "\e302";
}
.uni-icons-clear:before {
content: "\e434";
}
.uni-icons-smallcircle:before {
content: "\e868";
}
.uni-icons-close:before {
content: "\e404";
}
.uni-icons-closeempty:before {
content: "\e460";
}
.uni-icons-paperplane:before {
content: "\e503";
}
.uni-icons-paperplane-filled:before {
content: "\e86e";
}
.uni-icons-image:before {
content: "\e363";
}
.uni-icons-image-filled:before {
content: "\e877";
}
.uni-icons-location-filled:before {
content: "\e333";
}
.uni-icons-location:before {
content: "\e303";
}
.uni-icons-plus-filled:before {
content: "\e439";
}
.uni-icons-plus:before {
content: "\e409";
}
.uni-icons-plusempty:before {
content: "\e468";
}
.uni-icons-help-filled:before {
content: "\e535";
}
.uni-icons-help:before {
content: "\e505";
}
.uni-icons-navigate-filled:before {
content: "\e884";
}
.uni-icons-navigate:before {
content: "\e501";
}
.uni-icons-mic-slash-filled:before {
content: "\e892";
}
.uni-icons-sound:before {
content: "\e590";
}
.uni-icons-sound-filled:before {
content: "\e8a1";
}
.uni-icons-spinner-cycle:before {
content: "\e465";
}
.uni-icons-download-filled:before {
content: "\e8a4";
}
.uni-icons-videocam-filled:before {
content: "\e8af";
}
.uni-icons-upload:before {
content: "\e402";
}
.uni-icons-upload-filled:before {
content: "\e8b1";
}
.uni-icons-starhalf:before {
content: "\e463";
}
.uni-icons-star-filled:before {
content: "\e438";
}
.uni-icons-star:before {
content: "\e408";
}
.uni-icons-trash:before {
content: "\e401";
}
.uni-icons-compose:before {
content: "\e400";
}
.uni-icons-videocam:before {
content: "\e300";
}
.uni-icons-trash-filled:before {
content: "\e8dc";
}
.uni-icons-download:before {
content: "\e403";
}
.uni-icons-qq:before {
content: "\e264";
}
.uni-icons-weibo:before {
content: "\e260";
}
.uni-icons-weixin:before {
content: "\e261";
}
.uni-icons-pengyouquan:before {
content: "\e262";
}
.uni-icons-chatboxes:before {
content: "\e203";
}
.uni-icons-chatboxes-filled:before {
content: "\e233";
}
.uni-icons-email-filled:before {
content: "\e231";
}
.uni-icons-email:before {
content: "\e201";
}
.uni-icons-person-filled:before {
content: "\e131";
}
.uni-icons-contact-filled:before {
content: "\e130";
}
.uni-icons-person:before {
content: "\e101";
}
.uni-icons-contact:before {
content: "\e100";
}
.uni-icons-phone:before {
content: "\e200";
}
.uni-icons-personadd-filled:before {
content: "\e132";
}
.uni-icons-personadd:before {
content: "\e102";
}
.uni-icons-phone-filled:before {
content: "\e230";
}
.uni-icons-chatbubble-filled:before {
content: "\e232";
}
.uni-icons-chatbubble:before {
content: "\e202";
}
/* 全局公共样式 */
body,
html {
-webkit-user-select: auto;
user-select: auto;
}
/* #ifdef H5 */
.uni-app--showleftwindow uni-main {
position: relative;
background-color: #f5f5f5;
}
.uni-mask+.uni-left-window, .uni-mask+.uni-right-window{
position: fixed;
}
.uni-app--showleftwindow uni-page-head .uni-page-head {
/* margin-right: 15px; */
}
.uni-app--showleftwindow uni-page-head[uni-page-head-type=default]~uni-page-wrapper {
height: auto;
padding-top: 59px;
}
.uni-app--showleftwindow uni-page-head~uni-page-wrapper uni-page-body {
/* padding-top: 44px; */
}
.uni-app--showleftwindow uni-page-wrapper {
position: absolute;
width: 100%;
top: 0;
bottom: 0;
padding: 15px;
overflow-y: auto;
box-sizing: border-box;
background-color: #F5F5F5;
}
.uni-app--showleftwindow uni-page-body {
width: 100%;
min-height: 100%;
box-sizing: border-box;
border-radius: 5px;
box-shadow: -1px -1px 5px 0 rgba(0, 0, 0, .1);
background-color: #fff;
}
.uni-app--showleftwindow .uni-container .uni-forms {
padding: 15px;
max-width: 460px;
}
/* #endif */
/* #ifndef H5 */
.uni-nav-menu {
height: 100vh;
}
/* #endif */
.pointer {
cursor: pointer;
}
.uni-top-window {
z-index: 998;
overflow: visible;
}
.uni-tips {
font-size: 12px;
color: #666;
}
/* 容器 */
.uni-container {
padding: 15px;
box-sizing: border-box;
}
/* 标题栏 */
.uni-header {
padding: 0 15px;
display: flex;
height: 55px;
align-items: center;
justify-content: space-between;
border-bottom: 1px #f5f5f5 solid;
}
.uni-title {
margin-right: 10px;
font-size: 16px;
font-weight: 500;
color: #333;
}
.uni-sub-title {
margin-top: 3px;
font-size: 14px;
color: #999;
}
.uni-link {
color: #3A8EE6;
cursor: pointer;
text-decoration: underline;
}
.uni-group {
display: flex;
align-items: center;
justify-content: center;
word-break: keep-all;
}
/* 按钮样式 */
.uni-button-group {
margin-top: 30px;
display: flex;
align-items: center;
justify-content: center;
}
.uni-button {
padding: 10px 20px;
font-size: 14px;
border-radius: 4px;
line-height: 1;
margin: 0;
box-sizing: border-box;
overflow: initial;
}
.uni-button+.uni-button {
margin-left: 10px;
}
.uni-button:hover,
.uni-button:focus {
opacity: 0.9;
}
.uni-button:active {
opacity: 1;
}
.uni-button-full {
width: 100%;
}
/* 搜索框样式 */
.uni-search {
height: 30px;
line-height: 30px;
font-size: 12px;
padding: 0 10px;
border: 1px #eee solid;
margin-right: 10px;
border-radius: 5px;
}
/* 分页容器 */
.uni-pagination-box {
display: flex;
justify-content: center;
margin-top: 20px;
}
.uni-input-border,
.uni-textarea-border {
width: 100%;
font-size: 14px;
color: #666;
border: 1px #e5e5e5 solid;
border-radius: 5px;
box-sizing: border-box;
}
.uni-input-border {
padding: 0 10px;
height: 35px;
}
.uni-textarea-border {
padding: 10px;
height: 80px;
}
.uni-disabled {
background-color: #F5F7FA;
color: #C0C4CC;
}
.uni-icon-password-eye {
position: absolute;
right: 8px;
top: 6px;
font-family: uniicons;
font-size: 20px;
font-weight: normal;
font-style: normal;
width: 24px;
height: 24px;
line-height: 24px;
color: #999999;
}
.uni-eye-active {
color: #007AFF;
}
.uni-tabs__header {
position: relative;
background-color: #f5f7fa;
border-bottom: 1px solid #e4e7ed;
}
.uni-tabs__nav-wrap {
overflow: hidden;
margin-bottom: -1px;
position: relative;
}
.uni-tabs__nav-scroll {
overflow: hidden;
}
.uni-tabs__nav {
position: relative;
white-space: nowrap;
}
.uni-tabs__item {
position: relative;
padding: 0 20px;
height: 40px;
box-sizing: border-box;
line-height: 40px;
display: inline-block;
list-style: none;
font-size: 14px;
font-weight: 500;
color: #909399;
margin-top: -1px;
margin-left: -1px;
border: 1px solid transparent;
cursor: pointer;
}
.uni-tabs__item.is-active {
color: #007aff;
background-color: #fff;
border-right-color: #dcdfe6;
border-left-color: #dcdfe6;
}
.uni-form-item-tips {
color: #999;
font-size: 12px;
margin-top: 3px;
position: absolute;
}
.uni-form-item-empty {
color: #999;
min-height: 36px;
line-height: 36px;
}
<template>
<view class="fix-window">
<top-window class="fix-window-top"/>
<view class="fix-window-button" @click="tiggerWindow"></view>
<view v-if="visible" class="fix-window--mask" @click="tiggerWindow"></view>
<left-window v-if="visible" class="fix-window--popup" />
</view>
</template>
<script>
import topWindow from '../../windows/topWindow.vue'
import leftWindow from '../../windows/leftWindow.vue'
export default {
components:{
topWindow,
leftWindow
},
data() {
return {
visible: false
};
},
methods: {
tiggerWindow() {
this.visible = !this.visible
}
}
}
</script>
<style>
.fix-window {
}
.fix-window-button {
width: 30px;
height: 30px;
opacity: 0.5;
position: fixed;
top: 40px;
left: 20px;
z-index: 999;
}
.fix-window-top {
width: 100%;
position: fixed;
top: 25px;
left: 0;
z-index: 999;
}
.fix-window--mask {
position: fixed;
bottom: 0px;
top: 25px;
left: 0px;
right: 0px;
background-color: rgba(0, 0, 0, 0.4);
transition-duration: 0.3s;
z-index: 997;
}
.fix-window--popup {
position: fixed;
top: 85px;
left: 0;
/* transform: translate(-50%, -50%); */
transition-duration: 0.3s;
z-index: 998;
}
</style>
<template>
<text v-if="text" :class="inverted ? 'uni-badge--' + type + ' uni-badge--' + size + ' uni-badge--' + type + '-inverted' : 'uni-badge--' + type + ' uni-badge--' + size" :style="badgeStyle" class="uni-badge" @click="onClick()">{{ text }}</text>
</template>
<script>
/**
* Badge 数字角标
* @description 数字角标一般和其它控件(列表、9宫格等)配合使用,用于进行数量提示,默认为实心灰色背景
* @tutorial https://ext.dcloud.net.cn/plugin?id=21
* @property {String} text 角标内容
* @property {String} type = [default|primary|success|warning|error] 颜色类型
* @value default 灰色
* @value primary 蓝色
* @value success 绿色
* @value warning 黄色
* @value error 红色
* @property {String} size = [normal|small] Badge 大小
* @value normal 一般尺寸
* @value small 小尺寸
* @property {String} inverted = [true|false] 是否无需背景颜色
* @event {Function} click 点击 Badge 触发事件
* @example <uni-badge text="1"></uni-badge>
*/
export default {
name: 'UniBadge',
props: {
type: {
type: String,
default: 'default'
},
inverted: {
type: Boolean,
default: false
},
text: {
type: [String, Number],
default: ''
},
size: {
type: String,
default: 'normal'
}
},
data() {
return {
badgeStyle: ''
};
},
watch: {
text() {
this.setStyle()
}
},
mounted() {
this.setStyle()
},
methods: {
setStyle() {
this.badgeStyle = `width: ${String(this.text).length * 8 + 12}px`
},
onClick() {
this.$emit('click');
}
}
};
</script>
<style scoped>
.uni-badge {
/* #ifndef APP-PLUS */
display: flex;
box-sizing: border-box;
overflow: hidden;
/* #endif */
justify-content: center;
flex-direction: row;
height: 20px;
line-height: 20px;
color: #333;
border-radius: 100px;
background-color: #f1f1f1;
background-color: transparent;
text-align: center;
font-family: 'Helvetica Neue', Helvetica, sans-serif;
font-size: 12px;
padding: 0px 6px;
}
.uni-badge--inverted {
padding: 0 5px 0 0;
color: #f1f1f1;
}
.uni-badge--default {
color: #333;
background-color: #f1f1f1;
}
.uni-badge--default-inverted {
color: #999;
background-color: transparent;
}
.uni-badge--primary {
color: #fff;
background-color: #007aff;
}
.uni-badge--primary-inverted {
color: #007aff;
background-color: transparent;
}
.uni-badge--success {
color: #fff;
background-color: #4cd964;
}
.uni-badge--success-inverted {
color: #4cd964;
background-color: transparent;
}
.uni-badge--warning {
color: #fff;
background-color: #f0ad4e;
}
.uni-badge--warning-inverted {
color: #f0ad4e;
background-color: transparent;
}
.uni-badge--error {
color: #fff;
background-color: #dd524d;
}
.uni-badge--error-inverted {
color: #dd524d;
background-color: transparent;
}
.uni-badge--small {
transform: scale(0.8);
transform-origin: center center;
}
</style>
\ No newline at end of file
<template>
<view>
<slot :options="options" :data="dataList" :pagination="paginationInternal" :loading="loading" :error="errorMessage"></slot>
</view>
</template>
<script>
const db = uniCloud.database();
const dbCmd = db.command;
const events = {
load: 'load',
error: 'error'
}
const pageMode = {
add: 'add',
replace: 'replace'
}
const attrs = [
'pageCurrent',
'pageSize',
'collection',
'action',
'field',
'getcount',
'orderby',
'where'
]
/**
* uni-clientdb
* @description uni-clientdb是一个数据库查询组件,它是对uni-clientdb的js库的再封装。
* @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-clientdb-component
* @property {String} collection 表名
* @property {String} action 云端执行数据库查询的前或后,触发某个action函数操作,进行预处理或后处理
* @property {String} field 查询字段,多个字段用 `,` 分割
* @property {String} orderby 排序字段及正序倒叙设置
* @property {String} where 查询条件
* @property {String} pageData = [add|replace] `add` 多次查询的集合, `replace` 当前查询的集合
* @value add 多次查询的集合
* @value replace 当前查询的集合
* @property {Number} pageCurrent 当前页
* @property {Number} pageSize 每页数据数量
* @property {Boolean} getone = [true|false] 指定查询结果是否返回数组第一条数据,默认 false。在false情况下返回的是数组,即便只有一条结果,也需要[0]的方式获取。在true下,直接返回结果数据,少一层数组
* @value true 返回数组第一条数据
* @value false 返回类型是数组,即便只有一条结果
* @property {Boolean} getcount 是否查询总数量
* @property {Boolean} manual 是否手动加载数据,默认为 false,页面onready时自动联网加载数据
* @value true 开启后需要手动加载数据
* @value false 页面onready时自动联网加载数据
* @event {Function} load 成功回调。如联网返回结果后,想修改下数据再渲染界面,则在本方法里对data进行修改
* @event {Function} error 失败回调
*/
export default {
name: 'UniClientdb',
props: {
options: {
type: [Object, Array],
default () {
return {}
}
},
collection: {
type: String,
default: ''
},
action: {
type: String,
default: ''
},
field: {
type: String,
default: ''
},
pageData: {
type: String,
default: 'add'
},
pageCurrent: {
type: Number,
default: 1
},
pageSize: {
type: Number,
default: 20
},
getcount: {
type: [Boolean, String],
default: false
},
orderby: {
type: String,
default: ''
},
where: {
type: [String, Object],
default: ''
},
getone: {
type: [Boolean, String],
default: false
},
manual: {
type: Boolean,
default: false
}
},
data() {
return {
loading: false,
dataList: this.getone ? {} : [],
paginationInternal: {
current: this.pageCurrent,
size: this.pageSize,
count: 0
},
errorMessage: ''
}
},
created() {
this._isEnded = false
this.$watch(() => {
var al = []
attrs.forEach(key => {
al.push(this[key])
})
return al
}, (newValue, oldValue) => {
this.paginationInternal.pageSize = this.pageSize
let needReset = false
for (let i = 2; i < newValue.length; i++) {
if (newValue[i] != oldValue[i]) {
needReset = true
break
}
}
if (needReset) {
this.clear()
this.reset()
}
if (newValue[0] != oldValue[0]) {
this.paginationInternal.current = this.pageCurrent
}
this._execLoadData()
})
// #ifdef H5
if (process.env.NODE_ENV === 'development') {
this._debugDataList = []
if (!window.unidev) {
window.unidev = {
clientDB: {
data: []
}
}
}
unidev.clientDB.data.push(this._debugDataList)
}
// #endif
// #ifdef MP-TOUTIAO
let changeName
let events = this.$scope.dataset.eventOpts
for (var i = 0; i < events.length; i++) {
let event = events[i]
if (event[0].includes('^load')) {
changeName = event[1][0][0]
}
}
if (changeName) {
let parent = this.$parent
let maxDepth = 16
this._changeDataFunction = null
while (parent && maxDepth > 0) {
let fun = parent[changeName]
if (fun && typeof fun === 'function') {
this._changeDataFunction = fun
maxDepth = 0
break
}
parent = parent.$parent
maxDepth--;
}
}
// #endif
if (!this.manual) {
this.loadData()
}
},
// #ifdef H5
beforeDestroy() {
if (process.env.NODE_ENV === 'development' && window.unidev) {
var cd = this._debugDataList
var dl = unidev.clientDB.data
for (var i = dl.length - 1; i >= 0; i--) {
if (dl[i] === cd) {
dl.splice(i, 1)
break
}
}
}
},
// #endif
methods: {
loadData(args1, args2) {
let callback = null
if (typeof args1 === 'object') {
if (args1.clear) {
this.clear()
this.reset()
}
if (args1.current !== undefined) {
this.paginationInternal.current = args1.current
}
if (typeof args2 === 'function') {
callback = args2
}
} else if (typeof args1 === 'function') {
callback = args1
}
this._execLoadData(callback)
},
loadMore() {
if (this._isEnded) {
return
}
this._execLoadData()
},
refresh() {
this.clear()
this._execLoadData()
},
clear() {
this._isEnded = false
this.dataList = []
},
reset() {
this.paginationInternal.current = 1
},
remove(id, {
action,
callback,
confirmTitle,
confirmContent
} = {}) {
if (!id || !id.length) {
return
}
uni.showModal({
title: confirmTitle || '提示',
content: confirmContent || '是否删除该数据',
showCancel: true,
success: (res) => {
if (!res.confirm) {
return
}
this._execRemove(id, action, callback)
}
})
},
_execLoadData(callback) {
if (this.loading) {
return
}
this.loading = true
this.errorMessage = ''
this._getExec().then((res) => {
this.loading = false
const {
data,
count
} = res.result
this._isEnded = data.length < this.pageSize
callback && callback(data, this._isEnded)
this._dispatchEvent(events.load, data)
if (this.getone) {
this.dataList = data.length ? data[0] : undefined
} else if (this.pageData === pageMode.add) {
this.dataList.push(...data)
if (this.dataList.length) {
this.paginationInternal.current++
}
} else if (this.pageData === pageMode.replace) {
this.dataList = data
this.paginationInternal.count = count
}
// #ifdef H5
if (process.env.NODE_ENV === 'development') {
this._debugDataList.length = 0
this._debugDataList.push(...JSON.parse(JSON.stringify(this.dataList)))
}
// #endif
}).catch((err) => {
this.loading = false
this.errorMessage = err
callback && callback()
this.$emit(events.error, err)
})
},
_getExec() {
let exec = db
if (this.action) {
exec = exec.action(this.action)
}
exec = exec.collection(this.collection)
if (!(!this.where || !Object.keys(this.where).length)) {
exec = exec.where(this.where)
}
if (this.field) {
exec = exec.field(this.field)
}
if (this.orderby) {
exec = exec.orderBy(this.orderby)
}
const {
current,
size
} = this.paginationInternal
exec = exec.skip(size * (current - 1)).limit(size).get({
getCount: this.getcount
})
return exec
},
_execRemove(id, action, callback) {
if (!this.collection || !id) {
return
}
const ids = Array.isArray(id) ? id : [id]
if (!ids.length) {
return
}
uni.showLoading({
mask: true
})
let exec = db
if (action) {
exec = exec.action(action)
}
exec.collection(this.collection).where({
_id: dbCmd.in(ids)
}).remove().then((res) => {
callback && callback(res.result)
if (this.pageData === pageMode.replace) {
this.refresh()
} else {
this.removeData(ids)
}
}).catch((err) => {
uni.showModal({
content: err.message,
showCancel: false
})
}).finally(() => {
uni.hideLoading()
})
},
removeData(ids) {
let il = ids.slice(0)
let dl = this.dataList
for (let i = dl.length - 1; i >= 0; i--) {
let index = il.indexOf(dl[i]._id)
if (index >= 0) {
dl.splice(i, 1)
il.splice(index, 1)
}
}
},
_dispatchEvent(type, data) {
if (this._changeDataFunction) {
this._changeDataFunction(data, this._isEnded)
} else {
this.$emit(type, data, this._isEnded)
}
}
}
}
</script>
const events = {
load: 'load',
error: 'error'
}
const pageMode = {
add: 'add',
replace: 'replace'
}
const attrs = [
'pageCurrent',
'pageSize',
'collection',
'action',
'field',
'getcount',
'orderby',
'where'
]
export default {
data() {
return {
loading: false,
listData: this.getone ? {} : [],
paginationInternal: {
current: this.pageCurrent,
size: this.pageSize,
count: 0
},
errorMessage: ''
}
},
created() {
let db = null;
let dbCmd = null;
if(this.collection){
this.db = uniCloud.database();
this.dbCmd = this.db.command;
}
this._isEnded = false
this.$watch(() => {
var al = []
attrs.forEach(key => {
al.push(this[key])
})
return al
}, (newValue, oldValue) => {
this.paginationInternal.pageSize = this.pageSize
let needReset = false
for (let i = 2; i < newValue.length; i++) {
if (newValue[i] != oldValue[i]) {
needReset = true
break
}
}
if (needReset) {
this.clear()
this.reset()
}
if (newValue[0] != oldValue[0]) {
this.paginationInternal.current = this.pageCurrent
}
this._execLoadData()
})
// #ifdef H5
if (process.env.NODE_ENV === 'development') {
this._debugDataList = []
if (!window.unidev) {
window.unidev = {
clientDB: {
data: []
}
}
}
unidev.clientDB.data.push(this._debugDataList)
}
// #endif
// #ifdef MP-TOUTIAO
let changeName
let events = this.$scope.dataset.eventOpts
for (var i = 0; i < events.length; i++) {
let event = events[i]
if (event[0].includes('^load')) {
changeName = event[1][0][0]
}
}
if (changeName) {
let parent = this.$parent
let maxDepth = 16
this._changeDataFunction = null
while (parent && maxDepth > 0) {
let fun = parent[changeName]
if (fun && typeof fun === 'function') {
this._changeDataFunction = fun
maxDepth = 0
break
}
parent = parent.$parent
maxDepth--;
}
}
// #endif
// if (!this.manual) {
// this.loadData()
// }
},
// #ifdef H5
beforeDestroy() {
if (process.env.NODE_ENV === 'development' && window.unidev) {
var cd = this._debugDataList
var dl = unidev.clientDB.data
for (var i = dl.length - 1; i >= 0; i--) {
if (dl[i] === cd) {
dl.splice(i, 1)
break
}
}
}
},
// #endif
methods: {
loadData(args1, args2) {
let callback = null
if (typeof args1 === 'object') {
if (args1.clear) {
this.clear()
this.reset()
}
if (args1.current !== undefined) {
this.paginationInternal.current = args1.current
}
if (typeof args2 === 'function') {
callback = args2
}
} else if (typeof args1 === 'function') {
callback = args1
}
this._execLoadData(callback)
},
loadMore() {
if (this._isEnded) {
return
}
this._execLoadData()
},
refresh() {
this.clear()
this._execLoadData()
},
clear() {
this._isEnded = false
this.listData = []
},
reset() {
this.paginationInternal.current = 1
},
remove(id, {
action,
callback,
confirmTitle,
confirmContent
} = {}) {
if (!id || !id.length) {
return
}
uni.showModal({
title: confirmTitle || '提示',
content: confirmContent || '是否删除该数据',
showCancel: true,
success: (res) => {
if (!res.confirm) {
return
}
this._execRemove(id, action, callback)
}
})
},
_execLoadData(callback) {
if (this.loading) {
return
}
this.loading = true
this.errorMessage = ''
this._getExec().then((res) => {
this.loading = false
const {
data,
count
} = res.result
this._isEnded = data.length < this.pageSize
callback && callback(data, this._isEnded)
this._dispatchEvent(events.load, data)
if (this.getone) {
this.listData = data.length ? data[0] : undefined
} else if (this.pageData === pageMode.add) {
this.listData.push(...data)
if (this.listData.length) {
this.paginationInternal.current++
}
} else if (this.pageData === pageMode.replace) {
this.listData = data
this.paginationInternal.count = count
}
// #ifdef H5
if (process.env.NODE_ENV === 'development') {
this._debugDataList.length = 0
this._debugDataList.push(...JSON.parse(JSON.stringify(this.listData)))
}
// #endif
}).catch((err) => {
this.loading = false
this.errorMessage = err
callback && callback()
this.$emit(events.error, err)
})
},
_getExec() {
let exec = this.db
if (this.action) {
exec = exec.action(this.action)
}
exec = exec.collection(this.collection)
if (!(!this.where || !Object.keys(this.where).length)) {
exec = exec.where(this.where)
}
if (this.field) {
exec = exec.field(this.field)
}
if (this.orderby) {
exec = exec.orderBy(this.orderby)
}
const {
current,
size
} = this.paginationInternal
exec = exec.skip(size * (current - 1)).limit(size).get({
getCount: this.getcount
})
return exec
},
_execRemove(id, action, callback) {
if (!this.collection || !id) {
return
}
const ids = Array.isArray(id) ? id : [id]
if (!ids.length) {
return
}
uni.showLoading({
mask: true
})
let exec = this.db
if (action) {
exec = exec.action(action)
}
exec.collection(this.collection).where({
_id: dbCmd.in(ids)
}).remove().then((res) => {
callback && callback(res.result)
if (this.pageData === pageMode.replace) {
this.refresh()
} else {
this.removeData(ids)
}
}).catch((err) => {
uni.showModal({
content: err.message,
showCancel: false
})
}).finally(() => {
uni.hideLoading()
})
},
removeData(ids) {
let il = ids.slice(0)
let dl = this.listData
for (let i = dl.length - 1; i >= 0; i--) {
let index = il.indexOf(dl[i]._id)
if (index >= 0) {
dl.splice(i, 1)
il.splice(index, 1)
}
}
},
_dispatchEvent(type, data) {
if (this._changeDataFunction) {
this._changeDataFunction(data, this._isEnded)
} else {
this.$emit(type, data, this._isEnded)
}
}
}
}
<template>
<view class="uni-data-checklist">
<template v-if="loading">
<view class="uni-data-loading">
<uni-load-more status="loading" iconType="snow" :iconSize="18" :content-text="contentText"></uni-load-more>
</view>
</template>
<template v-else>
<checkbox-group v-if="multiple" class="checklist-group" :class="{'is-list':mode==='list','is-wrap':wrap}" @change="chagne">
<label class="checklist-box" :class="item.labelClass" :style="[item.styleBackgroud]" v-for="(item,index) in dataList"
:key="index">
<checkbox class="hidden" hidden :disabled="!!item.disabled" :value="item.value+''" :checked="item.selected" />
<view v-if="(mode !=='tag' && mode !== 'list') || ( mode === 'list' && icon === 'left')" class="checkbox__inner"
:class="item.checkboxBgClass" :style="[item.styleIcon]">
<view class="checkbox__inner-icon" :class="item.checkboxClass"></view>
</view>
<view class="checklist-content" :class="{'list-content':mode === 'list' && icon ==='left'}">
<text class="checklist-text" :class="item.textClass" :style="[item.styleIconText]">{{item.text}}</text>
<view v-if="mode === 'list' && icon === 'right'" class="checkobx__list" :class="item.listClass" :style="[item.styleBackgroud]"></view>
</view>
</label>
</checkbox-group>
<radio-group v-else class="checklist-group" :class="{'is-list':mode==='list','is-wrap':wrap}" @change="chagne">
<label class="checklist-box" :class="item.labelClass" :style="[item.styleBackgroud]" v-for="(item,index) in dataList" :key="index">
<radio hidden :disabled="item.disabled" :value="item.value+''" :checked="item.selected" />
<view v-if="(mode !=='tag' && mode !== 'list') || ( mode === 'list' && icon === 'left')" class="radio__inner"
:class="item.checkboxBgClass" :style="[item.styleBackgroud]">
<view class="radio__inner-icon" :class="item.checkboxClass" :style="[item.styleIcon]"></view>
</view>
<view class="checklist-content" :class="{'list-content':mode === 'list' && icon ==='left'}">
<text class="checklist-text" :class="item.textClass" :style="[item.styleIconText]">{{item.text}}</text>
<view v-if="mode === 'list' && icon === 'right'" class="checkobx__list" :class="item.listClass" :style="[item.styleRightIcon]"></view>
</view>
</label>
</radio-group>
</template>
</view>
</template>
<script>
/**
* DataChecklist 数据选择器
* @description 通过数据渲染 checkbox 和 radio
* @tutorial https://ext.dcloud.net.cn/plugin?id=xxx
* @property {String} mode = [default| list | button | tag] 显示模式
* @value default 默认横排模式
* @value list 列表模式
* @value button 按钮模式
* @value tag 标签模式
* @property {Boolean} multiple = [true|false] 是否多选
* @property {Array|String|Number} value 默认值
* @property {Array} localdata 本地数据 ,格式 [{text:'',value:''}]
* @property {Number|String} min 最小选择个数 ,multiple为true时生效
* @property {Number|String} max 最大选择个数 ,multiple为true时生效
* @property {Boolean} wrap 是否换行显示
* @property {String} icon = [left|right] list 列表模式下icon显示位置
* @property {Boolean} selectedColor 选中颜色
* @property {Boolean} selectedTextColor 选中文本颜色,如不填写则自动显示
* @value left 左侧显示
* @value right 右侧显示
* @event {Function} change 选中发生变化触发
*/
import clientdb from './clientdb.js'
export default {
name: 'uniDataChecklist',
mixins: [clientdb],
props: {
mode: {
type: String,
default: 'default'
},
multiple: {
type: Boolean,
default: false
},
value: {
type: [Array, String, Number],
default () {
return ''
}
},
localdata: {
type: Array,
default () {
return []
}
},
min: {
type: [Number, String],
default: ''
},
max: {
type: [Number, String],
default: ''
},
wrap: {
type: Boolean,
default: false
},
icon: {
type: String,
default: 'left'
},
selectedColor:{
type: String,
default: ''
},
selectedTextColor:{
type: String,
default: ''
},
// clientDB 相关
options: {
type: [Object, Array],
default () {
return {}
}
},
collection: {
type: String,
default: ''
},
action: {
type: String,
default: ''
},
field: {
type: String,
default: ''
},
pageData: {
type: String,
default: 'add'
},
pageCurrent: {
type: Number,
default: 1
},
pageSize: {
type: Number,
default: 20
},
getcount: {
type: [Boolean, String],
default: false
},
orderby: {
type: String,
default: ''
},
where: {
type: [String, Object],
default: ''
},
getone: {
type: [Boolean, String],
default: false
},
manual: {
type: Boolean,
default: false
}
},
watch: {
localdata: {
handler(newVal) {
this.range = newVal
this.dataList = this.getDataList(this.getSelectedValue(newVal))
},
deep: true
},
listData(newVal) {
this.range = newVal
this.dataList = this.getDataList(this.getSelectedValue(newVal))
},
value(newVal) {
this.dataList = this.getDataList(newVal)
this.formItem && this.formItem.setValue(newVal)
}
},
data() {
return {
dataList: [],
range: [],
contentText: {
contentdown: '查看更多',
contentrefresh: '加载中',
contentnomore: '没有更多'
},
styles: {
selectedColor: '#007aff',
selectedTextColor: '#333',
}
};
},
created() {
this.form = this.getForm('uniForms')
this.formItem = this.getForm('uniFormsItem')
this.formItem && this.formItem.setValue(this.value)
this.styles = {
selectedColor: this.selectedColor,
selectedTextColor: this.selectedTextColor
}
if (this.formItem) {
if (this.formItem.name) {
this.rename = this.formItem.name
this.form.inputChildrens.push(this)
}
}
if (this.localdata && this.localdata.length !== 0) {
this.range = this.localdata
this.dataList = this.getDataList(this.getSelectedValue(this.range))
} else {
if (this.collection) {
this.loadData()
}
}
},
methods: {
init(range) {},
/**
* 获取父元素实例
*/
getForm(name = 'uniForms') {
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;
},
chagne(e) {
const values = e.detail.value
let detail = {
value: [],
data: []
}
if (this.multiple) {
this.range.forEach(item => {
if (values.includes(item.value + '')) {
detail.value.push(item.value)
detail.data.push(item)
}
})
} else {
const range = this.range.find(item => (item.value + '') === values)
if (range) {
detail = {
value: range.value,
data: range
}
}
}
this.formItem && this.formItem.setValue(detail.value)
this.$emit('input', detail.value)
this.$emit('change', {
detail
})
if (this.multiple) {
// 如果 v-model 没有绑定 ,则走内部逻辑
// if (this.value.length === 0) {
this.dataList = this.getDataList(detail.value, true)
// }
} else {
this.dataList = this.getDataList(detail.value)
}
},
getLabelClass(item, index) {
let classes = []
switch (this.mode) {
case 'default':
item.disabled && classes.push('disabled-cursor')
break
case 'button':
classes.push(...['is-button', ...this.getClasses(item, 'button')])
break
case 'list':
if (this.multiple) {
classes.push('is-list-multiple-box')
} else {
classes.push('is-list-box')
}
item.disabled && classes.push('is-list-disabled')
index !== 0 && classes.push('is-list-border')
break
case 'tag':
classes.push(...['is-tag', ...this.getClasses(item, 'tag')])
break
}
classes = classes.join(' ')
return classes
},
getCheckboxClass(item, type = '') {
let classes = []
if (this.multiple) {
classes.push(...this.getClasses(item, 'default-multiple', type))
} else {
classes.push(...this.getClasses(item, 'default', type))
}
classes = classes.join(' ')
return classes
},
getTextClass(item) {
let classes = []
switch (this.mode) {
case 'default':
classes.push(...this.getClasses(item, 'list'))
break
case 'button':
classes.push(...this.getClasses(item, 'list'))
break
case 'list':
classes.push(...this.getClasses(item, 'list'))
break
case 'tag':
classes.push(...['is-tag-text', ...this.getClasses(item, 'tag-text')])
break
}
classes = classes.join(' ')
return classes
},
/**
* 获取渲染的新数组
* @param {Object} value 选中内容
*/
getDataList(value) {
// 解除引用关系,破坏原引用关系,避免污染源数据
let dataList = JSON.parse(JSON.stringify(this.range))
let list = []
if (this.multiple) {
if (!Array.isArray(value)) {
value = []
// console.error('props 类型错误');
}
}
dataList.forEach((item, index) => {
item.disabled = item.disable || item.disabled || false
if (this.multiple) {
if (value.length > 0) {
let have = value.find(val => val === item.value)
item.selected = have !== undefined
} else {
item.selected = false
}
} else {
item.selected = value === item.value
}
list.push(item)
})
return this.setRange(list)
},
/**
* 处理最大最小值
* @param {Object} list
*/
setRange(list) {
let selectList = list.filter(item => item.selected)
let min = Number(this.min) || 0
let max = Number(this.max) || ''
list.forEach((item, index) => {
if (this.multiple) {
if (selectList.length <= min) {
let have = selectList.find(val => val.value === item.value)
if (have !== undefined) {
item.disabled = true
}
}
if (selectList.length >= max && max !== '') {
let have = selectList.find(val => val.value === item.value)
if (have === undefined) {
item.disabled = true
}
}
}
this.setClass(item, index)
list[index] = item
})
return list
},
/**
* 设置 class
* @param {Object} item
* @param {Object} index
*/
setClass(item, index) {
// 设置 label 的 class
item.labelClass = this.getLabelClass(item, index)
// 设置 checkbox外层样式
item.checkboxBgClass = this.getCheckboxClass(item, '-bg')
// 设置 checkbox 内层样式
item.checkboxClass = this.getCheckboxClass(item)
// 设置文本样式
item.textClass = this.getTextClass(item)
// 设置 list 对勾右侧样式
item.listClass = this.getCheckboxClass(item, '-list')
// 设置自定义样式
item.styleBackgroud = this.setStyleBackgroud(item)
item.styleIcon = this.setStyleIcon(item)
item.styleIconText = this.setStyleIconText(item)
item.styleRightIcon = this.setStyleRightIcon(item)
},
/**
* 获取 class
*/
getClasses(item, name, type = '') {
let classes = []
item.disabled && classes.push('is-' + name + '-disabled' + type)
item.selected && classes.push('is-' + name + '-checked' + type)
if (this.mode !== 'button' || name === 'button') {
item.selected && item.disabled && classes.push('is-' + name + '-disabled-checked' + type)
}
return classes
},
/**
* 获取选中值
* @param {Object} range
*/
getSelectedValue(range) {
if (!this.multiple) return this.value
let selectedArr = []
range.forEach((item) => {
if (item.selected) {
selectedArr.push(item.value)
}
})
return this.value.length > 0 ? this.value : selectedArr
},
/**
* 设置背景样式
*/
setStyleBackgroud(item) {
let styles = {}
if (item.selected) {
if (this.mode !== 'list') {
styles.borderColor = this.styles.selectedColor
}
if (this.mode === 'tag') {
styles.backgroundColor = this.styles.selectedColor
}
}
return styles
},
setStyleIcon(item) {
let styles = {}
if (item.selected) {
styles.backgroundColor = this.styles.selectedColor
styles.borderColor = this.styles.selectedColor
}
return styles
},
setStyleIconText(item) {
let styles = {}
if (item.selected) {
if (this.styles.selectedTextColor) {
styles.color = this.styles.selectedTextColor
} else {
if(this.mode === 'tag'){
styles.color = '#fff'
}else{
styles.color = this.styles.selectedColor
}
}
}
return styles
},
setStyleRightIcon(item){
let styles = {}
if (item.selected) {
if(this.mode === 'list'){
styles.borderColor = this.styles.selectedColor
}
}
return styles
}
}
}
</script>
<style>
.uni-data-checklist {
position: relative;
z-index: 0;
/* min-height: 36px; */
}
.uni-data-loading {
display: flex;
align-items: center;
/* justify-content: center; */
height: 36px;
padding-left: 10px;
}
.checklist-group {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
flex-wrap: wrap;
}
.checklist-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
margin: 5px 0;
margin-right: 25px;
}
.checklist-text {
font-size: 14px;
color: #333;
margin-left: 5px;
transition: color 0.2s;
}
.is-button {
margin-right: 10px;
padding: 3px 15px;
border: 1px #DCDFE6 solid;
border-radius: 3px;
transition: border-color 0.2s;
}
.is-list {
flex-direction: column;
}
.is-list-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
padding: 10px 15px;
padding-left: 0;
margin: 0;
}
.checklist-content {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.list-content {
margin-left: 5px;
}
.is-list-multiple-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
padding: 10px 15px;
padding-left: 0;
margin: 0;
}
.is-list-border {
border-top: 1px #eee solid;
}
.is-tag {
margin-right: 10px;
padding: 3px 10px;
border: 1px #eee solid;
border-radius: 3px;
background-color: #f5f5f5;
/* transition: border-color 0.1s; */
}
.is-tag-text {
margin: 0;
color: #666;
}
.checkbox__inner {
flex-shrink: 0;
position: relative;
border: 1px solid #DCDFE6;
border-radius: 2px;
box-sizing: border-box;
width: 16px;
height: 16px;
background-color: #fff;
z-index: 1;
transition: border-color 0.1s;
}
.checkbox__inner-icon {
border: 1px solid #fff;
border-left: 0;
border-top: 0;
height: 8px;
left: 5px;
position: absolute;
top: 1px;
width: 3px;
opacity: 0;
transition: transform .2s;
transform-origin: center;
transform: rotate(40deg) scaleY(0.4);
}
.radio__inner {
flex-shrink: 0;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
align-items: center;
position: relative;
border: 1px solid #DCDFE6;
border-radius: 2px;
box-sizing: border-box;
width: 16px;
height: 16px;
border-radius: 16px;
background-color: #fff;
z-index: 1;
transition: border-color .3s;
}
.radio__inner-icon {
width: 8px;
height: 8px;
border-radius: 10px;
opacity: 0;
transition: transform .3s;
}
.checkobx__list {
border: 1px solid #fff;
border-left: 0;
border-top: 0;
height: 12px;
width: 6px;
transform-origin: center;
opacity: 0;
transition: all 0.3s;
transform: rotate(45deg);
}
/* 禁用样式 */
.is-default-disabled-bg {
background-color: #F2F6FC;
border-color: #DCDFE6;
/* #ifdef H5 */
cursor: not-allowed;
/* #endif */
}
.is-default-multiple-disabled-bg {
background-color: #F2F6FC;
border-color: #DCDFE6;
/* #ifdef H5 */
cursor: not-allowed;
/* #endif */
}
.is-default-disabled {
border-color: #F2F6FC;
}
.is-default-multiple-disabled {
border-color: #F2F6FC;
}
.is-list-disabled {
/* #ifdef H5 */
cursor: not-allowed;
/* #endif */
color: #999;
}
.is-list-disabled-checked {
color: #a1dcc1;
}
.is-button-disabled {
/* #ifdef H5 */
cursor: not-allowed;
/* #endif */
border-color: #EBEEF5;
}
.is-button-text-disabled {
color: #C0C4CC;
}
.is-button-disabled-checked {
border-color: #a1dcc1;
}
.is-tag-disabled {
/* #ifdef H5 */
cursor: not-allowed;
/* #endif */
border-color: #e9e9eb;
background-color: #f4f4f5;
}
.is-tag-text-disabled {
color: #bcbec2;
}
/* 选中样式 */
.is-default-checked-bg {
border-color: #007aff;
}
.is-default-multiple-checked-bg {
border-color: #007aff;
background-color: #007aff;
}
.is-default-checked {
opacity: 1;
background-color: #007aff;
transform: rotate(45deg) scaleY(1);
}
.is-default-multiple-checked {
opacity: 1;
transform: rotate(45deg) scaleY(1);
}
.is-default-disabled-checked-bg {
opacity: 0.4;
}
.is-default-multiple-disabled-checked-bg {
opacity: 0.4;
}
.is-default-checked-list {
border-color: #007aff;
opacity: 1;
transform: rotate(45deg) scaleY(1);
}
.is-default-multiple-checked-list {
border-color: #007aff;
opacity: 1;
transform: rotate(45deg) scaleY(1);
}
.is-list-disabled-checked {
opacity: 0.4;
}
.is-default-disabled-checked-list {
opacity: 0.4;
}
.is-default-multiple-disabled-checked-list {
opacity: 0.4;
}
.is-button-checked {
border-color: #007aff;
}
.is-button-disabled-checked {
opacity: 0.4;
}
.is-list-checked {
color: #007aff;
}
.is-tag-checked {
border-color: #007aff;
background-color: #007aff;
}
.is-tag-text-checked {
color: #fff;
}
.is-tag-disabled-checked {
opacity: 0.4;
}
.disabled-cursor {
/* #ifdef H5 */
cursor: not-allowed;
/* #endif */
}
.is-wrap {
flex-direction: column;
}
.hidden {
/* #ifdef MP-ALIPAY */
display: none;
/* #endif */
}
</style>
<template>
<view class="uni-data-checklist">
<checkbox-group v-if="multiple" class="checklist-group" :class="{'is-list':mode==='list','is-wrap':wrap}" @change="chagne">
<label class="checklist-box" :class="item.labelClass" v-for="(item,index) in dataList" :key="index">
<checkbox hidden :disabled="item.disable" :value="item.value+''" :checked="item.selected" />
<!-- mode !== 'list' && -->
<view v-if=" mode !=='tag' " class="checkbox__inner" :class="item.checkboxBgClass">
<view class="checkbox__inner-icon" :class="item.checkboxClass"></view>
</view>
<view class="checklist-content">
<text class="checklist-text" :class="item.textClass">{{item.text}}</text>
<view v-if="mode === 'list'" class="checkobx__list" :class="item.listClass"></view>
</view>
</label>
</checkbox-group>
<radio-group v-else class="checklist-group" :class="{'is-list':mode==='list','is-wrap':wrap}" @change="chagne">
<label class="checklist-box" :class="item.labelClass" v-for="(item,index) in dataList" :key="index">
<radio hidden :disabled="item.disable" :value="item.value+''" :checked="item.selected" />
<view v-if="mode !=='tag' " class="radio__inner" :class="item.checkboxBgClass">
<view class="radio__inner-icon" :class="item.checkboxClass"></view>
</view>
<view class="checklist-content">
<text class="checklist-text" :class="item.textClass">{{item.text}}</text>
<view v-if="mode === 'list'" class="checkobx__list" :class="item.listClass"></view>
</view>
</label>
</radio-group>
</view>
</template>
<script>
export default {
name: 'uniDataChecklist',
props: {
// 模s式,可选值 default row ,list,button,tag
mode: {
type: String,
default: 'default'
},
multiple: {
type: Boolean,
default: false
},
// 默认值 ,如果不指定,则取 range 的 selected 属性
value: {
type: [Array, String, Number],
default () {
return ''
}
},
// 范围
range: {
type: Array,
default () {
return []
}
},
// 最大值
min: {
type: [Number, String],
default: ''
},
// 最小值
max: {
type: [Number, String],
default: ''
},
wrap: {
type: Boolean,
default: false
},
// style:{
// type : Object,
// default(){
// return {}
// }
// }
},
watch: {
range: {
handler(newVal) {
this.dataList = this.getDataList(this.getSelectedValue(newVal))
},
deep: true
},
value(newVal) {
this.dataList = this.getDataList(newVal)
}
},
data() {
return {
dataList: [],
styles: {
selectedBackgroudColor: 'red',
selectedColor: 'blue',
backgroundColor: '#ffffff',
color: '#333'
}
};
},
created() {
this.dataList = this.getDataList(this.getSelectedValue(this.range))
},
methods: {
chagne(e) {
const values = e.detail.value
let detail = {
value: [],
data: []
}
if (this.multiple) {
this.range.forEach(item => {
if (values.includes(item.value + '')) {
detail.value.push(item.value)
detail.data.push(item)
}
})
} else {
const range = this.range.find(item => (item.value + '') === values)
if (range) {
detail = {
value: range.value,
data: range
}
}
}
this.$emit('input', detail.value)
this.$emit('change', {
detail
})
if (this.multiple) {
// 如果 v-model 没有绑定 ,则走内部逻辑
if (this.value.length === 0) {
this.dataList = this.getDataList(detail.value, true)
}
} else {
this.dataList = this.getDataList(detail.value)
}
},
getLabelClass(item, index) {
let classes = []
switch (this.mode) {
case 'default':
item.disable && classes.push('disabled-cursor')
break
case 'button':
classes.push(...['is-button', ...this.getClasses(item, 'button')])
break
case 'list':
if (this.multiple) {
classes.push('is-list-multiple-box')
} else {
classes.push('is-list-box')
}
item.disable && classes.push('is-list-disabled')
index !== 0 && classes.push('is-list-border')
break
case 'tag':
classes.push(...['is-tag', ...this.getClasses(item, 'tag')])
break
}
classes = classes.join(' ')
return classes
},
getCheckboxClass(item, type = '') {
let classes = []
if (this.multiple) {
classes.push(...this.getClasses(item, 'default-multiple', type))
} else {
classes.push(...this.getClasses(item, 'default', type))
}
classes = classes.join(' ')
return classes
},
getTextClass(item) {
let classes = []
switch (this.mode) {
case 'default':
classes.push(...this.getClasses(item, 'list'))
break
case 'button':
classes.push(...this.getClasses(item, 'list'))
break
case 'list':
classes.push(...this.getClasses(item, 'list'))
break
case 'tag':
classes.push(...['is-tag-text', ...this.getClasses(item, 'tag-text')])
break
}
classes = classes.join(' ')
return classes
},
/**
* 获取渲染的新数组
* @param {Object} value 选中内容
*/
getDataList(value) {
// 解除引用关系,破坏原引用关系,避免污染源数据
let dataList = JSON.parse(JSON.stringify(this.range))
let list = []
if (this.multiple) {
if (!Array.isArray(value)) {
value = []
// console.error('props 类型错误');
}
}
dataList.forEach((item, index) => {
if (this.multiple) {
if (value.length > 0) {
let have = value.find(val => val === item.value)
item.selected = have !== undefined
} else {
item.selected = false
}
} else {
item.selected = value === item.value
}
list.push(item)
})
return this.setRange(list)
},
/**
* 处理最大最小值
* @param {Object} list
*/
setRange(list) {
let selectList = list.filter(item => item.selected)
let min = Number(this.min) || 0
let max = Number(this.max) || ''
list.forEach((item, index) => {
if (this.multiple) {
if (selectList.length <= min) {
let have = selectList.find(val => val.value === item.value)
if (have !== undefined) {
item.disable = true
}
}
if (selectList.length >= max && max !== '') {
let have = selectList.find(val => val.value === item.value)
if (have === undefined) {
item.disable = true
}
}
}
this.setClass(item, index)
list[index] = item
})
return list
},
/**
* 设置 class
* @param {Object} item
* @param {Object} index
*/
setClass(item, index) {
// 设置 label 的 class
item.labelClass = this.getLabelClass(item, index)
// 设置 checkbox外层样式
item.checkboxBgClass = this.getCheckboxClass(item, '-bg')
// 设置 checkbox 内层样式
item.checkboxClass = this.getCheckboxClass(item)
// 设置文本样式
item.textClass = this.getTextClass(item)
// 设置 list 对勾右侧样式
item.listClass = this.getCheckboxClass(item, '-list')
},
/**
* 获取 class
*/
getClasses(item, name, type = '') {
let classes = []
item.disable && classes.push('is-' + name + '-disabled' + type)
item.selected && classes.push('is-' + name + '-checked' + type)
if(this.mode !== 'button' || name === 'button'){
item.selected && item.disable && classes.push('is-' + name + '-disabled-checked' + type)
}
return classes
},
/**
* 获取选中值
* @param {Object} range
*/
getSelectedValue(range) {
if (!this.multiple) return this.value
let selectedArr = []
range.forEach((item) => {
if (item.selected) {
selectedArr.push(item.value)
}
})
return this.value.length > 0 ? this.value : selectedArr
}
}
}
</script>
<style>
.checklist-group {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.checklist-box {
display: flex;
flex-direction: row;
align-items: center;
margin: 5px 0;
margin-right: 25px;
}
.checklist-text {
font-size: 14px;
color: #333;
margin-left: 5px;
transition: color 0.2s;
}
.is-button {
margin-right: 10px;
padding: 3px 15px;
border: 1px #DCDFE6 solid;
border-radius: 3px;
transition: border-color 0.2s;
}
.is-list {
flex-direction: column;
}
.is-list-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
padding: 10px 15px;
padding-left: 0;
margin: 0;
}
.checklist-content {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.is-list-multiple-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
padding: 10px 15px;
padding-left: 0;
margin: 0;
}
.is-list-border {
border-top: 1px #eee solid;
}
.is-tag {
margin-right: 10px;
padding: 3px 10px;
border: 1px #eee solid;
border-radius: 3px;
background-color: #f5f5f5;
transition: border-color 0.2s;
}
.is-tag-text {
margin: 0;
color: #666;
}
.checkbox__inner {
flex-shrink: 0;
position: relative;
border: 1px solid #DCDFE6;
border-radius: 2px;
box-sizing: border-box;
width: 16px;
height: 16px;
background-color: #fff;
z-index: 1;
transition: border-color 0.1s;
}
.checkbox__inner-icon {
border: 1px solid #fff;
border-left: 0;
border-top: 0;
height: 8px;
left: 5px;
position: absolute;
top: 1px;
width: 3px;
opacity: 0;
transition: transform .1s;
transform-origin: center;
transform: rotate(40deg) scaleY(0.4);
}
.radio__inner {
flex-shrink: 0;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
align-items: center;
position: relative;
border: 1px solid #DCDFE6;
border-radius: 2px;
box-sizing: border-box;
width: 16px;
height: 16px;
border-radius: 16px;
background-color: #fff;
z-index: 1;
transition: border-color .3s;
}
.radio__inner-icon {
width: 8px;
height: 8px;
border-radius: 10px;
opacity: 0;
transition: transform .3s;
}
.checkobx__list {
border: 1px solid #fff;
border-left: 0;
border-top: 0;
height: 12px;
width: 6px;
transform-origin: center;
opacity: 0;
transition: all 0.2s;
}
/* 禁用样式 */
.is-default-disabled-bg {
background-color: #F2F6FC;
border-color: #DCDFE6;
/* #ifdef H5 */
cursor: not-allowed;
/* #endif */
}
.is-default-multiple-disabled-bg {
background-color: #F2F6FC;
border-color: #DCDFE6;
/* #ifdef H5 */
cursor: not-allowed;
/* #endif */
}
.is-default-disabled {
border-color: #F2F6FC;
}
.is-default-multiple-disabled {
border-color: #F2F6FC;
}
.is-list-disabled {
/* #ifdef H5 */
cursor: not-allowed;
/* #endif */
color: #999;
}
.is-list-disabled-checked {
color: #a1dcc1;
}
.is-button-disabled {
/* #ifdef H5 */
cursor: not-allowed;
/* #endif */
border-color: #EBEEF5;
}
.is-button-text-disabled {
color: #C0C4CC;
}
.is-button-disabled-checked {
border-color: #a1dcc1;
}
.is-tag-disabled {
/* #ifdef H5 */
cursor: not-allowed;
/* #endif */
border-color: #e9e9eb;
background-color: #f4f4f5;
}
.is-tag-text-disabled {
color: #bcbec2;
}
/* 选中样式 */
.is-default-checked-bg {
border-color: #007aff;
}
.is-default-multiple-checked-bg {
border-color: #007aff;
background-color: #007aff;
}
.is-default-checked {
opacity: 1;
background-color: #007aff;
transform: rotate(45deg) scaleY(1);
}
.is-default-multiple-checked {
opacity: 1;
transform: rotate(45deg) scaleY(1);
}
.is-default-disabled-checked-bg {
opacity: 0.4;
}
.is-default-multiple-disabled-checked-bg {
opacity: 0.4;
}
.is-default-checked-list {
border-color: #007aff;
opacity: 1;
transform: rotate(45deg) scaleY(1);
}
.is-default-multiple-checked-list {
border-color: #007aff;
opacity: 1;
transform: rotate(45deg) scaleY(1);
}
.is-list-disabled-checked {
opacity: 0.4;
}
.is-default-disabled-checked-list {
opacity: 0.4;
}
.is-default-multiple-disabled-checked-list {
opacity: 0.4;
}
.is-button-checked {
border-color: #007aff;
}
.is-button-disabled-checked {
opacity: 0.4;
}
.is-list-checked {
color: #007aff;
}
.is-tag-checked {
border-color: #007aff;
background-color: #007aff;
}
.is-tag-text-checked {
color: #fff;
}
.is-tag-disabled-checked {
opacity: 0.4;
}
.disabled-cursor {
/* #ifdef H5 */
cursor: not-allowed;
/* #endif */
}
.is-wrap {
flex-direction: column;
}
</style>
// yyyy-MM-dd hh:mm:ss.SSS 所有支持的类型
function pad(str, length = 2) {
str += ''
while (str.length < length) {
str = '0' + str
}
return str.slice(-length)
}
const parser = {
yyyy: (dateObj) => {
return pad(dateObj.year, 4)
},
yy: (dateObj) => {
return pad(dateObj.year)
},
MM: (dateObj) => {
return pad(dateObj.month)
},
M: (dateObj) => {
return dateObj.month
},
dd: (dateObj) => {
return pad(dateObj.day)
},
d: (dateObj) => {
return dateObj.day
},
hh: (dateObj) => {
return pad(dateObj.hour)
},
h: (dateObj) => {
return dateObj.hour
},
mm: (dateObj) => {
return pad(dateObj.minute)
},
m: (dateObj) => {
return dateObj.minute
},
ss: (dateObj) => {
return pad(dateObj.second)
},
s: (dateObj) => {
return dateObj.second
},
SSS: (dateObj) => {
return pad(dateObj.millisecond, 3)
},
S: (dateObj) => {
return dateObj.millisecond
},
}
export function formatDate(date, format = 'yyyy/MM/dd hh:mm:ss') {
date = date instanceof Date ? date : new Date(date)
const dateObj = {
year: date.getFullYear(),
month: date.getMonth() + 1,
day: date.getDate(),
hour: date.getHours(),
minute: date.getMinutes(),
second: date.getSeconds(),
millisecond: date.getMilliseconds()
}
const tokenRegExp = /yyyy|yy|MM|M|dd|d|hh|h|mm|m|ss|s|SSS|SS|S/
let flag = true
let result = format
while (flag) {
flag = false
result = result.replace(tokenRegExp, function(matched) {
flag = true
return parser[matched](dateObj)
})
}
return result
}
export function friendlyDate(time, {
locale = 'zh',
threshold = [60000, 3600000],
format = 'yyyy/MM/dd hh:mm:ss'
}) {
const localeText = {
zh: {
year: '',
month: '',
day: '',
hour: '小时',
minute: '分钟',
second: '',
ago: '',
later: '',
justNow: '刚刚',
soon: '马上',
template: '{num}{unit}{suffix}'
},
en: {
year: 'year',
month: 'month',
day: 'day',
hour: 'hour',
minute: 'minute',
second: 'second',
ago: 'ago',
later: 'later',
justNow: 'just now',
soon: 'soon',
template: '{num} {unit} {suffix}'
}
}
const text = localeText[locale] || localeText.zh
let date = new Date(time)
let ms = date.getTime() - Date.now()
let absMs = Math.abs(ms)
if (absMs < threshold[0]) {
return ms < 0 ? text.justNow : text.soon
}
if (absMs >= threshold[1]) {
return formatDate(date, format)
}
let num
let unit
let suffix = text.later
if (ms < 0) {
suffix = text.ago
ms = -ms
}
const seconds = Math.floor((ms) / 1000)
const minutes = Math.floor(seconds / 60)
const hours = Math.floor(minutes / 60)
const days = Math.floor(hours / 24)
const months = Math.floor(days / 30)
const years = Math.floor(months / 12)
switch (true) {
case years > 0:
num = years
unit = text.year
break
case months > 0:
num = months
unit = text.month
break
case days > 0:
num = days
unit = text.day
break
case hours > 0:
num = hours
unit = text.hour
break
case minutes > 0:
num = minutes
unit = text.minute
break
default:
num = seconds
unit = text.second
break
}
if (locale === 'en') {
if (num === 1) {
num = 'a'
} else {
unit += 's'
}
}
return text.template.replace(/{\s*num\s*}/g, num + '').replace(/{\s*unit\s*}/g, unit).replace(/{\s*suffix\s*}/g,
suffix)
}
<template>
<text>{{dateShow}}</text>
</template>
<script>
/**
* Dateformat 日期格式化
* @description 日期格式化组件
* @tutorial https://ext.dcloud.net.cn/plugin?id=xxx
* @property {Object|String|Number} date 日期对象/日期字符串/时间戳
* @property {String} locale 格式化使用的语言
* @value zh 中文
* @value en 英文
* @property {Array} threshold 应用不同类型格式化的阈值
* @property {String} format 输出日期字符串时的格式
*/
import {
friendlyDate
} from './date-format.js'
export default {
name: 'uniDateformat',
props: {
date: {
type: [Object, String, Number],
default () {
return Date.now()
}
},
locale: {
type: String,
default: 'zh',
},
threshold: {
type: Array,
default () {
return [0, 0]
}
},
format: {
type: String,
default: 'yyyy/MM/dd hh:mm:ss'
},
// refreshRate使用不当可能导致性能问题,谨慎使用
refreshRate: {
type: [Number, String],
default: 0
}
},
data() {
return {
refreshMark: 0
}
},
computed: {
dateShow() {
this.refreshMark
return friendlyDate(this.date, {
locale: this.locale,
threshold: this.threshold,
format: this.format
})
}
},
watch: {
refreshRate: {
handler() {
this.setAutoRefresh()
},
immediate: true
}
},
methods: {
refresh() {
this.refreshMark++
},
setAutoRefresh() {
clearInterval(this.refreshInterval)
if (this.refreshRate) {
this.refreshInterval = setInterval(() => {
this.refresh()
}, parseInt(this.refreshRate))
}
}
}
}
</script>
<style>
</style>
<template>
<view class="uni-datetime-picker">
<view @click="tiggerTimePicker">
<slot>
<view class="uni-datetime-picker-timebox uni-datetime-picker-flex">
{{time}}<view v-if="!time" class="uni-datetime-picker-time">选择日期时间</view>
<view class="uni-datetime-picker-down-arrow"></view>
</view>
</slot>
</view>
<view v-if="visible" class="uni-datetime-picker-mask" @click="initTimePicker"></view>
<view v-if="visible" class="uni-datetime-picker-popup">
<view class="uni-title">
设置日期和时间
</view>
<picker-view class="uni-datetime-picker-view" :indicator-style="indicatorStyle" :value="ymd" @change="bindDateChange">
<picker-view-column class="uni-datetime-picker-hyphen">
<view class="uni-datetime-picker-item" v-for="(item,index) in years" :key="index">{{item}}</view>
</picker-view-column>
<picker-view-column class="uni-datetime-picker-hyphen">
<view class="uni-datetime-picker-item" v-for="(item,index) in months" :key="index">{{item < 10 ? '0' + item : item}}</view>
</picker-view-column>
<picker-view-column>
<view class="uni-datetime-picker-item" v-for="(item,index) in days" :key="index">{{item < 10 ? '0' + item : item}}</view>
</picker-view-column>
</picker-view>
<picker-view class="uni-datetime-picker-view" :indicator-style="indicatorStyle" :value="hms" @change="bindTimeChange">
<picker-view-column class="uni-datetime-picker-colon">
<view class="uni-datetime-picker-item" v-for="(item,index) in hours" :key="index">{{item < 10 ? '0' + item : item}}</view>
</picker-view-column>
<picker-view-column class="uni-datetime-picker-colon">
<view class="uni-datetime-picker-item" v-for="(item,index) in minutes" :key="index">{{item < 10 ? '0' + item : item}}</view>
</picker-view-column>
<picker-view-column>
<view class="uni-datetime-picker-item" v-for="(item,index) in seconds" :key="index">{{item < 10 ? '0' + item : item}}</view>
</picker-view-column>
</picker-view>
<view class="uni-datetime-picker-btn">
<view class="" @click="clearTime">重置</view>
<view class="uni-datetime-picker-btn-group">
<view class="uni-datetime-picker-cancel" @click="tiggerTimePicker">取消</view>
<view class="" @click="setTime">确定</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
visible: false,
time: '',
years: [],
months: [],
days: [],
hours: [],
minutes: [],
seconds: [],
year: 1900,
month: 0,
day: 0,
hour: 0,
minute: 0,
second: 0,
indicatorStyle: `height: 50px;`,
}
},
props: {
type: {
type: String,
default: 'datetime-local'
},
timestamp: {
type: Boolean,
default: false
},
value: {
type: [String, Number],
default: ''
},
maxYear: {
type: [Number, String],
default: 2100
},
minYear: {
type: [Number, String],
default: 1900
}
},
computed: {
ymd() {
return [this.year - this.minYear, this.month - 1, this.day - 1]
},
hms() {
return [this.hour, this.minute, this.second]
}
},
watch: {
value(newValue) {
this.parseValue(this.value)
this.initTime()
}
},
created() {
this.form = this.getForm('uniForms')
this.formItem = this.getForm('uniFormsItem')
if (this.formItem) {
if (this.formItem.name) {
this.rename = this.formItem.name
this.form.inputChildrens.push(this)
}
}
},
mounted() {
const date = new Date()
for (let i = this.minYear; i <= this.maxYear; i++) {
this.years.push(i)
}
for (let i = 1; i <= 12; i++) {
this.months.push(i)
}
for (let i = 1; i <= 31; i++) {
this.days.push(i)
}
for (let i = 0; i <= 23; i++) {
this.hours.push(i)
}
for (let i = 0; i <= 59; i++) {
this.minutes.push(i)
}
for (let i = 0; i <= 59; i++) {
this.seconds.push(i)
}
this.parseValue(this.value)
if (this.value) {
this.initTime()
}
},
methods: {
/**
* 获取父元素实例
*/
getForm(name = 'uniForms') {
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;
},
parseDateTime(datetime) {
let defaultDate = null
if (!datetime) {
defaultDate = new Date()
} else {
defaultDate = new Date(datetime)
}
this.year = defaultDate.getFullYear()
if (this.year < this.minYear || this.year > this.maxYear) {
const now = Date.now()
this.parseDateTime(now)
return
}
this.month = defaultDate.getMonth() + 1
this.day = defaultDate.getDate()
this.hour = defaultDate.getHours()
this.minute = defaultDate.getMinutes()
this.second = defaultDate.getSeconds()
},
parseValue(defaultTime) {
if (Number(defaultTime)) {
defaultTime = parseInt(defaultTime)
}
this.parseDateTime(defaultTime)
},
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.time) {
// this.parseValue()
// }
this.parseValue(this.value)
this.visible = !this.visible
},
tiggerTimePicker() {
this.visible = !this.visible
},
clearTime() {
this.time = ''
this.tiggerTimePicker()
},
initTime() {
this.time = this.createDomSting()
if (!this.timestamp) {
this.formItem && this.formItem.setValue(this.time)
this.$emit('change', this.time)
} else {
this.formItem && this.formItem.setValue(this.createTimeStamp(this.time))
this.$emit('change', this.createTimeStamp(this.time))
}
},
setTime() {
this.initTime()
this.tiggerTimePicker()
},
createTimeStamp(time) {
return Date.parse(new Date(time))
},
createDomSting() {
const yymmdd = this.year +
'-' +
(this.month < 10 ? '0' + this.month : this.month) +
'-' +
(this.day < 10 ? '0' + this.day : this.day) +
' ' +
(this.hour < 10 ? '0' + this.hour : this.hour) +
':' +
(this.minute < 10 ? '0' + this.minute : this.minute) +
':' +
(this.second < 10 ? '0' + this.second : this.second)
return yymmdd
}
}
}
</script>
<style>
.uni-datetime-picker-view {
width: 100%;
height: 130px;
margin-top: 30px;
}
.uni-datetime-picker-item {
line-height: 50px;
text-align: center;
}
.uni-datetime-picker-btn {
margin-top: 60px;
display: flex;
justify-content: space-between;
color: blue;
cursor: pointer;
}
.uni-datetime-picker-btn-group {
display: flex;
}
.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;
background-color: #fff;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
transition-duration: 0.3s;
z-index: 999;
}
.uni-datetime-picker-time {
color: grey;
}
.uni-datetime-picker-colon::after {
content: ':';
position: absolute;
top: 53px;
right: 0;
}
.uni-datetime-picker-hyphen::after {
content: '-';
position: absolute;
top: 53px;
right: -2px;
}
.uni-datetime-picker-timebox {
border: 1px solid #E5E5E5;
border-radius: 5px;
padding: 7px 10px;
box-sizing: border-box;
cursor: pointer;
}
// 下箭头
.uni-datetime-picker-down-arrow {
display :inline-block;
position: relative;
width: 20px;
height: 15px;
}
.uni-datetime-picker-down-arrow::after {
display: inline-block;
content: " ";
height: 9px;
width: 9px;
border-width: 0 1px 1px 0;
border-color: #E5E5E5;
border-style: solid;
transform: matrix(0.71, 0.71, -0.71, 0.71, 0, 0);
transform-origin: center;
transition: transform .3s;
position: absolute;
top: 50%;
right: 5px;
margin-top: -5px;
}
.uni-datetime-picker-flex {
display: flex;
justify-content: space-between;
}
</style>
/**
* @desc 函数防抖
* @param func 目标函数
* @param wait 延迟执行毫秒数
* @param immediate true - 立即执行, false - 延迟执行
*/
export const debounce = function(func, wait = 1000, immediate = true) {
let timer;
console.log(1);
return function() {
console.log(123);
let context = this,
args = arguments;
if (timer) clearTimeout(timer);
if (immediate) {
let callNow = !timer;
timer = setTimeout(() => {
timer = null;
}, wait);
if (callNow) func.apply(context, args);
} else {
timer = setTimeout(() => {
func.apply(context, args);
}, wait)
}
}
}
/**
* @desc 函数节流
* @param func 函数
* @param wait 延迟执行毫秒数
* @param type 1 使用表时间戳,在时间段开始的时候触发 2 使用表定时器,在时间段结束的时候触发
*/
export const throttle = (func, wait = 1000, type = 1) => {
let previous = 0;
let timeout;
return function() {
let context = this;
let args = arguments;
if (type === 1) {
let now = Date.now();
if (now - previous > wait) {
func.apply(context, args);
previous = now;
}
} else if (type === 2) {
if (!timeout) {
timeout = setTimeout(() => {
timeout = null;
func.apply(context, args)
}, wait)
}
}
}
}
<template>
<view class="uni-easyinput" :class="{'uni-easyinput-error':msg}" :style="{color:inputBorder && msg?'#dd524d':styles.color}">
<view class="uni-easyinput__content" :class="{'is-input-border':inputBorder ,'is-input-error-border':inputBorder && msg,'is-textarea':type==='textarea','is-disabled':disabled}"
:style="{'border-color':inputBorder && msg?'#dd524d':styles.borderColor,'background-color':disabled?styles.disableColor:'#fff'}">
<uni-icons v-if="prefixIcon" class="content-clear-icon" :type="prefixIcon" color="#c0c4cc" @click="onClickIcon('prefix')"></uni-icons>
<textarea v-if="type === 'textarea'" class="uni-easyinput__content-textarea" :class="{'input-padding':inputBorder}"
:name="name" :value="val" :placeholder="placeholder" :placeholderStyle="placeholderStyle" :disabled="disabled"
:maxlength="inputMaxlength" :focus="focused" :autoHeight="autoHeight" @input="onInput" @blur="onBlur" @focus="onFocus"
@confirm="onConfirm"></textarea>
<input v-else :type="type === 'password'?'text':type" class="uni-easyinput__content-input" :style="{
'padding-right':type === 'password' ||clearable || prefixIcon?'':'10px',
'padding-left':prefixIcon?'':'10px'
}"
:name="name" :value="val" :password="!showPassword && type === 'password'" :placeholder="placeholder"
:placeholderStyle="placeholderStyle" :disabled="disabled" :maxlength="inputMaxlength" :focus="focused" @focus="onFocus"
@blur="onBlur" @input="onInput" @confirm="onConfirm" />
<template v-if="type === 'password'">
<uni-icons v-if="val != '' " class="content-clear-icon" :class="{'is-textarea-icon':type==='textarea'}" :type="showPassword?'eye-slash-filled':'eye-filled'"
:size="18" color="#c0c4cc" @click="onEyes"></uni-icons>
</template>
<template v-else-if="suffixIcon">
<uni-icons v-if="suffixIcon" class="content-clear-icon" :type="suffixIcon" color="#c0c4cc" @click="onClickIcon('suffix')"></uni-icons>
</template>
<template v-else>
<uni-icons class="content-clear-icon" :class="{'is-textarea-icon':type==='textarea'}" type="clear" :size="clearSize"
v-if="clearable && focused && val " color="#c0c4cc" @click="onClear"></uni-icons>
</template>
</view>
</view>
</template>
<script>
/**
* Field 输入框
* @description 此组件可以实现表单的输入与校验,包括 "text" 和 "textarea" 类型。
* @tutorial https://ext.dcloud.net.cn/plugin?id=21001
* @property {String| Number} value 输入内容
* @property {String } type 输入框的类型(默认text) password/text/textarea/..
* @value text 文本输入键盘
* @value textarea 多行文本输入键盘
* @value password 密码输入键盘
* @value number 数字输入键盘,注意iOS上app-vue弹出的数字键盘并非9宫格方式
* @value idcard 身份证输入键盘,信、支付宝、百度、QQ小程序
* @value digit 带小数点的数字键盘 ,App的nvue页面、微信、支付宝、百度、头条、QQ小程序支持
* @property {Boolean} clearable 是否显示右侧清空内容的图标控件(输入框有内容,且获得焦点时才显示),点击可清空输入框内容(默认true)
* @property {Boolean} autoHeight 是否自动增高输入区域,type为textarea时有效(默认true)
* @property {String } placeholder 输入框的提示文字
* @property {String } placeholderStyle placeholder的样式(内联样式,字符串),如"color: #ddd"
* @property {Boolean} focus 是否自动获得焦点(默认false)
* @property {Boolean} disabled 是否不可输入(默认false)
* @property {Number } maxlength 最大输入长度,设置为 -1 的时候不限制最大长度(默认140)
* @property {String } confirmType 设置键盘右下角按钮的文字,仅在type="text"时生效(默认done)
* @property {Number } clearSize 清除图标的大小,单位px(默认15)
* @property {String} prefixIcon 输入框头部图标
* @property {String} suffixIcon 输入框尾部图标
* @property {Boolean} trim 是否自动去除两端的空格
* @property {Boolean} inputBorder 是否显示input输入框的边框(默认false)
* @property {Object} styles 自定义颜色
* @event {Function} input 输入框内容发生变化时触发
* @event {Function} focus 输入框获得焦点时触发
* @event {Function} blur 输入框失去焦点时触发
* @event {Function} confirm 点击完成按钮时触发
* @event {Function} iconClick 点击图标时触发
* @example <uni-easyinput v-model="mobile"></uni-easyinput>
*/
import {
debounce,
throttle
} from './common.js'
export default {
name: 'uni-easyinput',
props: {
name: String,
value: [Number, String],
type: {
type: String,
default: 'text'
},
clearable: {
type: Boolean,
default: true
},
autoHeight: {
type: Boolean,
default: false
},
placeholder: String,
placeholderStyle: String,
focus: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
maxlength: {
type: [Number, String],
default: 140
},
confirmType: {
type: String,
default: 'done'
},
// 清除按钮的大小
clearSize: {
type: [Number, String],
default: 15
},
// 是否显示 input 边框
inputBorder: {
type: Boolean,
default: true
},
prefixIcon: {
type: String,
default: ''
},
suffixIcon: {
type: String,
default: ''
},
// 是否自动去除两端的空格
trim: {
type: [Boolean, String],
default: true
},
// 自定义样式
styles: {
type: Object,
default () {
return {
color: '#333',
disableColor: '#eee',
borderColor: '#e5e5e5'
}
}
}
},
data() {
return {
focused: false,
errMsg: '',
val: '',
showMsg: '',
border: false,
isFirstBorder: false,
showClearIcon: false,
showPassword: false
};
},
computed: {
msg() {
return this.errorMessage || this.errMsg;
},
// 因为uniapp的input组件的maxlength组件必须要数值,这里转为数值,给用户可以传入字符串数值
inputMaxlength() {
return Number(this.maxlength);
},
},
watch: {
value(newVal) {
if (this.errMsg) this.errMsg = ''
this.val = newVal
if (this.formItem) {
this.formItem.setValue(newVal)
}
},
focus(newVal) {
this.$nextTick(() => {
this.focused = this.focus
})
}
},
created() {
this.val = this.value
this.form = this.getForm('uniForms')
this.formItem = this.getForm('uniFormsItem')
if (this.formItem) {
if (this.formItem.name) {
this.rename = this.formItem.name
this.form.inputChildrens.push(this)
}
}
},
mounted() {
// this.onInput = throttle(this.input, 500)
this.$nextTick(() => {
this.focused = this.focus
})
},
methods: {
/**
* 初始化变量值
*/
init() {
},
onClickIcon(type) {
this.$emit('iconClick', type)
},
/**
* 获取父元素实例
*/
getForm(name = 'uniForms') {
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;
},
onEyes() {
this.showPassword = !this.showPassword
},
onInput(event) {
let value = event.detail.value;
// 判断是否去除空格
if (this.trim) {
if (typeof(this.trim) === 'boolean' && this.trim) {
value = this.trimStr(value)
}
if (typeof(this.trim) === 'string') {
value = this.trimStr(value, this.trim)
}
};
if (this.errMsg) this.errMsg = ''
this.val = value
this.$emit('input', value);
},
onFocus(event) {
this.focused = true;
this.$emit('focus', event);
},
onBlur(event) {
let value = event.detail.value;
// 最开始使用的是监听图标@touchstart事件,自从hx2.8.4后,此方法在微信小程序出错
// 这里改为监听点击事件,手点击清除图标时,同时也发生了@blur事件,导致图标消失而无法点击,这里做一个延时
setTimeout(() => {
this.focused = false;
}, 100);
this.$emit('blur', event);
},
onConfirm(e) {
this.$emit('confirm', e.detail.value);
},
onClear(event) {
this.val = '';
this.$emit('input', '');
},
fieldClick() {
this.$emit('click');
},
trimStr(str, pos = 'both') {
if (pos === 'both') {
return str.trim();
} else if (pos === 'left') {
return str.trimLeft();
} else if (pos === 'right') {
return str.trimRight();
} else if (pos === 'all') {
return str.replace(/\s+/g, '');
} else if (pos === 'none') {
return str;
}
return str;
}
}
};
</script>
<style lang="scss" scoped>
.uni-easyinput {
/* #ifndef APP-NVUE */
width: 100%;
/* #endif */
flex: 1;
position: relative;
// padding: 16px 14px;
text-align: left;
color: #333;
font-size: 14px;
}
.uni-easyinput__content {
flex: 1;
/* #ifndef APP-NVUE */
width: 100%;
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
box-sizing: border-box;
min-height: 36px;
}
.uni-easyinput__content-input {
position: relative;
overflow: hidden;
flex: 1;
width: auto;
line-height: 2;
font-size: 14px;
// padding-right: 10px;
}
.is-textarea {
align-items: flex-start;
}
.is-textarea-icon {
margin-top: 5px;
}
.uni-easyinput__content-textarea {
position: relative;
overflow: hidden;
flex: 1;
width: auto;
line-height: 1.5;
font-size: 14px;
// padding-right: 10px;
padding-top: 6px;
padding-bottom: 10px;
// box-sizing: border-box;
min-height: 80px;
height: 80px;
}
.input-padding {
padding-left: 10px;
}
.content-clear-icon {
padding: 0 5px;
}
.label-icon {
margin-right: 5px;
margin-top: -1px;
}
// 显示边框
.is-input-border {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
border: 1px solid $uni-border-color;
border-radius: 4px;
box-sizing: border-box;
}
.uni-easyinput__right {
// margin-left: 5px;
}
// 必填
.is-required {
color: $uni-color-error;
}
.uni-error-message {
position: absolute;
bottom: -17px;
left: 0;
line-height: 12px;
color: $uni-color-error;
font-size: 12px;
text-align: left;
}
.uni-error-msg--boeder {
position: relative;
bottom: 0;
line-height: 22px;
}
.is-input-error-border {
border-color: $uni-color-error;
}
.uni-easyinput--border {
margin-bottom: 0;
padding: 10px 15px;
// padding-bottom: 0;
border-top: 1px #eee solid;
}
.uni-easyinput-error {
padding-bottom: 0;
}
.is-first-border {
border: none;
}
.is-disabled {
background-color: #eee;
}
</style>
<template>
<view class="uni-forms-item" :class="{'uni-forms-item--border':border,'is-first-border':border&&isFirstBorder,'uni-forms-item-error':msg}">
<view class="uni-forms-item__inner" :class="['is-direction-'+labelPos,]">
<view v-if="label" class="uni-forms-item__label" :style="{width:labelWid+'px',justifyContent: justifyContent}">
<slot name="left">
<uni-icons v-if="leftIcon" class="label-icon" size="16" :type="leftIcon" :color="iconColor" />
<text>{{label}}</text>
<text v-if="required" class="is-required">*</text>
</slot>
</view>
<view class="uni-forms-item__content" :class="{'is-input-error-border': msg}">
<slot></slot>
</view>
</view>
<view class="uni-error-message" :class="{'uni-error-msg--boeder':border}" :style="{
paddingLeft: (labelPos === 'left'? Number(labelWid)+5:5) + 'px'
}">{{ showMsg === 'undertext' ? msg:'' }}</view>
</view>
</template>
<script>
/**
* Field 输入框
* @description 此组件可以实现表单的输入与校验,包括 "text" 和 "textarea" 类型。
* @tutorial https://ext.dcloud.net.cn/plugin?id=21001
* @property {Boolean} required 是否必填,左边显示红色"*"号(默认false)
* @property {String} validateTrigger = [bind|submit] 校验触发器方式 默认 submit 可选
* @value bind 发生变化时触发
* @value submit 提交时触发
* @property {String } leftIcon label左边的图标,限 uni-ui 的图标名称
* @property {String } iconColor 左边通过icon配置的图标的颜色(默认#606266)
* @property {String } label 输入框左边的文字提示
* @property {Number } labelWidth label的宽度,单位px(默认65)
* @property {String } labelAlign = [left|center|right] label的文字对齐方式(默认left)
* @value left label 左侧显示
* @value center label 居中
* @value right label 右侧对齐
* @property {String } labelPosition = [top|left] label的文字的位置(默认left)
* @value top 顶部显示 label
* @value left 左侧显示 label
* @property {String } errorMessage 显示的错误提示内容,如果为空字符串或者false,则不显示错误信息
* @property {String } name 表单域的属性名,在使用校验规则时必填
*/
export default {
name: "uniFormsItem",
props: {
// 自定义内容
custom: {
type: Boolean,
default: false
},
// 是否显示报错信息
showMessage: {
type: Boolean,
default: true
},
name: String,
required: Boolean,
validateTrigger: {
type: String,
default: ''
},
leftIcon: String,
iconColor: {
type: String,
default: '#606266'
},
label: String,
// 左边标题的宽度单位px
labelWidth: {
type: [Number, String],
default: ''
},
// 对齐方式,left|center|right
labelAlign: {
type: String,
default: ''
},
// lable的位置,可选为 left-左边,top-上边
labelPosition: {
type: String,
default: ''
},
errorMessage: {
type: [String, Boolean],
default: ''
}
},
data() {
return {
errorTop: false,
errorBottom: false,
labelMarginBottom: '',
errorWidth: '',
errMsg: '',
val: '',
labelPos: '',
labelWid: '',
labelAli: '',
showMsg: 'undertext',
border: false,
isFirstBorder: false
};
},
computed: {
msg() {
return this.errorMessage || this.errMsg;
},
fieldStyle() {
let style = {}
if (this.labelPos == 'top') {
style.padding = '0 0'
this.labelMarginBottom = '6px'
}
if (this.labelPos == 'left' && this.msg !== false && this.msg != '') {
style.paddingBottom = '0px'
this.errorBottom = true
this.errorTop = false
} else if (this.labelPos == 'top' && this.msg !== false && this.msg != '') {
this.errorBottom = false
this.errorTop = true
} else {
// style.paddingBottom = ''
this.errorTop = false
this.errorBottom = false
}
return style
},
// uni不支持在computed中写style.justifyContent = 'center'的形式,故用此方法
justifyContent() {
if (this.labelAli === 'left') return 'flex-start';
if (this.labelAli === 'center') return 'center';
if (this.labelAli === 'right') return 'flex-end';
}
},
watch: {
validateTrigger(trigger) {
this.formTrigger = trigger
}
},
created() {
this.form = this.getForm()
this.group = this.getForm('uniGroup')
this.formRules = []
this.formTrigger = this.validateTrigger
// if (this.form) {
this.form.childrens.push(this)
// }
this.init()
},
destroyed() {
if (this.form) {
this.form.childrens.forEach((item, index) => {
if (item === this) {
this.form.childrens.splice(index, 1)
}
})
}
},
methods: {
init() {
if (this.form) {
let {
formRules,
validator,
formData,
value,
labelPosition,
labelWidth,
labelAlign,
errShowType
} = this.form
this.labelPos = this.labelPosition ? this.labelPosition : labelPosition
this.labelWid = this.label ? (this.labelWidth ? this.labelWidth : labelWidth):0
this.labelAli = this.labelAlign ? this.labelAlign : labelAlign
// 判断第一个 item
if (!this.form.isFirstBorder) {
this.form.isFirstBorder = true
this.isFirstBorder = true
}
// 判断 group 里的第一个 item
if (this.group) {
if (!this.group.isFirstBorder) {
this.group.isFirstBorder = true
this.isFirstBorder = true
}
}
this.border = this.form.border
this.showMsg = errShowType
if (formRules) {
this.formRules = formRules[this.name] || {}
}
this.validator = validator
if (this.name) {
formData[this.name] = value.hasOwnProperty(this.name) ? value[this.name] : this.form._getValue(this, '')
}
} else {
this.labelPos = this.labelPosition || 'left'
this.labelWid = this.labelWidth || 65
this.labelAli = this.labelAlign || 'left'
}
},
/**
* 获取父元素实例
*/
getForm(name = 'uniForms') {
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;
},
/**
* 移除该表单项的校验结果
*/
clearValidate() {
this.errMsg = ''
},
setValue(value){
if (this.name) {
if(this.errMsg) this.errMsg = ''
this.form.formData[this.name] = this.form._getValue(this, value)
}
},
/**
* 校验规则
* @param {Object} value
*/
async triggerCheck(value, callback) {
let promise = null;
this.errMsg = ''
// if no callback, return promise
if (callback && typeof callback !== 'function' && Promise) {
promise = new Promise((resolve, reject) => {
callback = function(valid) {
!valid ? resolve(valid) : reject(valid)
};
});
}
if (!this.validator) {
typeof callback === 'function' && callback(null);
if (promise) return promise
}
const isNoField = this.isRequired(this.formRules.rules || [])
let isTrigger = this.isTrigger(this.formRules.validateTrigger, this.validateTrigger, this.form.validateTrigger)
let result = null
if (!(!isTrigger)) {
result = this.validator && (await this.validator.validateUpdate({
[this.name]: value
}, this.form.formData))
}
// 判断是否必填
if (!isNoField && !value) {
result = null
}
if (isTrigger && result && result.errorMessage) {
if (this.form.errShowType === 'toast') {
uni.showToast({
title: result.errorMessage || '校验错误',
icon: 'none'
})
}
if (this.form.errShowType === 'modal') {
uni.showModal({
title: '提示',
content: result.errorMessage || '校验错误'
})
}
}
this.errMsg = !result ? '' : result.errorMessage
this.form.validateCheck(result ? result : null)
typeof callback === 'function' && callback(result ? result : null);
if (promise) return promise
},
/**
* 触发时机
* @param {Object} event
*/
isTrigger(rule, itemRlue, parentRule) {
let rl = true;
// bind submit
if (rule === 'submit' || !rule) {
if (rule === undefined) {
if (itemRlue !== 'bind') {
if (!itemRlue) {
return parentRule === 'bind' ? true : false
}
return false
}
return true
}
return false
}
return true;
},
// 是否有必填字段
isRequired(rules) {
let isNoField = false
for (let i = 0; i < rules.length; i++) {
const ruleData = rules[i]
if (ruleData.required) {
isNoField = true
break
}
}
return isNoField
}
}
};
</script>
<style lang="scss" scoped>
.uni-forms-item {
position: relative;
// padding: 16px 14px;
text-align: left;
color: #333;
font-size: 14px;
margin-bottom: 22px;
background-color: #fff;
}
.uni-forms-item__inner {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
// flex-direction: row;
// align-items: center;
}
.is-direction-left {
flex-direction: row;
}
.is-direction-top {
flex-direction: column;
}
.uni-forms-item__label {
/* #ifndef APP-NVUE */
display: flex;
flex-shrink: 0;
/* #endif */
flex-direction: row;
align-items: center;
font-size: 14px;
color: #333;
width: 65px;
// line-height: 2;
// margin-top: 3px;
padding: 5px 0;
box-sizing: border-box;
height: 36px;
margin-right: 5px;
}
.uni-forms-item__content {
/* #ifndef APP-NVUE */
width: 100%;
// display: flex;
/* #endif */
// flex: 1;
// flex-direction: row;
// align-items: center;
box-sizing: border-box;
min-height: 36px;
}
.label-icon {
margin-right: 5px;
margin-top: -1px;
}
// 必填
.is-required {
color: $uni-color-error;
}
.uni-error-message {
position: absolute;
bottom: -17px;
left: 0;
line-height: 12px;
color: $uni-color-error;
font-size: 12px;
text-align: left;
}
.uni-error-msg--boeder {
position: relative;
bottom: 0;
line-height: 22px;
}
.is-input-error-border {
border-color: $uni-color-error;
}
.uni-forms-item--border {
margin-bottom: 0;
padding: 10px 15px;
// padding-bottom: 0;
border-top: 1px #eee solid;
}
.uni-forms-item-error {
padding-bottom: 0;
}
.is-first-border {
border: none;
}
</style>
此差异已折叠。
此差异已折叠。
<template>
<view class="uni-group" :class="['uni-group--'+mode ,margin?'group-margin':'']" :style="{marginTop: `${top}px` }">
<slot name="title">
<view v-if="title" class="uni-group__title" :style="{'padding-left':border?'30px':'15px'}">
<text class="uni-group__title-text">{{ title }}</text>
</view>
</slot>
<view class="uni-group__content" :class="{'group-conent-padding':border}">
<slot />
</view>
</view>
</template>
<script>
/**
* Group 分组
* @description 表单字段分组
* @tutorial https://ext.dcloud.net.cn/plugin?id=21002
* @property {String} title 主标题
* @property {Number} top 分组间隔
*/
export default {
name: 'uniGroup',
props: {
title: {
type: String,
default: ''
},
top: {
type: [Number, String],
default: 10
},
mode: {
type: String,
default: 'default'
}
},
data() {
return {
margin: false,
border: false
}
},
watch: {
title(newVal) {
if (uni.report && newVal !== '') {
uni.report('title', newVal)
}
}
},
created() {
this.form = this.getForm()
if (this.form) {
this.margin = true
this.border = this.form.border
}
},
methods: {
/**
* 获取父元素实例
*/
getForm() {
let parent = this.$parent;
let parentName = parent.$options.name;
while (parentName !== 'uniForms') {
parent = parent.$parent;
if (!parent) return false
parentName = parent.$options.name;
}
return parent;
},
onClick() {
this.$emit('click')
}
}
}
</script>
<style lang="scss" scoped>
.uni-group {
background: #fff;
margin-top: 10px;
// border: 1px red solid;
}
.group-margin {
margin: 0 -15px;
}
.uni-group__title {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
align-items: center;
padding-left: 15px;
height: 40px;
background-color: $uni-bg-color-grey;
font-weight: normal;
color: $uni-text-color;
}
.uni-group__content {
padding: 15px;
// padding-bottom: 5px;
background-color: #FFF;
}
.group-conent-padding {
padding: 0 15px;
}
.uni-group__title-text {
font-size: $uni-font-size-base;
color: $uni-text-color;
}
.distraction {
flex-direction: row;
align-items: center;
}
.uni-group--card {
margin: 10px;
border-radius: 5px;
overflow: hidden;
box-shadow: 0 0 5px 1px rgba($color: #000000, $alpha: 0.08);
}
</style>
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
export default {
methods:{
/**
* 获取所有父元素
* @param {Object} name
* @param {Object} parent
*/
getParentAll(name, parent) {
parent = this.getParent(`uni${name}`, parent)
if (parent) {
this.rootMenu[name].push(parent)
this.getParentAll(name, parent)
}
},
/**
* 获取父元素实例
*/
getParent(name, parent, type) {
parent = parent.$parent;
let parentName = parent.$options.name;
while (parentName !== name) {
parent = parent.$parent;
if (!parent) return false
parentName = parent.$options.name;
}
return parent;
}
}
}
\ No newline at end of file
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
export default {
created() {
if (this.type === 'share') {
// 关闭点击
this.mkclick = false
}
},
methods: {
customOpen() {
console.log('share 打开了');
},
customClose() {
console.log('share 关闭了');
}
}
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册