作者 左学珍

首页

正在显示 37 个修改的文件 包含 4529 行增加0 行删除

要显示太多修改。

为保证性能只显示 37 of 37+ 个文件。

  1 +{ // launch.json 配置了启动调试时相关设置,configurations下节点名称可为 app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/
  2 + // launchtype项可配置值为local或remote, local代表前端连本地云函数,remote代表前端连云端云函数
  3 + "version": "0.0",
  4 + "configurations": [{
  5 + "default" :
  6 + {
  7 + "launchtype" : "local"
  8 + },
  9 + "mp-weixin" :
  10 + {
  11 + "launchtype" : "local"
  12 + },
  13 + "type" : "uniCloud"
  14 + }
  15 + ]
  16 +}
  1 +<script>
  2 + export default {
  3 + onLaunch: function() {
  4 + console.log('App Launch')
  5 + },
  6 + onShow: function() {
  7 + console.log('App Show')
  8 + },
  9 + onHide: function() {
  10 + console.log('App Hide')
  11 + }
  12 + }
  13 +</script>
  14 +
  15 +<style lang="scss">
  16 + /*每个页面公共css */
  17 + @import "node_modules/uview-ui/index.scss";
  18 +</style>
  1 +import {
  2 + request
  3 +} from '@/utils/request.js'
  4 +
  5 +
  6 +//大戏优选 /api/index/daxi
  7 +export const getIndexOpera = (jd_page,more_page) => request({url: '/api/index/daxi',method: 'get',data: {jd_page,more_page}})
  1 +<template>
  2 + <view class="filter-wrapper" :style="{ height: height + 'rpx', top: top,'border-top':border?'1rpx solid #f2f2f2':'none' }" @touchmove.stop.prevent="discard">
  3 + <view class="inner-wrapper">
  4 + <view class="mask" :class="showMask ? 'show' : 'hide'" @tap="tapMask"></view>
  5 + <view class="navs">
  6 + <view class="c-flex-align" :class="{ 'c-flex-center': index > 0, actNav: index === actNav }" v-for="(item, index) in navData" :key="index" @click="navClick(index)">
  7 + <view v-for="(child, childx) in item" :key="childx" v-if="child.select">{{ child.text }}</view>
  8 + <image style="width:30rpx;height:30rpx;" src="/static/2-2筛选-全城/ic-arrow-putaway@2x.png" mode="" class="icon-triangle" v-if="index === actNav"></image>
  9 + <image style="width:30rpx;height:30rpx;" src="/static/2-1筛选-分类/ic-arrow-unfold@2x(2).png" mode="" class="icon-triangle" v-else></image>
  10 + </view>
  11 +
  12 + <!-- <view class="date-wrapper">
  13 + <picker mode="date" @change="handleDate">
  14 + <view class="date c-flex-align" :style="{ height: height + 'rpx' }" @click="dateClick">
  15 + <view>{{ selDate }}</view>
  16 + <image src="https://i.loli.net/2020/07/15/xjVSvzWcH9NO7al.png" mode="" class="icon-triangle"></image>
  17 + </view>
  18 + </picker>
  19 + </view> -->
  20 + </view>
  21 + <scroll-view scroll-y="true" class="popup" :class="popupShow ? 'popupShow' : ''">
  22 + <view class="item-opt c-flex-align" :class="item.select ? 'actOpt' : ''" v-for="(item, index) in navData[actNav]" :key="index" @click="handleOpt(index)">
  23 + {{ item.text }}
  24 + </view>
  25 + </scroll-view>
  26 + </view>
  27 + </view>
  28 +</template>
  29 +
  30 +<script>
  31 +// import { getCurDateTime } from '@/libs/utils.js';
  32 +export default {
  33 + props: {
  34 + height: {
  35 + type: Number,
  36 + default: 108
  37 + },
  38 + top: {
  39 + type: String,
  40 + default: 'calc(var(--window-statsu-bar) + 44px)'
  41 + },
  42 + border: {
  43 + type: Boolean,
  44 + default: false
  45 + },
  46 + filterData: {
  47 + //必填
  48 + type: Array,
  49 + default: () => {
  50 + return [];
  51 + }
  52 + // default: () => {
  53 + // return [
  54 + // [{ text: '全部状态', value: '' }, { text: '状态1', value: 1 }, { text: '状态2', value: 2 }, { text: '状态3', value: 3 }],
  55 + // [{ text: '全部类型', value: '' }, { text: '类型1', value: 1 }, { text: '类型2', value: 2 }, { text: '类型3', value: 3 }]
  56 + // ];
  57 + // }
  58 + },
  59 + defaultIndex: {
  60 + //默认选中条件索引,超出一类时必填
  61 + type: Array,
  62 + default: () => {
  63 + return [0];
  64 + }
  65 + }
  66 + },
  67 + data() {
  68 + return {
  69 + navData: [],
  70 + popupShow: false,
  71 + showMask: false,
  72 + actNav: null,
  73 + selDate: '选择日期',
  74 + selIndex: [] //选中条件索引
  75 + };
  76 + },
  77 + created() {
  78 + this.navData = this.filterData;
  79 + this.selIndex = this.defaultIndex;
  80 + this.keepStatus();
  81 + },
  82 + mounted() {
  83 + // this.selDate = getCurDateTime().formatDate;
  84 + },
  85 + methods: {
  86 + keepStatus() {
  87 + this.navData.forEach(itemnavData => {
  88 + itemnavData.map(child => {
  89 + child.select = false;
  90 + });
  91 + return itemnavData;
  92 + });
  93 + for (let i = 0; i < this.selIndex.length; i++) {
  94 + let selindex = this.selIndex[i];
  95 + this.navData[i][selindex].select = true;
  96 + }
  97 + },
  98 + navClick(index) {
  99 + if (index === this.actNav) {
  100 + this.tapMask();
  101 + return;
  102 + }
  103 + this.popupShow = true;
  104 + this.showMask = true;
  105 + this.actNav = index;
  106 + },
  107 + handleOpt(index) {
  108 + this.selIndex[this.actNav] = index;
  109 + this.keepStatus();
  110 + setTimeout(() => {
  111 + this.tapMask();
  112 + }, 100);
  113 + let data = [];
  114 + let res = this.navData.forEach(item => {
  115 + let sel = item.filter(child => child.select);
  116 + data.push(sel);
  117 + });
  118 + console.log(data);
  119 + this.$emit('onSelected', data);
  120 + },
  121 + dateClick() {
  122 + this.tapMask();
  123 + },
  124 + tapMask() {
  125 + this.showMask = false;
  126 + this.popupShow = false;
  127 + this.actNav = null;
  128 + },
  129 + handleDate(e) {
  130 + let d = e.detail.value;
  131 + this.selDate = d;
  132 + this.$emit('dateChange', d);
  133 + },
  134 + discard() {}
  135 + }
  136 +};
  137 +</script>
  138 +
  139 +<style lang="scss" scoped>
  140 +page {
  141 + font-size: 28rpx;
  142 +}
  143 +.c-flex-align {
  144 + display: flex;
  145 + align-items: center;
  146 +}
  147 +.c-flex-center {
  148 + display: flex;
  149 + align-items: center;
  150 + justify-content: center;
  151 + flex-direction: column;
  152 +}
  153 +.filter-wrapper {
  154 + position: fixed;
  155 + left: 0;
  156 + width: 750rpx;
  157 + z-index: 999;
  158 + .inner-wrapper {
  159 + // position: relative;
  160 + .navs {
  161 + position: relative;
  162 + height: 110rpx;
  163 + padding: 0 40rpx;
  164 + display: flex;
  165 + align-items: center;
  166 + justify-content: space-between;
  167 + background-color: #fff;
  168 + border-bottom: 2rpx solid #f5f6f9;
  169 + color: #8b9aae;
  170 + z-index: 999;
  171 + box-sizing: border-box;
  172 + & > view {
  173 + flex: 1;
  174 + height: 100%;
  175 + flex-direction: row;
  176 + z-index: 999;
  177 + }
  178 + .date {
  179 + justify-content: flex-end;
  180 + }
  181 + .actNav {
  182 + color: #4d7df9;
  183 + font-weight: bold;
  184 + }
  185 + }
  186 + .mask {
  187 + z-index: 666;
  188 + position: fixed;
  189 + top: calc(var(--status-bar-height) + 44px);
  190 + left: 0;
  191 + right: 0;
  192 + bottom: 0;
  193 + background-color: rgba(0, 0, 0, 0);
  194 + transition: background-color 0.15s linear;
  195 + &.show {
  196 + background-color: rgba(0, 0, 0, 0.4);
  197 + }
  198 + &.hide {
  199 + display: none;
  200 + }
  201 + }
  202 + .popup {
  203 + position: relative;
  204 + max-height: 500rpx;
  205 + background-color: #fff;
  206 + border-bottom-left-radius: 20rpx;
  207 + border-bottom-right-radius: 20rpx;
  208 + overflow: scroll;
  209 + z-index: 999;
  210 + transition: all 1s linear;
  211 + opacity: 0;
  212 + display: none;
  213 + .item-opt {
  214 + height: 100rpx;
  215 + padding: 0 40rpx;
  216 + color: #8b9aae;
  217 + border-bottom: 2rpx solid #f5f6f9;
  218 + }
  219 + .actOpt {
  220 + color: #4d7df9;
  221 + font-weight: bold;
  222 + position: relative;
  223 + &::after {
  224 + content: '✓';
  225 + font-weight: bold;
  226 + font-size: 36rpx;
  227 + position: absolute;
  228 + right: 40rpx;
  229 + }
  230 + }
  231 + }
  232 + .popupShow {
  233 + display: block;
  234 + opacity: 1;
  235 + }
  236 + }
  237 +
  238 + .icon-triangle {
  239 + width: 16rpx;
  240 + height: 16rpx;
  241 + margin-left: 10rpx;
  242 + }
  243 +}
  244 +</style>
  1 +<!DOCTYPE html>
  2 +<html lang="en">
  3 + <head>
  4 + <meta charset="UTF-8" />
  5 + <script>
  6 + var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
  7 + CSS.supports('top: constant(a)'))
  8 + document.write(
  9 + '<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
  10 + (coverSupport ? ', viewport-fit=cover' : '') + '" />')
  11 + </script>
  12 + <title></title>
  13 + <!--preload-links-->
  14 + <!--app-context-->
  15 + </head>
  16 + <body>
  17 + <div id="app"><!--app-html--></div>
  18 + <script type="module" src="/main.js"></script>
  19 + </body>
  20 +</html>
  1 +import App from './App'
  2 +
  3 +// #ifndef VUE3
  4 +import Vue from 'vue'
  5 +Vue.config.productionTip = false
  6 +App.mpType = 'app'
  7 +
  8 +import uView from "uview-ui";
  9 +Vue.use(uView);
  10 +const app = new Vue({
  11 + ...App
  12 +})
  13 +app.$mount()
  14 +// #endif
  15 +
  16 +// #ifdef VUE3
  17 +import { createSSRApp } from 'vue'
  18 +export function createApp() {
  19 + const app = createSSRApp(App)
  20 + return {
  21 + app
  22 + }
  23 +}
  24 +// #endif
  1 +{
  2 + "name" : "beijingTheatreGoing",
  3 + "appid" : "",
  4 + "description" : "",
  5 + "versionName" : "1.0.0",
  6 + "versionCode" : "100",
  7 + "transformPx" : false,
  8 + /* 5+App特有相关 */
  9 + "app-plus" : {
  10 + "usingComponents" : true,
  11 + "nvueStyleCompiler" : "uni-app",
  12 + "compilerVersion" : 3,
  13 + "splashscreen" : {
  14 + "alwaysShowBeforeRender" : true,
  15 + "waiting" : true,
  16 + "autoclose" : true,
  17 + "delay" : 0
  18 + },
  19 + /* 快应用特有相关 */
  20 + "quickapp" : {},
  21 + /* 小程序特有相关 */
  22 + "mp-weixin" : {
  23 + "appid" : "wx8a42f2d5eaa6b32e",
  24 + "setting" : {
  25 + "urlCheck" : false
  26 + },
  27 + "usingComponents" : true
  28 + },
  29 + /* 模块配置 */
  30 + "modules" : {},
  31 + /* 应用发布信息 */
  32 + "distribute" : {
  33 + /* android打包配置 */
  34 + "android" : {
  35 + "permissions" : [
  36 + "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
  37 + "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
  38 + "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
  39 + "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
  40 + "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
  41 + "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
  42 + "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
  43 + "<uses-permission android:name=\"android.permission.CAMERA\"/>",
  44 + "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
  45 + "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
  46 + "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
  47 + "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
  48 + "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
  49 + "<uses-feature android:name=\"android.hardware.camera\"/>",
  50 + "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
  51 + ]
  52 + },
  53 + /* ios打包配置 */
  54 + "ios" : {},
  55 + /* SDK配置 */
  56 + "sdkConfigs" : {}
  57 + }
  58 + },
  59 + /* 快应用特有相关 */
  60 + "quickapp" : {},
  61 + /* 小程序特有相关 */
  62 + "mp-alipay" : {
  63 + "usingComponents" : true
  64 + },
  65 + "mp-baidu" : {
  66 + "usingComponents" : true
  67 + },
  68 + "mp-toutiao" : {
  69 + "usingComponents" : true
  70 + },
  71 + "uniStatistics" : {
  72 + "enable" : false
  73 + },
  74 + "vueVersion" : "2",
  75 + "mp-weixin" : {
  76 + "appid" : "wxcfaf35f5706cc64c"
  77 + }
  78 +}
  1 +{
  2 + "name": "beijingtheatregoing",
  3 + "version": "1.0.0",
  4 + "lockfileVersion": 2,
  5 + "requires": true,
  6 + "packages": {
  7 + "node_modules/uview-ui": {
  8 + "version": "2.0.31",
  9 + "resolved": "https://registry.npmmirror.com/uview-ui/-/uview-ui-2.0.31.tgz",
  10 + "integrity": "sha512-I/0fGuvtiKHH/mBb864SGYk+SJ7WaF32tsBgYgeBOsxlUp+Th+Ac2tgz2cTvsQJl6eZYWsKZ3ixiSXCAcxZ8Sw==",
  11 + "engines": {
  12 + "HBuilderX": "^3.1.0"
  13 + }
  14 + }
  15 + }
  16 +}
  1 +MIT License
  2 +
  3 +Copyright (c) 2020 www.uviewui.com
  4 +
  5 +Permission is hereby granted, free of charge, to any person obtaining a copy
  6 +of this software and associated documentation files (the "Software"), to deal
  7 +in the Software without restriction, including without limitation the rights
  8 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9 +copies of the Software, and to permit persons to whom the Software is
  10 +furnished to do so, subject to the following conditions:
  11 +
  12 +The above copyright notice and this permission notice shall be included in all
  13 +copies or substantial portions of the Software.
  14 +
  15 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  21 +SOFTWARE.
  1 +<p align="center">
  2 + <img alt="logo" src="https://uviewui.com/common/logo.png" width="120" height="120" style="margin-bottom: 10px;">
  3 +</p>
  4 +<h3 align="center" style="margin: 30px 0 30px;font-weight: bold;font-size:40px;">uView</h3>
  5 +<h3 align="center">多平台快速开发的UI框架</h3>
  6 +
  7 +## 说明
  8 +
  9 +uView UI,是[uni-app](https://uniapp.dcloud.io/)生态优秀的UI框架,全面的组件和便捷的工具会让您信手拈来,如鱼得水
  10 +
  11 +## 特性
  12 +
  13 +- 兼容安卓,iOS,微信小程序,H5,QQ小程序,百度小程序,支付宝小程序,头条小程序
  14 +- 60+精选组件,功能丰富,多端兼容,让您快速集成,开箱即用
  15 +- 众多贴心的JS利器,让您飞镖在手,召之即来,百步穿杨
  16 +- 众多的常用页面和布局,让您专注逻辑,事半功倍
  17 +- 详尽的文档支持,现代化的演示效果
  18 +- 按需引入,精简打包体积
  19 +
  20 +
  21 +## 安装
  22 +
  23 +```bash
  24 +# npm方式安装,插件市场导入无需执行此命令
  25 +npm i uview-ui
  26 +```
  27 +
  28 +## 快速上手
  29 +
  30 +1. `main.js`引入uView库
  31 +```js
  32 +// main.js
  33 +import uView from 'uview-ui';
  34 +Vue.use(uView);
  35 +```
  36 +
  37 +2. `App.vue`引入基础样式(注意style标签需声明scss属性支持)
  38 +```css
  39 +/* App.vue */
  40 +<style lang="scss">
  41 +@import "uview-ui/index.scss";
  42 +</style>
  43 +```
  44 +
  45 +3. `uni.scss`引入全局scss变量文件
  46 +```css
  47 +/* uni.scss */
  48 +@import "uview-ui/theme.scss";
  49 +```
  50 +
  51 +4. `pages.json`配置easycom规则(按需引入)
  52 +
  53 +```js
  54 +// pages.json
  55 +{
  56 + "easycom": {
  57 + // npm安装的方式不需要前面的"@/",下载安装的方式需要"@/"
  58 + // npm安装方式
  59 + "^u-(.*)": "uview-ui/components/u-$1/u-$1.vue"
  60 + // 下载安装方式
  61 + // "^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue"
  62 + },
  63 + // 此为本身已有的内容
  64 + "pages": [
  65 + // ......
  66 + ]
  67 +}
  68 +```
  69 +
  70 +请通过[快速上手](https://www.uviewui.com/components/quickstart.html)了解更详细的内容
  71 +
  72 +## 使用方法
  73 +配置easycom规则后,自动按需引入,无需`import`组件,直接引用即可。
  74 +
  75 +```html
  76 +<template>
  77 + <u-button text="按钮"></u-button>
  78 +</template>
  79 +```
  80 +
  81 +请通过[快速上手](https://www.uviewui.com/components/quickstart.html)了解更详细的内容
  82 +
  83 +## 链接
  84 +
  85 +- [官方文档](https://www.uviewui.com/)
  86 +- [更新日志](https://www.www.uviewui.com/components/changelog.html)
  87 +- [升级指南](https://www.uviewui.com/components/changelog.html)
  88 +- [关于我们](https://www.uviewui.com/cooperation/about.html)
  89 +
  90 +## 预览
  91 +
  92 +您可以通过**微信**扫码,查看最佳的演示效果。
  93 +<br>
  94 +<br>
  95 +<img src="https://uviewui.com/common/weixin_mini_qrcode.png" width="220" height="220" >
  96 +
  97 +## 捐赠uView的研发
  98 +
  99 +uView文档和源码全部开源免费,如果您认为uView帮到了您的开发工作,您可以捐赠uView的研发工作,捐赠无门槛,哪怕是一杯可乐也好(相信这比打赏主播更有意义)。
  100 +
  101 +<img src="https://uviewui.com/common/alipay.png" width="220" ><img style="margin-left: 100px;" src="https://uviewui.com/common/wechat.png" width="220" >
  102 +
  103 +## 版权信息
  104 +uView遵循[MIT](https://en.wikipedia.org/wiki/MIT_License)开源协议,意味着您无需支付任何费用,也无需授权,即可将uView应用到您的产品中。
  1 +## 2.0.31(2022-04-19)
  2 +# uView2.0重磅发布,利剑出鞘,一统江湖
  3 +
  4 +1. 修复`upload`在`vue`页面上传成功后没有成功标志的问题
  5 +2. 解决演示项目中微信小程序模拟上传图片一直出于上传中问题
  6 +3. 修复`u-code-input`组件在`nvue`页面编译到`app`平台上光标异常问题(`app`去除此功能)
  7 +4. 修复`actionSheet`组件标题关闭按钮点击事件名称错误的问题
  8 +5. 其他修复
  9 +## 2.0.30(2022-04-04)
  10 +# uView2.0重磅发布,利剑出鞘,一统江湖
  11 +
  12 +1. `u-rate`增加`readonly`属性
  13 +2. `tabs`滑块支持设置背景图片
  14 +3. 修复`u-subsection` `mode`为`subsection`时,滑块样式不正确的问题
  15 +4. `u-code-input`添加光标效果动画
  16 +5. 修复`popup`的`open`事件不触发
  17 +6. 修复`u-flex-column`无效的问题
  18 +7. 修复`u-datetime-picker`索引在特定场合异常问题
  19 +8. 修复`u-datetime-picker`最小时间字符串模板错误问题
  20 +9. `u-swiper`添加`m3u8`验证
  21 +10. `u-swiper`修改判断image和video逻辑
  22 +11. 修复`swiper`无法使用本地图片问题,增加`type`参数
  23 +12. 修复`u-row-notice`格式错误问题
  24 +13. 修复`u-switch`组件当`unit`为`rpx`时,`nodeStyle`消失的问题
  25 +14. 修复`datetime-picker`组件`showToolbar`与`visibleItemCount`属性无效的问题
  26 +15. 修复`upload`组件条件编译位置判断错误,导致`previewImage`属性设置为`false`时,整个组件都会被隐藏的问题
  27 +16. 修复`u-checkbox-group`设置`shape`属性无效的问题
  28 +17. 修复`u-upload`的`capture`传入字符串的时候不生效的问题
  29 +18. 修复`u-action-sheet`组件,关闭事件逻辑错误的问题
  30 +19. 修复`u-list`触顶事件的触发错误的问题
  31 +20. 修复`u-text`只有手机号可拨打的问题
  32 +21. 修复`u-textarea`不能换行的问题
  33 +22. 其他修复
  34 +## 2.0.29(2022-03-13)
  35 +# uView2.0重磅发布,利剑出鞘,一统江湖
  36 +
  37 +1. 修复`u--text`组件设置`decoration`属性未生效的问题
  38 +2. 修复`u-datetime-picker`使用`formatter`后返回值不正确
  39 +3. 修复`u-datetime-picker` `intercept` 可能为undefined
  40 +4. 修复已设置单位 uni..config.unit = 'rpx'时,线型指示器 `transform` 的位置翻倍,导致指示器超出宽度
  41 +5. 修复mixin中bem方法生成的类名在支付宝和字节小程序中失效
  42 +6. 修复默认值传值为空的时候,打开`u-datetime-picker`报错,不能选中第一列时间的bug
  43 +7. 修复`u-datetime-picker`使用`formatter`后返回值不正确
  44 +8. 修复`u-image`组件`loading`无效果的问题
  45 +9. 修复`config.unit`属性设为`rpx`时,导航栏占用高度不足导致塌陷的问题
  46 +10. 修复`u-datetime-picker`组件`itemHeight`无效问题
  47 +11. 其他修复
  48 +## 2.0.28(2022-02-22)
  49 +# uView2.0重磅发布,利剑出鞘,一统江湖
  50 +
  51 +1. search组件新增searchIconSize属性
  52 +2. 兼容Safari/Webkit中传入时间格式如2022-02-17 12:00:56
  53 +3. 修复text value.js 判断日期出format错误问题
  54 +4. priceFormat格式化金额出现精度错误
  55 +5. priceFormat在部分情况下出现精度损失问题
  56 +6. 优化表单rules提示
  57 +7. 修复avatar组件src为空时,展示状态不对
  58 +8. 其他修复
  59 +## 2.0.27(2022-01-28)
  60 +# uView2.0重磅发布,利剑出鞘,一统江湖
  61 +
  62 +1.样式修复
  63 +## 2.0.26(2022-01-28)
  64 +# uView2.0重磅发布,利剑出鞘,一统江湖
  65 +
  66 +1.样式修复
  67 +## 2.0.25(2022-01-27)
  68 +# uView2.0重磅发布,利剑出鞘,一统江湖
  69 +
  70 +1. 修复text组件mode=price时,可能会导致精度错误的问题
  71 +2. 添加$u.setConfig()方法,可设置uView内置的config, props, zIndex, color属性,详见:[修改uView内置配置方案](https://uviewui.com/components/setting.html#%E9%BB%98%E8%AE%A4%E5%8D%95%E4%BD%8D%E9%85%8D%E7%BD%AE)
  72 +3. 优化form组件在errorType=toast时,如果输入错误页面会有抖动的问题
  73 +4. 修复$u.addUnit()对配置默认单位可能无效的问题
  74 +## 2.0.24(2022-01-25)
  75 +# uView2.0重磅发布,利剑出鞘,一统江湖
  76 +
  77 +1. 修复swiper在current指定非0时缩放有误
  78 +2. 修复u-icon添加stop属性的时候报错
  79 +3. 优化遗留的通过正则判断rpx单位的问题
  80 +4. 优化Layout布局 vue使用gutter时,会超出固定区域
  81 +5. 优化search组件高度单位问题(rpx -> px)
  82 +6. 修复u-image slot 加载和错误的图片失去了高度
  83 +7. 修复u-index-list中footer插槽与header插槽存在性判断错误
  84 +8. 修复部分机型下u-popup关闭时会闪烁
  85 +9. 修复u-image在nvue-app下失去宽高
  86 +10. 修复u-popup运行报错
  87 +11. 修复u-tooltip报错
  88 +12. 修复box-sizing在app下的警告
  89 +13. 修复u-navbar在小程序中报运行时错误
  90 +14. 其他修复
  91 +## 2.0.23(2022-01-24)
  92 +# uView2.0重磅发布,利剑出鞘,一统江湖
  93 +
  94 +1. 修复image组件在hx3.3.9的nvue下可能会显示异常的问题
  95 +2. 修复col组件gutter参数带rpx单位处理不正确的问题
  96 +3. 修复text组件单行时无法显示省略号的问题
  97 +4. navbar添加titleStyle参数
  98 +5. 升级到hx3.3.9可消除nvue下控制台样式警告的问题
  99 +## 2.0.22(2022-01-19)
  100 +# uView2.0重磅发布,利剑出鞘,一统江湖
  101 +
  102 +1. $u.page()方法优化,避免在特殊场景可能报错的问题
  103 +2. picker组件添加immediateChange参数
  104 +3. 新增$u.pages()方法
  105 +## 2.0.21(2022-01-19)
  106 +# uView2.0重磅发布,利剑出鞘,一统江湖
  107 +
  108 +1. 优化:form组件在用户设置rules的时候提示用户model必传
  109 +2. 优化遗留的通过正则判断rpx单位的问题
  110 +3. 修复微信小程序环境中tabbar组件开启safeAreaInsetBottom属性后,placeholder高度填充不正确
  111 +4. 修复swiper在current指定非0时缩放有误
  112 +5. 修复u-icon添加stop属性的时候报错
  113 +6. 修复upload组件在accept=all的时候没有作用
  114 +7. 修复在text组件mode为phone时call属性无效的问题
  115 +8. 处理u-form clearValidate方法
  116 +9. 其他修复
  117 +## 2.0.20(2022-01-14)
  118 +# uView2.0重磅发布,利剑出鞘,一统江湖
  119 +
  120 +1. 修复calendar默认会选择一个日期,如果直接点确定的话,无法取到值的问题
  121 +2. 修复Slider缺少disabled props 还有注释
  122 +3. 修复u-notice-bar点击事件无法拿到index索引值的问题
  123 +4. 修复u-collapse-item在vue文件下,app端自定义插槽不生效的问题
  124 +5. 优化头像为空时显示默认头像
  125 +6. 修复图片地址赋值后判断加载状态为完成问题
  126 +7. 修复日历滚动到默认日期月份区域
  127 +8. search组件暴露点击左边icon事件
  128 +9. 修复u-form clearValidate方法不生效
  129 +10. upload h5端增加返回文件参数(文件的name参数)
  130 +11. 处理upload选择文件后url为blob类型无法预览的问题
  131 +12. u-code-input 修复输入框没有往左移出一半屏幕
  132 +13. 修复Upload上传 disabled为true时,控制台报hoverClass类型错误
  133 +14. 临时处理ios app下grid点击坍塌问题
  134 +15. 其他修复
  135 +## 2.0.19(2021-12-29)
  136 +# uView2.0重磅发布,利剑出鞘,一统江湖
  137 +
  138 +1. 优化微信小程序包体积可在微信中预览,请升级HbuilderX3.3.4,同时在“运行->运行到小程序模拟器”中勾选“运行时是否压缩代码”
  139 +2. 优化微信小程序setData性能,处理某些方法如$u.route()无法在模板中使用的问题
  140 +3. navbar添加autoBack参数
  141 +4. 允许avatar组件的事件冒泡
  142 +5. 修复cell组件报错问题
  143 +6. 其他修复
  144 +## 2.0.18(2021-12-28)
  145 +# uView2.0重磅发布,利剑出鞘,一统江湖
  146 +
  147 +1. 修复app端编译报错问题
  148 +2. 重新处理微信小程序端setData过大的性能问题
  149 +3. 修复边框问题
  150 +4. 修复最大最小月份不大于0则没有数据出现的问题
  151 +5. 修复SwipeAction微信小程序端无法上下滑动问题
  152 +6. 修复input的placeholder在小程序端默认显示为true问题
  153 +7. 修复divider组件click事件无效问题
  154 +8. 修复u-code-input maxlength 属性值为 String 类型时显示异常
  155 +9. 修复当 grid只有 1到2时 在小程序端algin设置无效的问题
  156 +10. 处理form-item的label为top时,取消错误提示的左边距
  157 +11. 其他修复
  158 +## 2.0.17(2021-12-26)
  159 +## uView正在参与开源中国的“年度最佳项目”评选,之前投过票的现在也可以投票,恳请同学们投一票,[点此帮助uView](https://www.oschina.net/project/top_cn_2021/?id=583)
  160 +
  161 +# uView2.0重磅发布,利剑出鞘,一统江湖
  162 +
  163 +1. 解决HBuilderX3.3.3.20211225版本导致的样式问题
  164 +2. calendar日历添加monthNum参数
  165 +3. navbar添加center slot
  166 +## 2.0.16(2021-12-25)
  167 +## uView正在参与开源中国的“年度最佳项目”评选,之前投过票的现在也可以投票,恳请同学们投一票,[点此帮助uView](https://www.oschina.net/project/top_cn_2021/?id=583)
  168 +
  169 +# uView2.0重磅发布,利剑出鞘,一统江湖
  170 +
  171 +1. 解决微信小程序setData性能问题
  172 +2. 修复count-down组件change事件不触发问题
  173 +## 2.0.15(2021-12-21)
  174 +## uView正在参与开源中国的“年度最佳项目”评选,之前投过票的现在也可以投票,恳请同学们投一票,[点此帮助uView](https://www.oschina.net/project/top_cn_2021/?id=583)
  175 +
  176 +# uView2.0重磅发布,利剑出鞘,一统江湖
  177 +
  178 +1. 修复Cell单元格titleWidth无效
  179 +2. 修复cheakbox组件ischecked不更新
  180 +3. 修复keyboard是否显示"."按键默认值问题
  181 +4. 修复number-keyboard是否显示键盘的"."符号问题
  182 +5. 修复Input输入框 readonly无效
  183 +6. 修复u-avatar 导致打包app、H5时候报错问题
  184 +7. 修复Upload上传deletable无效
  185 +8. 修复upload当设置maxSize时无效的问题
  186 +9. 修复tabs lineWidth传入带单位的字符串的时候偏移量计算错误问题
  187 +10. 修复rate组件在有padding的view内,显示的星星位置和可触摸区域不匹配,无法正常选中星星
  188 +## 2.0.13(2021-12-14)
  189 +## [点击加群交流反馈:364463526](https://jq.qq.com/?_chanwv=1027&k=mCxS3TGY)
  190 +
  191 +# uView2.0重磅发布,利剑出鞘,一统江湖
  192 +
  193 +1. 修复配置默认单位为rpx可能会导致自定义导航栏高度异常的问题
  194 +## 2.0.12(2021-12-14)
  195 +## [点击加群交流反馈:364463526](https://jq.qq.com/?_chanwv=1027&k=mCxS3TGY)
  196 +
  197 +# uView2.0重磅发布,利剑出鞘,一统江湖
  198 +
  199 +1. 修复tabs组件在vue环境下划线消失的问题
  200 +2. 修复upload组件在安卓小程序无法选择视频的问题
  201 +3. 添加uni.$u.config.unit配置,用于配置参数默认单位,详见:[默认单位配置](https://www.uviewui.com/components/setting.html#%E9%BB%98%E8%AE%A4%E5%8D%95%E4%BD%8D%E9%85%8D%E7%BD%AE)
  202 +4. 修复textarea组件在没绑定v-model时,字符统计不生效问题
  203 +5. 修复nvue下控制是否出现滚动条失效问题
  204 +## 2.0.11(2021-12-13)
  205 +## [点击加群交流反馈:364463526](https://jq.qq.com/?_chanwv=1027&k=mCxS3TGY)
  206 +
  207 +# uView2.0重磅发布,利剑出鞘,一统江湖
  208 +
  209 +1. text组件align参数无效的问题
  210 +2. subsection组件添加keyName参数
  211 +3. upload组件无法判断[Object file]类型的问题
  212 +4. 处理notify层级过低问题
  213 +5. codeInput组件添加disabledDot参数
  214 +6. 处理actionSheet组件round参数无效的问题
  215 +7. calendar组件添加round参数用于控制圆角值
  216 +8. 处理swipeAction组件在vue环境下默认被打开的问题
  217 +9. button组件的throttleTime节流参数无效的问题
  218 +10. 解决u-notify手动关闭方法close()无效的问题
  219 +11. input组件readonly不生效问题
  220 +12. tag组件type参数为info不生效问题
  221 +## 2.0.10(2021-12-08)
  222 +## [点击加群交流反馈:364463526](https://jq.qq.com/?_chanwv=1027&k=mCxS3TGY)
  223 +
  224 +# uView2.0重磅发布,利剑出鞘,一统江湖
  225 +
  226 +1. 修复button sendMessagePath属性不生效
  227 +2. 修复DatetimePicker选择器title无效
  228 +3. 修复u-toast设置loading=true不生效
  229 +4. 修复u-text金额模式传0报错
  230 +5. 修复u-toast组件的icon属性配置不生效
  231 +6. button的icon在特殊场景下的颜色优化
  232 +7. IndexList优化,增加#
  233 +## 2.0.9(2021-12-01)
  234 +## [点击加群交流反馈:232041042](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
  235 +
  236 +# uView2.0重磅发布,利剑出鞘,一统江湖
  237 +
  238 +1. 优化swiper的height支持100%值(仅vue有效),修复嵌入视频时click事件无法触发的问题
  239 +2. 优化tabs组件对list值为空的判断,或者动态变化list时重新计算相关尺寸的问题
  240 +3. 优化datetime-picker组件逻辑,让其后续打开的默认值为上一次的选中值,需要通过v-model绑定值才有效
  241 +4. 修复upload内嵌在其他组件中,选择图片可能不会换行的问题
  242 +## 2.0.8(2021-12-01)
  243 +## [点击加群交流反馈:232041042](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
  244 +
  245 +# uView2.0重磅发布,利剑出鞘,一统江湖
  246 +
  247 +1. 修复toast的position参数无效问题
  248 +2. 处理input在ios nvue上无法获得焦点的问题
  249 +3. avatar-group组件添加extraValue参数,让剩余展示数量可手动控制
  250 +4. tabs组件添加keyName参数用于配置从对象中读取的键名
  251 +5. 处理text组件名字脱敏默认配置无效的问题
  252 +6. 处理picker组件item文本太长换行问题
  253 +## 2.0.7(2021-11-30)
  254 +## [点击加群交流反馈:232041042](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
  255 +
  256 +# uView2.0重磅发布,利剑出鞘,一统江湖
  257 +
  258 +1. 修复radio和checkbox动态改变v-model无效的问题。
  259 +2. 优化form规则validator在微信小程序用法
  260 +3. 修复backtop组件mode参数在微信小程序无效的问题
  261 +4. 处理Album的previewFullImage属性无效的问题
  262 +5. 处理u-datetime-picker组件mode='time'在选择改变时间时,控制台报错的问题
  263 +## 2.0.6(2021-11-27)
  264 +## [点击加群交流反馈:232041042](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
  265 +
  266 +# uView2.0重磅发布,利剑出鞘,一统江湖
  267 +
  268 +1. 处理tag组件在vue下边框无效的问题。
  269 +2. 处理popup组件圆角参数可能无效的问题。
  270 +3. 处理tabs组件lineColor参数可能无效的问题。
  271 +4. propgress组件在值很小时,显示异常的问题。
  272 +## 2.0.5(2021-11-25)
  273 +## [点击加群交流反馈:232041042](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
  274 +
  275 +# uView2.0重磅发布,利剑出鞘,一统江湖
  276 +
  277 +1. calendar在vue下显示异常问题。
  278 +2. form组件labelPosition和errorType参数无效的问题
  279 +3. input组件inputAlign无效的问题
  280 +4. 其他一些修复
  281 +## 2.0.4(2021-11-23)
  282 +## [点击加群交流反馈:232041042](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
  283 +
  284 +# uView2.0重磅发布,利剑出鞘,一统江湖
  285 +
  286 +0. input组件缺失@confirm事件,以及subfix和prefix无效问题
  287 +1. component.scss文件样式在vue下干扰全局布局问题
  288 +2. 修复subsection在vue环境下表现异常的问题
  289 +3. tag组件的bgColor等参数无效的问题
  290 +4. upload组件不换行的问题
  291 +5. 其他的一些修复处理
  292 +## 2.0.3(2021-11-16)
  293 +## [点击加群交流反馈:1129077272](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
  294 +
  295 +# uView2.0重磅发布,利剑出鞘,一统江湖
  296 +
  297 +1. uView2.0已实现全面兼容nvue
  298 +2. uView2.0对1.x进行了架构重构,细节和性能都有极大提升
  299 +3. 目前uView2.0为公测阶段,相关细节可能会有变动
  300 +4. 我们写了一份与1.x的对比指南,详见[对比1.x](https://www.uviewui.com/components/diff1.x.html)
  301 +5. 处理modal的confirm回调事件拼写错误问题
  302 +6. 处理input组件@input事件参数错误问题
  303 +7. 其他一些修复
  304 +## 2.0.2(2021-11-16)
  305 +## [点击加群交流反馈:1129077272](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
  306 +
  307 +# uView2.0重磅发布,利剑出鞘,一统江湖
  308 +
  309 +1. uView2.0已实现全面兼容nvue
  310 +2. uView2.0对1.x进行了架构重构,细节和性能都有极大提升
  311 +3. 目前uView2.0为公测阶段,相关细节可能会有变动
  312 +4. 我们写了一份与1.x的对比指南,详见[对比1.x](https://www.uviewui.com/components/diff1.x.html)
  313 +5. 修复input组件formatter参数缺失问题
  314 +6. 优化loading-icon组件的scss写法问题,防止不兼容新版本scss
  315 +## 2.0.0(2020-11-15)
  316 +## [点击加群交流反馈:1129077272](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
  317 +
  318 +# uView2.0重磅发布,利剑出鞘,一统江湖
  319 +
  320 +1. uView2.0已实现全面兼容nvue
  321 +2. uView2.0对1.x进行了架构重构,细节和性能都有极大提升
  322 +3. 目前uView2.0为公测阶段,相关细节可能会有变动
  323 +4. 我们写了一份与1.x的对比指南,详见[对比1.x](https://www.uviewui.com/components/diff1.x.html)
  324 +5. 修复input组件formatter参数缺失问题
  325 +
  326 +
  1 +<template>
  2 + <uvForm
  3 + ref="uForm"
  4 + :model="model"
  5 + :rules="rules"
  6 + :errorType="errorType"
  7 + :borderBottom="borderBottom"
  8 + :labelPosition="labelPosition"
  9 + :labelWidth="labelWidth"
  10 + :labelAlign="labelAlign"
  11 + :labelStyle="labelStyle"
  12 + :customStyle="customStyle"
  13 + >
  14 + <slot />
  15 + </uvForm>
  16 +</template>
  17 +
  18 +<script>
  19 + /**
  20 + * 此组件存在的理由是,在nvue下,u-form被uni-app官方占用了,u-form在nvue中相当于form组件
  21 + * 所以在nvue下,取名为u--form,内部其实还是u-form.vue,只不过做一层中转
  22 + */
  23 + import uvForm from '../u-form/u-form.vue';
  24 + import props from '../u-form/props.js'
  25 + export default {
  26 + // #ifdef MP-WEIXIN
  27 + name: 'u-form',
  28 + // #endif
  29 + // #ifndef MP-WEIXIN
  30 + name: 'u--form',
  31 + // #endif
  32 + mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
  33 + components: {
  34 + uvForm
  35 + },
  36 + created() {
  37 + this.children = []
  38 + },
  39 + methods: {
  40 + // 手动设置校验的规则,如果规则中有函数的话,微信小程序中会过滤掉,所以只能手动调用设置规则
  41 + setRules(rules) {
  42 + this.$refs.uForm.setRules(rules)
  43 + },
  44 + validate() {
  45 + /**
  46 + * 在微信小程序中,通过this.$parent拿到的父组件是u--form,而不是其内嵌的u-form
  47 + * 导致在u-form组件中,拿不到对应的children数组,从而校验无效,所以这里每次调用u-form组件中的
  48 + * 对应方法的时候,在小程序中都先将u--form的children赋值给u-form中的children
  49 + */
  50 + // #ifdef MP-WEIXIN
  51 + this.setMpData()
  52 + // #endif
  53 + return this.$refs.uForm.validate()
  54 + },
  55 + validateField(value, callback) {
  56 + // #ifdef MP-WEIXIN
  57 + this.setMpData()
  58 + // #endif
  59 + return this.$refs.uForm.validateField(value, callback)
  60 + },
  61 + resetFields() {
  62 + // #ifdef MP-WEIXIN
  63 + this.setMpData()
  64 + // #endif
  65 + return this.$refs.uForm.resetFields()
  66 + },
  67 + clearValidate(props) {
  68 + // #ifdef MP-WEIXIN
  69 + this.setMpData()
  70 + // #endif
  71 + return this.$refs.uForm.clearValidate(props)
  72 + },
  73 + setMpData() {
  74 + this.$refs.uForm.children = this.children
  75 + }
  76 + },
  77 + }
  78 +</script>
  1 +<template>
  2 + <uvImage
  3 + :src="src"
  4 + :mode="mode"
  5 + :width="width"
  6 + :height="height"
  7 + :shape="shape"
  8 + :radius="radius"
  9 + :lazyLoad="lazyLoad"
  10 + :showMenuByLongpress="showMenuByLongpress"
  11 + :loadingIcon="loadingIcon"
  12 + :errorIcon="errorIcon"
  13 + :showLoading="showLoading"
  14 + :showError="showError"
  15 + :fade="fade"
  16 + :webp="webp"
  17 + :duration="duration"
  18 + :bgColor="bgColor"
  19 + :customStyle="customStyle"
  20 + @click="$emit('click')"
  21 + @error="$emit('error')"
  22 + @load="$emit('load')"
  23 + >
  24 + <template v-slot:loading>
  25 + <slot name="loading"></slot>
  26 + </template>
  27 + <template v-slot:error>
  28 + <slot name="error"></slot>
  29 + </template>
  30 + </uvImage>
  31 +</template>
  32 +
  33 +<script>
  34 + /**
  35 + * 此组件存在的理由是,在nvue下,u-image被uni-app官方占用了,u-image在nvue中相当于image组件
  36 + * 所以在nvue下,取名为u--image,内部其实还是u-iamge.vue,只不过做一层中转
  37 + */
  38 + import uvImage from '../u-image/u-image.vue';
  39 + import props from '../u-image/props.js';
  40 + export default {
  41 + name: 'u--image',
  42 + mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
  43 + components: {
  44 + uvImage
  45 + },
  46 + }
  47 +</script>
  1 +<template>
  2 + <uvInput
  3 + :value="value"
  4 + :type="type"
  5 + :fixed="fixed"
  6 + :disabled="disabled"
  7 + :disabledColor="disabledColor"
  8 + :clearable="clearable"
  9 + :password="password"
  10 + :maxlength="maxlength"
  11 + :placeholder="placeholder"
  12 + :placeholderClass="placeholderClass"
  13 + :placeholderStyle="placeholderStyle"
  14 + :showWordLimit="showWordLimit"
  15 + :confirmType="confirmType"
  16 + :confirmHold="confirmHold"
  17 + :holdKeyboard="holdKeyboard"
  18 + :focus="focus"
  19 + :autoBlur="autoBlur"
  20 + :disableDefaultPadding="disableDefaultPadding"
  21 + :cursor="cursor"
  22 + :cursorSpacing="cursorSpacing"
  23 + :selectionStart="selectionStart"
  24 + :selectionEnd="selectionEnd"
  25 + :adjustPosition="adjustPosition"
  26 + :inputAlign="inputAlign"
  27 + :fontSize="fontSize"
  28 + :color="color"
  29 + :prefixIcon="prefixIcon"
  30 + :suffixIcon="suffixIcon"
  31 + :suffixIconStyle="suffixIconStyle"
  32 + :prefixIconStyle="prefixIconStyle"
  33 + :border="border"
  34 + :readonly="readonly"
  35 + :shape="shape"
  36 + :customStyle="customStyle"
  37 + :formatter="formatter"
  38 + @focus="$emit('focus')"
  39 + @blur="$emit('blur')"
  40 + @keyboardheightchange="$emit('keyboardheightchange')"
  41 + @change="e => $emit('change', e)"
  42 + @input="e => $emit('input', e)"
  43 + @confirm="e => $emit('confirm', e)"
  44 + @clear="$emit('clear')"
  45 + @click="$emit('click')"
  46 + >
  47 + <!-- #ifdef MP -->
  48 + <slot name="prefix"></slot>
  49 + <slot name="suffix"></slot>
  50 + <!-- #endif -->
  51 + <!-- #ifndef MP -->
  52 + <slot name="prefix" slot="prefix"></slot>
  53 + <slot name="suffix" slot="suffix"></slot>
  54 + <!-- #endif -->
  55 + </uvInput>
  56 +</template>
  57 +
  58 +<script>
  59 + /**
  60 + * 此组件存在的理由是,在nvue下,u-input被uni-app官方占用了,u-input在nvue中相当于input组件
  61 + * 所以在nvue下,取名为u--input,内部其实还是u-input.vue,只不过做一层中转
  62 + */
  63 + import uvInput from '../u-input/u-input.vue';
  64 + import props from '../u-input/props.js'
  65 + export default {
  66 + name: 'u--input',
  67 + mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
  68 + components: {
  69 + uvInput
  70 + },
  71 + }
  72 +</script>
  1 +<template>
  2 + <uvText
  3 + :type="type"
  4 + :show="show"
  5 + :text="text"
  6 + :prefixIcon="prefixIcon"
  7 + :suffixIcon="suffixIcon"
  8 + :mode="mode"
  9 + :href="href"
  10 + :format="format"
  11 + :call="call"
  12 + :openType="openType"
  13 + :bold="bold"
  14 + :block="block"
  15 + :lines="lines"
  16 + :color="color"
  17 + :decoration="decoration"
  18 + :size="size"
  19 + :iconStyle="iconStyle"
  20 + :margin="margin"
  21 + :lineHeight="lineHeight"
  22 + :align="align"
  23 + :wordWrap="wordWrap"
  24 + :customStyle="customStyle"
  25 + @click="$emit('click')"
  26 + ></uvText>
  27 +</template>
  28 +
  29 +<script>
  30 +/**
  31 + * 此组件存在的理由是,在nvue下,u-text被uni-app官方占用了,u-text在nvue中相当于input组件
  32 + * 所以在nvue下,取名为u--input,内部其实还是u-text.vue,只不过做一层中转
  33 + * 不使用v-bind="$attrs",而是分开独立写传参,是因为微信小程序不支持此写法
  34 + */
  35 +import uvText from "../u-text/u-text.vue";
  36 +import props from "../u-text/props.js";
  37 +export default {
  38 + name: "u--text",
  39 + mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
  40 + components: {
  41 + uvText,
  42 + },
  43 +};
  44 +</script>
  1 +<template>
  2 + <uvTextarea
  3 + :value="value"
  4 + :placeholder="placeholder"
  5 + :height="height"
  6 + :confirmType="confirmType"
  7 + :disabled="disabled"
  8 + :count="count"
  9 + :focus="focus"
  10 + :autoHeight="autoHeight"
  11 + :fixed="fixed"
  12 + :cursorSpacing="cursorSpacing"
  13 + :cursor="cursor"
  14 + :showConfirmBar="showConfirmBar"
  15 + :selectionStart="selectionStart"
  16 + :selectionEnd="selectionEnd"
  17 + :adjustPosition="adjustPosition"
  18 + :disableDefaultPadding="disableDefaultPadding"
  19 + :holdKeyboard="holdKeyboard"
  20 + :maxlength="maxlength"
  21 + :border="border"
  22 + :customStyle="customStyle"
  23 + :formatter="formatter"
  24 + @focus="e => $emit('focus')"
  25 + @blur="e => $emit('blur')"
  26 + @linechange="e => $emit('linechange', e)"
  27 + @confirm="e => $emit('confirm')"
  28 + @input="e => $emit('input', e)"
  29 + @keyboardheightchange="e => $emit('keyboardheightchange')"
  30 + ></uvTextarea>
  31 +</template>
  32 +
  33 +<script>
  34 + /**
  35 + * 此组件存在的理由是,在nvue下,u--textarea被uni-app官方占用了,u-textarea在nvue中相当于textarea组件
  36 + * 所以在nvue下,取名为u--textarea,内部其实还是u-textarea.vue,只不过做一层中转
  37 + */
  38 + import uvTextarea from '../u-textarea/u-textarea.vue';
  39 + import props from '../u-textarea/props.js'
  40 + export default {
  41 + name: 'u--textarea',
  42 + mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
  43 + components: {
  44 + uvTextarea
  45 + },
  46 + }
  47 +</script>
  1 +export default {
  2 + props: {
  3 + // 操作菜单是否展示 (默认false)
  4 + show: {
  5 + type: Boolean,
  6 + default: uni.$u.props.actionSheet.show
  7 + },
  8 + // 标题
  9 + title: {
  10 + type: String,
  11 + default: uni.$u.props.actionSheet.title
  12 + },
  13 + // 选项上方的描述信息
  14 + description: {
  15 + type: String,
  16 + default: uni.$u.props.actionSheet.description
  17 + },
  18 + // 数据
  19 + actions: {
  20 + type: Array,
  21 + default: uni.$u.props.actionSheet.actions
  22 + },
  23 + // 取消按钮的文字,不为空时显示按钮
  24 + cancelText: {
  25 + type: String,
  26 + default: uni.$u.props.actionSheet.cancelText
  27 + },
  28 + // 点击某个菜单项时是否关闭弹窗
  29 + closeOnClickAction: {
  30 + type: Boolean,
  31 + default: uni.$u.props.actionSheet.closeOnClickAction
  32 + },
  33 + // 处理底部安全区(默认true)
  34 + safeAreaInsetBottom: {
  35 + type: Boolean,
  36 + default: uni.$u.props.actionSheet.safeAreaInsetBottom
  37 + },
  38 + // 小程序的打开方式
  39 + openType: {
  40 + type: String,
  41 + default: uni.$u.props.actionSheet.openType
  42 + },
  43 + // 点击遮罩是否允许关闭 (默认true)
  44 + closeOnClickOverlay: {
  45 + type: Boolean,
  46 + default: uni.$u.props.actionSheet.closeOnClickOverlay
  47 + },
  48 + // 圆角值
  49 + round: {
  50 + type: [Boolean, String, Number],
  51 + default: uni.$u.props.actionSheet.round
  52 + }
  53 + }
  54 +}
  1 +
  2 +<template>
  3 + <u-popup
  4 + :show="show"
  5 + mode="bottom"
  6 + @close="closeHandler"
  7 + :safeAreaInsetBottom="safeAreaInsetBottom"
  8 + :round="round"
  9 + >
  10 + <view class="u-action-sheet">
  11 + <view
  12 + class="u-action-sheet__header"
  13 + v-if="title"
  14 + >
  15 + <text class="u-action-sheet__header__title u-line-1">{{title}}</text>
  16 + <view
  17 + class="u-action-sheet__header__icon-wrap"
  18 + @tap.stop="cancel"
  19 + >
  20 + <u-icon
  21 + name="close"
  22 + size="17"
  23 + color="#c8c9cc"
  24 + bold
  25 + ></u-icon>
  26 + </view>
  27 + </view>
  28 + <text
  29 + class="u-action-sheet__description"
  30 + :style="[{
  31 + marginTop: `${title && description ? 0 : '18px'}`
  32 + }]"
  33 + v-if="description"
  34 + >{{description}}</text>
  35 + <slot>
  36 + <u-line v-if="description"></u-line>
  37 + <view class="u-action-sheet__item-wrap">
  38 + <template v-for="(item, index) in actions">
  39 + <!-- #ifdef MP -->
  40 + <button
  41 + :key="index"
  42 + class="u-reset-button"
  43 + :openType="item.openType"
  44 + @getuserinfo="onGetUserInfo"
  45 + @contact="onContact"
  46 + @getphonenumber="onGetPhoneNumber"
  47 + @error="onError"
  48 + @launchapp="onLaunchApp"
  49 + @opensetting="onOpenSetting"
  50 + :lang="lang"
  51 + :session-from="sessionFrom"
  52 + :send-message-title="sendMessageTitle"
  53 + :send-message-path="sendMessagePath"
  54 + :send-message-img="sendMessageImg"
  55 + :show-message-card="showMessageCard"
  56 + :app-parameter="appParameter"
  57 + @tap="selectHandler(index)"
  58 + :hover-class="!item.disabled && !item.loading ? 'u-action-sheet--hover' : ''"
  59 + >
  60 + <!-- #endif -->
  61 + <view
  62 + class="u-action-sheet__item-wrap__item"
  63 + @tap.stop="selectHandler(index)"
  64 + :hover-class="!item.disabled && !item.loading ? 'u-action-sheet--hover' : ''"
  65 + :hover-stay-time="150"
  66 + >
  67 + <template v-if="!item.loading">
  68 + <text
  69 + class="u-action-sheet__item-wrap__item__name"
  70 + :style="[itemStyle(index)]"
  71 + >{{ item.name }}</text>
  72 + <text
  73 + v-if="item.subname"
  74 + class="u-action-sheet__item-wrap__item__subname"
  75 + >{{ item.subname }}</text>
  76 + </template>
  77 + <u-loading-icon
  78 + v-else
  79 + custom-class="van-action-sheet__loading"
  80 + size="18"
  81 + mode="circle"
  82 + />
  83 + </view>
  84 + <!-- #ifdef MP -->
  85 + </button>
  86 + <!-- #endif -->
  87 + <u-line v-if="index !== actions.length - 1"></u-line>
  88 + </template>
  89 + </view>
  90 + </slot>
  91 + <u-gap
  92 + bgColor="#eaeaec"
  93 + height="6"
  94 + v-if="cancelText"
  95 + ></u-gap>
  96 + <view hover-class="u-action-sheet--hover">
  97 + <text
  98 + @touchmove.stop.prevent
  99 + :hover-stay-time="150"
  100 + v-if="cancelText"
  101 + class="u-action-sheet__cancel-text"
  102 + @tap="cancel"
  103 + >{{cancelText}}</text>
  104 + </view>
  105 + </view>
  106 + </u-popup>
  107 +</template>
  108 +
  109 +<script>
  110 + import openType from '../../libs/mixin/openType'
  111 + import button from '../../libs/mixin/button'
  112 + import props from './props.js';
  113 + /**
  114 + * ActionSheet 操作菜单
  115 + * @description 本组件用于从底部弹出一个操作菜单,供用户选择并返回结果。本组件功能类似于uni的uni.showActionSheetAPI,配置更加灵活,所有平台都表现一致。
  116 + * @tutorial https://www.uviewui.com/components/actionSheet.html
  117 + *
  118 + * @property {Boolean} show 操作菜单是否展示 (默认 false )
  119 + * @property {String} title 操作菜单标题
  120 + * @property {String} description 选项上方的描述信息
  121 + * @property {Array<Object>} actions 按钮的文字数组,见官方文档示例
  122 + * @property {String} cancelText 取消按钮的提示文字,不为空时显示按钮
  123 + * @property {Boolean} closeOnClickAction 点击某个菜单项时是否关闭弹窗 (默认 true )
  124 + * @property {Boolean} safeAreaInsetBottom 处理底部安全区 (默认 true )
  125 + * @property {String} openType 小程序的打开方式 (contact | launchApp | getUserInfo | openSetting |getPhoneNumber |error )
  126 + * @property {Boolean} closeOnClickOverlay 点击遮罩是否允许关闭 (默认 true )
  127 + * @property {Number|String} round 圆角值,默认无圆角 (默认 0 )
  128 + * @property {String} lang 指定返回用户信息的语言,zh_CN 简体中文,zh_TW 繁体中文,en 英文
  129 + * @property {String} sessionFrom 会话来源,openType="contact"时有效
  130 + * @property {String} sendMessageTitle 会话内消息卡片标题,openType="contact"时有效
  131 + * @property {String} sendMessagePath 会话内消息卡片点击跳转小程序路径,openType="contact"时有效
  132 + * @property {String} sendMessageImg 会话内消息卡片图片,openType="contact"时有效
  133 + * @property {Boolean} showMessageCard 是否显示会话内消息卡片,设置此参数为 true,用户进入客服会话会在右下角显示"可能要发送的小程序"提示,用户点击后可以快速发送小程序消息,openType="contact"时有效 (默认 false )
  134 + * @property {String} appParameter 打开 APP 时,向 APP 传递的参数,openType=launchApp 时有效
  135 + *
  136 + * @event {Function} select 点击ActionSheet列表项时触发
  137 + * @event {Function} close 点击取消按钮时触发
  138 + * @event {Function} getuserinfo 用户点击该按钮时,会返回获取到的用户信息,回调的 detail 数据与 wx.getUserInfo 返回的一致,openType="getUserInfo"时有效
  139 + * @event {Function} contact 客服消息回调,openType="contact"时有效
  140 + * @event {Function} getphonenumber 获取用户手机号回调,openType="getPhoneNumber"时有效
  141 + * @event {Function} error 当使用开放能力时,发生错误的回调,openType="error"时有效
  142 + * @event {Function} launchapp 打开 APP 成功的回调,openType="launchApp"时有效
  143 + * @event {Function} opensetting 在打开授权设置页后回调,openType="openSetting"时有效
  144 + * @example <u-action-sheet :actions="list" :title="title" :show="show"></u-action-sheet>
  145 + */
  146 + export default {
  147 + name: "u-action-sheet",
  148 + // 一些props参数和methods方法,通过mixin混入,因为其他文件也会用到
  149 + mixins: [openType, button, uni.$u.mixin, props],
  150 + data() {
  151 + return {
  152 +
  153 + }
  154 + },
  155 + computed: {
  156 + // 操作项目的样式
  157 + itemStyle() {
  158 + return (index) => {
  159 + let style = {};
  160 + if (this.actions[index].color) style.color = this.actions[index].color
  161 + if (this.actions[index].fontSize) style.fontSize = uni.$u.addUnit(this.actions[index].fontSize)
  162 + // 选项被禁用的样式
  163 + if (this.actions[index].disabled) style.color = '#c0c4cc'
  164 + return style;
  165 + }
  166 + },
  167 + },
  168 + methods: {
  169 + closeHandler() {
  170 + // 允许点击遮罩关闭时,才发出close事件
  171 + if(this.closeOnClickOverlay) {
  172 + this.$emit('close')
  173 + }
  174 + },
  175 + // 点击取消按钮
  176 + cancel() {
  177 + this.$emit('close')
  178 + },
  179 + selectHandler(index) {
  180 + const item = this.actions[index]
  181 + if (item && !item.disabled && !item.loading) {
  182 + this.$emit('select', item)
  183 + if (this.closeOnClickAction) {
  184 + this.$emit('close')
  185 + }
  186 + }
  187 + },
  188 + }
  189 + }
  190 +</script>
  191 +
  192 +<style lang="scss" scoped>
  193 + @import "../../libs/css/components.scss";
  194 + $u-action-sheet-reset-button-width:100% !default;
  195 + $u-action-sheet-title-font-size: 16px !default;
  196 + $u-action-sheet-title-padding: 12px 30px !default;
  197 + $u-action-sheet-title-color: $u-main-color !default;
  198 + $u-action-sheet-header-icon-wrap-right:15px !default;
  199 + $u-action-sheet-header-icon-wrap-top:15px !default;
  200 + $u-action-sheet-description-font-size:13px !default;
  201 + $u-action-sheet-description-color:14px !default;
  202 + $u-action-sheet-description-margin: 18px 15px !default;
  203 + $u-action-sheet-item-wrap-item-padding:15px !default;
  204 + $u-action-sheet-item-wrap-name-font-size:16px !default;
  205 + $u-action-sheet-item-wrap-subname-font-size:13px !default;
  206 + $u-action-sheet-item-wrap-subname-color: #c0c4cc !default;
  207 + $u-action-sheet-item-wrap-subname-margin-top:10px !default;
  208 + $u-action-sheet-cancel-text-font-size:16px !default;
  209 + $u-action-sheet-cancel-text-color:$u-content-color !default;
  210 + $u-action-sheet-cancel-text-font-size:15px !default;
  211 + $u-action-sheet-cancel-text-hover-background-color:rgb(242, 243, 245) !default;
  212 +
  213 + .u-reset-button {
  214 + width: $u-action-sheet-reset-button-width;
  215 + }
  216 +
  217 + .u-action-sheet {
  218 + text-align: center;
  219 + &__header {
  220 + position: relative;
  221 + padding: $u-action-sheet-title-padding;
  222 + &__title {
  223 + font-size: $u-action-sheet-title-font-size;
  224 + color: $u-action-sheet-title-color;
  225 + font-weight: bold;
  226 + text-align: center;
  227 + }
  228 +
  229 + &__icon-wrap {
  230 + position: absolute;
  231 + right: $u-action-sheet-header-icon-wrap-right;
  232 + top: $u-action-sheet-header-icon-wrap-top;
  233 + }
  234 + }
  235 +
  236 + &__description {
  237 + font-size: $u-action-sheet-description-font-size;
  238 + color: $u-tips-color;
  239 + margin: $u-action-sheet-description-margin;
  240 + text-align: center;
  241 + }
  242 +
  243 + &__item-wrap {
  244 +
  245 + &__item {
  246 + padding: $u-action-sheet-item-wrap-item-padding;
  247 + @include flex;
  248 + align-items: center;
  249 + justify-content: center;
  250 + flex-direction: column;
  251 +
  252 + &__name {
  253 + font-size: $u-action-sheet-item-wrap-name-font-size;
  254 + color: $u-main-color;
  255 + text-align: center;
  256 + }
  257 +
  258 + &__subname {
  259 + font-size: $u-action-sheet-item-wrap-subname-font-size;
  260 + color: $u-action-sheet-item-wrap-subname-color;
  261 + margin-top: $u-action-sheet-item-wrap-subname-margin-top;
  262 + text-align: center;
  263 + }
  264 + }
  265 + }
  266 +
  267 + &__cancel-text {
  268 + font-size: $u-action-sheet-cancel-text-font-size;
  269 + color: $u-action-sheet-cancel-text-color;
  270 + text-align: center;
  271 + padding: $u-action-sheet-cancel-text-font-size;
  272 + }
  273 +
  274 + &--hover {
  275 + background-color: $u-action-sheet-cancel-text-hover-background-color;
  276 + }
  277 + }
  278 +</style>
  1 +export default {
  2 + props: {
  3 + // 图片地址,Array<String>|Array<Object>形式
  4 + urls: {
  5 + type: Array,
  6 + default: uni.$u.props.album.urls
  7 + },
  8 + // 指定从数组的对象元素中读取哪个属性作为图片地址
  9 + keyName: {
  10 + type: String,
  11 + default: uni.$u.props.album.keyName
  12 + },
  13 + // 单图时,图片长边的长度
  14 + singleSize: {
  15 + type: [String, Number],
  16 + default: uni.$u.props.album.singleSize
  17 + },
  18 + // 多图时,图片边长
  19 + multipleSize: {
  20 + type: [String, Number],
  21 + default: uni.$u.props.album.multipleSize
  22 + },
  23 + // 多图时,图片水平和垂直之间的间隔
  24 + space: {
  25 + type: [String, Number],
  26 + default: uni.$u.props.album.space
  27 + },
  28 + // 单图时,图片缩放裁剪的模式
  29 + singleMode: {
  30 + type: String,
  31 + default: uni.$u.props.album.singleMode
  32 + },
  33 + // 多图时,图片缩放裁剪的模式
  34 + multipleMode: {
  35 + type: String,
  36 + default: uni.$u.props.album.multipleMode
  37 + },
  38 + // 最多展示的图片数量,超出时最后一个位置将会显示剩余图片数量
  39 + maxCount: {
  40 + type: [String, Number],
  41 + default: uni.$u.props.album.maxCount
  42 + },
  43 + // 是否可以预览图片
  44 + previewFullImage: {
  45 + type: Boolean,
  46 + default: uni.$u.props.album.previewFullImage
  47 + },
  48 + // 每行展示图片数量,如设置,singleSize和multipleSize将会无效
  49 + rowCount: {
  50 + type: [String, Number],
  51 + default: uni.$u.props.album.rowCount
  52 + },
  53 + // 超出maxCount时是否显示查看更多的提示
  54 + showMore: {
  55 + type: Boolean,
  56 + default: uni.$u.props.album.showMore
  57 + }
  58 + }
  59 +}
  1 +<template>
  2 + <view class="u-album">
  3 + <view
  4 + class="u-album__row"
  5 + ref="u-album__row"
  6 + v-for="(arr, index) in showUrls"
  7 + :forComputedUse="albumWidth"
  8 + :key="index"
  9 + >
  10 + <view
  11 + class="u-album__row__wrapper"
  12 + v-for="(item, index1) in arr"
  13 + :key="index1"
  14 + :style="[imageStyle(index + 1, index1 + 1)]"
  15 + @tap="previewFullImage ? onPreviewTap(getSrc(item)) : ''"
  16 + >
  17 + <image
  18 + :src="getSrc(item)"
  19 + :mode="
  20 + urls.length === 1
  21 + ? imageHeight > 0
  22 + ? singleMode
  23 + : 'widthFix'
  24 + : multipleMode
  25 + "
  26 + :style="[
  27 + {
  28 + width: imageWidth,
  29 + height: imageHeight
  30 + }
  31 + ]"
  32 + ></image>
  33 + <view
  34 + v-if="
  35 + showMore &&
  36 + urls.length > rowCount * showUrls.length &&
  37 + index === showUrls.length - 1 &&
  38 + index1 === showUrls[showUrls.length - 1].length - 1
  39 + "
  40 + class="u-album__row__wrapper__text"
  41 + >
  42 + <u--text
  43 + :text="`+${urls.length - maxCount}`"
  44 + color="#fff"
  45 + :size="multipleSize * 0.3"
  46 + align="center"
  47 + customStyle="justify-content: center"
  48 + ></u--text>
  49 + </view>
  50 + </view>
  51 + </view>
  52 + </view>
  53 +</template>
  54 +
  55 +<script>
  56 +import props from './props.js'
  57 +// #ifdef APP-NVUE
  58 +// 由于weex为阿里的KPI业绩考核的产物,所以不支持百分比单位,这里需要通过dom查询组件的宽度
  59 +const dom = uni.requireNativePlugin('dom')
  60 +// #endif
  61 +
  62 +/**
  63 + * Album 相册
  64 + * @description 本组件提供一个类似相册的功能,让开发者开发起来更加得心应手。减少重复的模板代码
  65 + * @tutorial https://www.uviewui.com/components/album.html
  66 + *
  67 + * @property {Array} urls 图片地址列表 Array<String>|Array<Object>形式
  68 + * @property {String} keyName 指定从数组的对象元素中读取哪个属性作为图片地址
  69 + * @property {String | Number} singleSize 单图时,图片长边的长度 (默认 180 )
  70 + * @property {String | Number} multipleSize 多图时,图片边长 (默认 70 )
  71 + * @property {String | Number} space 多图时,图片水平和垂直之间的间隔 (默认 6 )
  72 + * @property {String} singleMode 单图时,图片缩放裁剪的模式 (默认 'scaleToFill' )
  73 + * @property {String} multipleMode 多图时,图片缩放裁剪的模式 (默认 'aspectFill' )
  74 + * @property {String | Number} maxCount 取消按钮的提示文字 (默认 9 )
  75 + * @property {Boolean} previewFullImage 是否可以预览图片 (默认 true )
  76 + * @property {String | Number} rowCount 每行展示图片数量,如设置,singleSize和multipleSize将会无效 (默认 3 )
  77 + * @property {Boolean} showMore 超出maxCount时是否显示查看更多的提示 (默认 true )
  78 + *
  79 + * @event {Function} albumWidth 某些特殊的情况下,需要让文字与相册的宽度相等,这里事件的形式对外发送 (回调参数 width )
  80 + * @example <u-album :urls="urls2" @albumWidth="width => albumWidth = width" multipleSize="68" ></u-album>
  81 + */
  82 +export default {
  83 + name: 'u-album',
  84 + mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
  85 + data() {
  86 + return {
  87 + // 单图的宽度
  88 + singleWidth: 0,
  89 + // 单图的高度
  90 + singleHeight: 0,
  91 + // 单图时,如果无法获取图片的尺寸信息,让图片宽度默认为容器的一定百分比
  92 + singlePercent: 0.6
  93 + }
  94 + },
  95 + watch: {
  96 + urls: {
  97 + immediate: true,
  98 + handler(newVal) {
  99 + if (newVal.length === 1) {
  100 + this.getImageRect()
  101 + }
  102 + }
  103 + }
  104 + },
  105 + computed: {
  106 + imageStyle() {
  107 + return (index1, index2) => {
  108 + const { space, rowCount, multipleSize, urls } = this,
  109 + { addUnit, addStyle } = uni.$u,
  110 + rowLen = this.showUrls.length,
  111 + allLen = this.urls.length
  112 + const style = {
  113 + marginRight: addUnit(space),
  114 + marginBottom: addUnit(space)
  115 + }
  116 + // 如果为最后一行,则每个图片都无需下边框
  117 + if (index1 === rowLen) style.marginBottom = 0
  118 + // 每行的最右边一张和总长度的最后一张无需右边框
  119 + if (
  120 + index2 === rowCount ||
  121 + (index1 === rowLen &&
  122 + index2 === this.showUrls[index1 - 1].length)
  123 + )
  124 + style.marginRight = 0
  125 + return style
  126 + }
  127 + },
  128 + // 将数组划分为二维数组
  129 + showUrls() {
  130 + const arr = []
  131 + this.urls.map((item, index) => {
  132 + // 限制最大展示数量
  133 + if (index + 1 <= this.maxCount) {
  134 + // 计算该元素为第几个素组内
  135 + const itemIndex = Math.floor(index / this.rowCount)
  136 + // 判断对应的索引是否存在
  137 + if (!arr[itemIndex]) {
  138 + arr[itemIndex] = []
  139 + }
  140 + arr[itemIndex].push(item)
  141 + }
  142 + })
  143 + return arr
  144 + },
  145 + imageWidth() {
  146 + return uni.$u.addUnit(
  147 + this.urls.length === 1 ? this.singleWidth : this.multipleSize
  148 + )
  149 + },
  150 + imageHeight() {
  151 + return uni.$u.addUnit(
  152 + this.urls.length === 1 ? this.singleHeight : this.multipleSize
  153 + )
  154 + },
  155 + // 此变量无实际用途,仅仅是为了利用computed特性,让其在urls长度等变化时,重新计算图片的宽度
  156 + // 因为用户在某些特殊的情况下,需要让文字与相册的宽度相等,所以这里事件的形式对外发送
  157 + albumWidth() {
  158 + let width = 0
  159 + if (this.urls.length === 1) {
  160 + width = this.singleWidth
  161 + } else {
  162 + width =
  163 + this.showUrls[0].length * this.multipleSize +
  164 + this.space * (this.showUrls[0].length - 1)
  165 + }
  166 + this.$emit('albumWidth', width)
  167 + return width
  168 + }
  169 + },
  170 + methods: {
  171 + // 预览图片
  172 + onPreviewTap(url) {
  173 + const urls = this.urls.map((item) => {
  174 + return this.getSrc(item)
  175 + })
  176 + uni.previewImage({
  177 + current: url,
  178 + urls
  179 + })
  180 + },
  181 + // 获取图片的路径
  182 + getSrc(item) {
  183 + return uni.$u.test.object(item)
  184 + ? (this.keyName && item[this.keyName]) || item.src
  185 + : item
  186 + },
  187 + // 单图时,获取图片的尺寸
  188 + // 在小程序中,需要将网络图片的的域名添加到小程序的download域名才可能获取尺寸
  189 + // 在没有添加的情况下,让单图宽度默认为盒子的一定宽度(singlePercent)
  190 + getImageRect() {
  191 + const src = this.getSrc(this.urls[0])
  192 + uni.getImageInfo({
  193 + src,
  194 + success: (res) => {
  195 + // 判断图片横向还是竖向展示方式
  196 + const isHorizotal = res.width >= res.height
  197 + this.singleWidth = isHorizotal
  198 + ? this.singleSize
  199 + : (res.width / res.height) * this.singleSize
  200 + this.singleHeight = !isHorizotal
  201 + ? this.singleSize
  202 + : (res.height / res.width) * this.singleWidth
  203 + },
  204 + fail: () => {
  205 + this.getComponentWidth()
  206 + }
  207 + })
  208 + },
  209 + // 获取组件的宽度
  210 + async getComponentWidth() {
  211 + // 延时一定时间,以获取dom尺寸
  212 + await uni.$u.sleep(30)
  213 + // #ifndef APP-NVUE
  214 + this.$uGetRect('.u-album__row').then((size) => {
  215 + this.singleWidth = size.width * this.singlePercent
  216 + })
  217 + // #endif
  218 +
  219 + // #ifdef APP-NVUE
  220 + // 这里ref="u-album__row"所在的标签为通过for循环出来,导致this.$refs['u-album__row']是一个数组
  221 + const ref = this.$refs['u-album__row'][0]
  222 + ref &&
  223 + dom.getComponentRect(ref, (res) => {
  224 + this.singleWidth = res.size.width * this.singlePercent
  225 + })
  226 + // #endif
  227 + }
  228 + }
  229 +}
  230 +</script>
  231 +
  232 +<style lang="scss" scoped>
  233 +@import '../../libs/css/components.scss';
  234 +
  235 +.u-album {
  236 + @include flex(column);
  237 +
  238 + &__row {
  239 + @include flex(row);
  240 + flex-wrap: wrap;
  241 +
  242 + &__wrapper {
  243 + position: relative;
  244 +
  245 + &__text {
  246 + position: absolute;
  247 + top: 0;
  248 + left: 0;
  249 + right: 0;
  250 + bottom: 0;
  251 + background-color: rgba(0, 0, 0, 0.3);
  252 + @include flex(row);
  253 + justify-content: center;
  254 + align-items: center;
  255 + }
  256 + }
  257 + }
  258 +}
  259 +</style>
  1 +export default {
  2 + props: {
  3 + // 显示文字
  4 + title: {
  5 + type: String,
  6 + default: uni.$u.props.alert.title
  7 + },
  8 + // 主题,success/warning/info/error
  9 + type: {
  10 + type: String,
  11 + default: uni.$u.props.alert.type
  12 + },
  13 + // 辅助性文字
  14 + description: {
  15 + type: String,
  16 + default: uni.$u.props.alert.description
  17 + },
  18 + // 是否可关闭
  19 + closable: {
  20 + type: Boolean,
  21 + default: uni.$u.props.alert.closable
  22 + },
  23 + // 是否显示图标
  24 + showIcon: {
  25 + type: Boolean,
  26 + default: uni.$u.props.alert.showIcon
  27 + },
  28 + // 浅或深色调,light-浅色,dark-深色
  29 + effect: {
  30 + type: String,
  31 + default: uni.$u.props.alert.effect
  32 + },
  33 + // 文字是否居中
  34 + center: {
  35 + type: Boolean,
  36 + default: uni.$u.props.alert.center
  37 + },
  38 + // 字体大小
  39 + fontSize: {
  40 + type: [String, Number],
  41 + default: uni.$u.props.alert.fontSize
  42 + }
  43 + }
  44 +}
  1 +<template>
  2 + <u-transition
  3 + mode="fade"
  4 + :show="show"
  5 + >
  6 + <view
  7 + class="u-alert"
  8 + :class="[`u-alert--${type}--${effect}`]"
  9 + @tap.stop="clickHandler"
  10 + :style="[$u.addStyle(customStyle)]"
  11 + >
  12 + <view
  13 + class="u-alert__icon"
  14 + v-if="showIcon"
  15 + >
  16 + <u-icon
  17 + :name="iconName"
  18 + size="18"
  19 + :color="iconColor"
  20 + ></u-icon>
  21 + </view>
  22 + <view
  23 + class="u-alert__content"
  24 + :style="[{
  25 + paddingRight: closable ? '20px' : 0
  26 + }]"
  27 + >
  28 + <text
  29 + class="u-alert__content__title"
  30 + v-if="title"
  31 + :style="[{
  32 + fontSize: $u.addUnit(fontSize),
  33 + textAlign: center ? 'center' : 'left'
  34 + }]"
  35 + :class="[effect === 'dark' ? 'u-alert__text--dark' : `u-alert__text--${type}--light`]"
  36 + >{{ title }}</text>
  37 + <text
  38 + class="u-alert__content__desc"
  39 + v-if="description"
  40 + :style="[{
  41 + fontSize: $u.addUnit(fontSize),
  42 + textAlign: center ? 'center' : 'left'
  43 + }]"
  44 + :class="[effect === 'dark' ? 'u-alert__text--dark' : `u-alert__text--${type}--light`]"
  45 + >{{ description }}</text>
  46 + </view>
  47 + <view
  48 + class="u-alert__close"
  49 + v-if="closable"
  50 + @tap.stop="closeHandler"
  51 + >
  52 + <u-icon
  53 + name="close"
  54 + :color="iconColor"
  55 + size="15"
  56 + ></u-icon>
  57 + </view>
  58 + </view>
  59 + </u-transition>
  60 +</template>
  61 +
  62 +<script>
  63 + import props from './props.js';
  64 + /**
  65 + * Alert 警告提示
  66 + * @description 警告提示,展现需要关注的信息。
  67 + * @tutorial https://www.uviewui.com/components/alertTips.html
  68 + *
  69 + * @property {String} title 显示的文字
  70 + * @property {String} type 使用预设的颜色 (默认 'warning' )
  71 + * @property {String} description 辅助性文字,颜色比title浅一点,字号也小一点,可选
  72 + * @property {Boolean} closable 关闭按钮(默认为叉号icon图标) (默认 false )
  73 + * @property {Boolean} showIcon 是否显示左边的辅助图标 ( 默认 false )
  74 + * @property {String} effect 多图时,图片缩放裁剪的模式 (默认 'light' )
  75 + * @property {Boolean} center 文字是否居中 (默认 false )
  76 + * @property {String | Number} fontSize 字体大小 (默认 14 )
  77 + * @property {Object} customStyle 定义需要用到的外部样式
  78 + * @event {Function} click 点击组件时触发
  79 + * @example <u-alert :title="title" type = "warning" :closable="closable" :description = "description"></u-alert>
  80 + */
  81 + export default {
  82 + name: 'u-alert',
  83 + mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
  84 + data() {
  85 + return {
  86 + show: true
  87 + }
  88 + },
  89 + computed: {
  90 + iconColor() {
  91 + return this.effect === 'light' ? this.type : '#fff'
  92 + },
  93 + // 不同主题对应不同的图标
  94 + iconName() {
  95 + switch (this.type) {
  96 + case 'success':
  97 + return 'checkmark-circle-fill';
  98 + break;
  99 + case 'error':
  100 + return 'close-circle-fill';
  101 + break;
  102 + case 'warning':
  103 + return 'error-circle-fill';
  104 + break;
  105 + case 'info':
  106 + return 'info-circle-fill';
  107 + break;
  108 + case 'primary':
  109 + return 'more-circle-fill';
  110 + break;
  111 + default:
  112 + return 'error-circle-fill';
  113 + }
  114 + }
  115 + },
  116 + methods: {
  117 + // 点击内容
  118 + clickHandler() {
  119 + this.$emit('click')
  120 + },
  121 + // 点击关闭按钮
  122 + closeHandler() {
  123 + this.show = false
  124 + }
  125 + }
  126 + }
  127 +</script>
  128 +
  129 +<style lang="scss" scoped>
  130 + @import "../../libs/css/components.scss";
  131 +
  132 + .u-alert {
  133 + position: relative;
  134 + background-color: $u-primary;
  135 + padding: 8px 10px;
  136 + @include flex(row);
  137 + align-items: center;
  138 + border-top-left-radius: 4px;
  139 + border-top-right-radius: 4px;
  140 + border-bottom-left-radius: 4px;
  141 + border-bottom-right-radius: 4px;
  142 +
  143 + &--primary--dark {
  144 + background-color: $u-primary;
  145 + }
  146 +
  147 + &--primary--light {
  148 + background-color: #ecf5ff;
  149 + }
  150 +
  151 + &--error--dark {
  152 + background-color: $u-error;
  153 + }
  154 +
  155 + &--error--light {
  156 + background-color: #FEF0F0;
  157 + }
  158 +
  159 + &--success--dark {
  160 + background-color: $u-success;
  161 + }
  162 +
  163 + &--success--light {
  164 + background-color: #f5fff0;
  165 + }
  166 +
  167 + &--warning--dark {
  168 + background-color: $u-warning;
  169 + }
  170 +
  171 + &--warning--light {
  172 + background-color: #FDF6EC;
  173 + }
  174 +
  175 + &--info--dark {
  176 + background-color: $u-info;
  177 + }
  178 +
  179 + &--info--light {
  180 + background-color: #f4f4f5;
  181 + }
  182 +
  183 + &__icon {
  184 + margin-right: 5px;
  185 + }
  186 +
  187 + &__content {
  188 + @include flex(column);
  189 + flex: 1;
  190 +
  191 + &__title {
  192 + color: $u-main-color;
  193 + font-size: 14px;
  194 + font-weight: bold;
  195 + color: #fff;
  196 + margin-bottom: 2px;
  197 + }
  198 +
  199 + &__desc {
  200 + color: $u-main-color;
  201 + font-size: 14px;
  202 + flex-wrap: wrap;
  203 + color: #fff;
  204 + }
  205 + }
  206 +
  207 + &__title--dark,
  208 + &__desc--dark {
  209 + color: #FFFFFF;
  210 + }
  211 +
  212 + &__text--primary--light,
  213 + &__text--primary--light {
  214 + color: $u-primary;
  215 + }
  216 +
  217 + &__text--success--light,
  218 + &__text--success--light {
  219 + color: $u-success;
  220 + }
  221 +
  222 + &__text--warning--light,
  223 + &__text--warning--light {
  224 + color: $u-warning;
  225 + }
  226 +
  227 + &__text--error--light,
  228 + &__text--error--light {
  229 + color: $u-error;
  230 + }
  231 +
  232 + &__text--info--light,
  233 + &__text--info--light {
  234 + color: $u-info;
  235 + }
  236 +
  237 + &__close {
  238 + position: absolute;
  239 + top: 11px;
  240 + right: 10px;
  241 + }
  242 + }
  243 +</style>
  1 +export default {
  2 + props: {
  3 + // 头像图片组
  4 + urls: {
  5 + type: Array,
  6 + default: uni.$u.props.avatarGroup.urls
  7 + },
  8 + // 最多展示的头像数量
  9 + maxCount: {
  10 + type: [String, Number],
  11 + default: uni.$u.props.avatarGroup.maxCount
  12 + },
  13 + // 头像形状
  14 + shape: {
  15 + type: String,
  16 + default: uni.$u.props.avatarGroup.shape
  17 + },
  18 + // 图片裁剪模式
  19 + mode: {
  20 + type: String,
  21 + default: uni.$u.props.avatarGroup.mode
  22 + },
  23 + // 超出maxCount时是否显示查看更多的提示
  24 + showMore: {
  25 + type: Boolean,
  26 + default: uni.$u.props.avatarGroup.showMore
  27 + },
  28 + // 头像大小
  29 + size: {
  30 + type: [String, Number],
  31 + default: uni.$u.props.avatarGroup.size
  32 + },
  33 + // 指定从数组的对象元素中读取哪个属性作为图片地址
  34 + keyName: {
  35 + type: String,
  36 + default: uni.$u.props.avatarGroup.keyName
  37 + },
  38 + // 头像之间的遮挡比例
  39 + gap: {
  40 + type: [String, Number],
  41 + validator(value) {
  42 + return value >= 0 && value <= 1
  43 + },
  44 + default: uni.$u.props.avatarGroup.gap
  45 + },
  46 + // 需额外显示的值
  47 + extraValue: {
  48 + type: [Number, String],
  49 + default: uni.$u.props.avatarGroup.extraValue
  50 + }
  51 + }
  52 +}
  1 +<template>
  2 + <view class="u-avatar-group">
  3 + <view
  4 + class="u-avatar-group__item"
  5 + v-for="(item, index) in showUrl"
  6 + :key="index"
  7 + :style="{
  8 + marginLeft: index === 0 ? 0 : $u.addUnit(-size * gap)
  9 + }"
  10 + >
  11 + <u-avatar
  12 + :size="size"
  13 + :shape="shape"
  14 + :mode="mode"
  15 + :src="$u.test.object(item) ? keyName && item[keyName] || item.url : item"
  16 + ></u-avatar>
  17 + <view
  18 + class="u-avatar-group__item__show-more"
  19 + v-if="showMore && index === showUrl.length - 1 && (urls.length > maxCount || extraValue > 0)"
  20 + @tap="clickHandler"
  21 + >
  22 + <u--text
  23 + color="#ffffff"
  24 + :size="size * 0.4"
  25 + :text="`+${extraValue || urls.length - showUrl.length}`"
  26 + align="center"
  27 + customStyle="justify-content: center"
  28 + ></u--text>
  29 + </view>
  30 + </view>
  31 + </view>
  32 +</template>
  33 +
  34 +<script>
  35 + import props from './props.js';
  36 + /**
  37 + * AvatarGroup 头像组
  38 + * @description 本组件一般用于展示头像的地方,如个人中心,或者评论列表页的用户头像展示等场所。
  39 + * @tutorial https://www.uviewui.com/components/avatar.html
  40 + *
  41 + * @property {Array} urls 头像图片组 (默认 [] )
  42 + * @property {String | Number} maxCount 最多展示的头像数量 ( 默认 5 )
  43 + * @property {String} shape 头像形状( 'circle' (默认) | 'square' )
  44 + * @property {String} mode 图片裁剪模式(默认 'scaleToFill' )
  45 + * @property {Boolean} showMore 超出maxCount时是否显示查看更多的提示 (默认 true )
  46 + * @property {String | Number} size 头像大小 (默认 40 )
  47 + * @property {String} keyName 指定从数组的对象元素中读取哪个属性作为图片地址
  48 + * @property {String | Number} gap 头像之间的遮挡比例(0.4代表遮挡40%) (默认 0.5 )
  49 + * @property {String | Number} extraValue 需额外显示的值
  50 + * @event {Function} showMore 头像组更多点击
  51 + * @example <u-avatar-group:urls="urls" size="35" gap="0.4" ></u-avatar-group:urls=>
  52 + */
  53 + export default {
  54 + name: 'u-avatar-group',
  55 + mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
  56 + data() {
  57 + return {
  58 +
  59 + }
  60 + },
  61 + computed: {
  62 + showUrl() {
  63 + return this.urls.slice(0, this.maxCount)
  64 + }
  65 + },
  66 + methods: {
  67 + clickHandler() {
  68 + this.$emit('showMore')
  69 + }
  70 + },
  71 + }
  72 +</script>
  73 +
  74 +<style lang="scss" scoped>
  75 + @import "../../libs/css/components.scss";
  76 +
  77 + .u-avatar-group {
  78 + @include flex;
  79 +
  80 + &__item {
  81 + margin-left: -10px;
  82 + position: relative;
  83 +
  84 + &--no-indent {
  85 + // 如果你想质疑作者不会使用:first-child,说明你太年轻,因为nvue不支持
  86 + margin-left: 0;
  87 + }
  88 +
  89 + &__show-more {
  90 + position: absolute;
  91 + top: 0;
  92 + bottom: 0;
  93 + left: 0;
  94 + right: 0;
  95 + background-color: rgba(0, 0, 0, 0.3);
  96 + @include flex;
  97 + align-items: center;
  98 + justify-content: center;
  99 + border-radius: 100px;
  100 + }
  101 + }
  102 + }
  103 +</style>
  1 +export default {
  2 + props: {
  3 + // 头像图片路径(不能为相对路径)
  4 + src: {
  5 + type: String,
  6 + default: uni.$u.props.avatar.src
  7 + },
  8 + // 头像形状,circle-圆形,square-方形
  9 + shape: {
  10 + type: String,
  11 + default: uni.$u.props.avatar.shape
  12 + },
  13 + // 头像尺寸
  14 + size: {
  15 + type: [String, Number],
  16 + default: uni.$u.props.avatar.size
  17 + },
  18 + // 裁剪模式
  19 + mode: {
  20 + type: String,
  21 + default: uni.$u.props.avatar.mode
  22 + },
  23 + // 显示的文字
  24 + text: {
  25 + type: String,
  26 + default: uni.$u.props.avatar.text
  27 + },
  28 + // 背景色
  29 + bgColor: {
  30 + type: String,
  31 + default: uni.$u.props.avatar.bgColor
  32 + },
  33 + // 文字颜色
  34 + color: {
  35 + type: String,
  36 + default: uni.$u.props.avatar.color
  37 + },
  38 + // 文字大小
  39 + fontSize: {
  40 + type: [String, Number],
  41 + default: uni.$u.props.avatar.fontSize
  42 + },
  43 + // 显示的图标
  44 + icon: {
  45 + type: String,
  46 + default: uni.$u.props.avatar.icon
  47 + },
  48 + // 显示小程序头像,只对百度,微信,QQ小程序有效
  49 + mpAvatar: {
  50 + type: Boolean,
  51 + default: uni.$u.props.avatar.mpAvatar
  52 + },
  53 + // 是否使用随机背景色
  54 + randomBgColor: {
  55 + type: Boolean,
  56 + default: uni.$u.props.avatar.randomBgColor
  57 + },
  58 + // 加载失败的默认头像(组件有内置默认图片)
  59 + defaultUrl: {
  60 + type: String,
  61 + default: uni.$u.props.avatar.defaultUrl
  62 + },
  63 + // 如果配置了randomBgColor为true,且配置了此值,则从默认的背景色数组中取出对应索引的颜色值,取值0-19之间
  64 + colorIndex: {
  65 + type: [String, Number],
  66 + // 校验参数规则,索引在0-19之间
  67 + validator(n) {
  68 + return uni.$u.test.range(n, [0, 19]) || n === ''
  69 + },
  70 + default: uni.$u.props.avatar.colorIndex
  71 + },
  72 + // 组件标识符
  73 + name: {
  74 + type: String,
  75 + default: uni.$u.props.avatar.name
  76 + }
  77 + }
  78 +}
  1 +<template>
  2 + <view
  3 + class="u-avatar"
  4 + :class="[`u-avatar--${shape}`]"
  5 + :style="[{
  6 + backgroundColor: (text || icon) ? (randomBgColor ? colors[colorIndex !== '' ? colorIndex : $u.random(0, 19)] : bgColor) : 'transparent',
  7 + width: $u.addUnit(size),
  8 + height: $u.addUnit(size),
  9 + }, $u.addStyle(customStyle)]"
  10 + @tap="clickHandler"
  11 + >
  12 + <slot>
  13 + <!-- #ifdef MP-WEIXIN || MP-QQ || MP-BAIDU -->
  14 + <open-data
  15 + v-if="mpAvatar && allowMp"
  16 + type="userAvatarUrl"
  17 + :style="[{
  18 + width: $u.addUnit(size),
  19 + height: $u.addUnit(size)
  20 + }]"
  21 + />
  22 + <!-- #endif -->
  23 + <!-- #ifndef MP-WEIXIN && MP-QQ && MP-BAIDU -->
  24 + <template v-if="mpAvatar && allowMp"></template>
  25 + <!-- #endif -->
  26 + <u-icon
  27 + v-else-if="icon"
  28 + :name="icon"
  29 + :size="fontSize"
  30 + :color="color"
  31 + ></u-icon>
  32 + <u--text
  33 + v-else-if="text"
  34 + :text="text"
  35 + :size="fontSize"
  36 + :color="color"
  37 + align="center"
  38 + customStyle="justify-content: center"
  39 + ></u--text>
  40 + <image
  41 + class="u-avatar__image"
  42 + v-else
  43 + :class="[`u-avatar__image--${shape}`]"
  44 + :src="avatarUrl || defaultUrl"
  45 + :mode="mode"
  46 + @error="errorHandler"
  47 + :style="[{
  48 + width: $u.addUnit(size),
  49 + height: $u.addUnit(size)
  50 + }]"
  51 + ></image>
  52 + </slot>
  53 + </view>
  54 +</template>
  55 +
  56 +<script>
  57 + import props from './props.js';
  58 + const base64Avatar =
  59 + "data:image/jpg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAA8AAD/4QMraHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjMtYzAxMSA2Ni4xNDU2NjEsIDIwMTIvMDIvMDYtMTQ6NTY6MjcgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDUzYgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjREMEQwRkY0RjgwNDExRUE5OTY2RDgxODY3NkJFODMxIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjREMEQwRkY1RjgwNDExRUE5OTY2RDgxODY3NkJFODMxIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NEQwRDBGRjJGODA0MTFFQTk5NjZEODE4Njc2QkU4MzEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NEQwRDBGRjNGODA0MTFFQTk5NjZEODE4Njc2QkU4MzEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7/7gAOQWRvYmUAZMAAAAAB/9sAhAAGBAQEBQQGBQUGCQYFBgkLCAYGCAsMCgoLCgoMEAwMDAwMDBAMDg8QDw4MExMUFBMTHBsbGxwfHx8fHx8fHx8fAQcHBw0MDRgQEBgaFREVGh8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx//wAARCADIAMgDAREAAhEBAxEB/8QAcQABAQEAAwEBAAAAAAAAAAAAAAUEAQMGAgcBAQAAAAAAAAAAAAAAAAAAAAAQAAIBAwICBgkDBQAAAAAAAAABAhEDBCEFMVFBYXGREiKBscHRMkJSEyOh4XLxYjNDFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8A/fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHbHFyZ/Dam+yLA+Z2L0Pjtyj2poD4AAAAAAAAAAAAAAAAAAAAAAAAKWFs9y6lcvvwQeqj8z9wFaziY1n/HbUX9XF97A7QAGXI23EvJ1goyfzR0YEfN269jeZ+a03pNe0DIAAAAAAAAAAAAAAAAAAAACvtO3RcVkXlWutuL9YFYAAAAAOJRjKLjJVi9GmB5/csH/mu1h/in8PU+QGMAAAAAAAAAAAAAAAAAAaMDG/6MmMH8C80+xAelSSVFolwQAAAAAAAHVlWI37ErUulaPk+hgeYnCUJuElSUXRrrQHAAAAAAAAAAAAAAAAABa2Oz4bM7r4zdF2ICmAAAAAAAAAg7zZ8GX41wuJP0rRgYAAAAAAAAAAAAAAAAAD0m2R8ODaXU33tsDSAAAAAAAAAlb9HyWZcnJd9PcBHAAAAAAAAAAAAAAAAAPS7e64Vn+KA0AAAAAAAAAJm+v8Ftf3ewCKAAAAAAAAAAAAAAAAAX9muqeGo9NttP06+0DcAAAAAAAAAjb7dTu2ra+VOT9P8AQCWAAAAAAAAAAAAAAAAAUNmyPt5Ltv4bui/kuAF0AAAAAAADiUlGLlJ0SVW+oDzOXfd/Ind6JPRdS0QHSAAAAAAAAAAAAAAAAAE2nVaNcGB6Lbs6OTao9LsF51z60BrAAAAAABJ3jOVHjW3r/sa9QEgAAAAAAAAAAAAAAAAAAAPu1duWriuW34ZR4MC9hbnZyEoy8l36XwfYBsAAADaSq9EuLAlZ+7xSdrGdW9Hc5dgEdtt1erfFgAAAAAAAAAAAAAAAAADVjbblX6NR8MH80tEBRs7HYivyzlN8lovaBPzduvY0m6eK10TXtAyAarO55lpJK54orolr+4GqO/Xaea1FvqbXvA+Z77kNeW3GPbV+4DJfzcm/pcm3H6Vou5AdAFLC2ed2Pjv1txa8sV8T6wOL+yZEKu1JXFy4MDBOE4ScZxcZLinoB8gAAAAAAAAAAAB242LeyJ+C3GvN9C7QLmJtePYpKS+5c+p8F2IDYAANJqj1T4oCfk7Nj3G5Wn9qXJax7gJ93Z82D8sVNc4v30A6Xg5i42Z+iLfqARwcyT0sz9MWvWBps7LlTf5Grce9/oBTxdtxseklHxT+uWr9AGoAB138ezfj4bsFJdD6V2MCPm7RdtJzs1uW1xXzL3gTgAAAAAAAAADRhYc8q74I6RWs5ckB6GxYtWLat21SK731sDsAAAAAAAAAAAAAAAASt021NO/YjrxuQXT1oCOAAAAAAABzGLlJRSq26JAelwsWONYjbXxcZvmwO8AAAAAAAAAAAAAAAAAAef3TEWPkVivx3NY9T6UBiAAAAAABo2+VmGXblddIJ8eivRUD0oAAAAAAAAAAAAAAAAAAAYt4tKeFKVNYNSXfRgefAAAAAAAAr7VuSSWPedKaW5v1MCsAAAAAAAAAAAAAAAAAAIe6bj96Ts2n+JPzSXzP3ATgAAAAAAAAFbbt1UUrOQ9FpC4/UwK6aaqtU+DAAAAAAAAAAAAAAA4lKMIuUmoxWrb4ARNx3R3q2rLpa4Sl0y/YCcAAAAAAAAAAANmFud7G8r89r6X0dgFvGzLGRGtuWvTF6NAdwAAAAAAAAAAAy5W442PVN+K59EePp5ARMvOv5MvO6QXCC4AZwAAAAAAAAAAAAAcxlKLUotprg1owN+PvORborq+7Hnwl3gUbO74VzRydt8pKn68ANcJwmqwkpLmnUDkAAAAfNy9atqtyagut0AxXt5xIV8Fbj6lRd7Am5G65V6qUvtwfyx94GMAAAAAAAAAAAAAAAAAAAOU2nVOj5gdsc3LiqRvTpyqwOxbnnrhdfpSfrQB7pnv/AGvuS9gHXPMy5/Fem1yq0v0A6W29XqwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf//Z";
  60 + /**
  61 + * Avatar 头像
  62 + * @description 本组件一般用于展示头像的地方,如个人中心,或者评论列表页的用户头像展示等场所。
  63 + * @tutorial https://www.uviewui.com/components/avatar.html
  64 + *
  65 + * @property {String} src 头像路径,如加载失败,将会显示默认头像(不能为相对路径)
  66 + * @property {String} shape 头像形状 ( circle (默认) | square)
  67 + * @property {String | Number} size 头像尺寸,可以为指定字符串(large, default, mini),或者数值 (默认 40 )
  68 + * @property {String} mode 头像图片的裁剪类型,与uni的image组件的mode参数一致,如效果达不到需求,可尝试传widthFix值 (默认 'scaleToFill' )
  69 + * @property {String} text 用文字替代图片,级别优先于src
  70 + * @property {String} bgColor 背景颜色,一般显示文字时用 (默认 '#c0c4cc' )
  71 + * @property {String} color 文字颜色 (默认 '#ffffff' )
  72 + * @property {String | Number} fontSize 文字大小 (默认 18 )
  73 + * @property {String} icon 显示的图标
  74 + * @property {Boolean} mpAvatar 显示小程序头像,只对百度,微信,QQ小程序有效 (默认 false )
  75 + * @property {Boolean} randomBgColor 是否使用随机背景色 (默认 false )
  76 + * @property {String} defaultUrl 加载失败的默认头像(组件有内置默认图片)
  77 + * @property {String | Number} colorIndex 如果配置了randomBgColor为true,且配置了此值,则从默认的背景色数组中取出对应索引的颜色值,取值0-19之间
  78 + * @property {String} name 组件标识符 (默认 'level' )
  79 + * @property {Object} customStyle 定义需要用到的外部样式
  80 + *
  81 + * @event {Function} click 点击组件时触发 index: 用户传递的标识符
  82 + * @example <u-avatar :src="src" mode="square"></u-avatar>
  83 + */
  84 + export default {
  85 + name: 'u-avatar',
  86 + mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
  87 + data() {
  88 + return {
  89 + // 如果配置randomBgColor参数为true,在图标或者文字的模式下,会随机从中取出一个颜色值当做背景色
  90 + colors: ['#ffb34b', '#f2bba9', '#f7a196', '#f18080', '#88a867', '#bfbf39', '#89c152', '#94d554', '#f19ec2',
  91 + '#afaae4', '#e1b0df', '#c38cc1', '#72dcdc', '#9acdcb', '#77b1cc', '#448aca', '#86cefa', '#98d1ee',
  92 + '#73d1f1',
  93 + '#80a7dc'
  94 + ],
  95 + avatarUrl: this.src,
  96 + allowMp: false
  97 + }
  98 + },
  99 + watch: {
  100 + // 监听头像src的变化,赋值给内部的avatarUrl变量,因为图片加载失败时,需要修改图片的src为默认值
  101 + // 而组件内部不能直接修改props的值,所以需要一个中间变量
  102 + src: {
  103 + immediate: true,
  104 + handler(newVal) {
  105 + this.avatarUrl = newVal
  106 + // 如果没有传src,则主动触发error事件,用于显示默认的头像,否则src为''空字符等的时候,会无内容展示
  107 + if(!newVal) {
  108 + this.errorHandler()
  109 + }
  110 + }
  111 + }
  112 + },
  113 + computed: {
  114 + imageStyle() {
  115 + const style = {}
  116 + return style
  117 + }
  118 + },
  119 + created() {
  120 + this.init()
  121 + },
  122 + methods: {
  123 + init() {
  124 + // 目前只有这几个小程序平台具有open-data标签
  125 + // 其他平台可以通过uni.getUserInfo类似接口获取信息,但是需要弹窗授权(首次),不合符组件逻辑
  126 + // 故目前自动获取小程序头像只支持这几个平台
  127 + // #ifdef MP-WEIXIN || MP-QQ || MP-BAIDU
  128 + this.allowMp = true
  129 + // #endif
  130 + },
  131 + // 判断传入的name属性,是否图片路径,只要带有"/"均认为是图片形式
  132 + isImg() {
  133 + return this.src.indexOf('/') !== -1
  134 + },
  135 + // 图片加载时失败时触发
  136 + errorHandler() {
  137 + this.avatarUrl = this.defaultUrl || base64Avatar
  138 + },
  139 + clickHandler() {
  140 + this.$emit('click', this.name)
  141 + }
  142 + }
  143 + }
  144 +</script>
  145 +
  146 +<style lang="scss" scoped>
  147 + @import "../../libs/css/components.scss";
  148 +
  149 + .u-avatar {
  150 + @include flex;
  151 + align-items: center;
  152 + justify-content: center;
  153 +
  154 + &--circle {
  155 + border-radius: 100px;
  156 + }
  157 +
  158 + &--square {
  159 + border-radius: 4px;
  160 + }
  161 +
  162 + &__image {
  163 + &--circle {
  164 + border-radius: 100px;
  165 + }
  166 +
  167 + &--square {
  168 + border-radius: 4px;
  169 + }
  170 + }
  171 + }
  172 +</style>
  1 +export default {
  2 + props: {
  3 + // 返回顶部的形状,circle-圆形,square-方形
  4 + mode: {
  5 + type: String,
  6 + default: uni.$u.props.backtop.mode
  7 + },
  8 + // 自定义图标
  9 + icon: {
  10 + type: String,
  11 + default: uni.$u.props.backtop.icon
  12 + },
  13 + // 提示文字
  14 + text: {
  15 + type: String,
  16 + default: uni.$u.props.backtop.text
  17 + },
  18 + // 返回顶部滚动时间
  19 + duration: {
  20 + type: [String, Number],
  21 + default: uni.$u.props.backtop.duration
  22 + },
  23 + // 滚动距离
  24 + scrollTop: {
  25 + type: [String, Number],
  26 + default: uni.$u.props.backtop.scrollTop
  27 + },
  28 + // 距离顶部多少距离显示,单位px
  29 + top: {
  30 + type: [String, Number],
  31 + default: uni.$u.props.backtop.top
  32 + },
  33 + // 返回顶部按钮到底部的距离,单位px
  34 + bottom: {
  35 + type: [String, Number],
  36 + default: uni.$u.props.backtop.bottom
  37 + },
  38 + // 返回顶部按钮到右边的距离,单位px
  39 + right: {
  40 + type: [String, Number],
  41 + default: uni.$u.props.backtop.right
  42 + },
  43 + // 层级
  44 + zIndex: {
  45 + type: [String, Number],
  46 + default: uni.$u.props.backtop.zIndex
  47 + },
  48 + // 图标的样式,对象形式
  49 + iconStyle: {
  50 + type: Object,
  51 + default: uni.$u.props.backtop.iconStyle
  52 + }
  53 + }
  54 +}
  1 +<template>
  2 + <u-transition
  3 + mode="fade"
  4 + :customStyle="backTopStyle"
  5 + :show="show"
  6 + >
  7 + <view
  8 + class="u-back-top"
  9 + :style="[contentStyle]"
  10 + v-if="!$slots.default && !$slots.$default"
  11 + @click="backToTop"
  12 + >
  13 + <u-icon
  14 + :name="icon"
  15 + :custom-style="iconStyle"
  16 + ></u-icon>
  17 + <text
  18 + v-if="text"
  19 + class="u-back-top__text"
  20 + >{{text}}</text>
  21 + </view>
  22 + <slot v-else />
  23 + </u-transition>
  24 +</template>
  25 +
  26 +<script>
  27 + import props from './props.js';
  28 + // #ifdef APP-NVUE
  29 + const dom = weex.requireModule('dom')
  30 + // #endif
  31 + /**
  32 + * backTop 返回顶部
  33 + * @description 本组件一个用于长页面,滑动一定距离后,出现返回顶部按钮,方便快速返回顶部的场景。
  34 + * @tutorial https://uviewui.com/components/backTop.html
  35 + *
  36 + * @property {String} mode 返回顶部的形状,circle-圆形,square-方形 (默认 'circle' )
  37 + * @property {String} icon 自定义图标 (默认 'arrow-upward' ) 见官方文档示例
  38 + * @property {String} text 提示文字
  39 + * @property {String | Number} duration 返回顶部滚动时间 (默认 100)
  40 + * @property {String | Number} scrollTop 滚动距离 (默认 0 )
  41 + * @property {String | Number} top 距离顶部多少距离显示,单位px (默认 400 )
  42 + * @property {String | Number} bottom 返回顶部按钮到底部的距离,单位px (默认 100 )
  43 + * @property {String | Number} right 返回顶部按钮到右边的距离,单位px (默认 20 )
  44 + * @property {String | Number} zIndex 层级 (默认 9 )
  45 + * @property {Object<Object>} iconStyle 图标的样式,对象形式 (默认 {color: '#909399',fontSize: '19px'})
  46 + * @property {Object} customStyle 定义需要用到的外部样式
  47 + *
  48 + * @example <u-back-top :scrollTop="scrollTop"></u-back-top>
  49 + */
  50 + export default {
  51 + name: 'u-back-top',
  52 + mixins: [uni.$u.mpMixin, uni.$u.mixin,props],
  53 + computed: {
  54 + backTopStyle() {
  55 + // 动画组件样式
  56 + const style = {
  57 + bottom: uni.$u.addUnit(this.bottom),
  58 + right: uni.$u.addUnit(this.right),
  59 + width: '40px',
  60 + height: '40px',
  61 + position: 'fixed',
  62 + zIndex: 10,
  63 + }
  64 + return style
  65 + },
  66 + show() {
  67 + return uni.$u.getPx(this.scrollTop) > uni.$u.getPx(this.top)
  68 + },
  69 + contentStyle() {
  70 + const style = {}
  71 + let radius = 0
  72 + // 是否圆形
  73 + if(this.mode === 'circle') {
  74 + radius = '100px'
  75 + } else {
  76 + radius = '4px'
  77 + }
  78 + // 为了兼容安卓nvue,只能这么分开写
  79 + style.borderTopLeftRadius = radius
  80 + style.borderTopRightRadius = radius
  81 + style.borderBottomLeftRadius = radius
  82 + style.borderBottomRightRadius = radius
  83 + return uni.$u.deepMerge(style, uni.$u.addStyle(this.customStyle))
  84 + }
  85 + },
  86 + methods: {
  87 + backToTop() {
  88 + // #ifdef APP-NVUE
  89 + if (!this.$parent.$refs['u-back-top']) {
  90 + uni.$u.error(`nvue页面需要给页面最外层元素设置"ref='u-back-top'`)
  91 + }
  92 + dom.scrollToElement(this.$parent.$refs['u-back-top'], {
  93 + offset: 0
  94 + })
  95 + // #endif
  96 +
  97 + // #ifndef APP-NVUE
  98 + uni.pageScrollTo({
  99 + scrollTop: 0,
  100 + duration: this.duration
  101 + });
  102 + // #endif
  103 + this.$emit('click')
  104 + }
  105 + }
  106 + }
  107 +</script>
  108 +
  109 +<style lang="scss" scoped>
  110 + @import '../../libs/css/components.scss';
  111 + $u-back-top-flex:1 !default;
  112 + $u-back-top-height:100% !default;
  113 + $u-back-top-background-color:#E1E1E1 !default;
  114 + $u-back-top-tips-font-size:12px !default;
  115 + .u-back-top {
  116 + @include flex;
  117 + flex-direction: column;
  118 + align-items: center;
  119 + flex:$u-back-top-flex;
  120 + height: $u-back-top-height;
  121 + justify-content: center;
  122 + background-color: $u-back-top-background-color;
  123 +
  124 + &__tips {
  125 + font-size:$u-back-top-tips-font-size;
  126 + transform: scale(0.8);
  127 + }
  128 + }
  129 +</style>
  1 +export default {
  2 + props: {
  3 + // 是否显示圆点
  4 + isDot: {
  5 + type: Boolean,
  6 + default: uni.$u.props.badge.isDot
  7 + },
  8 + // 显示的内容
  9 + value: {
  10 + type: [Number, String],
  11 + default: uni.$u.props.badge.value
  12 + },
  13 + // 是否显示
  14 + show: {
  15 + type: Boolean,
  16 + default: uni.$u.props.badge.show
  17 + },
  18 + // 最大值,超过最大值会显示 '{max}+'
  19 + max: {
  20 + type: [Number, String],
  21 + default: uni.$u.props.badge.max
  22 + },
  23 + // 主题类型,error|warning|success|primary
  24 + type: {
  25 + type: String,
  26 + default: uni.$u.props.badge.type
  27 + },
  28 + // 当数值为 0 时,是否展示 Badge
  29 + showZero: {
  30 + type: Boolean,
  31 + default: uni.$u.props.badge.showZero
  32 + },
  33 + // 背景颜色,优先级比type高,如设置,type参数会失效
  34 + bgColor: {
  35 + type: [String, null],
  36 + default: uni.$u.props.badge.bgColor
  37 + },
  38 + // 字体颜色
  39 + color: {
  40 + type: [String, null],
  41 + default: uni.$u.props.badge.color
  42 + },
  43 + // 徽标形状,circle-四角均为圆角,horn-左下角为直角
  44 + shape: {
  45 + type: String,
  46 + default: uni.$u.props.badge.shape
  47 + },
  48 + // 设置数字的显示方式,overflow|ellipsis|limit
  49 + // overflow会根据max字段判断,超出显示`${max}+`
  50 + // ellipsis会根据max判断,超出显示`${max}...`
  51 + // limit会依据1000作为判断条件,超出1000,显示`${value/1000}K`,比如2.2k、3.34w,最多保留2位小数
  52 + numberType: {
  53 + type: String,
  54 + default: uni.$u.props.badge.numberType
  55 + },
  56 + // 设置badge的位置偏移,格式为 [x, y],也即设置的为top和right的值,absolute为true时有效
  57 + offset: {
  58 + type: Array,
  59 + default: uni.$u.props.badge.offset
  60 + },
  61 + // 是否反转背景和字体颜色
  62 + inverted: {
  63 + type: Boolean,
  64 + default: uni.$u.props.badge.inverted
  65 + },
  66 + // 是否绝对定位
  67 + absolute: {
  68 + type: Boolean,
  69 + default: uni.$u.props.badge.absolute
  70 + }
  71 + }
  72 +}
  1 +<template>
  2 + <text
  3 + v-if="show && ((Number(value) === 0 ? showZero : true) || isDot)"
  4 + :class="[isDot ? 'u-badge--dot' : 'u-badge--not-dot', inverted && 'u-badge--inverted', shape === 'horn' && 'u-badge--horn', `u-badge--${type}${inverted ? '--inverted' : ''}`]"
  5 + :style="[$u.addStyle(customStyle), badgeStyle]"
  6 + class="u-badge"
  7 + >{{ isDot ? '' :showValue }}</text>
  8 +</template>
  9 +
  10 +<script>
  11 + import props from './props.js';
  12 + /**
  13 + * badge 徽标数
  14 + * @description 该组件一般用于图标右上角显示未读的消息数量,提示用户点击,有圆点和圆包含文字两种形式。
  15 + * @tutorial https://uviewui.com/components/badge.html
  16 + *
  17 + * @property {Boolean} isDot 是否显示圆点 (默认 false )
  18 + * @property {String | Number} value 显示的内容
  19 + * @property {Boolean} show 是否显示 (默认 true )
  20 + * @property {String | Number} max 最大值,超过最大值会显示 '{max}+' (默认999)
  21 + * @property {String} type 主题类型,error|warning|success|primary (默认 'error' )
  22 + * @property {Boolean} showZero 当数值为 0 时,是否展示 Badge (默认 false )
  23 + * @property {String} bgColor 背景颜色,优先级比type高,如设置,type参数会失效
  24 + * @property {String} color 字体颜色 (默认 '#ffffff' )
  25 + * @property {String} shape 徽标形状,circle-四角均为圆角,horn-左下角为直角 (默认 'circle' )
  26 + * @property {String} numberType 设置数字的显示方式,overflow|ellipsis|limit (默认 'overflow' )
  27 + * @property {Array}} offset 设置badge的位置偏移,格式为 [x, y],也即设置的为top和right的值,absolute为true时有效
  28 + * @property {Boolean} inverted 是否反转背景和字体颜色(默认 false )
  29 + * @property {Boolean} absolute 是否绝对定位(默认 false )
  30 + * @property {Object} customStyle 定义需要用到的外部样式
  31 + * @example <u-badge :type="type" :count="count"></u-badge>
  32 + */
  33 + export default {
  34 + name: 'u-badge',
  35 + mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
  36 + computed: {
  37 + // 是否将badge中心与父组件右上角重合
  38 + boxStyle() {
  39 + let style = {};
  40 + return style;
  41 + },
  42 + // 整个组件的样式
  43 + badgeStyle() {
  44 + const style = {}
  45 + if(this.color) {
  46 + style.color = this.color
  47 + }
  48 + if (this.bgColor && !this.inverted) {
  49 + style.backgroundColor = this.bgColor
  50 + }
  51 + if (this.absolute) {
  52 + style.position = 'absolute'
  53 + // 如果有设置offset参数
  54 + if(this.offset.length) {
  55 + // top和right分为为offset的第一个和第二个值,如果没有第二个值,则right等于top
  56 + const top = this.offset[0]
  57 + const right = this.offset[1] || top
  58 + style.top = uni.$u.addUnit(top)
  59 + style.right = uni.$u.addUnit(right)
  60 + }
  61 + }
  62 + return style
  63 + },
  64 + showValue() {
  65 + switch (this.numberType) {
  66 + case "overflow":
  67 + return Number(this.value) > Number(this.max) ? this.max + "+" : this.value
  68 + break;
  69 + case "ellipsis":
  70 + return Number(this.value) > Number(this.max) ? "..." : this.value
  71 + break;
  72 + case "limit":
  73 + return Number(this.value) > 999 ? Number(this.value) >= 9999 ?
  74 + Math.floor(this.value / 1e4 * 100) / 100 + "w" : Math.floor(this.value /
  75 + 1e3 * 100) / 100 + "k" : this.value
  76 + break;
  77 + default:
  78 + return Number(this.value)
  79 + }
  80 + },
  81 + }
  82 + }
  83 +</script>
  84 +
  85 +<style lang="scss" scoped>
  86 + @import "../../libs/css/components.scss";
  87 +
  88 + $u-badge-primary: $u-primary !default;
  89 + $u-badge-error: $u-error !default;
  90 + $u-badge-success: $u-success !default;
  91 + $u-badge-info: $u-info !default;
  92 + $u-badge-warning: $u-warning !default;
  93 + $u-badge-dot-radius: 100px !default;
  94 + $u-badge-dot-size: 8px !default;
  95 + $u-badge-dot-right: 4px !default;
  96 + $u-badge-dot-top: 0 !default;
  97 + $u-badge-text-font-size: 11px !default;
  98 + $u-badge-text-right: 10px !default;
  99 + $u-badge-text-padding: 2px 5px !default;
  100 + $u-badge-text-align: center !default;
  101 + $u-badge-text-color: #FFFFFF !default;
  102 +
  103 + .u-badge {
  104 + border-top-right-radius: $u-badge-dot-radius;
  105 + border-top-left-radius: $u-badge-dot-radius;
  106 + border-bottom-left-radius: $u-badge-dot-radius;
  107 + border-bottom-right-radius: $u-badge-dot-radius;
  108 + @include flex;
  109 + line-height: $u-badge-text-font-size;
  110 + text-align: $u-badge-text-align;
  111 + font-size: $u-badge-text-font-size;
  112 + color: $u-badge-text-color;
  113 +
  114 + &--dot {
  115 + height: $u-badge-dot-size;
  116 + width: $u-badge-dot-size;
  117 + }
  118 +
  119 + &--inverted {
  120 + font-size: 13px;
  121 + }
  122 +
  123 + &--not-dot {
  124 + padding: $u-badge-text-padding;
  125 + }
  126 +
  127 + &--horn {
  128 + border-bottom-left-radius: 0;
  129 + }
  130 +
  131 + &--primary {
  132 + background-color: $u-badge-primary;
  133 + }
  134 +
  135 + &--primary--inverted {
  136 + color: $u-badge-primary;
  137 + }
  138 +
  139 + &--error {
  140 + background-color: $u-badge-error;
  141 + }
  142 +
  143 + &--error--inverted {
  144 + color: $u-badge-error;
  145 + }
  146 +
  147 + &--success {
  148 + background-color: $u-badge-success;
  149 + }
  150 +
  151 + &--success--inverted {
  152 + color: $u-badge-success;
  153 + }
  154 +
  155 + &--info {
  156 + background-color: $u-badge-info;
  157 + }
  158 +
  159 + &--info--inverted {
  160 + color: $u-badge-info;
  161 + }
  162 +
  163 + &--warning {
  164 + background-color: $u-badge-warning;
  165 + }
  166 +
  167 + &--warning--inverted {
  168 + color: $u-badge-warning;
  169 + }
  170 + }
  171 +</style>
  1 +$u-button-active-opacity:0.75 !default;
  2 +$u-button-loading-text-margin-left:4px !default;
  3 +$u-button-text-color: #FFFFFF !default;
  4 +$u-button-text-plain-error-color:$u-error !default;
  5 +$u-button-text-plain-warning-color:$u-warning !default;
  6 +$u-button-text-plain-success-color:$u-success !default;
  7 +$u-button-text-plain-info-color:$u-info !default;
  8 +$u-button-text-plain-primary-color:$u-primary !default;
  9 +.u-button {
  10 + &--active {
  11 + opacity: $u-button-active-opacity;
  12 + }
  13 +
  14 + &--active--plain {
  15 + background-color: rgb(217, 217, 217);
  16 + }
  17 +
  18 + &__loading-text {
  19 + margin-left:$u-button-loading-text-margin-left;
  20 + }
  21 +
  22 + &__text,
  23 + &__loading-text {
  24 + color:$u-button-text-color;
  25 + }
  26 +
  27 + &__text--plain--error {
  28 + color:$u-button-text-plain-error-color;
  29 + }
  30 +
  31 + &__text--plain--warning {
  32 + color:$u-button-text-plain-warning-color;
  33 + }
  34 +
  35 + &__text--plain--success{
  36 + color:$u-button-text-plain-success-color;
  37 + }
  38 +
  39 + &__text--plain--info {
  40 + color:$u-button-text-plain-info-color;
  41 + }
  42 +
  43 + &__text--plain--primary {
  44 + color:$u-button-text-plain-primary-color;
  45 + }
  46 +}
  1 +/*
  2 + * @Author : LQ
  3 + * @Description :
  4 + * @version : 1.0
  5 + * @Date : 2021-08-16 10:04:04
  6 + * @LastAuthor : LQ
  7 + * @lastTime : 2021-08-16 10:04:24
  8 + * @FilePath : /u-view2.0/uview-ui/components/u-button/props.js
  9 + */
  10 +export default {
  11 + props: {
  12 + // 是否细边框
  13 + hairline: {
  14 + type: Boolean,
  15 + default: uni.$u.props.button.hairline
  16 + },
  17 + // 按钮的预置样式,info,primary,error,warning,success
  18 + type: {
  19 + type: String,
  20 + default: uni.$u.props.button.type
  21 + },
  22 + // 按钮尺寸,large,normal,small,mini
  23 + size: {
  24 + type: String,
  25 + default: uni.$u.props.button.size
  26 + },
  27 + // 按钮形状,circle(两边为半圆),square(带圆角)
  28 + shape: {
  29 + type: String,
  30 + default: uni.$u.props.button.shape
  31 + },
  32 + // 按钮是否镂空
  33 + plain: {
  34 + type: Boolean,
  35 + default: uni.$u.props.button.plain
  36 + },
  37 + // 是否禁止状态
  38 + disabled: {
  39 + type: Boolean,
  40 + default: uni.$u.props.button.disabled
  41 + },
  42 + // 是否加载中
  43 + loading: {
  44 + type: Boolean,
  45 + default: uni.$u.props.button.loading
  46 + },
  47 + // 加载中提示文字
  48 + loadingText: {
  49 + type: [String, Number],
  50 + default: uni.$u.props.button.loadingText
  51 + },
  52 + // 加载状态图标类型
  53 + loadingMode: {
  54 + type: String,
  55 + default: uni.$u.props.button.loadingMode
  56 + },
  57 + // 加载图标大小
  58 + loadingSize: {
  59 + type: [String, Number],
  60 + default: uni.$u.props.button.loadingSize
  61 + },
  62 + // 开放能力,具体请看uniapp稳定关于button组件部分说明
  63 + // https://uniapp.dcloud.io/component/button
  64 + openType: {
  65 + type: String,
  66 + default: uni.$u.props.button.openType
  67 + },
  68 + // 用于 <form> 组件,点击分别会触发 <form> 组件的 submit/reset 事件
  69 + // 取值为submit(提交表单),reset(重置表单)
  70 + formType: {
  71 + type: String,
  72 + default: uni.$u.props.button.formType
  73 + },
  74 + // 打开 APP 时,向 APP 传递的参数,open-type=launchApp时有效
  75 + // 只微信小程序、QQ小程序有效
  76 + appParameter: {
  77 + type: String,
  78 + default: uni.$u.props.button.appParameter
  79 + },
  80 + // 指定是否阻止本节点的祖先节点出现点击态,微信小程序有效
  81 + hoverStopPropagation: {
  82 + type: Boolean,
  83 + default: uni.$u.props.button.hoverStopPropagation
  84 + },
  85 + // 指定返回用户信息的语言,zh_CN 简体中文,zh_TW 繁体中文,en 英文。只微信小程序有效
  86 + lang: {
  87 + type: String,
  88 + default: uni.$u.props.button.lang
  89 + },
  90 + // 会话来源,open-type="contact"时有效。只微信小程序有效
  91 + sessionFrom: {
  92 + type: String,
  93 + default: uni.$u.props.button.sessionFrom
  94 + },
  95 + // 会话内消息卡片标题,open-type="contact"时有效
  96 + // 默认当前标题,只微信小程序有效
  97 + sendMessageTitle: {
  98 + type: String,
  99 + default: uni.$u.props.button.sendMessageTitle
  100 + },
  101 + // 会话内消息卡片点击跳转小程序路径,open-type="contact"时有效
  102 + // 默认当前分享路径,只微信小程序有效
  103 + sendMessagePath: {
  104 + type: String,
  105 + default: uni.$u.props.button.sendMessagePath
  106 + },
  107 + // 会话内消息卡片图片,open-type="contact"时有效
  108 + // 默认当前页面截图,只微信小程序有效
  109 + sendMessageImg: {
  110 + type: String,
  111 + default: uni.$u.props.button.sendMessageImg
  112 + },
  113 + // 是否显示会话内消息卡片,设置此参数为 true,用户进入客服会话会在右下角显示"可能要发送的小程序"提示,
  114 + // 用户点击后可以快速发送小程序消息,open-type="contact"时有效
  115 + showMessageCard: {
  116 + type: Boolean,
  117 + default: uni.$u.props.button.showMessageCard
  118 + },
  119 + // 额外传参参数,用于小程序的data-xxx属性,通过target.dataset.name获取
  120 + dataName: {
  121 + type: String,
  122 + default: uni.$u.props.button.dataName
  123 + },
  124 + // 节流,一定时间内只能触发一次
  125 + throttleTime: {
  126 + type: [String, Number],
  127 + default: uni.$u.props.button.throttleTime
  128 + },
  129 + // 按住后多久出现点击态,单位毫秒
  130 + hoverStartTime: {
  131 + type: [String, Number],
  132 + default: uni.$u.props.button.hoverStartTime
  133 + },
  134 + // 手指松开后点击态保留时间,单位毫秒
  135 + hoverStayTime: {
  136 + type: [String, Number],
  137 + default: uni.$u.props.button.hoverStayTime
  138 + },
  139 + // 按钮文字,之所以通过props传入,是因为slot传入的话
  140 + // nvue中无法控制文字的样式
  141 + text: {
  142 + type: [String, Number],
  143 + default: uni.$u.props.button.text
  144 + },
  145 + // 按钮图标
  146 + icon: {
  147 + type: String,
  148 + default: uni.$u.props.button.icon
  149 + },
  150 + // 按钮图标
  151 + iconColor: {
  152 + type: String,
  153 + default: uni.$u.props.button.icon
  154 + },
  155 + // 按钮颜色,支持传入linear-gradient渐变色
  156 + color: {
  157 + type: String,
  158 + default: uni.$u.props.button.color
  159 + }
  160 + }
  161 +}
  1 +<template>
  2 + <!-- #ifndef APP-NVUE -->
  3 + <button
  4 + :hover-start-time="Number(hoverStartTime)"
  5 + :hover-stay-time="Number(hoverStayTime)"
  6 + :form-type="formType"
  7 + :open-type="openType"
  8 + :app-parameter="appParameter"
  9 + :hover-stop-propagation="hoverStopPropagation"
  10 + :send-message-title="sendMessageTitle"
  11 + :send-message-path="sendMessagePath"
  12 + :lang="lang"
  13 + :data-name="dataName"
  14 + :session-from="sessionFrom"
  15 + :send-message-img="sendMessageImg"
  16 + :show-message-card="showMessageCard"
  17 + @getphonenumber="getphonenumber"
  18 + @getuserinfo="getuserinfo"
  19 + @error="error"
  20 + @opensetting="opensetting"
  21 + @launchapp="launchapp"
  22 + :hover-class="!disabled && !loading ? 'u-button--active' : ''"
  23 + class="u-button u-reset-button"
  24 + :style="[baseColor, $u.addStyle(customStyle)]"
  25 + @tap="clickHandler"
  26 + :class="bemClass"
  27 + >
  28 + <template v-if="loading">
  29 + <u-loading-icon
  30 + :mode="loadingMode"
  31 + :size="textSize * 1.15"
  32 + :color="loadingColor"
  33 + ></u-loading-icon>
  34 + <text
  35 + class="u-button__loading-text"
  36 + :style="[{ fontSize: textSize + 'px' }]"
  37 + >{{ loadingText || text }}</text
  38 + >
  39 + </template>
  40 + <template v-else>
  41 + <u-icon
  42 + v-if="icon"
  43 + :name="icon"
  44 + :color="iconColorCom"
  45 + :size="textSize * 1.35"
  46 + :customStyle="{ marginRight: '2px' }"
  47 + ></u-icon>
  48 + <slot>
  49 + <text
  50 + class="u-button__text"
  51 + :style="[{ fontSize: textSize + 'px' }]"
  52 + >{{ text }}</text
  53 + >
  54 + </slot>
  55 + </template>
  56 + </button>
  57 + <!-- #endif -->
  58 +
  59 + <!-- #ifdef APP-NVUE -->
  60 + <view
  61 + :hover-start-time="Number(hoverStartTime)"
  62 + :hover-stay-time="Number(hoverStayTime)"
  63 + class="u-button"
  64 + :hover-class="
  65 + !disabled && !loading && !color && (plain || type === 'info')
  66 + ? 'u-button--active--plain'
  67 + : !disabled && !loading && !plain
  68 + ? 'u-button--active'
  69 + : ''
  70 + "
  71 + @tap="clickHandler"
  72 + :class="bemClass"
  73 + :style="[baseColor, $u.addStyle(customStyle)]"
  74 + >
  75 + <template v-if="loading">
  76 + <u-loading-icon
  77 + :mode="loadingMode"
  78 + :size="textSize * 1.15"
  79 + :color="loadingColor"
  80 + ></u-loading-icon>
  81 + <text
  82 + class="u-button__loading-text"
  83 + :style="[nvueTextStyle]"
  84 + :class="[plain && `u-button__text--plain--${type}`]"
  85 + >{{ loadingText || text }}</text
  86 + >
  87 + </template>
  88 + <template v-else>
  89 + <u-icon
  90 + v-if="icon"
  91 + :name="icon"
  92 + :color="iconColorCom"
  93 + :size="textSize * 1.35"
  94 + ></u-icon>
  95 + <text
  96 + class="u-button__text"
  97 + :style="[
  98 + {
  99 + marginLeft: icon ? '2px' : 0,
  100 + },
  101 + nvueTextStyle,
  102 + ]"
  103 + :class="[plain && `u-button__text--plain--${type}`]"
  104 + >{{ text }}</text
  105 + >
  106 + </template>
  107 + </view>
  108 + <!-- #endif -->
  109 +</template>
  110 +
  111 +<script>
  112 +import button from "../../libs/mixin/button.js";
  113 +import openType from "../../libs/mixin/openType.js";
  114 +import props from "./props.js";
  115 +/**
  116 + * button 按钮
  117 + * @description Button 按钮
  118 + * @tutorial https://www.uviewui.com/components/button.html
  119 + *
  120 + * @property {Boolean} hairline 是否显示按钮的细边框 (默认 true )
  121 + * @property {String} type 按钮的预置样式,info,primary,error,warning,success (默认 'info' )
  122 + * @property {String} size 按钮尺寸,large,normal,mini (默认 normal)
  123 + * @property {String} shape 按钮形状,circle(两边为半圆),square(带圆角) (默认 'square' )
  124 + * @property {Boolean} plain 按钮是否镂空,背景色透明 (默认 false)
  125 + * @property {Boolean} disabled 是否禁用 (默认 false)
  126 + * @property {Boolean} loading 按钮名称前是否带 loading 图标(App-nvue 平台,在 ios 上为雪花,Android上为圆圈) (默认 false)
  127 + * @property {String | Number} loadingText 加载中提示文字
  128 + * @property {String} loadingMode 加载状态图标类型 (默认 'spinner' )
  129 + * @property {String | Number} loadingSize 加载图标大小 (默认 15 )
  130 + * @property {String} openType 开放能力,具体请看uniapp稳定关于button组件部分说明
  131 + * @property {String} formType 用于 <form> 组件,点击分别会触发 <form> 组件的 submit/reset 事件
  132 + * @property {String} appParameter 打开 APP 时,向 APP 传递的参数,open-type=launchApp时有效 (注:只微信小程序、QQ小程序有效)
  133 + * @property {Boolean} hoverStopPropagation 指定是否阻止本节点的祖先节点出现点击态,微信小程序有效(默认 true )
  134 + * @property {String} lang 指定返回用户信息的语言,zh_CN 简体中文,zh_TW 繁体中文,en 英文(默认 en )
  135 + * @property {String} sessionFrom 会话来源,openType="contact"时有效
  136 + * @property {String} sendMessageTitle 会话内消息卡片标题,openType="contact"时有效
  137 + * @property {String} sendMessagePath 会话内消息卡片点击跳转小程序路径,openType="contact"时有效
  138 + * @property {String} sendMessageImg 会话内消息卡片图片,openType="contact"时有效
  139 + * @property {Boolean} showMessageCard 是否显示会话内消息卡片,设置此参数为 true,用户进入客服会话会在右下角显示"可能要发送的小程序"提示,用户点击后可以快速发送小程序消息,openType="contact"时有效(默认false)
  140 + * @property {String} dataName 额外传参参数,用于小程序的data-xxx属性,通过target.dataset.name获取
  141 + * @property {String | Number} throttleTime 节流,一定时间内只能触发一次 (默认 0 )
  142 + * @property {String | Number} hoverStartTime 按住后多久出现点击态,单位毫秒 (默认 0 )
  143 + * @property {String | Number} hoverStayTime 手指松开后点击态保留时间,单位毫秒 (默认 200 )
  144 + * @property {String | Number} text 按钮文字,之所以通过props传入,是因为slot传入的话(注:nvue中无法控制文字的样式)
  145 + * @property {String} icon 按钮图标
  146 + * @property {String} iconColor 按钮图标颜色
  147 + * @property {String} color 按钮颜色,支持传入linear-gradient渐变色
  148 + * @property {Object} customStyle 定义需要用到的外部样式
  149 + *
  150 + * @event {Function} click 非禁止并且非加载中,才能点击
  151 + * @event {Function} getphonenumber open-type="getPhoneNumber"时有效
  152 + * @event {Function} getuserinfo 用户点击该按钮时,会返回获取到的用户信息,从返回参数的detail中获取到的值同uni.getUserInfo
  153 + * @event {Function} error 当使用开放能力时,发生错误的回调
  154 + * @event {Function} opensetting 在打开授权设置页并关闭后回调
  155 + * @event {Function} launchapp 打开 APP 成功的回调
  156 + * @example <u-button>月落</u-button>
  157 + */
  158 +export default {
  159 + name: "u-button",
  160 + // #ifdef MP
  161 + mixins: [uni.$u.mpMixin, uni.$u.mixin, button, openType, props],
  162 + // #endif
  163 + // #ifndef MP
  164 + mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
  165 + // #endif
  166 + data() {
  167 + return {};
  168 + },
  169 + computed: {
  170 + // 生成bem风格的类名
  171 + bemClass() {
  172 + // this.bem为一个computed变量,在mixin中
  173 + if (!this.color) {
  174 + return this.bem(
  175 + "button",
  176 + ["type", "shape", "size"],
  177 + ["disabled", "plain", "hairline"]
  178 + );
  179 + } else {
  180 + // 由于nvue的原因,在有color参数时,不需要传入type,否则会生成type相关的类型,影响最终的样式
  181 + return this.bem(
  182 + "button",
  183 + ["shape", "size"],
  184 + ["disabled", "plain", "hairline"]
  185 + );
  186 + }
  187 + },
  188 + loadingColor() {
  189 + if (this.plain) {
  190 + // 如果有设置color值,则用color值,否则使用type主题颜色
  191 + return this.color
  192 + ? this.color
  193 + : uni.$u.config.color[`u-${this.type}`];
  194 + }
  195 + if (this.type === "info") {
  196 + return "#c9c9c9";
  197 + }
  198 + return "rgb(200, 200, 200)";
  199 + },
  200 + iconColorCom() {
  201 + // 如果是镂空状态,设置了color就用color值,否则使用主题颜色,
  202 + // u-icon的color能接受一个主题颜色的值
  203 + if (this.iconColor) return this.iconColor;
  204 + if (this.plain) {
  205 + return this.color ? this.color : this.type;
  206 + } else {
  207 + return this.type === "info" ? "#000000" : "#ffffff";
  208 + }
  209 + },
  210 + baseColor() {
  211 + let style = {};
  212 + if (this.color) {
  213 + // 针对自定义了color颜色的情况,镂空状态下,就是用自定义的颜色
  214 + style.color = this.plain ? this.color : "white";
  215 + if (!this.plain) {
  216 + // 非镂空,背景色使用自定义的颜色
  217 + style["background-color"] = this.color;
  218 + }
  219 + if (this.color.indexOf("gradient") !== -1) {
  220 + // 如果自定义的颜色为渐变色,不显示边框,以及通过backgroundImage设置渐变色
  221 + // weex文档说明可以写borderWidth的形式,为什么这里需要分开写?
  222 + // 因为weex是阿里巴巴为了部门业绩考核而做的你懂的东西,所以需要这么写才有效
  223 + style.borderTopWidth = 0;
  224 + style.borderRightWidth = 0;
  225 + style.borderBottomWidth = 0;
  226 + style.borderLeftWidth = 0;
  227 + if (!this.plain) {
  228 + style.backgroundImage = this.color;
  229 + }
  230 + } else {
  231 + // 非渐变色,则设置边框相关的属性
  232 + style.borderColor = this.color;
  233 + style.borderWidth = "1px";
  234 + style.borderStyle = "solid";
  235 + }
  236 + }
  237 + return style;
  238 + },
  239 + // nvue版本按钮的字体不会继承父组件的颜色,需要对每一个text组件进行单独的设置
  240 + nvueTextStyle() {
  241 + let style = {};
  242 + // 针对自定义了color颜色的情况,镂空状态下,就是用自定义的颜色
  243 + if (this.type === "info") {
  244 + style.color = "#323233";
  245 + }
  246 + if (this.color) {
  247 + style.color = this.plain ? this.color : "white";
  248 + }
  249 + style.fontSize = this.textSize + "px";
  250 + return style;
  251 + },
  252 + // 字体大小
  253 + textSize() {
  254 + let fontSize = 14,
  255 + { size } = this;
  256 + if (size === "large") fontSize = 16;
  257 + if (size === "normal") fontSize = 14;
  258 + if (size === "small") fontSize = 12;
  259 + if (size === "mini") fontSize = 10;
  260 + return fontSize;
  261 + },
  262 + },
  263 + methods: {
  264 + clickHandler() {
  265 + // 非禁止并且非加载中,才能点击
  266 + if (!this.disabled && !this.loading) {
  267 + // 进行节流控制,每this.throttle毫秒内,只在开始处执行
  268 + uni.$u.throttle(() => {
  269 + this.$emit("click");
  270 + }, this.throttleTime);
  271 + }
  272 + },
  273 + // 下面为对接uniapp官方按钮开放能力事件回调的对接
  274 + getphonenumber(res) {
  275 + this.$emit("getphonenumber", res);
  276 + },
  277 + getuserinfo(res) {
  278 + this.$emit("getuserinfo", res);
  279 + },
  280 + error(res) {
  281 + this.$emit("error", res);
  282 + },
  283 + opensetting(res) {
  284 + this.$emit("opensetting", res);
  285 + },
  286 + launchapp(res) {
  287 + this.$emit("launchapp", res);
  288 + },
  289 + },
  290 +};
  291 +</script>
  292 +
  293 +<style lang="scss" scoped>
  294 +@import "../../libs/css/components.scss";
  295 +
  296 +/* #ifndef APP-NVUE */
  297 +@import "./vue.scss";
  298 +/* #endif */
  299 +
  300 +/* #ifdef APP-NVUE */
  301 +@import "./nvue.scss";
  302 +/* #endif */
  303 +
  304 +$u-button-u-button-height: 40px !default;
  305 +$u-button-text-font-size: 15px !default;
  306 +$u-button-loading-text-font-size: 15px !default;
  307 +$u-button-loading-text-margin-left: 4px !default;
  308 +$u-button-large-width: 100% !default;
  309 +$u-button-large-height: 50px !default;
  310 +$u-button-normal-padding: 0 12px !default;
  311 +$u-button-large-padding: 0 15px !default;
  312 +$u-button-normal-font-size: 14px !default;
  313 +$u-button-small-min-width: 60px !default;
  314 +$u-button-small-height: 30px !default;
  315 +$u-button-small-padding: 0px 8px !default;
  316 +$u-button-mini-padding: 0px 8px !default;
  317 +$u-button-small-font-size: 12px !default;
  318 +$u-button-mini-height: 22px !default;
  319 +$u-button-mini-font-size: 10px !default;
  320 +$u-button-mini-min-width: 50px !default;
  321 +$u-button-disabled-opacity: 0.5 !default;
  322 +$u-button-info-color: #323233 !default;
  323 +$u-button-info-background-color: #fff !default;
  324 +$u-button-info-border-color: #ebedf0 !default;
  325 +$u-button-info-border-width: 1px !default;
  326 +$u-button-info-border-style: solid !default;
  327 +$u-button-success-color: #fff !default;
  328 +$u-button-success-background-color: $u-success !default;
  329 +$u-button-success-border-color: $u-button-success-background-color !default;
  330 +$u-button-success-border-width: 1px !default;
  331 +$u-button-success-border-style: solid !default;
  332 +$u-button-primary-color: #fff !default;
  333 +$u-button-primary-background-color: $u-primary !default;
  334 +$u-button-primary-border-color: $u-button-primary-background-color !default;
  335 +$u-button-primary-border-width: 1px !default;
  336 +$u-button-primary-border-style: solid !default;
  337 +$u-button-error-color: #fff !default;
  338 +$u-button-error-background-color: $u-error !default;
  339 +$u-button-error-border-color: $u-button-error-background-color !default;
  340 +$u-button-error-border-width: 1px !default;
  341 +$u-button-error-border-style: solid !default;
  342 +$u-button-warning-color: #fff !default;
  343 +$u-button-warning-background-color: $u-warning !default;
  344 +$u-button-warning-border-color: $u-button-warning-background-color !default;
  345 +$u-button-warning-border-width: 1px !default;
  346 +$u-button-warning-border-style: solid !default;
  347 +$u-button-block-width: 100% !default;
  348 +$u-button-circle-border-top-right-radius: 100px !default;
  349 +$u-button-circle-border-top-left-radius: 100px !default;
  350 +$u-button-circle-border-bottom-left-radius: 100px !default;
  351 +$u-button-circle-border-bottom-right-radius: 100px !default;
  352 +$u-button-square-border-top-right-radius: 3px !default;
  353 +$u-button-square-border-top-left-radius: 3px !default;
  354 +$u-button-square-border-bottom-left-radius: 3px !default;
  355 +$u-button-square-border-bottom-right-radius: 3px !default;
  356 +$u-button-icon-min-width: 1em !default;
  357 +$u-button-plain-background-color: #fff !default;
  358 +$u-button-hairline-border-width: 0.5px !default;
  359 +
  360 +.u-button {
  361 + height: $u-button-u-button-height;
  362 + position: relative;
  363 + align-items: center;
  364 + justify-content: center;
  365 + @include flex;
  366 + /* #ifndef APP-NVUE */
  367 + box-sizing: border-box;
  368 + /* #endif */
  369 + flex-direction: row;
  370 +
  371 + &__text {
  372 + font-size: $u-button-text-font-size;
  373 + }
  374 +
  375 + &__loading-text {
  376 + font-size: $u-button-loading-text-font-size;
  377 + margin-left: $u-button-loading-text-margin-left;
  378 + }
  379 +
  380 + &--large {
  381 + /* #ifndef APP-NVUE */
  382 + width: $u-button-large-width;
  383 + /* #endif */
  384 + height: $u-button-large-height;
  385 + padding: $u-button-large-padding;
  386 + }
  387 +
  388 + &--normal {
  389 + padding: $u-button-normal-padding;
  390 + font-size: $u-button-normal-font-size;
  391 + }
  392 +
  393 + &--small {
  394 + /* #ifndef APP-NVUE */
  395 + min-width: $u-button-small-min-width;
  396 + /* #endif */
  397 + height: $u-button-small-height;
  398 + padding: $u-button-small-padding;
  399 + font-size: $u-button-small-font-size;
  400 + }
  401 +
  402 + &--mini {
  403 + height: $u-button-mini-height;
  404 + font-size: $u-button-mini-font-size;
  405 + /* #ifndef APP-NVUE */
  406 + min-width: $u-button-mini-min-width;
  407 + /* #endif */
  408 + padding: $u-button-mini-padding;
  409 + }
  410 +
  411 + &--disabled {
  412 + opacity: $u-button-disabled-opacity;
  413 + }
  414 +
  415 + &--info {
  416 + color: $u-button-info-color;
  417 + background-color: $u-button-info-background-color;
  418 + border-color: $u-button-info-border-color;
  419 + border-width: $u-button-info-border-width;
  420 + border-style: $u-button-info-border-style;
  421 + }
  422 +
  423 + &--success {
  424 + color: $u-button-success-color;
  425 + background-color: $u-button-success-background-color;
  426 + border-color: $u-button-success-border-color;
  427 + border-width: $u-button-success-border-width;
  428 + border-style: $u-button-success-border-style;
  429 + }
  430 +
  431 + &--primary {
  432 + color: $u-button-primary-color;
  433 + background-color: $u-button-primary-background-color;
  434 + border-color: $u-button-primary-border-color;
  435 + border-width: $u-button-primary-border-width;
  436 + border-style: $u-button-primary-border-style;
  437 + }
  438 +
  439 + &--error {
  440 + color: $u-button-error-color;
  441 + background-color: $u-button-error-background-color;
  442 + border-color: $u-button-error-border-color;
  443 + border-width: $u-button-error-border-width;
  444 + border-style: $u-button-error-border-style;
  445 + }
  446 +
  447 + &--warning {
  448 + color: $u-button-warning-color;
  449 + background-color: $u-button-warning-background-color;
  450 + border-color: $u-button-warning-border-color;
  451 + border-width: $u-button-warning-border-width;
  452 + border-style: $u-button-warning-border-style;
  453 + }
  454 +
  455 + &--block {
  456 + @include flex;
  457 + width: $u-button-block-width;
  458 + }
  459 +
  460 + &--circle {
  461 + border-top-right-radius: $u-button-circle-border-top-right-radius;
  462 + border-top-left-radius: $u-button-circle-border-top-left-radius;
  463 + border-bottom-left-radius: $u-button-circle-border-bottom-left-radius;
  464 + border-bottom-right-radius: $u-button-circle-border-bottom-right-radius;
  465 + }
  466 +
  467 + &--square {
  468 + border-bottom-left-radius: $u-button-square-border-top-right-radius;
  469 + border-bottom-right-radius: $u-button-square-border-top-left-radius;
  470 + border-top-left-radius: $u-button-square-border-bottom-left-radius;
  471 + border-top-right-radius: $u-button-square-border-bottom-right-radius;
  472 + }
  473 +
  474 + &__icon {
  475 + /* #ifndef APP-NVUE */
  476 + min-width: $u-button-icon-min-width;
  477 + line-height: inherit !important;
  478 + vertical-align: top;
  479 + /* #endif */
  480 + }
  481 +
  482 + &--plain {
  483 + background-color: $u-button-plain-background-color;
  484 + }
  485 +
  486 + &--hairline {
  487 + border-width: $u-button-hairline-border-width !important;
  488 + }
  489 +}
  490 +</style>
  1 +// nvue下hover-class无效
  2 +$u-button-before-top:50% !default;
  3 +$u-button-before-left:50% !default;
  4 +$u-button-before-width:100% !default;
  5 +$u-button-before-height:100% !default;
  6 +$u-button-before-transform:translate(-50%, -50%) !default;
  7 +$u-button-before-opacity:0 !default;
  8 +$u-button-before-background-color:#000 !default;
  9 +$u-button-before-border-color:#000 !default;
  10 +$u-button-active-before-opacity:.15 !default;
  11 +$u-button-icon-margin-left:4px !default;
  12 +$u-button-plain-u-button-info-color:$u-info;
  13 +$u-button-plain-u-button-success-color:$u-success;
  14 +$u-button-plain-u-button-error-color:$u-error;
  15 +$u-button-plain-u-button-warning-color:$u-error;
  16 +
  17 +.u-button {
  18 + width: 100%;
  19 +
  20 + &__text {
  21 + white-space: nowrap;
  22 + line-height: 1;
  23 + }
  24 +
  25 + &:before {
  26 + position: absolute;
  27 + top:$u-button-before-top;
  28 + left:$u-button-before-left;
  29 + width:$u-button-before-width;
  30 + height:$u-button-before-height;
  31 + border: inherit;
  32 + border-radius: inherit;
  33 + transform:$u-button-before-transform;
  34 + opacity:$u-button-before-opacity;
  35 + content: " ";
  36 + background-color:$u-button-before-background-color;
  37 + border-color:$u-button-before-border-color;
  38 + }
  39 +
  40 + &--active {
  41 + &:before {
  42 + opacity: .15
  43 + }
  44 + }
  45 +
  46 + &__icon+&__text:not(:empty),
  47 + &__loading-text {
  48 + margin-left:$u-button-icon-margin-left;
  49 + }
  50 +
  51 + &--plain {
  52 + &.u-button--primary {
  53 + color: $u-primary;
  54 + }
  55 + }
  56 +
  57 + &--plain {
  58 + &.u-button--info {
  59 + color:$u-button-plain-u-button-info-color;
  60 + }
  61 + }
  62 +
  63 + &--plain {
  64 + &.u-button--success {
  65 + color:$u-button-plain-u-button-success-color;
  66 + }
  67 + }
  68 +
  69 + &--plain {
  70 + &.u-button--error {
  71 + color:$u-button-plain-u-button-error-color;
  72 + }
  73 + }
  74 +
  75 + &--plain {
  76 + &.u-button--warning {
  77 + color:$u-button-plain-u-button-warning-color;
  78 + }
  79 + }
  80 +}
  1 +<template>
  2 + <view class="u-calendar-header u-border-bottom">
  3 + <text
  4 + class="u-calendar-header__title"
  5 + v-if="showTitle"
  6 + >{{ title }}</text>
  7 + <text
  8 + class="u-calendar-header__subtitle"
  9 + v-if="showSubtitle"
  10 + >{{ subtitle }}</text>
  11 + <view class="u-calendar-header__weekdays">
  12 + <text class="u-calendar-header__weekdays__weekday">一</text>
  13 + <text class="u-calendar-header__weekdays__weekday">二</text>
  14 + <text class="u-calendar-header__weekdays__weekday">三</text>
  15 + <text class="u-calendar-header__weekdays__weekday">四</text>
  16 + <text class="u-calendar-header__weekdays__weekday">五</text>
  17 + <text class="u-calendar-header__weekdays__weekday">六</text>
  18 + <text class="u-calendar-header__weekdays__weekday">日</text>
  19 + </view>
  20 + </view>
  21 +</template>
  22 +
  23 +<script>
  24 + export default {
  25 + name: 'u-calendar-header',
  26 + mixins: [uni.$u.mpMixin, uni.$u.mixin],
  27 + props: {
  28 + // 标题
  29 + title: {
  30 + type: String,
  31 + default: ''
  32 + },
  33 + // 副标题
  34 + subtitle: {
  35 + type: String,
  36 + default: ''
  37 + },
  38 + // 是否显示标题
  39 + showTitle: {
  40 + type: Boolean,
  41 + default: true
  42 + },
  43 + // 是否显示副标题
  44 + showSubtitle: {
  45 + type: Boolean,
  46 + default: true
  47 + },
  48 + },
  49 + data() {
  50 + return {
  51 +
  52 + }
  53 + },
  54 + methods: {
  55 + name() {
  56 +
  57 + }
  58 + },
  59 + }
  60 +</script>
  61 +
  62 +<style lang="scss" scoped>
  63 + @import "../../libs/css/components.scss";
  64 +
  65 + .u-calendar-header {
  66 + padding-bottom: 4px;
  67 +
  68 + &__title {
  69 + font-size: 16px;
  70 + color: $u-main-color;
  71 + text-align: center;
  72 + height: 42px;
  73 + line-height: 42px;
  74 + font-weight: bold;
  75 + }
  76 +
  77 + &__subtitle {
  78 + font-size: 14px;
  79 + color: $u-main-color;
  80 + height: 40px;
  81 + text-align: center;
  82 + line-height: 40px;
  83 + font-weight: bold;
  84 + }
  85 +
  86 + &__weekdays {
  87 + @include flex;
  88 + justify-content: space-between;
  89 +
  90 + &__weekday {
  91 + font-size: 13px;
  92 + color: $u-main-color;
  93 + line-height: 30px;
  94 + flex: 1;
  95 + text-align: center;
  96 + }
  97 + }
  98 + }
  99 +</style>
  1 +<template>
  2 + <view class="u-calendar-month-wrapper" ref="u-calendar-month-wrapper">
  3 + <view v-for="(item, index) in months" :key="index" :class="[`u-calendar-month-${index}`]"
  4 + :ref="`u-calendar-month-${index}`" :id="`month-${index}`">
  5 + <text v-if="index !== 0" class="u-calendar-month__title">{{ item.year }}年{{ item.month }}月</text>
  6 + <view class="u-calendar-month__days">
  7 + <view v-if="showMark" class="u-calendar-month__days__month-mark-wrapper">
  8 + <text class="u-calendar-month__days__month-mark-wrapper__text">{{ item.month }}</text>
  9 + </view>
  10 + <view class="u-calendar-month__days__day" v-for="(item1, index1) in item.date" :key="index1"
  11 + :style="[dayStyle(index, index1, item1)]" @tap="clickHandler(index, index1, item1)"
  12 + :class="[item1.selected && 'u-calendar-month__days__day__select--selected']">
  13 + <view class="u-calendar-month__days__day__select" :style="[daySelectStyle(index, index1, item1)]">
  14 + <text class="u-calendar-month__days__day__select__info"
  15 + :class="[item1.disabled && 'u-calendar-month__days__day__select__info--disabled']"
  16 + :style="[textStyle(item1)]">{{ item1.day }}</text>
  17 + <text v-if="getBottomInfo(index, index1, item1)"
  18 + class="u-calendar-month__days__day__select__buttom-info"
  19 + :class="[item1.disabled && 'u-calendar-month__days__day__select__buttom-info--disabled']"
  20 + :style="[textStyle(item1)]">{{ getBottomInfo(index, index1, item1) }}</text>
  21 + <text v-if="item1.dot" class="u-calendar-month__days__day__select__dot"></text>
  22 + </view>
  23 + </view>
  24 + </view>
  25 + </view>
  26 + </view>
  27 +</template>
  28 +
  29 +<script>
  30 + // #ifdef APP-NVUE
  31 + // 由于nvue不支持百分比单位,需要查询宽度来计算每个日期的宽度
  32 + const dom = uni.requireNativePlugin('dom')
  33 + // #endif
  34 + import dayjs from '../../libs/util/dayjs.js';
  35 + export default {
  36 + name: 'u-calendar-month',
  37 + mixins: [uni.$u.mpMixin, uni.$u.mixin],
  38 + props: {
  39 + // 是否显示月份背景色
  40 + showMark: {
  41 + type: Boolean,
  42 + default: true
  43 + },
  44 + // 主题色,对底部按钮和选中日期有效
  45 + color: {
  46 + type: String,
  47 + default: '#3c9cff'
  48 + },
  49 + // 月份数据
  50 + months: {
  51 + type: Array,
  52 + default: () => []
  53 + },
  54 + // 日期选择类型
  55 + mode: {
  56 + type: String,
  57 + default: 'single'
  58 + },
  59 + // 日期行高
  60 + rowHeight: {
  61 + type: [String, Number],
  62 + default: 58
  63 + },
  64 + // mode=multiple时,最多可选多少个日期
  65 + maxCount: {
  66 + type: [String, Number],
  67 + default: Infinity
  68 + },
  69 + // mode=range时,第一个日期底部的提示文字
  70 + startText: {
  71 + type: String,
  72 + default: '开始'
  73 + },
  74 + // mode=range时,最后一个日期底部的提示文字
  75 + endText: {
  76 + type: String,
  77 + default: '结束'
  78 + },
  79 + // 默认选中的日期,mode为multiple或range是必须为数组格式
  80 + defaultDate: {
  81 + type: [Array, String, Date],
  82 + default: null
  83 + },
  84 + // 最小的可选日期
  85 + minDate: {
  86 + type: [String, Number],
  87 + default: 0
  88 + },
  89 + // 最大可选日期
  90 + maxDate: {
  91 + type: [String, Number],
  92 + default: 0
  93 + },
  94 + // 如果没有设置maxDate,则往后推多少个月
  95 + maxMonth: {
  96 + type: [String, Number],
  97 + default: 2
  98 + },
  99 + // 是否为只读状态,只读状态下禁止选择日期
  100 + readonly: {
  101 + type: Boolean,
  102 + default: uni.$u.props.calendar.readonly
  103 + },
  104 + // 日期区间最多可选天数,默认无限制,mode = range时有效
  105 + maxRange: {
  106 + type: [Number, String],
  107 + default: Infinity
  108 + },
  109 + // 范围选择超过最多可选天数时的提示文案,mode = range时有效
  110 + rangePrompt: {
  111 + type: String,
  112 + default: ''
  113 + },
  114 + // 范围选择超过最多可选天数时,是否展示提示文案,mode = range时有效
  115 + showRangePrompt: {
  116 + type: Boolean,
  117 + default: true
  118 + },
  119 + // 是否允许日期范围的起止时间为同一天,mode = range时有效
  120 + allowSameDay: {
  121 + type: Boolean,
  122 + default: false
  123 + }
  124 + },
  125 + data() {
  126 + return {
  127 + // 每个日期的宽度
  128 + width: 0,
  129 + // 当前选中的日期item
  130 + item: {},
  131 + selected: []
  132 + }
  133 + },
  134 + watch: {
  135 + selectedChange: {
  136 + immediate: true,
  137 + handler(n) {
  138 + this.setDefaultDate()
  139 + }
  140 + }
  141 + },
  142 + computed: {
  143 + // 多个条件的变化,会引起选中日期的变化,这里统一管理监听
  144 + selectedChange() {
  145 + return [this.minDate, this.maxDate, this.defaultDate]
  146 + },
  147 + dayStyle(index1, index2, item) {
  148 + return (index1, index2, item) => {
  149 + const style = {}
  150 + let week = item.week
  151 + // 不进行四舍五入的形式保留2位小数
  152 + const dayWidth = Number(parseFloat(this.width / 7).toFixed(3).slice(0, -1))
  153 + // 得出每个日期的宽度
  154 + // #ifdef APP-NVUE
  155 + style.width = uni.$u.addUnit(dayWidth)
  156 + // #endif
  157 + style.height = uni.$u.addUnit(this.rowHeight)
  158 + if (index2 === 0) {
  159 + // 获取当前为星期几,如果为0,则为星期天,减一为每月第一天时,需要向左偏移的item个数
  160 + week = (week === 0 ? 7 : week) - 1
  161 + style.marginLeft = uni.$u.addUnit(week * dayWidth)
  162 + }
  163 + if (this.mode === 'range') {
  164 + // 之所以需要这么写,是因为DCloud公司的iOS客户端的开发者能力有限导致的bug
  165 + style.paddingLeft = 0
  166 + style.paddingRight = 0
  167 + style.paddingBottom = 0
  168 + style.paddingTop = 0
  169 + }
  170 + return style
  171 + }
  172 + },
  173 + daySelectStyle() {
  174 + return (index1, index2, item) => {
  175 + let date = dayjs(item.date).format("YYYY-MM-DD"),
  176 + style = {}
  177 + // 判断date是否在selected数组中,因为月份可能会需要补0,所以使用dateSame判断,而不用数组的includes判断
  178 + if (this.selected.some(item => this.dateSame(item, date))) {
  179 + style.backgroundColor = this.color
  180 + }
  181 + if (this.mode === 'single') {
  182 + if (date === this.selected[0]) {
  183 + // 因为需要对nvue的兼容,只能这么写,无法缩写,也无法通过类名控制等等
  184 + style.borderTopLeftRadius = '3px'
  185 + style.borderBottomLeftRadius = '3px'
  186 + style.borderTopRightRadius = '3px'
  187 + style.borderBottomRightRadius = '3px'
  188 + }
  189 + } else if (this.mode === 'range') {
  190 + if (this.selected.length >= 2) {
  191 + const len = this.selected.length - 1
  192 + // 第一个日期设置左上角和左下角的圆角
  193 + if (this.dateSame(date, this.selected[0])) {
  194 + style.borderTopLeftRadius = '3px'
  195 + style.borderBottomLeftRadius = '3px'
  196 + }
  197 + // 最后一个日期设置右上角和右下角的圆角
  198 + if (this.dateSame(date, this.selected[len])) {
  199 + style.borderTopRightRadius = '3px'
  200 + style.borderBottomRightRadius = '3px'
  201 + }
  202 + // 处于第一和最后一个之间的日期,背景色设置为浅色,通过将对应颜色进行等分,再取其尾部的颜色值
  203 + if (dayjs(date).isAfter(dayjs(this.selected[0])) && dayjs(date).isBefore(dayjs(this
  204 + .selected[len]))) {
  205 + style.backgroundColor = uni.$u.colorGradient(this.color, '#ffffff', 100)[90]
  206 + // 增加一个透明度,让范围区间的背景色也能看到底部的mark水印字符
  207 + style.opacity = 0.7
  208 + }
  209 + } else if (this.selected.length === 1) {
  210 + // 之所以需要这么写,是因为DCloud公司的iOS客户端的开发者能力有限导致的bug
  211 + // 进行还原操作,否则在nvue的iOS,uni-app有bug,会导致诡异的表现
  212 + style.borderTopLeftRadius = '3px'
  213 + style.borderBottomLeftRadius = '3px'
  214 + }
  215 + } else {
  216 + if (this.selected.some(item => this.dateSame(item, date))) {
  217 + style.borderTopLeftRadius = '3px'
  218 + style.borderBottomLeftRadius = '3px'
  219 + style.borderTopRightRadius = '3px'
  220 + style.borderBottomRightRadius = '3px'
  221 + }
  222 + }
  223 + return style
  224 + }
  225 + },
  226 + // 某个日期是否被选中
  227 + textStyle() {
  228 + return (item) => {
  229 + const date = dayjs(item.date).format("YYYY-MM-DD"),
  230 + style = {}
  231 + // 选中的日期,提示文字设置白色
  232 + if (this.selected.some(item => this.dateSame(item, date))) {
  233 + style.color = '#ffffff'
  234 + }
  235 + if (this.mode === 'range') {
  236 + const len = this.selected.length - 1
  237 + // 如果是范围选择模式,第一个和最后一个之间的日期,文字颜色设置为高亮的主题色
  238 + if (dayjs(date).isAfter(dayjs(this.selected[0])) && dayjs(date).isBefore(dayjs(this
  239 + .selected[len]))) {
  240 + style.color = this.color
  241 + }
  242 + }
  243 + return style
  244 + }
  245 + },
  246 + // 获取底部的提示文字
  247 + getBottomInfo() {
  248 + return (index1, index2, item) => {
  249 + const date = dayjs(item.date).format("YYYY-MM-DD")
  250 + const bottomInfo = item.bottomInfo
  251 + // 当为日期范围模式时,且选择的日期个数大于0时
  252 + if (this.mode === 'range' && this.selected.length > 0) {
  253 + if (this.selected.length === 1) {
  254 + // 选择了一个日期时,如果当前日期为数组中的第一个日期,则显示底部文字为“开始”
  255 + if (this.dateSame(date, this.selected[0])) return this.startText
  256 + else return bottomInfo
  257 + } else {
  258 + const len = this.selected.length - 1
  259 + // 如果数组中的日期大于2个时,第一个和最后一个显示为开始和结束日期
  260 + if (this.dateSame(date, this.selected[0]) && this.dateSame(date, this.selected[1]) &&
  261 + len === 1) {
  262 + // 如果长度为2,且第一个等于第二个日期,则提示语放在同一个item中
  263 + return `${this.startText}/${this.endText}`
  264 + } else if (this.dateSame(date, this.selected[0])) {
  265 + return this.startText
  266 + } else if (this.dateSame(date, this.selected[len])) {
  267 + return this.endText
  268 + } else {
  269 + return bottomInfo
  270 + }
  271 + }
  272 + } else {
  273 + return bottomInfo
  274 + }
  275 + }
  276 + }
  277 + },
  278 + mounted() {
  279 + this.init()
  280 + },
  281 + methods: {
  282 + init() {
  283 + // 初始化默认选中
  284 + this.$emit('monthSelected', this.selected)
  285 + this.$nextTick(() => {
  286 + // 这里需要另一个延时,因为获取宽度后,会进行月份数据渲染,只有渲染完成之后,才有真正的高度
  287 + // 因为nvue下,$nextTick并不是100%可靠的
  288 + uni.$u.sleep(10).then(() => {
  289 + this.getWrapperWidth()
  290 + this.getMonthRect()
  291 + })
  292 + })
  293 + },
  294 + // 判断两个日期是否相等
  295 + dateSame(date1, date2) {
  296 + return dayjs(date1).isSame(dayjs(date2))
  297 + },
  298 + // 获取月份数据区域的宽度,因为nvue不支持百分比,所以无法通过css设置每个日期item的宽度
  299 + getWrapperWidth() {
  300 + // #ifdef APP-NVUE
  301 + dom.getComponentRect(this.$refs['u-calendar-month-wrapper'], res => {
  302 + this.width = res.size.width
  303 + })
  304 + // #endif
  305 + // #ifndef APP-NVUE
  306 + this.$uGetRect('.u-calendar-month-wrapper').then(size => {
  307 + this.width = size.width
  308 + })
  309 + // #endif
  310 + },
  311 + getMonthRect() {
  312 + // 获取每个月份数据的尺寸,用于父组件在scroll-view滚动事件中,监听当前滚动到了第几个月份
  313 + const promiseAllArr = this.months.map((item, index) => this.getMonthRectByPromise(
  314 + `u-calendar-month-${index}`))
  315 + // 一次性返回
  316 + Promise.all(promiseAllArr).then(
  317 + sizes => {
  318 + let height = 1
  319 + const topArr = []
  320 + for (let i = 0; i < this.months.length; i++) {
  321 + // 添加到months数组中,供scroll-view滚动事件中,判断当前滚动到哪个月份
  322 + topArr[i] = height
  323 + height += sizes[i].height
  324 + }
  325 + // 由于微信下,无法通过this.months[i].top的形式(引用类型)去修改父组件的month的top值,所以使用事件形式对外发出
  326 + this.$emit('updateMonthTop', topArr)
  327 + })
  328 + },
  329 + // 获取每个月份区域的尺寸
  330 + getMonthRectByPromise(el) {
  331 + // #ifndef APP-NVUE
  332 + // $uGetRect为uView自带的节点查询简化方法,详见文档介绍:https://www.uviewui.com/js/getRect.html
  333 + // 组件内部一般用this.$uGetRect,对外的为uni.$u.getRect,二者功能一致,名称不同
  334 + return new Promise(resolve => {
  335 + this.$uGetRect(`.${el}`).then(size => {
  336 + resolve(size)
  337 + })
  338 + })
  339 + // #endif
  340 +
  341 + // #ifdef APP-NVUE
  342 + // nvue下,使用dom模块查询元素高度
  343 + // 返回一个promise,让调用此方法的主体能使用then回调
  344 + return new Promise(resolve => {
  345 + dom.getComponentRect(this.$refs[el][0], res => {
  346 + resolve(res.size)
  347 + })
  348 + })
  349 + // #endif
  350 + },
  351 + // 点击某一个日期
  352 + clickHandler(index1, index2, item) {
  353 + if (this.readonly) {
  354 + return;
  355 + }
  356 + this.item = item
  357 + const date = dayjs(item.date).format("YYYY-MM-DD")
  358 + if (item.disabled) return
  359 + // 对上一次选择的日期数组进行深度克隆
  360 + let selected = uni.$u.deepClone(this.selected)
  361 + if (this.mode === 'single') {
  362 + // 单选情况下,让数组中的元素为当前点击的日期
  363 + selected = [date]
  364 + } else if (this.mode === 'multiple') {
  365 + if (selected.some(item => this.dateSame(item, date))) {
  366 + // 如果点击的日期已在数组中,则进行移除操作,也就是达到反选的效果
  367 + const itemIndex = selected.findIndex(item => item === date)
  368 + selected.splice(itemIndex, 1)
  369 + } else {
  370 + // 如果点击的日期不在数组中,且已有的长度小于总可选长度时,则添加到数组中去
  371 + if (selected.length < this.maxCount) selected.push(date)
  372 + }
  373 + } else {
  374 + // 选择区间形式
  375 + if (selected.length === 0 || selected.length >= 2) {
  376 + // 如果原来就为0或者大于2的长度,则当前点击的日期,就是开始日期
  377 + selected = [date]
  378 + } else if (selected.length === 1) {
  379 + // 如果已经选择了开始日期
  380 + const existsDate = selected[0]
  381 + // 如果当前选择的日期小于上一次选择的日期,则当前的日期定为开始日期
  382 + if (dayjs(date).isBefore(existsDate)) {
  383 + selected = [date]
  384 + } else if (dayjs(date).isAfter(existsDate)) {
  385 + // 当前日期减去最大可选的日期天数,如果大于起始时间,则进行提示
  386 + if(dayjs(dayjs(date).subtract(this.maxRange, 'day')).isAfter(dayjs(selected[0])) && this.showRangePrompt) {
  387 + if(this.rangePrompt) {
  388 + uni.$u.toast(this.rangePrompt)
  389 + } else {
  390 + uni.$u.toast(`选择天数不能超过 ${this.maxRange} 天`)
  391 + }
  392 + return
  393 + }
  394 + // 如果当前日期大于已有日期,将当前的添加到数组尾部
  395 + selected.push(date)
  396 + const startDate = selected[0]
  397 + const endDate = selected[1]
  398 + const arr = []
  399 + let i = 0
  400 + do {
  401 + // 将开始和结束日期之间的日期添加到数组中
  402 + arr.push(dayjs(startDate).add(i, 'day').format("YYYY-MM-DD"))
  403 + i++
  404 + // 累加的日期小于结束日期时,继续下一次的循环
  405 + } while (dayjs(startDate).add(i, 'day').isBefore(dayjs(endDate)))
  406 + // 为了一次性修改数组,避免computed中多次触发,这里才用arr变量一次性赋值的方式,同时将最后一个日期添加近来
  407 + arr.push(endDate)
  408 + selected = arr
  409 + } else {
  410 + // 选择区间时,只有一个日期的情况下,且不允许选择起止为同一天的话,不允许选择自己
  411 + if (selected[0] === date && !this.allowSameDay) return
  412 + selected.push(date)
  413 + }
  414 + }
  415 + }
  416 + this.setSelected(selected)
  417 + },
  418 + // 设置默认日期
  419 + setDefaultDate() {
  420 + if (!this.defaultDate) {
  421 + // 如果没有设置默认日期,则将当天日期设置为默认选中的日期
  422 + const selected = [dayjs().format("YYYY-MM-DD")]
  423 + return this.setSelected(selected, false)
  424 + }
  425 + let defaultDate = []
  426 + const minDate = this.minDate || dayjs().format("YYYY-MM-DD")
  427 + const maxDate = this.maxDate || dayjs(minDate).add(this.maxMonth - 1, 'month').format("YYYY-MM-DD")
  428 + if (this.mode === 'single') {
  429 + // 单选模式,可以是字符串或数组,Date对象等
  430 + if (!uni.$u.test.array(this.defaultDate)) {
  431 + defaultDate = [dayjs(this.defaultDate).format("YYYY-MM-DD")]
  432 + } else {
  433 + defaultDate = [this.defaultDate[0]]
  434 + }
  435 + } else {
  436 + // 如果为非数组,则不执行
  437 + if (!uni.$u.test.array(this.defaultDate)) return
  438 + defaultDate = this.defaultDate
  439 + }
  440 + // 过滤用户传递的默认数组,取出只在可允许最大值与最小值之间的元素
  441 + defaultDate = defaultDate.filter(item => {
  442 + return dayjs(item).isAfter(dayjs(minDate).subtract(1, 'day')) && dayjs(item).isBefore(dayjs(
  443 + maxDate).add(1, 'day'))
  444 + })
  445 + this.setSelected(defaultDate, false)
  446 + },
  447 + setSelected(selected, event = true) {
  448 + this.selected = selected
  449 + event && this.$emit('monthSelected', this.selected)
  450 + }
  451 + }
  452 + }
  453 +</script>
  454 +
  455 +<style lang="scss" scoped>
  456 + @import "../../libs/css/components.scss";
  457 +
  458 + .u-calendar-month-wrapper {
  459 + margin-top: 4px;
  460 + }
  461 +
  462 + .u-calendar-month {
  463 +
  464 + &__title {
  465 + font-size: 14px;
  466 + line-height: 42px;
  467 + height: 42px;
  468 + color: $u-main-color;
  469 + text-align: center;
  470 + font-weight: bold;
  471 + }
  472 +
  473 + &__days {
  474 + position: relative;
  475 + @include flex;
  476 + flex-wrap: wrap;
  477 +
  478 + &__month-mark-wrapper {
  479 + position: absolute;
  480 + top: 0;
  481 + bottom: 0;
  482 + left: 0;
  483 + right: 0;
  484 + @include flex;
  485 + justify-content: center;
  486 + align-items: center;
  487 +
  488 + &__text {
  489 + font-size: 155px;
  490 + color: rgba(231, 232, 234, 0.83);
  491 + }
  492 + }
  493 +
  494 + &__day {
  495 + @include flex;
  496 + padding: 2px;
  497 + /* #ifndef APP-NVUE */
  498 + // vue下使用css进行宽度计算,因为某些安卓机会无法进行js获取父元素宽度进行计算得出,会有偏移
  499 + width: calc(100% / 7);
  500 + box-sizing: border-box;
  501 + /* #endif */
  502 +
  503 + &__select {
  504 + flex: 1;
  505 + @include flex;
  506 + align-items: center;
  507 + justify-content: center;
  508 + position: relative;
  509 +
  510 + &__dot {
  511 + width: 7px;
  512 + height: 7px;
  513 + border-radius: 100px;
  514 + background-color: $u-error;
  515 + position: absolute;
  516 + top: 12px;
  517 + right: 7px;
  518 + }
  519 +
  520 + &__buttom-info {
  521 + color: $u-content-color;
  522 + text-align: center;
  523 + position: absolute;
  524 + bottom: 5px;
  525 + font-size: 10px;
  526 + text-align: center;
  527 + left: 0;
  528 + right: 0;
  529 +
  530 + &--selected {
  531 + color: #ffffff;
  532 + }
  533 +
  534 + &--disabled {
  535 + color: #cacbcd;
  536 + }
  537 + }
  538 +
  539 + &__info {
  540 + text-align: center;
  541 + font-size: 16px;
  542 +
  543 + &--selected {
  544 + color: #ffffff;
  545 + }
  546 +
  547 + &--disabled {
  548 + color: #cacbcd;
  549 + }
  550 + }
  551 +
  552 + &--selected {
  553 + background-color: $u-primary;
  554 + @include flex;
  555 + justify-content: center;
  556 + align-items: center;
  557 + flex: 1;
  558 + border-radius: 3px;
  559 + }
  560 +
  561 + &--range-selected {
  562 + opacity: 0.3;
  563 + border-radius: 0;
  564 + }
  565 +
  566 + &--range-start-selected {
  567 + border-top-right-radius: 0;
  568 + border-bottom-right-radius: 0;
  569 + }
  570 +
  571 + &--range-end-selected {
  572 + border-top-left-radius: 0;
  573 + border-bottom-left-radius: 0;
  574 + }
  575 + }
  576 + }
  577 + }
  578 + }
  579 +</style>
  1 +export default {
  2 + props: {
  3 + // 日历顶部标题
  4 + title: {
  5 + type: String,
  6 + default: uni.$u.props.calendar.title
  7 + },
  8 + // 是否显示标题
  9 + showTitle: {
  10 + type: Boolean,
  11 + default: uni.$u.props.calendar.showTitle
  12 + },
  13 + // 是否显示副标题
  14 + showSubtitle: {
  15 + type: Boolean,
  16 + default: uni.$u.props.calendar.showSubtitle
  17 + },
  18 + // 日期类型选择,single-选择单个日期,multiple-可以选择多个日期,range-选择日期范围
  19 + mode: {
  20 + type: String,
  21 + default: uni.$u.props.calendar.mode
  22 + },
  23 + // mode=range时,第一个日期底部的提示文字
  24 + startText: {
  25 + type: String,
  26 + default: uni.$u.props.calendar.startText
  27 + },
  28 + // mode=range时,最后一个日期底部的提示文字
  29 + endText: {
  30 + type: String,
  31 + default: uni.$u.props.calendar.endText
  32 + },
  33 + // 自定义列表
  34 + customList: {
  35 + type: Array,
  36 + default: uni.$u.props.calendar.customList
  37 + },
  38 + // 主题色,对底部按钮和选中日期有效
  39 + color: {
  40 + type: String,
  41 + default: uni.$u.props.calendar.color
  42 + },
  43 + // 最小的可选日期
  44 + minDate: {
  45 + type: [String, Number],
  46 + default: uni.$u.props.calendar.minDate
  47 + },
  48 + // 最大可选日期
  49 + maxDate: {
  50 + type: [String, Number],
  51 + default: uni.$u.props.calendar.maxDate
  52 + },
  53 + // 默认选中的日期,mode为multiple或range是必须为数组格式
  54 + defaultDate: {
  55 + type: [Array, String, Date, null],
  56 + default: uni.$u.props.calendar.defaultDate
  57 + },
  58 + // mode=multiple时,最多可选多少个日期
  59 + maxCount: {
  60 + type: [String, Number],
  61 + default: uni.$u.props.calendar.maxCount
  62 + },
  63 + // 日期行高
  64 + rowHeight: {
  65 + type: [String, Number],
  66 + default: uni.$u.props.calendar.rowHeight
  67 + },
  68 + // 日期格式化函数
  69 + formatter: {
  70 + type: [Function, null],
  71 + default: uni.$u.props.calendar.formatter
  72 + },
  73 + // 是否显示农历
  74 + showLunar: {
  75 + type: Boolean,
  76 + default: uni.$u.props.calendar.showLunar
  77 + },
  78 + // 是否显示月份背景色
  79 + showMark: {
  80 + type: Boolean,
  81 + default: uni.$u.props.calendar.showMark
  82 + },
  83 + // 确定按钮的文字
  84 + confirmText: {
  85 + type: String,
  86 + default: uni.$u.props.calendar.confirmText
  87 + },
  88 + // 确认按钮处于禁用状态时的文字
  89 + confirmDisabledText: {
  90 + type: String,
  91 + default: uni.$u.props.calendar.confirmDisabledText
  92 + },
  93 + // 是否显示日历弹窗
  94 + show: {
  95 + type: Boolean,
  96 + default: uni.$u.props.calendar.show
  97 + },
  98 + // 是否允许点击遮罩关闭日历
  99 + closeOnClickOverlay: {
  100 + type: Boolean,
  101 + default: uni.$u.props.calendar.closeOnClickOverlay
  102 + },
  103 + // 是否为只读状态,只读状态下禁止选择日期
  104 + readonly: {
  105 + type: Boolean,
  106 + default: uni.$u.props.calendar.readonly
  107 + },
  108 + // 是否展示确认按钮
  109 + showConfirm: {
  110 + type: Boolean,
  111 + default: uni.$u.props.calendar.showConfirm
  112 + },
  113 + // 日期区间最多可选天数,默认无限制,mode = range时有效
  114 + maxRange: {
  115 + type: [Number, String],
  116 + default: uni.$u.props.calendar.maxRange
  117 + },
  118 + // 范围选择超过最多可选天数时的提示文案,mode = range时有效
  119 + rangePrompt: {
  120 + type: String,
  121 + default: uni.$u.props.calendar.rangePrompt
  122 + },
  123 + // 范围选择超过最多可选天数时,是否展示提示文案,mode = range时有效
  124 + showRangePrompt: {
  125 + type: Boolean,
  126 + default: uni.$u.props.calendar.showRangePrompt
  127 + },
  128 + // 是否允许日期范围的起止时间为同一天,mode = range时有效
  129 + allowSameDay: {
  130 + type: Boolean,
  131 + default: uni.$u.props.calendar.allowSameDay
  132 + },
  133 + // 圆角值
  134 + round: {
  135 + type: [Boolean, String, Number],
  136 + default: uni.$u.props.calendar.round
  137 + },
  138 + // 最多展示月份数量
  139 + monthNum: {
  140 + type: [Number, String],
  141 + default: 3
  142 + }
  143 + }
  144 +}