更换banner组件,添加用户隐私协议链接

This commit is contained in:
zhouyanli
2026-06-26 10:07:44 +08:00
parent d0e80824d8
commit f19fb0d9d9
591 changed files with 79931 additions and 83 deletions

View File

@@ -0,0 +1,16 @@
// 为了给某些特殊场景使用和向后兼容,无需删除此文件(2020-06-20)
const color = {
primary: '#3c9cff',
info: '#909399',
default: '#909399',
warning: '#f9ae3d',
error: '#f56c6c',
success: '#5ac725',
mainColor: '#303133',
contentColor: '#606266',
tipsColor: '#909399',
lightColor: '#c0c4cc',
borderColor: '#e4e7ed'
}
export default color

View File

@@ -0,0 +1,58 @@
const version = '3'
// 开发环境才提示,生产环境不会提示
if (process.env.NODE_ENV === 'development') {
console.log(`\n %c uview-plus V${version} %c https://uview-plus.jiangruyi.com/ \n\n`, 'color: #ffffff; background: #3c9cff; padding:5px 0;', 'color: #3c9cff;background: #ffffff; padding:5px 0;');
}
export default {
v: version,
version,
// 主题名称
type: [
'primary',
'success',
'info',
'error',
'warning'
],
// 颜色部分,本来可以通过scss的:export导出供js使用,但是奈何nvue不支持
color: {
'u-primary': '#2979ff',
'u-warning': '#ff9900',
'u-success': '#19be6b',
'u-error': '#fa3534',
'u-info': '#909399',
'u-main-color': '#303133',
'u-content-color': '#606266',
'u-tips-color': '#909399',
'u-light-color': '#c0c4cc',
'up-primary': '#2979ff',
'up-warning': '#ff9900',
'up-success': '#19be6b',
'up-error': '#fa3534',
'up-info': '#909399',
'up-main-color': '#303133',
'up-content-color': '#606266',
'up-tips-color': '#909399',
'up-light-color': '#c0c4cc'
},
// 字体图标地址
iconUrl: 'https://at.alicdn.com/t/font_2225171_8kdcwk4po24.ttf',
// 自定义图标
customIcon: {
family: '',
url: ''
},
customIcons: {}, // 自定义图标与unicode对应关系
// 默认单位,可以通过配置为rpx,那么在用于传入组件大小参数为数值时,就默认为rpx
unit: 'px',
// 是否由运行时主题同步原生导航栏、页面背景、tabBar等全局UI
nativeThemeSync: false,
// 拦截器
interceptor: {
navbarLeftClick: null
},
// 只加载一次字体
loadFontOnce: false
}

View File

@@ -0,0 +1,220 @@
/**
* 此文件的作用为统一配置所有组件的props参数
* 借此用户可以全局覆盖组件的props默认值
* 无需在每个引入组件的页面中都配置一次
*/
import config from './config'
// 各个需要fixed的地方的z-index配置文件
import zIndex from './zIndex.js'
// 关于颜色的配置,特殊场景使用
import color from './color.js'
// http
import http from '../function/http.js'
import { shallowMerge } from '../function/index.js'
// 组件props
import ActionSheet from '../../components/u-action-sheet/actionSheet'
import Album from '../../components/u-album/album'
import Alert from '../../components/u-alert/alert'
import Avatar from '../../components/u-avatar/avatar'
import AvatarGroup from '../../components/u-avatar-group/avatarGroup'
import Backtop from '../../components/u-back-top/backtop'
import Badge from '../../components/u-badge/badge'
import Button from '../../components/u-button/button'
import Calendar from '../../components/u-calendar/calendar'
import CalendarStrip from '../../components/u-calendar-strip/calendarStrip'
import CarKeyboard from '../../components/u-car-keyboard/carKeyboard'
import Card from '../../components/u-card/card'
import Cell from '../../components/u-cell/cell'
import CellGroup from '../../components/u-cell-group/cellGroup'
import Checkbox from '../../components/u-checkbox/checkbox'
import CheckboxGroup from '../../components/u-checkbox-group/checkboxGroup'
import CircleProgress from '../../components/u-circle-progress/circleProgress'
import Code from '../../components/u-code/code'
import CodeInput from '../../components/u-code-input/codeInput'
import Col from '../../components/u-col/col'
import Collapse from '../../components/u-collapse/collapse'
import CollapseItem from '../../components/u-collapse-item/collapseItem'
import ColumnNotice from '../../components/u-column-notice/columnNotice'
import CountDown from '../../components/u-count-down/countDown'
import CountTo from '../../components/u-count-to/countTo'
import DatetimePicker from '../../components/u-datetime-picker/datetimePicker'
import Divider from '../../components/u-divider/divider'
import Empty from '../../components/u-empty/empty'
import Form from '../../components/u-form/form'
import FormItem from '../../components/u-form-item/formItem'
import Gap from '../../components/u-gap/gap'
import Guide from '../../components/u-guide/guide'
import Grid from '../../components/u-grid/grid'
import GridItem from '../../components/u-grid-item/gridItem'
import Icon from '../../components/u-icon/icon'
import Image from '../../components/u-image/image'
import IndexAnchor from '../../components/u-index-anchor/indexAnchor'
import IndexList from '../../components/u-index-list/indexList'
import Input from '../../components/u-input/input'
import Keyboard from '../../components/u-keyboard/keyboard'
import Line from '../../components/u-line/line'
import LineProgress from '../../components/u-line-progress/lineProgress'
import Link from '../../components/u-link/link'
import List from '../../components/u-list/list'
import ListItem from '../../components/u-list-item/listItem'
import LoadingIcon from '../../components/u-loading-icon/loadingIcon'
import LoadingPage from '../../components/u-loading-page/loadingPage'
import Loadmore from '../../components/u-loadmore/loadmore'
import Modal from '../../components/u-modal/modal'
import Navbar from '../../components/u-navbar/navbar'
import NoNetwork from '../../components/u-no-network/noNetwork'
import NoticeBar from '../../components/u-notice-bar/noticeBar'
import Notify from '../../components/u-notify/notify'
import NumberBox from '../../components/u-number-box/numberBox'
import NumberKeyboard from '../../components/u-number-keyboard/numberKeyboard'
import Overlay from '../../components/u-overlay/overlay'
import Parse from '../../components/u-parse/parse'
import Picker from '../../components/u-picker/picker'
import Popup from '../../components/u-popup/popup'
import Radio from '../../components/u-radio/radio'
import RadioGroup from '../../components/u-radio-group/radioGroup'
import Rate from '../../components/u-rate/rate'
import ReadMore from '../../components/u-read-more/readMore'
import Row from '../../components/u-row/row'
import RowNotice from '../../components/u-row-notice/rowNotice'
import ScrollList from '../../components/u-scroll-list/scrollList'
import Search from '../../components/u-search/search'
import Section from '../../components/u-section/section'
import Skeleton from '../../components/u-skeleton/skeleton'
import Slider from '../../components/u-slider/slider'
import StatusBar from '../../components/u-status-bar/statusBar'
import Steps from '../../components/u-steps/steps'
import StepsItem from '../../components/u-steps-item/stepsItem'
import Sticky from '../../components/u-sticky/sticky'
import Subsection from '../../components/u-subsection/subsection'
import SwipeAction from '../../components/u-swipe-action/swipeAction'
import SwipeActionItem from '../../components/u-swipe-action-item/swipeActionItem'
import Swiper from '../../components/u-swiper/swiper'
import SwipterIndicator from '../../components/u-swiper-indicator/swipterIndicator'
import Switch from '../../components/u-switch/switch'
import Tabbar from '../../components/u-tabbar/tabbar'
import TabbarItem from '../../components/u-tabbar-item/tabbarItem'
import Tabs from '../../components/u-tabs/tabs'
import Tag from '../../components/u-tag/tag'
import Text from '../../components/u-text/text'
import Textarea from '../../components/u-textarea/textarea'
import Toast from '../../components/u-toast/toast'
import Toolbar from '../../components/u-toolbar/toolbar'
import Tooltip from '../../components/u-tooltip/tooltip'
import Transition from '../../components/u-transition/transition'
import Upload from '../../components/u-upload/upload'
const props = {
...ActionSheet,
...Album,
...Alert,
...Avatar,
...AvatarGroup,
...Backtop,
...Badge,
...Button,
...Calendar,
...CalendarStrip,
...CarKeyboard,
...Card,
...Cell,
...CellGroup,
...Checkbox,
...CheckboxGroup,
...CircleProgress,
...Code,
...CodeInput,
...Col,
...Collapse,
...CollapseItem,
...ColumnNotice,
...CountDown,
...CountTo,
...DatetimePicker,
...Divider,
...Empty,
...Form,
...FormItem,
...Gap,
...Guide,
...Grid,
...GridItem,
...Icon,
...Image,
...IndexAnchor,
...IndexList,
...Input,
...Keyboard,
...Line,
...LineProgress,
...Link,
...List,
...ListItem,
...LoadingIcon,
...LoadingPage,
...Loadmore,
...Modal,
...Navbar,
...NoNetwork,
...NoticeBar,
...Notify,
...NumberBox,
...NumberKeyboard,
...Overlay,
...Parse,
...Picker,
...Popup,
...Radio,
...RadioGroup,
...Rate,
...ReadMore,
...Row,
...RowNotice,
...ScrollList,
...Search,
...Section,
...Skeleton,
...Slider,
...StatusBar,
...Steps,
...StepsItem,
...Sticky,
...Subsection,
...SwipeAction,
...SwipeActionItem,
...Swiper,
...SwipterIndicator,
...Switch,
...Tabbar,
...TabbarItem,
...Tabs,
...Tag,
...Text,
...Textarea,
...Toast,
...Toolbar,
...Tooltip,
...Transition,
...Upload
}
function setConfig(configs) {
shallowMerge(config, configs.config || {})
shallowMerge(props, configs.props || {})
shallowMerge(color, configs.color || {})
shallowMerge(zIndex, configs.zIndex || {})
}
// 初始化自定义配置
if (typeof uni !== 'undefined' && uni && uni.upuiParams) {
console.log('setting uview-plus')
let temp = uni.upuiParams()
if (temp.httpIns) {
temp.httpIns(http)
}
if (temp.options) {
setConfig(temp.options)
}
}
export default props

View File

@@ -0,0 +1,20 @@
// uniapp在H5中各API的z-index值如下:
/**
* actionsheet: 999
* modal: 999
* navigate: 998
* tabbar: 998
* toast: 999
*/
export default {
toast: 10090,
noNetwork: 10080,
// popup包含popup,actionsheet,keyboard,picker的值
popup: 10075,
mask: 10070,
navbar: 980,
topTips: 975,
sticky: 970,
indexListSticky: 965
}

View File

@@ -0,0 +1,311 @@
.u-primary-light {
color: $u-primary-light;
}
.u-warning-light {
color: $u-warning-light;
}
.u-success-light {
color: $u-success-light;
}
.u-error-light {
color: $u-error-light;
}
.u-info-light {
color: $u-info-light;
}
.u-primary-light-bg {
background-color: $u-primary-light;
}
.u-warning-light-bg {
background-color: $u-warning-light;
}
.u-success-light-bg {
background-color: $u-success-light;
}
.u-error-light-bg {
background-color: $u-error-light;
}
.u-info-light-bg {
background-color: $u-info-light;
}
.u-primary-dark {
color: $u-primary-dark;
}
.u-warning-dark {
color: $u-warning-dark;
}
.u-success-dark {
color: $u-success-dark;
}
.u-error-dark {
color: $u-error-dark;
}
.u-info-dark {
color: $u-info-dark;
}
.u-primary-dark-bg {
background-color: $u-primary-dark;
}
.u-warning-dark-bg {
background-color: $u-warning-dark;
}
.u-success-dark-bg {
background-color: $u-success-dark;
}
.u-error-dark-bg {
background-color: $u-error-dark;
}
.u-info-dark-bg {
background-color: $u-info-dark;
}
.u-primary-disabled {
color: $u-primary-disabled;
}
.u-warning-disabled {
color: $u-warning-disabled;
}
.u-success-disabled {
color: $u-success-disabled;
}
.u-error-disabled {
color: $u-error-disabled;
}
.u-info-disabled {
color: $u-info-disabled;
}
.u-primary {
color: $u-primary;
}
.u-warning {
color: $u-warning;
}
.u-success {
color: $u-success;
}
.u-error {
color: $u-error;
}
.u-info {
color: $u-info;
}
.u-primary-bg {
background-color: $u-primary;
}
.u-warning-bg {
background-color: $u-warning;
}
.u-success-bg {
background-color: $u-success;
}
.u-error-bg {
background-color: $u-error;
}
.u-info-bg {
background-color: $u-info;
}
.u-main-color {
color: $u-main-color;
}
.u-content-color {
color: $u-content-color;
}
.u-tips-color {
color: $u-tips-color;
}
.u-light-color {
color: $u-light-color;
}
.up-primary-light {
color: $u-primary-light;
}
.up-warning-light {
color: $u-warning-light;
}
.up-success-light {
color: $u-success-light;
}
.up-error-light {
color: $u-error-light;
}
.up-info-light {
color: $u-info-light;
}
.up-primary-light-bg {
background-color: $u-primary-light;
}
.up-warning-light-bg {
background-color: $u-warning-light;
}
.up-success-light-bg {
background-color: $u-success-light;
}
.up-error-light-bg {
background-color: $u-error-light;
}
.up-info-light-bg {
background-color: $u-info-light;
}
.up-primary-dark {
color: $u-primary-dark;
}
.up-warning-dark {
color: $u-warning-dark;
}
.up-success-dark {
color: $u-success-dark;
}
.up-error-dark {
color: $u-error-dark;
}
.up-info-dark {
color: $u-info-dark;
}
.up-primary-dark-bg {
background-color: $u-primary-dark;
}
.up-warning-dark-bg {
background-color: $u-warning-dark;
}
.up-success-dark-bg {
background-color: $u-success-dark;
}
.up-error-dark-bg {
background-color: $u-error-dark;
}
.up-info-dark-bg {
background-color: $u-info-dark;
}
.up-primary-disabled {
color: $u-primary-disabled;
}
.up-warning-disabled {
color: $u-warning-disabled;
}
.up-success-disabled {
color: $u-success-disabled;
}
.up-error-disabled {
color: $u-error-disabled;
}
.up-info-disabled {
color: $u-info-disabled;
}
.up-primary {
color: $u-primary;
}
.up-warning {
color: $u-warning;
}
.up-success {
color: $u-success;
}
.up-error {
color: $u-error;
}
.up-info {
color: $u-info;
}
.up-primary-bg {
background-color: $u-primary;
}
.up-warning-bg {
background-color: $u-warning;
}
.up-success-bg {
background-color: $u-success;
}
.up-error-bg {
background-color: $u-error;
}
.up-info-bg {
background-color: $u-info;
}
.up-main-color {
color: $u-main-color;
}
.up-content-color {
color: $u-content-color;
}
.up-tips-color {
color: $u-tips-color;
}
.up-light-color {
color: $u-light-color;
}

View File

@@ -0,0 +1,112 @@
// 超出行数,自动显示行尾省略号,最多5行
// 来自uview-plus的温馨提示:当您在控制台看到此报错,说明需要在App.vue的style标签加上【lang="scss"】
@for $i from 1 through 10 {
.u-line-#{$i},
.up-line-#{$i} {
/* #ifdef APP-NVUE */
// nvue下,可以直接使用lines属性,这是weex特有样式
lines: $i;
text-overflow: ellipsis;
overflow: hidden;
flex: 1;
/* #endif */
/* #ifndef APP-NVUE */
// vue下,单行和多行显示省略号需要单独处理
@if $i == 1 {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
} @else {
display: -webkit-box!important;
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
-webkit-line-clamp: $i;
-webkit-box-orient: vertical!important;
}
/* #endif */
}
}
// 此处加上!important并非随意乱用,而是因为目前*.nvue页面编译到H5时,
// App.vue的样式会被uni-app的view元素的自带border属性覆盖,导致无效
// 综上,这是uni-app的缺陷导致我们为了多端兼容,而必须要加上!important
// 移动端兼容性较好,直接使用0.5px去实现细边框,不使用伪元素形式实现
.u-border,
.up-border {
border-width: 0.5px!important;
border-color: $u-border-color!important;
border-style: solid;
}
.u-border-top,
.up-border-top {
border-top-width: 0.5px!important;
border-color: $u-border-color!important;
border-top-style: solid;
}
.u-border-left,
.up-border-left {
border-left-width: 0.5px!important;
border-color: $u-border-color!important;
border-left-style: solid;
}
.u-border-right,
.up-border-right {
border-right-width: 0.5px!important;
border-color: $u-border-color!important;
border-right-style: solid;
}
.u-border-bottom,
.up-border-bottom {
border-bottom-width: 0.5px!important;
border-color: $u-border-color!important;
border-bottom-style: solid;
}
.u-border-top-bottom,
.up-border-top-bottom {
border-top-width: 0.5px!important;
border-bottom-width: 0.5px!important;
border-color: $u-border-color!important;
border-top-style: solid;
border-bottom-style: solid;
}
// 去除button的所有默认样式,让其表现跟普通的view、text元素一样
.u-reset-button,
.up-reset-button {
padding: 0;
background-color: transparent;
/* #ifndef APP-PLUS */
font-size: inherit;
line-height: inherit;
color: inherit;
/* #endif */
/* #ifdef APP-NVUE */
border-width: 0;
/* #endif */
}
/* #ifndef APP-NVUE */
.u-reset-button::after,
.up-reset-button::after {
border: none;
}
/* #endif */
.u-hover-class,
.up-hover-class {
opacity: 0.7;
}
.cursor-pointer {
/* #ifdef H5 */
cursor: pointer;
/* #endif */
}

View File

@@ -0,0 +1,36 @@
@import "./mixin.scss";
/* #ifndef APP-NVUE */
// 由于uview-plus是基于nvue环境进行开发的,此环境中普通元素默认为flex-direction: column;
// 所以在非nvue中,需要对元素进行重置为flex-direction: column; 否则可能会表现异常
// 2024-04-09由于微信小程序会提示 Some selectors are not allowed in component wxss所以注释以下几行
// view,
// scroll-view,
// swiper-item,
.u-empty,
.u-empty__wrap,
.u-transition,
.u-tabs,
.u-tabs__wrapper,
.u-tabs__wrapper__scroll-view-wrapper,
.u-tabs__wrapper__scroll-view,
.u-tabs__wrapper__nav,
.u-tabs__wrapper__nav__line,
.up-empty,
.up-empty__wrap,
.up-transition,
.up-tabs,
.up-tabs__wrapper,
.up-tabs__wrapper__scroll-view-wrapper,
.up-tabs__wrapper__scroll-view,
.up-tabs__wrapper__nav,
.up-tabs__wrapper__nav__line {
display: flex;
flex-direction: column;
flex-shrink: 0;
flex-grow: 0;
flex-basis: auto;
align-items: stretch;
align-content: flex-start;
}
/* #endif */

View File

@@ -0,0 +1,369 @@
// .u-flex {
// @include vue-flex(row);
// }
// .u-flex-x {
// @include vue-flex(row);
// }
// .u-flex-y {
// @include vue-flex(column);
// }
// .u-flex-xy-center {
// @include vue-flex(row);
// justify-content: center;
// align-items: center;
// }
// .u-flex-x-center {
// @include vue-flex(row);
// justify-content: center;
// }
// .u-flex-y-center {
// @include vue-flex(column);
// justify-content: center;
// }
// flex布局
.u-flex,
.u-flex-row,
.u-flex-x,
.up-flex,
.up-flex-row,
.up-flex-x {
@include flex;
display: flex !important;
flex-direction: row !important;
}
.u-flex-y,
.u-flex-column,
.up-flex-y,
.up-flex-column {
@include flex(column);
display: flex !important;
flex-direction: column !important;
}
.u-flex-x-center,
.up-flex-x-center {
@include flex;
justify-content: center !important;
}
.u-flex-xy-center,
.up-flex-xy-center {
@include flex;
justify-content: center !important;
align-items: center !important;
}
.u-flex-y-center,
.up-flex-y-center {
@include flex;
align-items: center !important;
}
.u-flex-x-left,
.up-flex-x-left {
@include flex;
}
.u-flex-x-reverse,
.u-flex-row-reverse,
.up-flex-x-reverse,
.up-flex-row-reverse {
flex-direction: row-reverse !important;
}
.u-flex-y-reverse,
.u-flex-column-reverse,
.up-flex-y-reverse,
.up-flex-column-reverse {
flex-direction: column-reverse !important;
}
/* #ifndef APP-NVUE */
// 此处为vue版本的简写,因为nvue不支持同时作用于两个类名的样式写法
// nvue下只能写成class="u-flex-x u-flex-x-reverse的形式"
.u-flex.u-flex-reverse,
.u-flex-row.u-flex-reverse,
.u-flex-x.u-flex-reverse,
.up-flex.up-flex-reverse,
.up-flex-row.up-flex-reverse,
.up-flex-x.up-flex-reverse {
flex-direction: row-reverse !important;
}
.u-flex-column.u-flex-reverse,
.u-flex-y.u-flex-reverse,
.up-flex-column.up-flex-reverse,
.up-flex-y.up-flex-reverse {
flex-direction: column-reverse !important;
}
// 自动伸缩
.u-flex-fill,
.up-flex-fill {
flex: 1 1 auto !important;
}
// 边界自动伸缩
.u-margin-top-auto,
.u-m-t-auto,
.up-margin-top-auto,
.up-m-t-auto {
margin-top: auto !important;
}
.u-margin-right-auto,
.u-m-r-auto,
.up-margin-right-auto,
.up-m-r-auto {
margin-right: auto !important;
}
.u-margin-bottom-auto,
.u-m-b-auto,
.up-margin-bottom-auto,
.up-m-b-auto {
margin-bottom: auto !important;
}
.u-margin-left-auto,
.u-m-l-auto,
.up-margin-left-auto,
.up-m-l-auto {
margin-left: auto !important;
}
.u-margin-center-auto,
.u-m-c-auto,
.up-margin-center-auto,
.up-m-c-auto {
margin-left: auto !important;
margin-right: auto !important;
}
.u-margin-middle-auto,
.u-m-m-auto,
.up-margin-middle-auto,
.up-m-m-auto {
margin-top: auto !important;
margin-bottom: auto !important;
}
/* #endif */
// 换行
.u-flex-wrap,
.up-flex-wrap {
flex-wrap: wrap !important;
}
// 反向换行
.u-flex-wrap-reverse,
.up-flex-wrap-reverse {
flex-wrap: wrap-reverse !important;
}
// 主轴起点对齐
.u-flex-start,
.up-flex-start {
justify-content: flex-start !important;
}
// 主轴中间对齐
.u-flex-center,
.up-flex-center {
justify-content: center !important;
}
// 主轴终点对齐
.u-flex-end,
.up-flex-end {
justify-content: flex-end !important;
}
// 主轴等比间距
.u-flex-between,
.up-flex-between {
justify-content: space-between !important;
}
// 主轴均分间距
.u-flex-around,
.up-flex-around {
justify-content: space-around !important;
}
// 交叉轴起点对齐
.u-flex-items-start,
.up-flex-items-start {
align-items: flex-start !important;
}
// 交叉轴中间对齐
.u-flex-items-center,
.up-flex-items-center {
align-items: center !important;
}
// 交叉轴终点对齐
.u-flex-items-end,
.up-flex-items-end {
align-items: flex-end !important;
}
// 交叉轴第一行文字基线对齐
.u-flex-items-baseline,
.up-flex-items-baseline {
/* #ifndef APP-NVUE */
align-items: baseline !important;
/* #endif */
}
// 交叉轴方向拉伸对齐
.u-flex-items-stretch,
.up-flex-items-stretch {
align-items: stretch !important;
}
// 以下属于项目(子元素)的类
// 子元素交叉轴起点对齐
/* #ifndef APP-NVUE */
.u-flex-self-start,
.up-flex-self-start {
align-self: flex-start !important;
}
// 子元素交叉轴居中对齐
.u-flex-self-center,
.up-flex-self-center {
align-self: center !important;
}
// 子元素交叉轴终点对齐
.u-flex-self-end,
.up-flex-self-end {
align-self: flex-end !important;
}
// 子元素交叉轴第一行文字基线对齐
.u-flex-self-baseline,
.up-flex-self-baseline {
align-self: baseline !important;
}
// 子元素交叉轴方向拉伸对齐
.u-flex-self-stretch,
.up-flex-self-stretch {
align-self: stretch !important;
}
/* #endif */
// 多轴交叉时的对齐方式
// 起点对齐
/* #ifndef APP-NVUE */
.u-flex-content-start,
.up-flex-content-start {
align-content: flex-start !important;
}
// 居中对齐
.u-flex-content-center,
.up-flex-content-center {
align-content: center !important;
}
// 终点对齐
.u-flex-content-end,
.up-flex-content-end {
align-content: flex-end !important;
}
// 两端对齐
.u-flex-content-between,
.up-flex-content-between {
align-content: space-between !important;
}
// 均分间距
.u-flex-content-around,
.up-flex-content-around {
align-content: space-around !important;
}
// 全部居中对齐
.u-flex-middle,
.up-flex-middle {
justify-content: center !important;
align-items: center !important;
align-self: center !important;
align-content: center !important;
}
// 是否可以放大
.u-flex-grow,
.up-flex-grow {
flex-grow: 1 !important;
}
// 是否可以缩小
.u-flex-shrink,
.up-flex-shrink {
flex-shrink: 1 !important;
}
/* #endif */
// 定义内外边距,历遍1-80
@for $i from 0 through 80 {
// 只要双数和能被5除尽的数
@if $i % 2 == 0 or $i % 5 == 0 {
// 得出:up-margin-30或者u-m-30
.u-margin-#{$i}, .u-m-#{$i},
.up-margin-#{$i}, .up-m-#{$i} {
margin: $i + rpx!important;
}
// 得出:up-padding-30或者u-p-30
.u-padding-#{$i}, .u-p-#{$i},
.up-padding-#{$i}, .up-p-#{$i} {
padding: $i + rpx!important;
}
@each $short, $long in l left, t top, r right, b bottom {
// 缩写版,结果如: up-m-l-30
// 定义外边距
.u-m-#{$short}-#{$i},
.up-m-#{$short}-#{$i} {
margin-#{$long}: $i + rpx!important;
}
// 定义内边距
.u-p-#{$short}-#{$i},
.up-p-#{$short}-#{$i} {
padding-#{$long}: $i + rpx!important;
}
// 完整版,结果如:up-margin-left-30
// 定义外边距
.u-margin-#{$long}-#{$i},
.up-margin-#{$long}-#{$i} {
margin-#{$long}: $i + rpx!important;
}
// 定义内边距
.u-padding-#{$long}-#{$i},
.up-padding-#{$long}-#{$i} {
padding-#{$long}: $i + rpx!important;
}
}
}
}

View File

@@ -0,0 +1,8 @@
// 通过scss的mixin功能,把原来需要写4行的css,变成一行
// 目的是保持代码干净整洁,不至于在nvue下,到处都要写display:flex的条件编译
@mixin flex($direction: row) {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: $direction;
}

View File

@@ -0,0 +1,6 @@
@import "../../theme.scss";
@include up-export-legacy-light-vars(':root');
@include up-export-legacy-light-vars('page');
@include up-export-legacy-light-vars('body');
@include up-export-legacy-light-vars("[data-up-theme='light']");

View File

@@ -0,0 +1,201 @@
:root,
page,
body {
--up-main-color: var(--up-light-main-color, #303133);
--up-content-color: var(--up-light-content-color, #606266);
--up-tips-color: var(--up-light-tips-color, #909193);
--up-light-color: var(--up-light-light-color, #c0c4cc);
--up-border-color: var(--up-light-border-color, #dadbde);
--up-bg-color: var(--up-light-bg-color, #f3f4f6);
--up-hover-bg-color: #e7ebf0;
--up-page-bg-color: #f3f4f6;
--up-card-bg-color: #ffffff;
--up-navbar-bg-color: #ffffff;
--up-disabled-color: var(--up-light-disabled-color, #c8c9cc);
--up-primary: var(--up-light-primary, #3c9cff);
--up-primary-dark: var(--up-light-primary-dark, #398ade);
--up-primary-disabled: var(--up-light-primary-disabled, #9acafc);
--up-primary-light: var(--up-light-primary-light, #ecf5ff);
--up-warning: var(--up-light-warning, #f9ae3d);
--up-warning-dark: var(--up-light-warning-dark, #f1a532);
--up-warning-disabled: var(--up-light-warning-disabled, #f9d39b);
--up-warning-light: var(--up-light-warning-light, #fdf6ec);
--up-success: var(--up-light-success, #5ac725);
--up-success-dark: var(--up-light-success-dark, #53c21d);
--up-success-disabled: var(--up-light-success-disabled, #a9e08f);
--up-success-light: var(--up-light-success-light, #f5fff0);
--up-error: var(--up-light-error, #f56c6c);
--up-error-dark: var(--up-light-error-dark, #e45656);
--up-error-disabled: var(--up-light-error-disabled, #f7b2b2);
--up-error-light: var(--up-light-error-light, #fef0f0);
--up-info: var(--up-light-info, #909399);
--up-info-dark: var(--up-light-info-dark, #767a82);
--up-info-disabled: var(--up-light-info-disabled, #c4c6c9);
--up-info-light: var(--up-light-info-light, #f4f4f5);
--up-table2-header-bg-color: #f5f7fa;
--up-table2-zebra-bg-color: #fafafa;
--up-table2-highlight-bg-color: #f5f7fa;
--up-gap-bg-color: #f3f4f6;
--up-skeleton-bg-color: #f1f2f4;
--up-skeleton-shimmer-color: #e6e6e6;
--up-swipe-action-button-bg-color: #c7c6cd;
--up-index-list-indicator-bg-color: #c9c9c9;
--up-calendar-month-mark-color: rgba(231, 232, 234, 0.83);
}
@media (prefers-color-scheme: dark) {
:root,
page,
body {
--up-main-color: #f5f5f5;
--up-content-color: #d1d5db;
--up-tips-color: #9ca3af;
--up-light-color: #6b7280;
--up-border-color: #3a3a3c;
--up-bg-color: #1f1f1f;
--up-hover-bg-color: #343741;
--up-page-bg-color: #1f1f1f;
--up-card-bg-color: #1c1c1e;
--up-navbar-bg-color: #1c1c1e;
--up-disabled-color: #4b5563;
--up-primary: #3c9cff;
--up-primary-dark: #5aa8ff;
--up-primary-disabled: #4c6f92;
--up-primary-light: #10243a;
--up-warning: #f9ae3d;
--up-warning-dark: #ffbf66;
--up-warning-disabled: #8a6a3a;
--up-warning-light: #3d2f1b;
--up-success: #5ac725;
--up-success-dark: #7ad94b;
--up-success-disabled: #5f7f4f;
--up-success-light: #1f3316;
--up-error: #f56c6c;
--up-error-dark: #ff8a8a;
--up-error-disabled: #8d5858;
--up-error-light: #3a2222;
--up-info: #909399;
--up-info-dark: #b0b3b8;
--up-info-disabled: #5f6368;
--up-info-light: #2f3238;
--up-table2-header-bg-color: #2a2d33;
--up-table2-zebra-bg-color: #23262b;
--up-table2-highlight-bg-color: #2f3440;
--up-gap-bg-color: #111111;
--up-skeleton-bg-color: #2f3135;
--up-skeleton-shimmer-color: rgba(255, 255, 255, 0.12);
--up-swipe-action-button-bg-color: #4b5563;
--up-index-list-indicator-bg-color: #4b5563;
--up-calendar-month-mark-color: rgba(255, 255, 255, 0.04);
}
}
[data-up-theme='light'] {
--up-main-color: var(--up-light-main-color, #303133);
--up-content-color: var(--up-light-content-color, #606266);
--up-tips-color: var(--up-light-tips-color, #909193);
--up-light-color: var(--up-light-light-color, #c0c4cc);
--up-border-color: var(--up-light-border-color, #dadbde);
--up-bg-color: var(--up-light-bg-color, #f3f4f6);
--up-hover-bg-color: #e7ebf0;
--up-page-bg-color: #f3f4f6;
--up-card-bg-color: #ffffff;
--up-navbar-bg-color: #ffffff;
--up-disabled-color: var(--up-light-disabled-color, #c8c9cc);
--up-primary: var(--up-light-primary, #3c9cff);
--up-primary-dark: var(--up-light-primary-dark, #398ade);
--up-primary-disabled: var(--up-light-primary-disabled, #9acafc);
--up-primary-light: var(--up-light-primary-light, #ecf5ff);
--up-warning: var(--up-light-warning, #f9ae3d);
--up-warning-dark: var(--up-light-warning-dark, #f1a532);
--up-warning-disabled: var(--up-light-warning-disabled, #f9d39b);
--up-warning-light: var(--up-light-warning-light, #fdf6ec);
--up-success: var(--up-light-success, #5ac725);
--up-success-dark: var(--up-light-success-dark, #53c21d);
--up-success-disabled: var(--up-light-success-disabled, #a9e08f);
--up-success-light: var(--up-light-success-light, #f5fff0);
--up-error: var(--up-light-error, #f56c6c);
--up-error-dark: var(--up-light-error-dark, #e45656);
--up-error-disabled: var(--up-light-error-disabled, #f7b2b2);
--up-error-light: var(--up-light-error-light, #fef0f0);
--up-info: var(--up-light-info, #909399);
--up-info-dark: var(--up-light-info-dark, #767a82);
--up-info-disabled: var(--up-light-info-disabled, #c4c6c9);
--up-info-light: var(--up-light-info-light, #f4f4f5);
--up-table2-header-bg-color: #f5f7fa;
--up-table2-zebra-bg-color: #fafafa;
--up-table2-highlight-bg-color: #f5f7fa;
--up-gap-bg-color: #f3f4f6;
--up-skeleton-bg-color: #f1f2f4;
--up-skeleton-shimmer-color: #e6e6e6;
--up-swipe-action-button-bg-color: #c7c6cd;
--up-index-list-indicator-bg-color: #c9c9c9;
--up-calendar-month-mark-color: rgba(231, 232, 234, 0.83);
}
[data-up-theme='dark'] {
--up-main-color: #f5f5f5;
--up-content-color: #d1d5db;
--up-tips-color: #9ca3af;
--up-light-color: #6b7280;
--up-border-color: #3a3a3c;
--up-bg-color: #1f1f1f;
--up-hover-bg-color: #343741;
--up-page-bg-color: #1f1f1f;
--up-card-bg-color: #1c1c1e;
--up-navbar-bg-color: #1c1c1e;
--up-disabled-color: #4b5563;
--up-primary: #3c9cff;
--up-primary-dark: #5aa8ff;
--up-primary-disabled: #4c6f92;
--up-primary-light: #10243a;
--up-warning: #f9ae3d;
--up-warning-dark: #ffbf66;
--up-warning-disabled: #8a6a3a;
--up-warning-light: #3d2f1b;
--up-success: #5ac725;
--up-success-dark: #7ad94b;
--up-success-disabled: #5f7f4f;
--up-success-light: #1f3316;
--up-error: #f56c6c;
--up-error-dark: #ff8a8a;
--up-error-disabled: #8d5858;
--up-error-light: #3a2222;
--up-info: #909399;
--up-info-dark: #b0b3b8;
--up-info-disabled: #5f6368;
--up-info-light: #2f3238;
--up-table2-header-bg-color: #2a2d33;
--up-table2-zebra-bg-color: #23262b;
--up-table2-highlight-bg-color: #2f3440;
--up-gap-bg-color: #111111;
--up-skeleton-bg-color: #2f3135;
--up-skeleton-shimmer-color: rgba(255, 255, 255, 0.12);
--up-swipe-action-button-bg-color: #4b5563;
--up-index-list-indicator-bg-color: #4b5563;
--up-calendar-month-mark-color: rgba(255, 255, 255, 0.04);
}

View File

@@ -0,0 +1 @@
@import "./theme-vars-core.scss";

View File

@@ -0,0 +1,28 @@
// 历遍生成4个方向的底部安全区
@each $d in top, right, bottom, left {
.u-safe-area-inset-#{$d},
.up-safe-area-inset-#{$d} {
padding-#{$d}: 0;
padding-#{$d}: constant(safe-area-inset-#{$d});
padding-#{$d}: env(safe-area-inset-#{$d});
}
}
//提升H5端uni.toast()的层级,避免被uview-plus的modal等遮盖
/* #ifdef H5 */
uni-toast {
z-index: 10090;
}
uni-toast .uni-toast {
z-index: 10090;
}
/* #endif */
// 隐藏scroll-view的滚动条
::-webkit-scrollbar {
display: none;
width: 0 !important;
height: 0 !important;
-webkit-appearance: none;
background: transparent;
}

View File

@@ -0,0 +1,64 @@
// 浮点数加法
export function add (arg1, arg2) {
var r1, r2, m
try {
r1 = arg1.toString().split('.')[1].length
} catch (e) {
r1 = 0
}
try {
r2 = arg2.toString().split('.')[1].length
} catch (e) {
r2 = 0
}
m = Math.pow(10, Math.max(r1, r2))
return (arg1 * m + arg2 * m) / m
}
// 浮点数减法
export function sub (arg1, arg2) {
var r1, r2, m, n
try {
r1 = arg1.toString().split('.')[1].length
} catch (e) {
r1 = 0
}
try {
r2 = arg2.toString().split('.')[1].length
} catch (e) {
r2 = 0
}
m = Math.pow(10, Math.max(r1, r2))
n = (r1 >= r2) ? r1 : r2
return Math.abs(((arg1 * m - arg2 * m) / m).toFixed(n))
}
//浮点乘法
export function mul (a, b) {
var c = 0,
d = a.toString(),
e = b.toString();
try {
c += d.split(".")[1].length;
} catch (f) {}
try {
c += e.split(".")[1].length;
} catch (f) {}
return Number(d.replace(".", "")) * Number(e.replace(".", "")) / Math.pow(10, c);
}
//浮点除法
export function div (a, b) {
var c, d, e = 0,
f = 0;
try {
e = a.toString().split(".")[1].length;
} catch (g) {}
try {
f = b.toString().split(".")[1].length;
} catch (g) {}
return c = Number(a.toString().replace(".", "")), d = Number(b.toString().replace(".", "")), xyutil.mul(c / d, Math.pow(10, f - e));
}
export default {
add,
sub,
mul,
div
}

View File

@@ -0,0 +1,134 @@
/**
* 求两个颜色之间的渐变值
* @param {string} startColor 开始的颜色
* @param {string} endColor 结束的颜色
* @param {number} step 颜色等分的份额
* */
export function colorGradient(startColor = 'rgb(0, 0, 0)', endColor = 'rgb(255, 255, 255)', step = 10) {
const startRGB = hexToRgb(startColor, false) // 转换为rgb数组模式
const startR = startRGB[0]
const startG = startRGB[1]
const startB = startRGB[2]
const endRGB = hexToRgb(endColor, false)
const endR = endRGB[0]
const endG = endRGB[1]
const endB = endRGB[2]
const sR = (endR - startR) / step // 总差值
const sG = (endG - startG) / step
const sB = (endB - startB) / step
const colorArr = []
for (let i = 0; i < step; i++) {
// 计算每一步的hex值
let hex = rgbToHex(`rgb(${Math.round((sR * i + startR))},${Math.round((sG * i + startG))},${Math.round((sB
* i + startB))})`)
// 确保第一个颜色值为startColor的值
if (i === 0) hex = rgbToHex(startColor)
// 确保最后一个颜色值为endColor的值
if (i === step - 1) hex = rgbToHex(endColor)
colorArr.push(hex)
}
return colorArr
}
// 将hex表示方式转换为rgb表示方式(这里返回rgb数组模式)
export function hexToRgb(sColor, str = true) {
const reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/
sColor = String(sColor).toLowerCase()
if (sColor && reg.test(sColor)) {
if (sColor.length === 4) {
let sColorNew = '#'
for (let i = 1; i < 4; i += 1) {
sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1))
}
sColor = sColorNew
}
// 处理六位的颜色值
const sColorChange = []
for (let i = 1; i < 7; i += 2) {
sColorChange.push(parseInt(`0x${sColor.slice(i, i + 2)}`))
}
if (!str) {
return sColorChange
}
return `rgb(${sColorChange[0]},${sColorChange[1]},${sColorChange[2]})`
} if (/^(rgb|RGB)/.test(sColor)) {
const arr = sColor.replace(/(?:\(|\)|rgb|RGB)*/g, '').split(',')
return arr.map((val) => Number(val))
}
return sColor
}
// 将rgb表示方式转换为hex表示方式
export function rgbToHex(rgb) {
const _this = rgb
const reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/
if (/^(rgb|RGB)/.test(_this)) {
const aColor = _this.replace(/(?:\(|\)|rgb|RGB)*/g, '').split(',')
let strHex = '#'
for (let i = 0; i < aColor.length; i++) {
let hex = Number(aColor[i]).toString(16)
hex = String(hex).length == 1 ? `${0}${hex}` : hex // 保证每个rgb的值为2位
if (hex === '0') {
hex += hex
}
strHex += hex
}
if (strHex.length !== 7) {
strHex = _this
}
return strHex
} if (reg.test(_this)) {
const aNum = _this.replace(/#/, '').split('')
if (aNum.length === 6) {
return _this
} if (aNum.length === 3) {
let numHex = '#'
for (let i = 0; i < aNum.length; i += 1) {
numHex += (aNum[i] + aNum[i])
}
return numHex
}
} else {
return _this
}
}
/**
* JS颜色十六进制转换为rgb或rgba,返回的格式为 rgba(255,255,255,0.5)字符串
* sHex为传入的十六进制的色值
* alpha为rgba的透明度
*/
export function colorToRgba(color, alpha) {
color = rgbToHex(color)
// 十六进制颜色值的正则表达式
const reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/
/* 16进制颜色转为RGB格式 */
let sColor = String(color).toLowerCase()
if (sColor && reg.test(sColor)) {
if (sColor.length === 4) {
let sColorNew = '#'
for (let i = 1; i < 4; i += 1) {
sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1))
}
sColor = sColorNew
}
// 处理六位的颜色值
const sColorChange = []
for (let i = 1; i < 7; i += 2) {
sColorChange.push(parseInt(`0x${sColor.slice(i, i + 2)}`))
}
// return sColorChange.join(',')
return `rgba(${sColorChange.join(',')},${alpha})`
}
return sColor
}
export default {
colorGradient,
hexToRgb,
rgbToHex,
colorToRgba
}

View File

@@ -0,0 +1,29 @@
let timeout = null
/**
* 防抖原理:一定时间内,只有最后一次操作,再过wait毫秒后才执行函数
*
* @param {Function} func 要执行的回调函数
* @param {Number} wait 延时的时间
* @param {Boolean} immediate 是否立即执行
* @return null
*/
export function debounce(func, wait = 500, immediate = false) {
// 清除定时器
if (timeout !== null) clearTimeout(timeout)
// 立即执行,此类情况一般用不到
if (immediate) {
const callNow = !timeout
timeout = setTimeout(() => {
timeout = null
}, wait)
if (callNow) typeof func === 'function' && func()
} else {
// 设置定时器,当最后一次操作后,timeout不会再被清除,所以在延时wait毫秒后执行func回调方法
timeout = setTimeout(() => {
typeof func === 'function' && func()
}, wait)
}
}
export default debounce

View File

@@ -0,0 +1,167 @@
let _boundaryCheckingState = true; // 是否进行越界检查的全局开关
/**
* 把错误的数据转正
* @private
* @example strip(0.09999999999999998)=0.1
*/
export function strip(num, precision = 15) {
return +parseFloat(Number(num).toPrecision(precision));
}
/**
* Return digits length of a number
* @private
* @param {*number} num Input number
*/
export function digitLength(num) {
// Get digit length of e
const eSplit = num.toString().split(/[eE]/);
const len = (eSplit[0].split('.')[1] || '').length - +(eSplit[1] || 0);
return len > 0 ? len : 0;
}
/**
* 把小数转成整数,如果是小数则放大成整数
* @private
* @param {*number} num 输入数
*/
export function float2Fixed(num) {
if (num.toString().indexOf('e') === -1) {
return Number(num.toString().replace('.', ''));
}
const dLen = digitLength(num);
return dLen > 0 ? strip(Number(num) * Math.pow(10, dLen)) : Number(num);
}
/**
* 检测数字是否越界,如果越界给出提示
* @private
* @param {*number} num 输入数
*/
export function checkBoundary(num) {
if (_boundaryCheckingState) {
if (num > Number.MAX_SAFE_INTEGER || num < Number.MIN_SAFE_INTEGER) {
console.warn(`${num} 超出了精度限制,结果可能不正确`);
}
}
}
/**
* 把递归操作扁平迭代化
* @param {number[]} arr 要操作的数字数组
* @param {function} operation 迭代操作
* @private
*/
export function iteratorOperation(arr, operation) {
const [num1, num2, ...others] = arr;
let res = operation(num1, num2);
others.forEach((num) => {
res = operation(res, num);
});
return res;
}
/**
* 高精度乘法
* @export
*/
export function times(...nums) {
if (nums.length > 2) {
return iteratorOperation(nums, times);
}
const [num1, num2] = nums;
const num1Changed = float2Fixed(num1);
const num2Changed = float2Fixed(num2);
const baseNum = digitLength(num1) + digitLength(num2);
const leftValue = num1Changed * num2Changed;
checkBoundary(leftValue);
return leftValue / Math.pow(10, baseNum);
}
/**
* 高精度加法
* @export
*/
export function plus(...nums) {
if (nums.length > 2) {
return iteratorOperation(nums, plus);
}
const [num1, num2] = nums;
// 取最大的小数位
const baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
// 把小数都转为整数然后再计算
return (times(num1, baseNum) + times(num2, baseNum)) / baseNum;
}
/**
* 高精度减法
* @export
*/
export function minus(...nums) {
if (nums.length > 2) {
return iteratorOperation(nums, minus);
}
const [num1, num2] = nums;
const baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
return (times(num1, baseNum) - times(num2, baseNum)) / baseNum;
}
/**
* 高精度除法
* @export
*/
export function divide(...nums) {
if (nums.length > 2) {
return iteratorOperation(nums, divide);
}
const [num1, num2] = nums;
const num1Changed = float2Fixed(num1);
const num2Changed = float2Fixed(num2);
checkBoundary(num1Changed);
checkBoundary(num2Changed);
// 重要,这里必须用strip进行修正
return times(num1Changed / num2Changed, strip(Math.pow(10, digitLength(num2) - digitLength(num1))));
}
/**
* 四舍五入
* @export
*/
export function round(num, ratio) {
const base = Math.pow(10, ratio);
let result = divide(Math.round(Math.abs(times(num, base))), base);
if (num < 0 && result !== 0) {
result = times(result, -1);
}
// 位数不足则补0
return result;
}
/**
* 是否进行边界检查,默认开启
* @param flag 标记开关,true 为开启,false 为关闭,默认为 true
* @export
*/
export function enableBoundaryChecking(flag = true) {
_boundaryCheckingState = flag;
}
export default {
times,
plus,
minus,
divide,
round,
enableBoundaryChecking,
};

View File

@@ -0,0 +1,4 @@
// 全局挂载引入http相关请求拦截插件
import Request from '../luch-request'
const http = new Request()
export default http

View File

@@ -0,0 +1,878 @@
import {
number as testNumber,
array as testArray,
empty as testEmpty
} from './test.js'
import { round } from './digit.js'
import config from '../config/config.js'
/**
* @description 如果value小于min,取min;如果value大于max,取max
* @param {number} min
* @param {number} max
* @param {number} value
*/
export function range(min = 0, max = 0, value = 0) {
return Math.max(min, Math.min(max, Number(value)))
}
/**
* @description 用于获取用户传递值的px值 如果用户传递了"xxpx"或者"xxrpx",取出其数值部分,如果是"xxxrpx"还需要用过uni.rpx2px进行转换
* @param {number|string} value 用户传递值的px值
* @param {boolean} unit
* @returns {number|string}
*/
export function getPx(value, unit = false) {
if (testNumber(value)) {
return unit ? `${value}px` : Number(value)
}
// 如果带有rpx,先取出其数值部分,再转为px值
if (/(rpx|upx)$/.test(value)) {
return unit ? `${uni.upx2px(parseInt(value))}px` : Number(uni.upx2px(parseInt(value)))
}
return unit ? `${parseInt(value)}px` : parseInt(value)
}
/**
* @description 用于统一rpx2px方法,因uni-app现有API未统一。
* @param {number} value 用户传递值的rpx值
* @returns {number}
*/
export function rpx2px(value) {
// #ifdef APP
return uni.upx2px(value)
// #endif
// #ifndef APP
return uni.rpx2px(value)
// #endif
}
/**
* @description 进行延时,以达到可以简写代码的目的 比如: await uni.$u.sleep(20)将会阻塞20ms
* @param {number} value 堵塞时间 单位ms 毫秒
* @returns {Promise} 返回promise
*/
export function sleep(value = 30) {
return new Promise((resolve) => {
setTimeout(() => {
resolve()
}, value)
})
}
/**
* @description 运行期判断平台
* @returns {string} 返回所在平台(小写)
* @link 运行期判断平台 https://uniapp.dcloud.io/frame?id=判断平台
*/
export function os() {
// #ifdef APP || H5 || MP-WEIXIN
return uni.getDeviceInfo().platform.toLowerCase()
// #endif
// #ifndef APP || H5 || MP-WEIXIN
return uni.getSystemInfoSync().platform.toLowerCase()
// #endif
}
/**
* @description 获取系统信息同步接口
* @link 获取系统信息同步接口 https://uniapp.dcloud.io/api/system/info?id=getsysteminfosync
*/
export function sys() {
return uni.getSystemInfoSync()
}
export function getWindowInfo() {
let ret = {}
// #ifdef APP || H5 || MP-WEIXIN
ret = uni.getWindowInfo()
// #endif
// #ifndef APP || H5 || MP-WEIXIN
ret = sys()
// #endif
return ret
}
export function getDeviceInfo() {
let ret = {}
// #ifdef APP || H5 || MP-WEIXIN
ret = uni.getDeviceInfo()
// #endif
// #ifndef APP || H5 || MP-WEIXIN
ret = sys()
// #endif
return ret
}
/**
* @description 取一个区间数
* @param {Number} min 最小值
* @param {Number} max 最大值
*/
export function random(min, max) {
if (min >= 0 && max > 0 && max >= min) {
const gab = max - min + 1
return Math.floor(Math.random() * gab + min)
}
return 0
}
/**
* @param {Number} len uuid的长度
* @param {Boolean} firstU 将返回的首字母置为"u"
* @param {Nubmer} radix 生成uuid的基数(意味着返回的字符串都是这个基数),2-二进制,8-八进制,10-十进制,16-十六进制
*/
export function guid(len = 32, firstU = true, radix = null) {
const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('')
const uuid = []
radix = radix || chars.length
if (len) {
// 如果指定uuid长度,只是取随机的字符,0|x为位运算,能去掉x的小数位,返回整数位
for (let i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix]
} else {
let r
// rfc4122标准要求返回的uuid中,某些位为固定的字符
uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'
uuid[14] = '4'
for (let i = 0; i < 36; i++) {
if (!uuid[i]) {
r = 0 | Math.random() * 16
uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r]
}
}
}
// 移除第一个字符,并用u替代,因为第一个字符为数值时,该guuid不能用作id或者class
if (firstU) {
uuid.shift()
return `u${uuid.join('')}`
}
return uuid.join('')
}
/**
* @description 获取父组件的参数,因为支付宝小程序不支持provide/inject的写法
this.$parent在非H5中,可以准确获取到父组件,但是在H5中,需要多次this.$parent.$parent.xxx
这里默认值等于undefined有它的含义,因为最顶层元素(组件)的$parent就是undefined,意味着不传name
值(默认为undefined),就是查找最顶层的$parent
* @param {string|undefined} name 父组件的参数名
*/
export function $parent(name = undefined) {
let parent = this.$parent
// 通过while历遍,这里主要是为了H5需要多层解析的问题
while (parent) {
// 父组件
let name2 = ''
if (name.startsWith('up-')) {
name2 = name.replace(/up-([a-zA-Z0-9-_]+)/g, 'u-$1')
} else if (name.startsWith('u-')) {
name2 = name.replace(/u-([a-zA-Z0-9-_]+)/g, 'up-$1')
}
if (parent.$options && parent.$options.name !== name && parent.$options.name !== name2) {
// 如果组件的name不相等,继续上一级寻找
parent = parent.$parent
} else {
return parent
}
}
return false
}
/**
* @description 样式转换
* 对象转字符串,或者字符串转对象
* @param {object | string} customStyle 需要转换的目标
* @param {String} target 转换的目的,object-转为对象,string-转为字符串
* @returns {object|string}
*/
export function addStyle(customStyle, target = 'object') {
// 字符串转字符串,对象转对象情形,直接返回
if (testEmpty(customStyle) || typeof(customStyle) === 'object' && target === 'object' || target === 'string' &&
typeof(customStyle) === 'string') {
return customStyle
}
// 字符串转对象
if (target === 'object') {
// 去除字符串样式中的两端空格(中间的空格不能去掉,比如padding: 20px 0如果去掉了就错了),空格是无用的
customStyle = trim(customStyle)
// 根据";"将字符串转为数组形式
const styleArray = customStyle.split(';')
const style = {}
// 历遍数组,拼接成对象
for (let i = 0; i < styleArray.length; i++) {
// 'font-size:20px;color:red;',如此最后字符串有";"的话,会导致styleArray最后一个元素为空字符串,这里需要过滤
if (styleArray[i]) {
const item = styleArray[i].split(':')
style[trim(item[0])] = trim(item[1])
}
}
return style
}
// 这里为对象转字符串形式
let string = ''
if (typeof customStyle === 'object') {
customStyle.forEach((val, i) => {
// 驼峰转为中划线的形式,否则css内联样式,无法识别驼峰样式属性名
const key = i.replace(/([A-Z])/g, '-$1').toLowerCase()
string += `${key}:${val};`
})
}
// 去除两端空格
return trim(string)
}
/**
* @description 添加单位,如果有rpx,upx,%,px等单位结尾或者值为auto,直接返回,否则加上px单位结尾
* @param {string|number} value 需要添加单位的值
* @param {string} unit 添加的单位名 比如px
*/
export function addUnit(value = 'auto', unit = '') {
if (!unit) {
unit = config.unit || 'px'
}
if (unit == 'rpx' && testNumber(String(value))) {
value = value * 2
}
value = String(value)
// 用内置验证规则中的number判断是否为数值
return testNumber(value) ? `${value}${unit}` : value
}
/**
* @description 深度克隆
* @param {object} obj 需要深度克隆的对象
* @returns {*} 克隆后的对象或者原值(不是对象)
*/
export function deepClone(obj) {
// 对常见的“非”值,直接返回原来值
if ([null, undefined, NaN, false].includes(obj)) return obj
if (typeof obj !== 'object' && typeof obj !== 'function') {
// 原始类型直接返回
return obj
}
const o = testArray(obj) ? [] : {}
for (const i in obj) {
if (obj.hasOwnProperty(i)) {
o[i] = typeof obj[i] === 'object' ? deepClone(obj[i]) : obj[i]
}
}
return o
}
/**
* @description JS对象深度合并
* @param {object} target 需要拷贝的对象
* @param {object} source 拷贝的来源对象
* @returns {object|boolean} 深度合并后的对象或者false(入参有不是对象)
*/
export function deepMerge(targetOrigin = {}, source = {}) {
let target = deepClone(targetOrigin)
if (typeof target !== 'object' || typeof source !== 'object') return false
for (const prop in source) {
if (!source.hasOwnProperty(prop)) continue
if (prop in target) {
if (source[prop] == null) {
target[prop] = source[prop]
}else if (typeof target[prop] !== 'object') {
target[prop] = source[prop]
} else if (typeof source[prop] !== 'object') {
target[prop] = source[prop]
} else if (target[prop].concat && source[prop].concat) {
target[prop] = target[prop].concat(source[prop])
} else {
target[prop] = deepMerge(target[prop], source[prop])
}
} else {
target[prop] = source[prop]
}
}
return target
}
/**
* @description JS对象深度合并
* @param {object} target 需要拷贝的对象
* @param {object} source 拷贝的来源对象
* @returns {object|boolean} 深度合并后的对象或者false(入参有不是对象)
*/
export function shallowMerge(target, source = {}) {
if (typeof target !== 'object' || typeof source !== 'object') return false
for (const prop in source) {
if (!source.hasOwnProperty(prop)) continue
if (prop in target) {
if (source[prop] == null) {
target[prop] = source[prop]
}else if (typeof target[prop] !== 'object') {
target[prop] = source[prop]
} else if (typeof source[prop] !== 'object') {
target[prop] = source[prop]
} else if (target[prop].concat && source[prop].concat) {
target[prop] = target[prop].concat(source[prop])
} else {
target[prop] = shallowMerge(target[prop], source[prop])
}
} else {
target[prop] = source[prop]
}
}
return target
}
/**
* @description error提示
* @param {*} err 错误内容
*/
export function error(err) {
// 开发环境才提示,生产环境不会提示
if (process.env.NODE_ENV === 'development') {
console.error(`uView提示:${err}`)
}
}
/**
* @description 打乱数组
* @param {array} array 需要打乱的数组
* @returns {array} 打乱后的数组
*/
export function randomArray(array = []) {
// 原理是sort排序,Math.random()产生0<= x < 1之间的数,会导致x-0.05大于或者小于0
return array.sort(() => Math.random() - 0.5)
}
// padStart 的 polyfill,因为某些机型或情况,还无法支持es7的padStart,比如电脑版的微信小程序
// 所以这里做一个兼容polyfill的兼容处理
if (!String.prototype.padStart) {
// 为了方便表示这里 fillString 用了ES6 的默认参数,不影响理解
String.prototype.padStart = function(maxLength, fillString = ' ') {
if (Object.prototype.toString.call(fillString) !== '[object String]') {
throw new TypeError(
'fillString must be String'
)
}
const str = this
// 返回 String(str) 这里是为了使返回的值是字符串字面量,在控制台中更符合直觉
if (str.length >= maxLength) return String(str)
const fillLength = maxLength - str.length
let times = Math.ceil(fillLength / fillString.length)
while (times >>= 1) {
fillString += fillString
if (times === 1) {
fillString += fillString
}
}
return fillString.slice(0, fillLength) + str
}
}
/**
* @description 格式化时间
* @param {String|Number} dateTime 需要格式化的时间戳
* @param {String} fmt 格式化规则 yyyy:mm:dd|yyyy:mm|yyyy年mm月dd日|yyyy年mm月dd日 hh时MM分等,可自定义组合 默认yyyy-mm-dd
* @returns {string} 返回格式化后的字符串
*/
export function timeFormat(dateTime = null, formatStr = 'yyyy-mm-dd') {
let date
// 若传入时间为假值,则取当前时间
if (!dateTime) {
date = new Date()
}
// 若为unix秒时间戳,则转为毫秒时间戳(逻辑有点奇怪,但不敢改,以保证历史兼容)
else if (/^\d{10}$/.test(dateTime.toString().trim())) {
date = new Date(dateTime * 1000)
}
// 若用户传入字符串格式时间戳,new Date无法解析,需做兼容
else if (typeof dateTime === 'string' && /^\d+$/.test(dateTime.trim())) {
date = new Date(Number(dateTime))
}
// 检查是否为UTC格式的时间字符串 (2024-12-18T02:25:31.432Z)
else if (typeof dateTime === 'string' && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,3})?(Z|[+-]\d{2}:\d{2})?$/.test(dateTime)) {
date = new Date(dateTime)
}
// 其他都认为符合 RFC 2822 规范
else {
// 处理平台性差异,在Safari/Webkit中,new Date仅支持/作为分割符的字符串时间
date = new Date(
typeof dateTime === 'string'
? dateTime.replace(/-/g, '/')
: dateTime
)
}
const timeSource = {
'y': date.getFullYear().toString(), // 年
'm': (date.getMonth() + 1).toString().padStart(2, '0'), // 月
'd': date.getDate().toString().padStart(2, '0'), // 日
'h': date.getHours().toString().padStart(2, '0'), // 时
'M': date.getMinutes().toString().padStart(2, '0'), // 分
's': date.getSeconds().toString().padStart(2, '0') // 秒
// 有其他格式化字符需求可以继续添加,必须转化成字符串
}
for (const key in timeSource) {
const [ret] = new RegExp(`${key}+`).exec(formatStr) || []
if (ret) {
// 年可能只需展示两位
const beginIndex = key === 'y' && ret.length === 2 ? 2 : 0
formatStr = formatStr.replace(ret, timeSource[key].slice(beginIndex))
}
}
return formatStr
}
/**
* @description 时间戳转为多久之前
* @param {String|Number} timestamp 时间戳
* @param {String|Boolean} format
* 格式化规则如果为时间格式字符串,超出一定时间范围,返回固定的时间格式;
* 如果为布尔值false,无论什么时间,都返回多久以前的格式
* @returns {string} 转化后的内容
*/
export function timeFrom(timestamp = null, format = 'yyyy-mm-dd') {
if (timestamp == null) timestamp = Number(new Date())
timestamp = parseInt(timestamp)
// 判断用户输入的时间戳是秒还是毫秒,一般前端js获取的时间戳是毫秒(13位),后端传过来的为秒(10位)
if (timestamp.toString().length == 10) timestamp *= 1000
let timer = (new Date()).getTime() - timestamp
timer = parseInt(timer / 1000)
// 如果小于5分钟,则返回"刚刚",其他以此类推
let tips = ''
switch (true) {
case timer < 300:
tips = '刚刚'
break
case timer >= 300 && timer < 3600:
tips = `${parseInt(timer / 60)}分钟前`
break
case timer >= 3600 && timer < 86400:
tips = `${parseInt(timer / 3600)}小时前`
break
case timer >= 86400 && timer < 2592000:
tips = `${parseInt(timer / 86400)}天前`
break
default:
// 如果format为false,则无论什么时间戳,都显示xx之前
if (format === false) {
if (timer >= 2592000 && timer < 365 * 86400) {
tips = `${parseInt(timer / (86400 * 30))}个月前`
} else {
tips = `${parseInt(timer / (86400 * 365))}年前`
}
} else {
tips = timeFormat(timestamp, format)
}
}
return tips
}
/**
* @description 去除空格
* @param String str 需要去除空格的字符串
* @param String pos both(左右)|left|right|all 默认both
*/
export function trim(str, pos = 'both') {
str = String(str)
if (pos == 'both') {
return str.replace(/^\s+|\s+$/g, '')
}
if (pos == 'left') {
return str.replace(/^\s*/, '')
}
if (pos == 'right') {
return str.replace(/(\s*$)/g, '')
}
if (pos == 'all') {
return str.replace(/\s+/g, '')
}
return str
}
/**
* @description 对象转url参数
* @param {object} data,对象
* @param {Boolean} isPrefix,是否自动加上"?"
* @param {string} arrayFormat 规则 indices|brackets|repeat|comma
*/
export function queryParams(data = {}, isPrefix = true, arrayFormat = 'brackets') {
const prefix = isPrefix ? '?' : ''
const _result = []
if (['indices', 'brackets', 'repeat', 'comma'].indexOf(arrayFormat) == -1) arrayFormat = 'brackets'
for (const key in data) {
const value = data[key]
// 去掉为空的参数
if (['', undefined, null].indexOf(value) >= 0) {
continue
}
// 如果值为数组,另行处理
if (value.constructor === Array) {
// e.g. {ids: [1, 2, 3]}
switch (arrayFormat) {
case 'indices':
// 结果: ids[0]=1&ids[1]=2&ids[2]=3
for (let i = 0; i < value.length; i++) {
_result.push(`${key}[${i}]=${value[i]}`)
}
break
case 'brackets':
// 结果: ids[]=1&ids[]=2&ids[]=3
value.forEach((_value) => {
_result.push(`${key}[]=${_value}`)
})
break
case 'repeat':
// 结果: ids=1&ids=2&ids=3
value.forEach((_value) => {
_result.push(`${key}=${_value}`)
})
break
case 'comma':
// 结果: ids=1,2,3
let commaStr = ''
value.forEach((_value) => {
commaStr += (commaStr ? ',' : '') + _value
})
_result.push(`${key}=${commaStr}`)
break
default:
value.forEach((_value) => {
_result.push(`${key}[]=${_value}`)
})
}
} else {
_result.push(`${key}=${value}`)
}
}
return _result.length ? prefix + _result.join('&') : ''
}
/**
* 显示消息提示框
* @param {String} title 提示的内容,长度与 icon 取值有关。
* @param {Number} duration 提示的延迟时间,单位毫秒,默认:2000
*/
export function toast(title, duration = 2000) {
uni.showToast({
title: String(title),
icon: 'none',
duration
})
}
/**
* @description 根据主题type值,获取对应的图标
* @param {String} type 主题名称,primary|info|error|warning|success
* @param {boolean} fill 是否使用fill填充实体的图标
*/
export function type2icon(type = 'success', fill = false) {
// 如果非预置值,默认为success
if (['primary', 'info', 'error', 'warning', 'success'].indexOf(type) == -1) type = 'success'
let iconName = ''
// 目前(2019-12-12),info和primary使用同一个图标
switch (type) {
case 'primary':
iconName = 'info-circle'
break
case 'info':
iconName = 'info-circle'
break
case 'error':
iconName = 'close-circle'
break
case 'warning':
iconName = 'error-circle'
break
case 'success':
iconName = 'checkmark-circle'
break
default:
iconName = 'checkmark-circle'
}
// 是否是实体类型,加上-fill,在icon组件库中,实体的类名是后面加-fill的
if (fill) iconName += '-fill'
return iconName
}
/**
* @description 数字格式化
* @param {number|string} number 要格式化的数字
* @param {number} decimals 保留几位小数
* @param {string} decimalPoint 小数点符号
* @param {string} thousandsSeparator 千分位符号
* @returns {string} 格式化后的数字
*/
export function priceFormat(number, decimals = 0, decimalPoint = '.', thousandsSeparator = ',') {
number = (`${number}`).replace(/[^0-9+-Ee.]/g, '')
const n = !isFinite(+number) ? 0 : +number
const prec = !isFinite(+decimals) ? 0 : Math.abs(decimals)
const sep = (typeof thousandsSeparator === 'undefined') ? ',' : thousandsSeparator
const dec = (typeof decimalPoint === 'undefined') ? '.' : decimalPoint
let s = ''
s = (prec ? round(n, prec) + '' : `${Math.round(n)}`).split('.')
const re = /(-?\d+)(\d{3})/
while (re.test(s[0])) {
s[0] = s[0].replace(re, `$1${sep}$2`)
}
if ((s[1] || '').length < prec) {
s[1] = s[1] || ''
s[1] += new Array(prec - s[1].length + 1).join('0')
}
return s.join(dec)
}
/**
* @description 获取duration值
* 如果带有ms或者s直接返回,如果大于一定值,认为是ms单位,小于一定值,认为是s单位
* 比如以30位阈值,那么300大于30,可以理解为用户想要的是300ms,而不是想花300s去执行一个动画
* @param {String|number} value 比如: "1s"|"100ms"|1|100
* @param {boolean} unit 提示: 如果是false 默认返回number
* @return {string|number}
*/
export function getDuration(value, unit = true) {
const valueNum = parseInt(value)
if (unit) {
if (/s$/.test(value)) return value
return value > 30 ? `${value}ms` : `${value}s`
}
if (/ms$/.test(value)) return valueNum
if (/s$/.test(value)) return valueNum > 30 ? valueNum : valueNum * 1000
return valueNum
}
/**
* @description 日期的月或日补零操作
* @param {String} value 需要补零的值
*/
export function padZero(value) {
return `00${value}`.slice(-2)
}
/**
* @description 在u-form的子组件内容发生变化,或者失去焦点时,尝试通知u-form执行校验方法
* @param {*} instance
* @param {*} event
*/
export function formValidate(instance, event) {
const formItem = $parent.call(instance, 'up-form-item')
const form = $parent.call(instance, 'up-form')
// 如果发生变化的input或者textarea等,其父组件中有u-form-item或者u-form等,就执行form的validate方法
// 同时将form-item的pros传递给form,让其进行精确对象验证
if (formItem && form) {
form.validateField(formItem.prop, () => {}, event)
}
}
/**
* @description 获取某个对象下的属性,用于通过类似'a.b.c'的形式去获取一个对象的的属性的形式
* @param {object} obj 对象
* @param {string} key 需要获取的属性字段
* @returns {*}
*/
export function getProperty(obj, key) {
if (typeof obj !== 'object' || null == obj) {
return ''
}
if (typeof key !== 'string' || key === '') {
return ''
}
if (key.indexOf('.') !== -1) {
const keys = key.split('.')
let firstObj = obj[keys[0]] || {}
for (let i = 1; i < keys.length; i++) {
if (firstObj) {
firstObj = firstObj[keys[i]]
}
}
return firstObj
}
return obj[key]
}
/**
* @description 设置对象的属性值,如果'a.b.c'的形式进行设置
* @param {object} obj 对象
* @param {string} key 需要设置的属性
* @param {string} value 设置的值
*/
export function setProperty(obj, key, value) {
if (typeof obj !== 'object' || null == obj) {
return
}
// 递归赋值
const inFn = function(_obj, keys, v) {
// 最后一个属性key
if (keys.length === 1) {
_obj[keys[0]] = v
return
}
// 0~length-1个key
while (keys.length > 1) {
const k = keys[0]
if (!_obj[k] || (typeof _obj[k] !== 'object')) {
_obj[k] = {}
}
const key = keys.shift()
// 自调用判断是否存在属性,不存在则自动创建对象
inFn(_obj[k], keys, v)
}
}
if (typeof key !== 'string' || key === '') {
} else if (key.indexOf('.') !== -1) { // 支持多层级赋值操作
const keys = key.split('.')
inFn(obj, keys, value)
} else {
obj[key] = value
}
}
/**
* @description 获取当前页面路径
*/
export function page() {
const pages = getCurrentPages()
// 某些特殊情况下(比如页面进行redirectTo时的一些时机),pages可能为空数组
return `/${pages[pages.length - 1].route || ''}`
}
/**
* @description 获取当前路由栈实例数组
*/
export function pages() {
const pages = getCurrentPages()
return pages
}
export function getValueByPath(obj, path) {
// 将路径字符串按 '.' 分割成数组
const pathArr = path.split('.');
// 使用 reduce 方法从 obj 开始,逐级访问嵌套属性
return pathArr.reduce((acc, curr) => {
// 如果当前累加器(acc)是对象且包含当前键(curr),则返回该键对应的值
// 否则返回 undefined(表示路径不存在)
return acc && acc[curr] !== undefined ? acc[curr] : undefined;
}, obj);
}
/**
* 生成同色系浅色背景色
* @param {string} textColor - 支持 #RGB、#RRGGBB、rgb()、rgba() 格式
* @param {number} [lightness=85] - 目标亮度百分比(默认85%)
* @returns {string} 十六进制颜色值
*/
export function genLightColor(textColor, lightness = 95) {
// 手动解析颜色值(避免使用document)
const rgb = parseColorWithoutDOM(textColor);
// RGB转HSL色域
const hsl = rgbToHsl(rgb.r, rgb.g, rgb.b);
// 生成浅色背景
const bgHsl = {
h: hsl.h,
s: hsl.s,
l: Math.min(lightness, 95)
};
return hslToHex(bgHsl.h, bgHsl.s, bgHsl.l);
}
/* 手动解析颜色字符串(兼容uni-app环境) */
function parseColorWithoutDOM(colorStr) {
// 统一转小写处理
const str = colorStr.toLowerCase().trim();
// 处理十六进制格式
if (str.startsWith('#')) {
const hex = str.replace('#', '');
const fullHex = hex.length === 3 ?
hex.split('').map(c => c + c).join('') : hex;
return {
r: parseInt(fullHex.substring(0,2), 16),
g: parseInt(fullHex.substring(2,4), 16),
b: parseInt(fullHex.substring(4,6), 16)
};
}
// 处理rgb/rgba格式
const rgbMatch = str.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);
if (rgbMatch) {
return {
r: +rgbMatch[1],
g: +rgbMatch[2],
b: +rgbMatch[3]
};
}
throw new Error('Invalid color format');
}
// 辅助函数:RGB 转 HSL(色相、饱和度、亮度)
function rgbToHsl(r, g, b) {
r /= 255, g /= 255, b /= 255;
const max = Math.max(r, g, b), min = Math.min(r, g, b);
let h, s, l = (max + min) / 2;
if (max === min) {
h = s = 0; // achromatic
} else {
const d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h = (h * 60).toFixed(1);
}
return { h: +h, s: +(s * 100).toFixed(1), l: +(l * 100).toFixed(1) };
}
// 辅助函数:HSL 转十六进制
function hslToHex(h, s, l) {
l /= 100;
const a = s * Math.min(l, 1 - l) / 100;
const f = n => {
const k = (n + h / 30) % 12;
const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
return Math.round(255 * color).toString(16).padStart(2, '0');
};
return `#${f(0)}${f(8)}${f(4)}`;
}
export default {
range,
getPx,
sleep,
os,
sys,
getWindowInfo,
random,
guid,
$parent,
addStyle,
addUnit,
deepClone,
deepMerge,
shallowMerge,
error,
randomArray,
timeFormat,
timeFrom,
trim,
queryParams,
toast,
type2icon,
priceFormat,
getDuration,
padZero,
formValidate,
getProperty,
setProperty,
page,
pages,
getValueByPath,
genLightColor,
rpx2px
}

View File

@@ -0,0 +1,75 @@
/**
* 注意:
* 此部分内容,在vue-cli模式下,需要在vue.config.js加入如下内容才有效:
* module.exports = {
* transpileDependencies: ['uview-v2']
* }
*/
let platform = 'none'
// #ifdef VUE3
platform = 'vue3'
// #endif
// #ifdef VUE2
platform = 'vue2'
// #endif
// #ifdef APP-PLUS
platform = 'plus'
// #endif
// #ifdef APP-NVUE
platform = 'nvue'
// #endif
// #ifdef H5
platform = 'h5'
// #endif
// #ifdef MP
platform = 'mp'
// #endif
// #ifdef MP-WEIXIN
platform = 'weixin'
// #endif
// #ifdef MP-ALIPAY
platform = 'alipay'
// #endif
// #ifdef MP-BAIDU
platform = 'baidu'
// #endif
// #ifdef MP-TOUTIAO
platform = 'toutiao'
// #endif
// #ifdef MP-QQ
platform = 'qq'
// #endif
// #ifdef MP-KUAISHOU
platform = 'kuaishou'
// #endif
// #ifdef MP-360
platform = '360'
// #endif
// #ifdef QUICKAPP-WEBVIEW
platform = 'quickapp-webview'
// #endif
// #ifdef QUICKAPP-WEBVIEW-HUAWEI
platform = 'quickapp-webview-huawei'
// #endif
// #ifdef QUICKAPP-WEBVIEW-UNION
platform = 'quckapp-webview-union'
// #endif
export default platform

View File

@@ -0,0 +1,327 @@
/**
* 验证电子邮箱格式
*/
export function email(value) {
return /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/.test(value)
}
/**
* 验证手机格式
*/
export function mobile(value) {
return /^1[23456789]\d{9}$/.test(value)
}
/**
* 验证URL格式
*/
export function url(value) {
return /^((https|http|ftp|rtsp|mms):\/\/)(([0-9a-zA-Z_!~*'().&=+$%-]+: )?[0-9a-zA-Z_!~*'().&=+$%-]+@)?(([0-9]{1,3}.){3}[0-9]{1,3}|([0-9a-zA-Z_!~*'()-]+.)*([0-9a-zA-Z][0-9a-zA-Z-]{0,61})?[0-9a-zA-Z].[a-zA-Z]{2,6})(:[0-9]{1,4})?((\/?)|(\/[0-9a-zA-Z_!~*'().;?:@&=+$,%#-]+)+\/?)$/
.test(value)
}
/**
* 验证日期格式
* @param {number | string} value yyyy-mm-dd hh:mm:ss 或 时间戳
*/
export function date(value) {
if (!value) return false;
// number类型,判断是否是时间戳
if (typeof value === "number") {
// len === 10 秒级时间戳 len === 13 毫秒级时间戳
if (value.toString().length !== 10 && value.toString().length !== 13) {
return false;
}
return !isNaN(new Date(value).getTime());
}
if (typeof value === "string") {
// 是否为string类型时间戳
const numV = Number(value);
if (!isNaN(numV)) {
if (
numV.toString().length === 10 ||
numV.toString().length === 13
) {
return !isNaN(new Date(numV).getTime());
}
}
// 非时间戳,且长度在yyyy-mm-dd 至 yyyy-mm-dd hh:mm:ss 之间
if (value.length < 10 || value.length > 19) {
return false;
}
const dateRegex =
/^\d{4}[-\/]\d{2}[-\/]\d{2}( \d{1,2}:\d{2}(:\d{2})?)?$/;
if (!dateRegex.test(value)) {
return false;
}
// 检查是否为有效日期
const dateValue = new Date(value);
return !isNaN(dateValue.getTime());
}
// 非number和string类型,不做校验
return false;
}
/**
* 验证ISO类型的日期格式
*/
export function dateISO(value) {
return /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test(value)
}
/**
* 验证十进制数字
*/
export function number(value) {
return /^[\+-]?(\d+\.?\d*|\.\d+|\d\.\d+e\+\d+)$/.test(value)
}
/**
* 验证字符串
*/
export function string(value) {
return typeof value === 'string'
}
/**
* 验证整数
*/
export function digits(value) {
return /^\d+$/.test(value)
}
/**
* 验证身份证号码
*/
export function idCard(value) {
return /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(
value
)
}
/**
* 是否车牌号
*/
export function carNo(value) {
// 新能源车牌
const xreg = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}(([0-9]{5}[DF]$)|([DF][A-HJ-NP-Z0-9][0-9]{4}$))/
// 旧车牌
const creg = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳]{1}$/
if (value.length === 7) {
return creg.test(value)
} if (value.length === 8) {
return xreg.test(value)
}
return false
}
/**
* 金额,只允许2位小数
*/
export function amount(value) {
// 金额,只允许保留两位小数
return /^[1-9]\d*(,\d{3})*(\.\d{1,2})?$|^0\.\d{1,2}$/.test(value)
}
/**
* 中文
*/
export function chinese(value) {
const reg = /^[\u4e00-\u9fa5]+$/gi
return reg.test(value)
}
/**
* 只能输入字母
*/
export function letter(value) {
return /^[a-zA-Z]*$/.test(value)
}
/**
* 只能是字母或者数字
*/
export function enOrNum(value) {
// 英文或者数字
const reg = /^[0-9a-zA-Z]*$/g
return reg.test(value)
}
/**
* 验证是否包含某个值
*/
export function contains(value, param) {
return value.indexOf(param) >= 0
}
/**
* 验证一个值范围[min, max]
*/
export function range(value, param) {
return value >= param[0] && value <= param[1]
}
/**
* 验证一个长度范围[min, max]
*/
export function rangeLength(value, param) {
return value.length >= param[0] && value.length <= param[1]
}
/**
* 是否固定电话
*/
export function landline(value) {
const reg = /^\d{3,4}-\d{7,8}(-\d{3,4})?$/
return reg.test(value)
}
/**
* 判断是否为空
*/
export function empty(value) {
switch (typeof value) {
case 'undefined':
return true
case 'string':
if (value.replace(/(^[ \t\n\r]*)|([ \t\n\r]*$)/g, '').length == 0) return true
break
case 'boolean':
if (!value) return true
break
case 'number':
if (value === 0 || isNaN(value)) return true
break
case 'object':
if (value === null || value.length === 0) return true
for (const i in value) {
return false
}
return true
}
return false
}
/**
* 是否json字符串
*/
export function jsonString(value) {
if (typeof value === 'string') {
try {
const obj = JSON.parse(value)
if (typeof obj === 'object' && obj) {
return true
}
return false
} catch (e) {
return false
}
}
return false
}
/**
* 是否数组
*/
export function array(value) {
if (typeof Array.isArray === 'function') {
return Array.isArray(value)
}
return Object.prototype.toString.call(value) === '[object Array]'
}
/**
* 是否对象
*/
export function object(value) {
return Object.prototype.toString.call(value) === '[object Object]'
}
/**
* 是否是Promise对象
*/
export function objectPromise(value) {
return Object.prototype.toString.call(value) === '[object Promise]';
}
/**
* 是否短信验证码
*/
export function code(value, len = 6) {
return new RegExp(`^\\d{${len}}$`).test(value)
}
/**
* 是否函数方法
* @param {Object} value
*/
export function func(value) {
return typeof value === 'function'
}
/**
* 是否promise对象
* @param {Object} value
*/
export function promise(value) {
return objectPromise(value) && func(value.then) && func(value.catch)
}
/** 是否图片格式
* @param {Object} value
*/
export function image(value) {
const newValue = value.split('?')[0]
const IMAGE_REGEXP = /\.(jpeg|jpg|gif|png|svg|webp|jfif|bmp|dpg)/i
return IMAGE_REGEXP.test(newValue)
}
/**
* 是否视频格式
* @param {Object} value
*/
export function video(value) {
const VIDEO_REGEXP = /\.(mp4|mpg|mpeg|dat|asf|avi|rm|rmvb|mov|wmv|flv|mkv|m3u8)/i
return VIDEO_REGEXP.test(value)
}
/**
* 是否为正则对象
* @param {Object}
* @return {Boolean}
*/
export function regExp(o) {
return o && Object.prototype.toString.call(o) === '[object RegExp]'
}
export default {
email,
mobile,
url,
date,
dateISO,
number,
digits,
idCard,
carNo,
amount,
chinese,
letter,
enOrNum,
contains,
range,
rangeLength,
empty,
isEmpty: empty,
jsonString,
landline,
object,
array,
code,
func,
promise,
video,
image,
regExp,
string
}

View File

@@ -0,0 +1,30 @@
let timer;
let flag;
/**
* 节流原理:在一定时间内,只能触发一次
*
* @param {Function} func 要执行的回调函数
* @param {Number} wait 延时的时间
* @param {Boolean} immediate 是否立即执行
* @return null
*/
export function throttle(func, wait = 500, immediate = true) {
if (immediate) {
if (!flag) {
flag = true
// 如果是立即执行,则在wait毫秒内开始时执行
typeof func === 'function' && func()
timer = setTimeout(() => {
flag = false
}, wait)
}
} else if (!flag) {
flag = true
// 如果是非立即执行,则在wait毫秒内的结束处执行
timer = setTimeout(() => {
flag = false
typeof func === 'function' && func()
}, wait)
}
}
export default throttle

View File

@@ -0,0 +1,54 @@
import zhHans from './locales/zh-Hans.json'
import zhHant from './locales/zh-Hant.json'
import en from './locales/en.json'
import es from './locales/es.json'
import fr from './locales/fr.json'
import de from './locales/de.json'
import ko from './locales/ko.json'
import ja from './locales/ja.json'
import ru from './locales/ru.json'
let settings = {
lang: uni.getLocale(),
locales: {
en,
es,
fr,
de,
ko,
ja,
ru,
'zh-Hant': zhHant,
'zh-Hans': zhHans
}
};
uni.onLocaleChange((locale) => {
settings.lang = locale;
})
/**
* 多语言方法
*/
export function t(value, params = {}) {
// console.log(settings.locales[settings.lang])
if (value) {
let lang = settings.lang
if (!settings.locales[settings.lang]) {
lang = 'zh-Hans'
}
let result = settings.locales[lang][value] || value;
// 替换{xxx}格式的变量
Object.keys(params).forEach(key => {
const reg = new RegExp(`{${key}}`, 'g');
result = result.replace(reg, params[key]);
});
return result;
} else {
return value;
}
}
export default {
settings: settings
}

View File

@@ -0,0 +1,86 @@
{
"up.common.cancel": "Abbrechen",
"up.common.confirm": "Bestätigen",
"up.common.start": "Start",
"up.common.end": "Ende",
"up.common.stop": "Stopp",
"up.common.copy": "Kopieren",
"up.common.none": "Keine",
"up.common.tip": "Hinweis",
"up.common.success": "Erfolg",
"up.common.fail": "Fehlgeschlagen",
"up.common.close": "Schließen",
"up.common.preview": "Vorschau",
"up.common.re-select": "Erneut auswählen",
"up.common.rotate": "Drehen",
"up.common.pleaseChoose": "Bitte wählen",
"up.common.loading": "Laden",
"up.common.loading2": "Wird geladen",
"up.common.inOperation": "In Bearbeitung",
"up.common.settings": "Einstellungen",
"up.common.retry": "Wiederholen",
"up.common.search": "Suchen",
"up.common.more": "Mehr",
"up.common.video": "Video",
"up.common.file": "Datei",
"up.week.one": "Mo",
"up.week.two": "Di",
"up.week.three": "Mi",
"up.week.four": "Do",
"up.week.five": "Fr",
"up.week.six": "Sa",
"up.week.seven": "So",
"up.barcode.error": "Barcode-Generierung fehlgeschlagen",
"up.calendar.chooseDates": "Datumsauswahl",
"up.calendar.disabled": "Dieses Datum ist deaktiviert",
"up.calendar.daysExceed": "Die Anzahl der ausgewählten Tage darf {days} Tage nicht überschreiten",
"up.calendar.today": "Heute",
"up.cityLocate.locateCity": "Stadt lokalisieren",
"up.cityLocate.fail": "Lokalisierung fehlgeschlagen, bitte klicken Sie zum Wiederholen.",
"up.cityLocate.locating": "Lokalisierung läuft",
"up.code.send": "Bestätigungscode erhalten",
"up.code.resendAfter": "Erneut senden in X Sekunden",
"up.code.resend": "Erneut senden",
"up.cropper.emptyWidhtOrHeight": "Breite oder Höhe des Zuschneidebereichs nicht festgelegt",
"up.empty.car": "Warenkorb ist leer",
"up.empty.page": "Seite existiert nicht",
"up.empty.search": "Keine Suchergebnisse",
"up.empty.address": "Keine Lieferadresse",
"up.empty.wifi": "Kein WLAN",
"up.empty.order": "Bestellungen sind leer",
"up.empty.coupon": "Keine Gutscheine",
"up.empty.favor": "Keine Favoriten",
"up.empty.permission": "Keine Berechtigung",
"up.empty.history": "Kein Verlauf",
"up.empty.news": "Keine Nachrichtenliste",
"up.empty.message": "Nachrichtenliste ist leer",
"up.empty.list": "Liste ist leer",
"up.empty.data": "Daten sind leer",
"up.empty.comment": "Keine Kommentare",
"up.link.copyed": "Link kopiert, bitte im Browser öffnen",
"up.loadmoe.loadmore": "Mehr laden",
"up.loadmoe.nomore": "Keine weiteren Daten",
"up.noNetwork.text": "Ups, Netzwerksignal verloren",
"up.noNetwork.pleaseCheck": "Bitte überprüfen Sie das Netzwerk oder gehen Sie zu",
"up.noNetwork.connect": "Netzwerk verbunden",
"up.noNetwork.disconnect": "Keine Netzwerkverbindung",
"up.pagination.previous": "Vorherige Seite",
"up.pagination.next": "Nächste Seite",
"up.pullRefresh.pull": "Zum Aktualisieren nach unten ziehen",
"up.pullRefresh.release": "Loslassen zum Aktualisieren",
"up.pullRefresh.refreshing": "Aktualisierung läuft",
"up.readMore.expand": "Erweitern zum vollständigen Lesen",
"up.readMore.fold": "Einklappen",
"up.search.placeholder": "Bitte Schlüsselwort eingeben",
"up.signature.penSize": "Strichstärke",
"up.signature.penColor": "Strichfarbe",
"up.upload.sizeExceed": "Größenbegrenzung überschritten",
"up.upload.uploading": "Upload läuft",
"up.upload.previewImageFail": "Bildvorschau fehlgeschlagen",
"up.upload.previewVideoFail": "Videovorschau fehlgeschlagen",
"up.goodsSku.stock": "Lagerbestand",
"up.goodsSku.price": "Preis",
"up.goodsSku.amount": "Stück",
"up.goodsSku.choosed": "Ausgewählt",
"up.goodsSku.buyAmount": "Anzahl"
}

View File

@@ -0,0 +1,86 @@
{
"up.common.cancel": "Cancel",
"up.common.confirm": "Confirm",
"up.common.start": "Start",
"up.common.end": "End",
"up.common.stop": "Stop",
"up.common.copy": "Copy",
"up.common.none": "None",
"up.common.tip": "Tip",
"up.common.success": "Success",
"up.common.fail": "Fail",
"up.common.close": "Close",
"up.common.preview": "Preview",
"up.common.re-select": "Re-select",
"up.common.rotate": "Rotate",
"up.common.pleaseChoose": "Please choose",
"up.common.loading": "Loading",
"up.common.loading2": "Loading",
"up.common.inOperation": "In operation",
"up.common.settings": "Settings",
"up.common.retry": "Retry",
"up.common.search": "Search",
"up.common.more": "More",
"up.common.video": "Video",
"up.common.file": "File",
"up.week.one": "Mon",
"up.week.two": "Tue",
"up.week.three": "Wed",
"up.week.four": "Thu",
"up.week.five": "Fri",
"up.week.six": "Sat",
"up.week.seven": "Sun",
"up.barcode.error": "Failed to generate barcode",
"up.calendar.chooseDates": "Date selection",
"up.calendar.disabled": "This date is disabled",
"up.calendar.daysExceed": "The number of selected days cannot exceed {days} days",
"up.calendar.today": "Today",
"up.cityLocate.locateCity": "Locate city",
"up.cityLocate.fail": "Location failed, please click to retry.",
"up.cityLocate.locating": "Locating",
"up.code.send": "Get verification code",
"up.code.resendAfter": "Resend after X seconds",
"up.code.resend": "Resend",
"up.cropper.emptyWidhtOrHeight": "The width or height of the cropping box is not set",
"up.empty.car": "Shopping cart is empty",
"up.empty.page": "Page not found",
"up.empty.search": "No search results",
"up.empty.address": "No shipping address",
"up.empty.wifi": "No WiFi",
"up.empty.order": "Order is empty",
"up.empty.coupon": "No coupons",
"up.empty.favor": "No favorites",
"up.empty.permission": "No permission",
"up.empty.history": "No history",
"up.empty.news": "No news list",
"up.empty.message": "Message list is empty",
"up.empty.list": "List is empty",
"up.empty.data": "Data is empty",
"up.empty.comment": "No comments",
"up.link.copyed": "Link copied, please open in browser",
"up.loadmoe.loadmore": "Load more",
"up.loadmoe.nomore": "No more",
"up.noNetwork.text": "Oops, network signal lost",
"up.noNetwork.pleaseCheck": "Please check the network, or go to",
"up.noNetwork.connect": "Network connected",
"up.noNetwork.disconnect": "No network connection",
"up.pagination.previous": "Previous",
"up.pagination.next": "Next",
"up.pullRefresh.pull": "Pull to refresh",
"up.pullRefresh.release": "Release to refresh",
"up.pullRefresh.refreshing": "Refreshing",
"up.readMore.expand": "Expand to read more",
"up.readMore.fold": "Collapse",
"up.search.placeholder": "Please enter keywords",
"up.signature.penSize": "Stroke size",
"up.signature.penColor": "Stroke color",
"up.upload.sizeExceed": "Size limit exceeded",
"up.upload.uploading": "Uploading",
"up.upload.previewImageFail": "Failed to preview image",
"up.upload.previewVideoFail": "Failed to preview video",
"up.goodsSku.stock": "Stock",
"up.goodsSku.price": "Price",
"up.goodsSku.amount": "Items",
"up.goodsSku.choosed": "Selected",
"up.goodsSku.buyAmount": "Quantity"
}

View File

@@ -0,0 +1,86 @@
{
"up.common.cancel": "Cancelar",
"up.common.confirm": "Confirmar",
"up.common.start": "Iniciar",
"up.common.end": "Finalizar",
"up.common.stop": "Detener",
"up.common.copy": "Copiar",
"up.common.none": "Ninguno",
"up.common.tip": "Consejo",
"up.common.success": "Éxito",
"up.common.fail": "Fallido",
"up.common.close": "Cerrar",
"up.common.preview": "Vista previa",
"up.common.re-select": "Re seleccionar",
"up.common.rotate": "Rotar",
"up.common.pleaseChoose": "Por favor seleccione",
"up.common.loading": "Cargando",
"up.common.loading2": "Cargando",
"up.common.inOperation": "En operación",
"up.common.settings": "Configuración",
"up.common.retry": "Reintentar",
"up.common.search": "Buscar",
"up.common.more": "Más",
"up.common.video": "Vídeo",
"up.common.file": "Archivo",
"up.week.one": "Lun",
"up.week.two": "Mar",
"up.week.three": "Mié",
"up.week.four": "Jue",
"up.week.five": "Vie",
"up.week.six": "Sáb",
"up.week.seven": "Dom",
"up.barcode.error": "Error al generar código de barras",
"up.calendar.chooseDates": "Selección de fecha",
"up.calendar.disabled": "Esta fecha está deshabilitada",
"up.calendar.daysExceed": "Los días seleccionados no pueden exceder {days} días",
"up.calendar.today": "Hoy",
"up.cityLocate.locateCity": "Localizar ciudad",
"up.cityLocate.fail": "Error de localización, haga clic para reintentar.",
"up.cityLocate.locating": "Localizando",
"up.code.send": "Obtener código de verificación",
"up.code.resendAfter": "Reenviar en X segundos",
"up.code.resend": "Reenviar",
"up.cropper.emptyWidhtOrHeight": "El ancho o alto del recorte no está configurado",
"up.empty.car": "Carrito de compras vacío",
"up.empty.page": "Página no encontrada",
"up.empty.search": "Sin resultados de búsqueda",
"up.empty.address": "Sin dirección de envío",
"up.empty.wifi": "Sin WiFi",
"up.empty.order": "Pedido vacío",
"up.empty.coupon": "Sin cupones",
"up.empty.favor": "Sin favoritos",
"up.empty.permission": "Sin permisos",
"up.empty.history": "Sin historial",
"up.empty.news": "Sin noticias",
"up.empty.message": "Lista de mensajes vacía",
"up.empty.list": "Lista vacía",
"up.empty.data": "Datos vacíos",
"up.empty.comment": "Sin comentarios",
"up.link.copyed": "Enlace copiado, por favor abra en el navegador",
"up.loadmoe.loadmore": "Cargar más",
"up.loadmoe.nomore": "No hay más",
"up.noNetwork.text": "¡Ups! Se perdió la señal de red",
"up.noNetwork.pleaseCheck": "Por favor verifique la red, o vaya a",
"up.noNetwork.connect": "Red conectada",
"up.noNetwork.disconnect": "Sin conexión a internet",
"up.pagination.previous": "Página anterior",
"up.pagination.next": "Página siguiente",
"up.pullRefresh.pull": "Deslizar hacia abajo para actualizar",
"up.pullRefresh.release": "Soltar para actualizar",
"up.pullRefresh.refreshing": "Actualizando",
"up.readMore.expand": "Expandir para leer más",
"up.readMore.fold": "Contraer",
"up.search.placeholder": "Ingrese palabra clave",
"up.signature.penSize": "Tamaño del trazo",
"up.signature.penColor": "Color del trazo",
"up.upload.sizeExceed": "Excede el límite de tamaño",
"up.upload.uploading": "Subiendo",
"up.upload.previewImageFail": "Error al previsualizar imagen",
"up.upload.previewVideoFail": "Error al previsualizar vídeo",
"up.goodsSku.stock": "Inventario",
"up.goodsSku.price": "Precio",
"up.goodsSku.amount": "Piezas",
"up.goodsSku.choosed": "Seleccionado",
"up.goodsSku.buyAmount": "Cantidad"
}

View File

@@ -0,0 +1,86 @@
{
"up.common.cancel": "Annuler",
"up.common.confirm": "Confirmer",
"up.common.start": "Démarrer",
"up.common.end": "Terminer",
"up.common.stop": "Arrêter",
"up.common.copy": "Copier",
"up.common.none": "Aucun",
"up.common.tip": "Conseil",
"up.common.success": "Succès",
"up.common.fail": "Échec",
"up.common.close": "Fermer",
"up.common.preview": "Aperçu",
"up.common.re-select": "Resélectionner",
"up.common.rotate": "Rotation",
"up.common.pleaseChoose": "Veuillez choisir",
"up.common.loading": "Chargement",
"up.common.loading2": "Chargement en cours",
"up.common.inOperation": "En cours d'opération",
"up.common.settings": "Paramètres",
"up.common.retry": "Réessayer",
"up.common.search": "Rechercher",
"up.common.more": "Plus",
"up.common.video": "Vidéo",
"up.common.file": "Fichier",
"up.week.one": "Lun",
"up.week.two": "Mar",
"up.week.three": "Mer",
"up.week.four": "Jeu",
"up.week.five": "Ven",
"up.week.six": "Sam",
"up.week.seven": "Dim",
"up.barcode.error": "Échec de génération du code-barres",
"up.calendar.chooseDates": "Sélection de dates",
"up.calendar.disabled": "Cette date est désactivée",
"up.calendar.daysExceed": "Le nombre de jours sélectionnés ne peut pas dépasser {days} jours",
"up.calendar.today": "Aujourd'hui",
"up.cityLocate.locateCity": "Localiser la ville",
"up.cityLocate.fail": "Échec de localisation, veuillez cliquer pour réessayer.",
"up.cityLocate.locating": "Localisation en cours",
"up.code.send": "Obtenir le code de vérification",
"up.code.resendAfter": "Renvoyer dans X secondes",
"up.code.resend": "Renvoyer",
"up.cropper.emptyWidhtOrHeight": "La largeur ou la hauteur de recadrage n'est pas définie",
"up.empty.car": "Panier vide",
"up.empty.page": "Page introuvable",
"up.empty.search": "Aucun résultat de recherche",
"up.empty.address": "Aucune adresse de livraison",
"up.empty.wifi": "Aucun Wi-Fi",
"up.empty.order": "Commande vide",
"up.empty.coupon": "Aucun coupon",
"up.empty.favor": "Aucun favori",
"up.empty.permission": "Aucune autorisation",
"up.empty.history": "Aucun historique",
"up.empty.news": "Aucune actualité",
"up.empty.message": "Liste de messages vide",
"up.empty.list": "Liste vide",
"up.empty.data": "Données vides",
"up.empty.comment": "Aucun commentaire",
"up.link.copyed": "Lien copié, veuillez ouvrir dans le navigateur",
"up.loadmoe.loadmore": "Charger plus",
"up.loadmoe.nomore": "Plus de contenu",
"up.noNetwork.text": "Oups, le signal réseau est perdu",
"up.noNetwork.pleaseCheck": "Veuillez vérifier le réseau, ou aller à",
"up.noNetwork.connect": "Réseau connecté",
"up.noNetwork.disconnect": "Aucune connexion réseau",
"up.pagination.previous": "Page précédente",
"up.pagination.next": "Page suivante",
"up.pullRefresh.pull": "Tirer pour actualiser",
"up.pullRefresh.release": "Relâcher pour actualiser",
"up.pullRefresh.refreshing": "Actualisation en cours",
"up.readMore.expand": "Développer pour lire la suite",
"up.readMore.fold": "Réduire",
"up.search.placeholder": "Veuillez saisir un mot-clé",
"up.signature.penSize": "Taille du trait",
"up.signature.penColor": "Couleur du trait",
"up.upload.sizeExceed": "Dépassement de la limite de taille",
"up.upload.uploading": "Téléchargement en cours",
"up.upload.previewImageFail": "Échec de l'aperçu de l'image",
"up.upload.previewVideoFail": "Échec de l'aperçu de la vidéo",
"up.goodsSku.stock": "Stock",
"up.goodsSku.price": "Prix",
"up.goodsSku.amount": "Pièces",
"up.goodsSku.choosed": "Sélectionné",
"up.goodsSku.buyAmount": "Quantité"
}

View File

@@ -0,0 +1,86 @@
{
"up.common.cancel": "キャンセル",
"up.common.confirm": "確認",
"up.common.start": "開始",
"up.common.end": "終了",
"up.common.stop": "停止",
"up.common.copy": "コピー",
"up.common.none": "なし",
"up.common.tip": "ヒント",
"up.common.success": "成功",
"up.common.fail": "失敗",
"up.common.close": "閉じる",
"up.common.preview": "プレビュー",
"up.common.re-select": "再選択",
"up.common.rotate": "回転",
"up.common.pleaseChoose": "選択してください",
"up.common.loading": "読み込み中",
"up.common.loading2": "読み込み中",
"up.common.inOperation": "操作中",
"up.common.settings": "設定",
"up.common.retry": "再試行",
"up.common.search": "検索",
"up.common.more": "もっと見る",
"up.common.video": "ビデオ",
"up.common.file": "ファイル",
"up.week.one": "月",
"up.week.two": "火",
"up.week.three": "水",
"up.week.four": "木",
"up.week.five": "金",
"up.week.six": "土",
"up.week.seven": "日",
"up.barcode.error": "バーコードの生成に失敗しました",
"up.calendar.chooseDates": "日付選択",
"up.calendar.disabled": "この日付は無効です",
"up.calendar.daysExceed": "選択日数は{days}日を超えることはできません",
"up.calendar.today": "今日",
"up.cityLocate.locateCity": "都市の位置を特定",
"up.cityLocate.fail": "位置特定に失敗しました。再試行するにはクリックしてください。",
"up.cityLocate.locating": "位置特定中",
"up.code.send": "認証コードを取得",
"up.code.resendAfter": "X秒後に再送信",
"up.code.resend": "再送信",
"up.cropper.emptyWidhtOrHeight": "切り抜き枠の幅または高さが設定されていません",
"up.empty.car": "ショッピングカートは空です",
"up.empty.page": "ページが存在しません",
"up.empty.search": "検索結果がありません",
"up.empty.address": "配送先住所がありません",
"up.empty.wifi": "Wi-Fiがありません",
"up.empty.order": "注文がありません",
"up.empty.coupon": "クーポンがありません",
"up.empty.favor": "お気に入りがありません",
"up.empty.permission": "権限がありません",
"up.empty.history": "履歴がありません",
"up.empty.news": "ニュースがありません",
"up.empty.message": "メッセージがありません",
"up.empty.list": "リストが空です",
"up.empty.data": "データがありません",
"up.empty.comment": "コメントがありません",
"up.link.copyed": "リンクがコピーされました。ブラウザで開いてください",
"up.loadmoe.loadmore": "さらに読み込む",
"up.loadmoe.nomore": "これ以上データがありません",
"up.noNetwork.text": "ネットワーク信号が失われました",
"up.noNetwork.pleaseCheck": "ネットワークを確認するか、移動してください",
"up.noNetwork.connect": "ネットワーク接続済み",
"up.noNetwork.disconnect": "ネットワーク未接続",
"up.pagination.previous": "前へ",
"up.pagination.next": "次へ",
"up.pullRefresh.pull": "引き下げて更新",
"up.pullRefresh.release": "指を離して更新",
"up.pullRefresh.refreshing": "更新中",
"up.readMore.expand": "全文表示",
"up.readMore.fold": "折りたたむ",
"up.search.placeholder": "キーワードを入力してください",
"up.signature.penSize": "線の太さ",
"up.signature.penColor": "線の色",
"up.upload.sizeExceed": "サイズ制限を超えています",
"up.upload.uploading": "アップロード中",
"up.upload.previewImageFail": "画像プレビュー失敗",
"up.upload.previewVideoFail": "ビデオプレビュー失敗",
"up.goodsSku.stock": "在庫",
"up.goodsSku.price": "価格",
"up.goodsSku.amount": "個",
"up.goodsSku.choosed": "選択済み",
"up.goodsSku.buyAmount": "購入数量"
}

View File

@@ -0,0 +1,86 @@
{
"up.common.cancel": "취소",
"up.common.confirm": "확인",
"up.common.start": "시작",
"up.common.end": "종료",
"up.common.stop": "정지",
"up.common.copy": "복사",
"up.common.none": "없음",
"up.common.tip": "팁",
"up.common.success": "성공",
"up.common.fail": "실패",
"up.common.close": "닫기",
"up.common.preview": "미리보기",
"up.common.re-select": "재선택",
"up.common.rotate": "회전",
"up.common.pleaseChoose": "선택해주세요",
"up.common.loading": "로딩중",
"up.common.loading2": "로딩중",
"up.common.inOperation": "작업중",
"up.common.settings": "설정",
"up.common.retry": "재시도",
"up.common.search": "검색",
"up.common.more": "더보기",
"up.common.video": "비디오",
"up.common.file": "파일",
"up.week.one": "월",
"up.week.two": "화",
"up.week.three": "수",
"up.week.four": "목",
"up.week.five": "금",
"up.week.six": "토",
"up.week.seven": "일",
"up.barcode.error": "바코드 생성 실패",
"up.calendar.chooseDates": "날짜 선택",
"up.calendar.disabled": "해당 날짜는 사용할 수 없습니다",
"up.calendar.daysExceed": "선택한 날짜 수가 {days}일을 초과할 수 없습니다",
"up.calendar.today": "오늘",
"up.cityLocate.locateCity": "도시 위치 찾기",
"up.cityLocate.fail": "위치 찾기 실패, 다시 시도하려면 클릭하세요.",
"up.cityLocate.locating": "위치 찾는 중",
"up.code.send": "인증코드 받기",
"up.code.resendAfter": "X초 후 재전송",
"up.code.resend": "재전송",
"up.cropper.emptyWidhtOrHeight": "자르기 영역의 너비 또는 높이가 설정되지 않았습니다",
"up.empty.car": "장바구니가 비어 있습니다",
"up.empty.page": "페이지가 존재하지 않습니다",
"up.empty.search": "검색 결과가 없습니다",
"up.empty.address": "배송 주소가 없습니다",
"up.empty.wifi": "Wi-Fi가 없습니다",
"up.empty.order": "주문이 없습니다",
"up.empty.coupon": "쿠폰이 없습니다",
"up.empty.favor": "즐겨찾기가 없습니다",
"up.empty.permission": "권한이 없습니다",
"up.empty.history": "기록이 없습니다",
"up.empty.news": "뉴스가 없습니다",
"up.empty.message": "메시지가 없습니다",
"up.empty.list": "목록이 비어 있습니다",
"up.empty.data": "데이터가 없습니다",
"up.empty.comment": "댓글이 없습니다",
"up.link.copyed": "링크가 복사되었습니다. 브라우저에서 열어주세요",
"up.loadmoe.loadmore": "더 불러오기",
"up.loadmoe.nomore": "더 이상 데이터가 없습니다",
"up.noNetwork.text": "네트워크 신호가 없습니다",
"up.noNetwork.pleaseCheck": "네트워크를 확인하거나 이동하세요",
"up.noNetwork.connect": "네트워크 연결됨",
"up.noNetwork.disconnect": "네트워크 연결 끊김",
"up.pagination.previous": "이전 페이지",
"up.pagination.next": "다음 페이지",
"up.pullRefresh.pull": "당겨서 새로고침",
"up.pullRefresh.release": "놓아서 새로고침",
"up.pullRefresh.refreshing": "새로고침 중",
"up.readMore.expand": "펼쳐서 전체 보기",
"up.readMore.fold": "접기",
"up.search.placeholder": "키워드를 입력하세요",
"up.signature.penSize": "선 굵기",
"up.signature.penColor": "선 색상",
"up.upload.sizeExceed": "용량 제한 초과",
"up.upload.uploading": "업로드 중",
"up.upload.previewImageFail": "이미지 미리보기 실패",
"up.upload.previewVideoFail": "비디오 미리보기 실패",
"up.goodsSku.stock": "재고",
"up.goodsSku.price": "가격",
"up.goodsSku.amount": "개",
"up.goodsSku.choosed": "선택됨",
"up.goodsSku.buyAmount": "구매 수량"
}

View File

@@ -0,0 +1,86 @@
{
"up.common.cancel": "Отмена",
"up.common.confirm": "Подтвердить",
"up.common.start": "Начало",
"up.common.end": "Конец",
"up.common.stop": "Стоп",
"up.common.copy": "Копировать",
"up.common.none": "Нет",
"up.common.tip": "Подсказка",
"up.common.success": "Успех",
"up.common.fail": "Ошибка",
"up.common.close": "Закрыть",
"up.common.preview": "Предпросмотр",
"up.common.re-select": "Выбрать снова",
"up.common.rotate": "Повернуть",
"up.common.pleaseChoose": "Пожалуйста, выберите",
"up.common.loading": "Загрузка",
"up.common.loading2": "Загружается",
"up.common.inOperation": "В процессе",
"up.common.settings": "Настройки",
"up.common.retry": "Повторить",
"up.common.search": "Поиск",
"up.common.more": "Больше",
"up.common.video": "Видео",
"up.common.file": "Файл",
"up.week.one": "Пн",
"up.week.two": "Вт",
"up.week.three": "Ср",
"up.week.four": "Чт",
"up.week.five": "Пт",
"up.week.six": "Сб",
"up.week.seven": "Вс",
"up.barcode.error": "Ошибка генерации штрихкода",
"up.calendar.chooseDates": "Выбор даты",
"up.calendar.disabled": "Эта дата отключена",
"up.calendar.daysExceed": "Количество выбранных дней не может превышать {days} дней",
"up.calendar.today": "Сегодня",
"up.cityLocate.locateCity": "Определение города",
"up.cityLocate.fail": "Ошибка определения местоположения, нажмите для повтора.",
"up.cityLocate.locating": "Определение местоположения",
"up.code.send": "Получить код подтверждения",
"up.code.resendAfter": "Повторная отправка через X секунд",
"up.code.resend": "Отправить снова",
"up.cropper.emptyWidhtOrHeight": "Ширина или высота области обрезки не задана",
"up.empty.car": "Корзина пуста",
"up.empty.page": "Страница не существует",
"up.empty.search": "Нет результатов поиска",
"up.empty.address": "Нет адреса доставки",
"up.empty.wifi": "Нет Wi-Fi",
"up.empty.order": "Заказы отсутствуют",
"up.empty.coupon": "Нет купонов",
"up.empty.favor": "Нет избранного",
"up.empty.permission": "Нет разрешения",
"up.empty.history": "Нет истории",
"up.empty.news": "Нет новостей",
"up.empty.message": "Список сообщений пуст",
"up.empty.list": "Список пуст",
"up.empty.data": "Нет данных",
"up.empty.comment": "Нет комментариев",
"up.link.copyed": "Ссылка скопирована, откройте в браузере",
"up.loadmoe.loadmore": "Загрузить еще",
"up.loadmoe.nomore": "Больше нет данных",
"up.noNetwork.text": "Ой, потеряно сетевое соединение",
"up.noNetwork.pleaseCheck": "Проверьте сеть или перейдите к",
"up.noNetwork.connect": "Сеть подключена",
"up.noNetwork.disconnect": "Нет сетевого подключения",
"up.pagination.previous": "Предыдущая страница",
"up.pagination.next": "Следующая страница",
"up.pullRefresh.pull": "Потяните вниз для обновления",
"up.pullRefresh.release": "Отпустите для обновления",
"up.pullRefresh.refreshing": "Обновление",
"up.readMore.expand": "Развернуть для полного чтения",
"up.readMore.fold": "Свернуть",
"up.search.placeholder": "Введите ключевое слово",
"up.signature.penSize": "Размер штриха",
"up.signature.penColor": "Цвет штриха",
"up.upload.sizeExceed": "Превышен лимит размера",
"up.upload.uploading": "Загрузка",
"up.upload.previewImageFail": "Ошибка предпросмотра изображения",
"up.upload.previewVideoFail": "Ошибка предпросмотра видео",
"up.goodsSku.stock": "Запас",
"up.goodsSku.price": "Цена",
"up.goodsSku.amount": "Штук",
"up.goodsSku.choosed": "Выбрано",
"up.goodsSku.buyAmount": "Количество"
}

View File

@@ -0,0 +1,86 @@
{
"up.common.cancel": "ยกเลิก",
"up.common.confirm": "ยืนยัน",
"up.common.start": "เริ่มต้น",
"up.common.end": "สิ้นสุด",
"up.common.stop": "หยุด",
"up.common.copy": "คัดลอก",
"up.common.none": "ไม่มี",
"up.common.tip": "คำแนะนำ",
"up.common.success": "สำเร็จ",
"up.common.fail": "ล้มเหลว",
"up.common.close": "ปิด",
"up.common.preview": "ดูตัวอย่าง",
"up.common.re-select": "เลือกใหม่",
"up.common.rotate": "หมุน",
"up.common.pleaseChoose": "กรุณาเลือก",
"up.common.loading": "กำลังโหลด",
"up.common.loading2": "กำลังโหลด",
"up.common.inOperation": "กำลังดำเนินการ",
"up.common.settings": "การตั้งค่า",
"up.common.retry": "ลองใหม่",
"up.common.search": "ค้นหา",
"up.common.more": "เพิ่มเติม",
"up.common.video": "วิดีโอ",
"up.common.file": "ไฟล์",
"up.week.one": "จันทร์",
"up.week.two": "อังคาร",
"up.week.three": "พุธ",
"up.week.four": "พฤหัสบดี",
"up.week.five": "ศุกร์",
"up.week.six": "เสาร์",
"up.week.seven": "อาทิตย์",
"up.barcode.error": "สร้างบาร์โค้ดไม่สำเร็จ",
"up.calendar.chooseDates": "เลือกวันที่",
"up.calendar.disabled": "วันที่นี้ถูกปิดการใช้งาน",
"up.calendar.daysExceed": "จำนวนวันที่เลือกต้องไม่เกิน {days} วัน",
"up.calendar.today": "วันนี้",
"up.cityLocate.locateCity": "ระบุตำแหน่งเมือง",
"up.cityLocate.fail": "การระบุตำแหน่งล้มเหลว กรุณาคลิกเพื่อลองใหม่",
"up.cityLocate.locating": "กำลังระบุตำแหน่ง",
"up.code.send": "รับรหัสยืนยัน",
"up.code.resendAfter": "ส่งใหม่ใน X วินาที",
"up.code.resend": "ส่งใหม่",
"up.cropper.emptyWidhtOrHeight": "ไม่ได้ตั้งค่าความกว้างหรือความสูงของกรอบตัดภาพ",
"up.empty.car": "รถเข็นว่างเปล่า",
"up.empty.page": "ไม่มีหน้านี้",
"up.empty.search": "ไม่มีผลลัพธ์การค้นหา",
"up.empty.address": "ไม่มีที่อยู่จัดส่ง",
"up.empty.wifi": "ไม่มี WiFi",
"up.empty.order": "ไม่มีคำสั่งซื้อ",
"up.empty.coupon": "ไม่มีคูปอง",
"up.empty.favor": "ไม่มีรายการโปรด",
"up.empty.permission": "ไม่มีสิทธิ์",
"up.empty.history": "ไม่มีประวัติ",
"up.empty.news": "ไม่มีรายการข่าว",
"up.empty.message": "รายการข้อความว่างเปล่า",
"up.empty.list": "รายการว่างเปล่า",
"up.empty.data": "ข้อมูลว่างเปล่า",
"up.empty.comment": "ไม่มีความคิดเห็น",
"up.link.copyed": "คัดลอกลิงก์แล้ว กรุณาเปิดในเบราว์เซอร์",
"up.loadmoe.loadmore": "โหลดเพิ่มเติม",
"up.loadmoe.nomore": "ไม่มีข้อมูลเพิ่มเติม",
"up.noNetwork.text": "อ๊ะ ขาดการเชื่อมต่อเครือข่าย",
"up.noNetwork.pleaseCheck": "กรุณาตรวจสอบเครือข่าย หรือไปที่",
"up.noNetwork.connect": "เชื่อมต่อเครือข่ายแล้ว",
"up.noNetwork.disconnect": "ไม่มีการเชื่อมต่อเครือข่าย",
"up.pagination.previous": "หน้าก่อนหน้า",
"up.pagination.next": "หน้าถัดไป",
"up.pullRefresh.pull": "ดึงเพื่อรีเฟรช",
"up.pullRefresh.release": "ปล่อยเพื่อรีเฟรช",
"up.pullRefresh.refreshing": "กำลังรีเฟรช",
"up.readMore.expand": "ขยายเพื่ออ่านทั้งหมด",
"up.readMore.fold": "ย่อ",
"up.search.placeholder": "กรุณาใส่คำสำคัญ",
"up.signature.penSize": "ขนาดเส้น",
"up.signature.penColor": "สีเส้น",
"up.upload.sizeExceed": "เกินขนาดที่กำหนด",
"up.upload.uploading": "กำลังอัปโหลด",
"up.upload.previewImageFail": "ดูตัวอย่างภาพไม่สำเร็จ",
"up.upload.previewVideoFail": "ดูตัวอย่างวิดีโอไม่สำเร็จ",
"up.goodsSku.stock": "สินค้าคงคลัง",
"up.goodsSku.price": "ราคา",
"up.goodsSku.amount": "ชิ้น",
"up.goodsSku.choosed": "เลือกแล้ว",
"up.goodsSku.buyAmount": "จำนวน"
}

View File

@@ -0,0 +1,86 @@
{
"up.common.cancel": "取消",
"up.common.confirm": "确定",
"up.common.start": "开始",
"up.common.end": "结束",
"up.common.stop": "停止",
"up.common.copy": "复制",
"up.common.none": "暂无",
"up.common.tip": "提示",
"up.common.success": "成功",
"up.common.fail": "失败",
"up.common.close": "关闭",
"up.common.preview": "预览",
"up.common.re-select": "重选",
"up.common.rotate": "旋转",
"up.common.pleaseChoose": "请选择",
"up.common.loading": "加载中",
"up.common.loading2": "正在加载",
"up.common.inOperation": "操作中",
"up.common.settings": "设置",
"up.common.retry": "重试",
"up.common.search": "搜索",
"up.common.more": "更多",
"up.common.video": "视频",
"up.common.file": "文件",
"up.week.one": "一",
"up.week.two": "二",
"up.week.three": "三",
"up.week.four": "四",
"up.week.five": "五",
"up.week.six": "六",
"up.week.seven": "日",
"up.barcode.error": "生成条码失败",
"up.calendar.chooseDates": "日期选择",
"up.calendar.disabled": "该日期已禁用",
"up.calendar.daysExceed": "选择天数不能超过{days}天",
"up.calendar.today": "今天",
"up.cityLocate.locateCity": "定位城市",
"up.cityLocate.fail": "定位失败,请点击重试。",
"up.cityLocate.locating": "定位中",
"up.code.send": "获取验证码",
"up.code.resendAfter": "X秒重新获取",
"up.code.resend": "重新获取",
"up.cropper.emptyWidhtOrHeight": "裁剪框的宽或高没有设置",
"up.empty.car": "购物车为空",
"up.empty.page": "页面不存在",
"up.empty.search": "没有搜索结果",
"up.empty.address": "没有收货地址",
"up.empty.wifi": "没有WiFi",
"up.empty.order": "订单为空",
"up.empty.coupon": "没有优惠券",
"up.empty.favor": "暂无收藏",
"up.empty.permission": "无权限",
"up.empty.history": "无历史记录",
"up.empty.news": "无新闻列表",
"up.empty.message": "消息列表为空",
"up.empty.list": "列表为空",
"up.empty.data": "数据为空",
"up.empty.comment": "暂无评论",
"up.link.copyed": "链接已复制,请在浏览器打开",
"up.loadmoe.loadmore": "加载更多",
"up.loadmoe.nomore": "没有更多了",
"up.noNetwork.text": "哎呀,网络信号丢失",
"up.noNetwork.pleaseCheck": "请检查网络,或前往",
"up.noNetwork.connect": "网络已连接",
"up.noNetwork.disconnect": "无网络连接",
"up.pagination.previous": "上一页",
"up.pagination.next": "下一页",
"up.pullRefresh.pull": "下拉刷新",
"up.pullRefresh.release": "释放刷新",
"up.pullRefresh.refreshing": "正在刷新",
"up.readMore.expand": "展开阅读全文",
"up.readMore.fold": "收起",
"up.search.placeholder": "请输入关键字",
"up.signature.penSize": "笔画大小",
"up.signature.penColor": "笔画颜色",
"up.upload.sizeExceed": "超过大小限制",
"up.upload.uploading": "上传中",
"up.upload.previewImageFail": "预览图片失败",
"up.upload.previewVideoFail": "预览视频失败",
"up.goodsSku.stock": "库存",
"up.goodsSku.price": "价格",
"up.goodsSku.amount": "件",
"up.goodsSku.choosed": "已选",
"up.goodsSku.buyAmount": "购买数量"
}

View File

@@ -0,0 +1,86 @@
{
"up.common.cancel": "取消",
"up.common.confirm": "確定",
"up.common.start": "開始",
"up.common.end": "結束",
"up.common.stop": "停止",
"up.common.copy": "複製",
"up.common.none": "暫無",
"up.common.tip": "提示",
"up.common.success": "成功",
"up.common.fail": "失敗",
"up.common.close": "關閉",
"up.common.preview": "預覽",
"up.common.re-select": "重選",
"up.common.rotate": "旋轉",
"up.common.pleaseChoose": "請選擇",
"up.common.loading": "加載中",
"up.common.loading2": "正在加載",
"up.common.inOperation": "操作中",
"up.common.settings": "設置",
"up.common.retry": "重試",
"up.common.search": "搜索",
"up.common.more": "更多",
"up.common.video": "視頻",
"up.common.file": "文件",
"up.week.one": "一",
"up.week.two": "二",
"up.week.three": "三",
"up.week.four": "四",
"up.week.five": "五",
"up.week.six": "六",
"up.week.seven": "日",
"up.barcode.error": "生成條碼失敗",
"up.calendar.chooseDates": "日期選擇",
"up.calendar.disabled": "該日期已禁用",
"up.calendar.daysExceed": "選擇天數不能超過{days}天",
"up.calendar.today": "今天",
"up.cityLocate.locateCity": "定位城市",
"up.cityLocate.fail": "定位失敗,請點擊重試。",
"up.cityLocate.locating": "定位中",
"up.code.send": "獲取驗證碼",
"up.code.resendAfter": "X秒重新獲取",
"up.code.resend": "重新獲取",
"up.cropper.emptyWidhtOrHeight": "裁剪框的寬或高沒有設置",
"up.empty.car": "購物車為空",
"up.empty.page": "頁面不存在",
"up.empty.search": "沒有搜索結果",
"up.empty.address": "沒有收貨地址",
"up.empty.wifi": "沒有WiFi",
"up.empty.order": "訂單為空",
"up.empty.coupon": "沒有優惠券",
"up.empty.favor": "暫無收藏",
"up.empty.permission": "無權限",
"up.empty.history": "無歷史記錄",
"up.empty.news": "無新聞列表",
"up.empty.message": "消息列表為空",
"up.empty.list": "列表為空",
"up.empty.data": "數據為空",
"up.empty.comment": "暫無評論",
"up.link.copyed": "鏈接已複製,請在瀏覽器打開",
"up.loadmoe.loadmore": "加載更多",
"up.loadmoe.nomore": "沒有更多了",
"up.noNetwork.text": "哎呀,網絡信號丟失",
"up.noNetwork.pleaseCheck": "請檢查網絡,或前往",
"up.noNetwork.connect": "網絡已連接",
"up.noNetwork.disconnect": "無網絡連接",
"up.pagination.previous": "上一頁",
"up.pagination.next": "下一頁",
"up.pullRefresh.pull": "下拉刷新",
"up.pullRefresh.release": "釋放刷新",
"up.pullRefresh.refreshing": "正在刷新",
"up.readMore.expand": "展開閱讀全文",
"up.readMore.fold": "收起",
"up.search.placeholder": "請輸入關鍵字",
"up.signature.penSize": "筆畫大小",
"up.signature.penColor": "筆畫顏色",
"up.upload.sizeExceed": "超過大小限制",
"up.upload.uploading": "上傳中",
"up.upload.previewImageFail": "預覽圖片失敗",
"up.upload.previewVideoFail": "預覽視頻失敗",
"up.goodsSku.stock": "庫存",
"up.goodsSku.price": "價格",
"up.goodsSku.amount": "件",
"up.goodsSku.choosed": "已選",
"up.goodsSku.buyAmount": "購買數量"
}

View File

@@ -0,0 +1,97 @@
import buildURL from '../helpers/buildURL'
import buildFullPath from '../core/buildFullPath'
import settle from '../core/settle'
import { isUndefined } from '../utils'
/**
* 返回可选值存在的配置
* @param {Array} keys - 可选值数组
* @param {Object} config2 - 配置
* @return {{}} - 存在的配置项
*/
const mergeKeys = (keys, config2) => {
const config = {}
keys.forEach((prop) => {
if (!isUndefined(config2[prop])) {
config[prop] = config2[prop]
}
})
return config
}
export default (config) => new Promise((resolve, reject) => {
const fullPath = buildURL(buildFullPath(config.baseURL, config.url), config.params)
const _config = {
url: fullPath,
header: config.header,
complete: (response) => {
config.fullPath = fullPath
response.config = config
try {
// 对可能字符串不是json 的情况容错
if (typeof response.data === 'string') {
response.data = JSON.parse(response.data)
}
// eslint-disable-next-line no-empty
} catch (e) {
}
settle(resolve, reject, response)
}
}
let requestTask
if (config.method === 'UPLOAD') {
delete _config.header['content-type']
delete _config.header['Content-Type']
const otherConfig = {
// #ifdef MP-ALIPAY
fileType: config.fileType,
// #endif
filePath: config.filePath,
name: config.name
}
const optionalKeys = [
// #ifdef APP-PLUS || H5
'files',
// #endif
// #ifdef H5
'file',
// #endif
// #ifdef H5 || APP-PLUS
'timeout',
// #endif
'formData'
]
requestTask = uni.uploadFile({ ..._config, ...otherConfig, ...mergeKeys(optionalKeys, config) })
} else if (config.method === 'DOWNLOAD') {
// #ifdef H5 || APP-PLUS
if (!isUndefined(config.timeout)) {
_config.timeout = config.timeout
}
// #endif
requestTask = uni.downloadFile(_config)
} else {
const optionalKeys = [
'data',
'method',
// #ifdef H5 || APP-PLUS || MP-ALIPAY || MP-WEIXIN
'timeout',
// #endif
'dataType',
// #ifndef MP-ALIPAY
'responseType',
// #endif
// #ifdef APP-PLUS
'sslVerify',
// #endif
// #ifdef H5
'withCredentials',
// #endif
// #ifdef APP-PLUS
'firstIpv4'
// #endif
]
requestTask = uni.request({ ..._config, ...mergeKeys(optionalKeys, config) })
}
if (config.getTask) {
config.getTask(requestTask, config)
}
})

View File

@@ -0,0 +1,50 @@
'use strict'
function InterceptorManager() {
this.handlers = []
}
/**
* Add a new interceptor to the stack
*
* @param {Function} fulfilled The function to handle `then` for a `Promise`
* @param {Function} rejected The function to handle `reject` for a `Promise`
*
* @return {Number} An ID used to remove interceptor later
*/
InterceptorManager.prototype.use = function use(fulfilled, rejected) {
this.handlers.push({
fulfilled,
rejected
})
return this.handlers.length - 1
}
/**
* Remove an interceptor from the stack
*
* @param {Number} id The ID that was returned by `use`
*/
InterceptorManager.prototype.eject = function eject(id) {
if (this.handlers[id]) {
this.handlers[id] = null
}
}
/**
* Iterate over all the registered interceptors
*
* This method is particularly useful for skipping over any
* interceptors that may have become `null` calling `eject`.
*
* @param {Function} fn The function to call for each interceptor
*/
InterceptorManager.prototype.forEach = function forEach(fn) {
this.handlers.forEach((h) => {
if (h !== null) {
fn(h)
}
})
}
export default InterceptorManager

View File

@@ -0,0 +1,199 @@
/**
* @Class Request
* @description luch-request http请求插件
* @version 3.0.7
* @Author lu-ch
* @Date 2021-09-04
* @Email webwork.s@qq.com
* 文档: https://www.quanzhan.co/luch-request/
* github: https://github.com/lei-mu/luch-request
* DCloud: http://ext.dcloud.net.cn/plugin?id=392
* HBuilderX: beat-3.0.4 alpha-3.0.4
*/
import dispatchRequest from './dispatchRequest'
import InterceptorManager from './InterceptorManager'
import mergeConfig from './mergeConfig'
import defaults from './defaults'
import { isPlainObject } from '../utils'
import clone from '../utils/clone'
export default class Request {
/**
* @param {Object} arg - 全局配置
* @param {String} arg.baseURL - 全局根路径
* @param {Object} arg.header - 全局header
* @param {String} arg.method = [GET|POST|PUT|DELETE|CONNECT|HEAD|OPTIONS|TRACE] - 全局默认请求方式
* @param {String} arg.dataType = [json] - 全局默认的dataType
* @param {String} arg.responseType = [text|arraybuffer] - 全局默认的responseType。支付宝小程序不支持
* @param {Object} arg.custom - 全局默认的自定义参数
* @param {Number} arg.timeout - 全局默认的超时时间,单位 ms。默认60000。H5(HBuilderX 2.9.9+)、APP(HBuilderX 2.9.9+)、微信小程序(2.10.0)、支付宝小程序
* @param {Boolean} arg.sslVerify - 全局默认的是否验证 ssl 证书。默认true.仅App安卓端支持(HBuilderX 2.3.3+)
* @param {Boolean} arg.withCredentials - 全局默认的跨域请求时是否携带凭证(cookies)。默认false。仅H5支持(HBuilderX 2.6.15+)
* @param {Boolean} arg.firstIpv4 - 全DNS解析时优先使用ipv4。默认false。仅 App-Android 支持 (HBuilderX 2.8.0+)
* @param {Function(statusCode):Boolean} arg.validateStatus - 全局默认的自定义验证器。默认statusCode >= 200 && statusCode < 300
*/
constructor(arg = {}) {
// console.info('初始化luch-request')
if (!isPlainObject(arg)) {
arg = {}
console.warn('设置全局参数必须接收一个Object')
}
this.config = clone({ ...defaults, ...arg })
this.interceptors = {
request: new InterceptorManager(),
response: new InterceptorManager()
}
}
/**
* @Function
* @param {Request~setConfigCallback} f - 设置全局默认配置
*/
setConfig(f) {
this.config = f(this.config)
}
middleware(config) {
config = mergeConfig(this.config, config)
const chain = [dispatchRequest, undefined]
let promise = Promise.resolve(config)
this.interceptors.request.forEach((interceptor) => {
chain.unshift(interceptor.fulfilled, interceptor.rejected)
})
this.interceptors.response.forEach((interceptor) => {
chain.push(interceptor.fulfilled, interceptor.rejected)
})
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift())
}
return promise
}
/**
* @Function
* @param {Object} config - 请求配置项
* @prop {String} options.url - 请求路径
* @prop {Object} options.data - 请求参数
* @prop {Object} [options.responseType = config.responseType] [text|arraybuffer] - 响应的数据类型
* @prop {Object} [options.dataType = config.dataType] - 如果设为 json,会尝试对返回的数据做一次 JSON.parse
* @prop {Object} [options.header = config.header] - 请求header
* @prop {Object} [options.method = config.method] - 请求方法
* @returns {Promise<unknown>}
*/
request(config = {}) {
return this.middleware(config)
}
get(url, options = {}) {
return this.middleware({
url,
method: 'GET',
...options
})
}
post(url, data, options = {}) {
return this.middleware({
url,
data,
method: 'POST',
...options
})
}
// #ifndef MP-ALIPAY
put(url, data, options = {}) {
return this.middleware({
url,
data,
method: 'PUT',
...options
})
}
// #endif
// #ifdef APP-PLUS || H5 || MP-WEIXIN || MP-BAIDU
delete(url, data, options = {}) {
return this.middleware({
url,
data,
method: 'DELETE',
...options
})
}
// #endif
// #ifdef H5 || MP-WEIXIN
connect(url, data, options = {}) {
return this.middleware({
url,
data,
method: 'CONNECT',
...options
})
}
// #endif
// #ifdef H5 || MP-WEIXIN || MP-BAIDU
head(url, data, options = {}) {
return this.middleware({
url,
data,
method: 'HEAD',
...options
})
}
// #endif
// #ifdef APP-PLUS || H5 || MP-WEIXIN || MP-BAIDU
options(url, data, options = {}) {
return this.middleware({
url,
data,
method: 'OPTIONS',
...options
})
}
// #endif
// #ifdef H5 || MP-WEIXIN
trace(url, data, options = {}) {
return this.middleware({
url,
data,
method: 'TRACE',
...options
})
}
// #endif
upload(url, config = {}) {
config.url = url
config.method = 'UPLOAD'
return this.middleware(config)
}
download(url, config = {}) {
config.url = url
config.method = 'DOWNLOAD'
return this.middleware(config)
}
}
/**
* setConfig回调
* @return {Object} - 返回操作后的config
* @callback Request~setConfigCallback
* @param {Object} config - 全局默认config
*/

View File

@@ -0,0 +1,20 @@
'use strict'
import isAbsoluteURL from '../helpers/isAbsoluteURL'
import combineURLs from '../helpers/combineURLs'
/**
* Creates a new URL by combining the baseURL with the requestedURL,
* only when the requestedURL is not already an absolute URL.
* If the requestURL is absolute, this function returns the requestedURL untouched.
*
* @param {string} baseURL The base URL
* @param {string} requestedURL Absolute or relative URL to combine
* @returns {string} The combined full path
*/
export default function buildFullPath(baseURL, requestedURL) {
if (baseURL && !isAbsoluteURL(requestedURL)) {
return combineURLs(baseURL, requestedURL)
}
return requestedURL
}

View File

@@ -0,0 +1,29 @@
/**
* 默认的全局配置
*/
export default {
baseURL: '',
header: {},
method: 'GET',
dataType: 'json',
// #ifndef MP-ALIPAY
responseType: 'text',
// #endif
custom: {},
// #ifdef H5 || APP-PLUS || MP-ALIPAY || MP-WEIXIN
timeout: 60000,
// #endif
// #ifdef APP-PLUS
sslVerify: true,
// #endif
// #ifdef H5
withCredentials: false,
// #endif
// #ifdef APP-PLUS
firstIpv4: false,
// #endif
validateStatus: function validateStatus(status) {
return status >= 200 && status < 300
}
}

View File

@@ -0,0 +1,3 @@
import adapter from '../adapters/index'
export default (config) => adapter(config)

View File

@@ -0,0 +1,103 @@
import { deepMerge, isUndefined } from '../utils'
/**
* 合并局部配置优先的配置,如果局部有该配置项则用局部,如果全局有该配置项则用全局
* @param {Array} keys - 配置项
* @param {Object} globalsConfig - 当前的全局配置
* @param {Object} config2 - 局部配置
* @return {{}}
*/
const mergeKeys = (keys, globalsConfig, config2) => {
const config = {}
keys.forEach((prop) => {
if (!isUndefined(config2[prop])) {
config[prop] = config2[prop]
} else if (!isUndefined(globalsConfig[prop])) {
config[prop] = globalsConfig[prop]
}
})
return config
}
/**
*
* @param globalsConfig - 当前实例的全局配置
* @param config2 - 当前的局部配置
* @return - 合并后的配置
*/
export default (globalsConfig, config2 = {}) => {
const method = config2.method || globalsConfig.method || 'GET'
let config = {
baseURL: globalsConfig.baseURL || '',
method,
url: config2.url || '',
params: config2.params || {},
custom: { ...(globalsConfig.custom || {}), ...(config2.custom || {}) },
header: deepMerge(globalsConfig.header || {}, config2.header || {})
}
const defaultToConfig2Keys = ['getTask', 'validateStatus']
config = { ...config, ...mergeKeys(defaultToConfig2Keys, globalsConfig, config2) }
// eslint-disable-next-line no-empty
if (method === 'DOWNLOAD') {
// #ifdef H5 || APP-PLUS
if (!isUndefined(config2.timeout)) {
config.timeout = config2.timeout
} else if (!isUndefined(globalsConfig.timeout)) {
config.timeout = globalsConfig.timeout
}
// #endif
} else if (method === 'UPLOAD') {
delete config.header['content-type']
delete config.header['Content-Type']
const uploadKeys = [
// #ifdef APP-PLUS || H5
'files',
// #endif
// #ifdef MP-ALIPAY
'fileType',
// #endif
// #ifdef H5
'file',
// #endif
'filePath',
'name',
// #ifdef H5 || APP-PLUS
'timeout',
// #endif
'formData'
]
uploadKeys.forEach((prop) => {
if (!isUndefined(config2[prop])) {
config[prop] = config2[prop]
}
})
// #ifdef H5 || APP-PLUS
if (isUndefined(config.timeout) && !isUndefined(globalsConfig.timeout)) {
config.timeout = globalsConfig.timeout
}
// #endif
} else {
const defaultsKeys = [
'data',
// #ifdef H5 || APP-PLUS || MP-ALIPAY || MP-WEIXIN
'timeout',
// #endif
'dataType',
// #ifndef MP-ALIPAY
'responseType',
// #endif
// #ifdef APP-PLUS
'sslVerify',
// #endif
// #ifdef H5
'withCredentials',
// #endif
// #ifdef APP-PLUS
'firstIpv4'
// #endif
]
config = { ...config, ...mergeKeys(defaultsKeys, globalsConfig, config2) }
}
return config
}

View File

@@ -0,0 +1,16 @@
/**
* Resolve or reject a Promise based on response status.
*
* @param {Function} resolve A function that resolves the promise.
* @param {Function} reject A function that rejects the promise.
* @param {object} response The response.
*/
export default function settle(resolve, reject, response) {
const { validateStatus } = response.config
const status = response.statusCode
if (status && (!validateStatus || validateStatus(status))) {
resolve(response)
} else {
reject(response)
}
}

View File

@@ -0,0 +1,69 @@
'use strict'
import * as utils from '../utils'
function encode(val) {
return encodeURIComponent(val)
.replace(/%40/gi, '@')
.replace(/%3A/gi, ':')
.replace(/%24/g, '$')
.replace(/%2C/gi, ',')
.replace(/%20/g, '+')
.replace(/%5B/gi, '[')
.replace(/%5D/gi, ']')
}
/**
* Build a URL by appending params to the end
*
* @param {string} url The base of the url (e.g., http://www.google.com)
* @param {object} [params] The params to be appended
* @returns {string} The formatted url
*/
export default function buildURL(url, params) {
/* eslint no-param-reassign:0 */
if (!params) {
return url
}
let serializedParams
if (utils.isURLSearchParams(params)) {
serializedParams = params.toString()
} else {
const parts = []
utils.forEach(params, (val, key) => {
if (val === null || typeof val === 'undefined') {
return
}
if (utils.isArray(val)) {
key = `${key}[]`
} else {
val = [val]
}
utils.forEach(val, (v) => {
if (utils.isDate(v)) {
v = v.toISOString()
} else if (utils.isObject(v)) {
v = JSON.stringify(v)
}
parts.push(`${encode(key)}=${encode(v)}`)
})
})
serializedParams = parts.join('&')
}
if (serializedParams) {
const hashmarkIndex = url.indexOf('#')
if (hashmarkIndex !== -1) {
url = url.slice(0, hashmarkIndex)
}
url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams
}
return url
}

View File

@@ -0,0 +1,14 @@
'use strict'
/**
* Creates a new URL by combining the specified URLs
*
* @param {string} baseURL The base URL
* @param {string} relativeURL The relative URL
* @returns {string} The combined URL
*/
export default function combineURLs(baseURL, relativeURL) {
return relativeURL
? `${baseURL.replace(/\/+$/, '')}/${relativeURL.replace(/^\/+/, '')}`
: baseURL
}

View File

@@ -0,0 +1,14 @@
'use strict'
/**
* Determines whether the specified URL is absolute
*
* @param {string} url The URL to test
* @returns {boolean} True if the specified URL is absolute, otherwise false
*/
export default function isAbsoluteURL(url) {
// A URL is considered absolute if it begins with "<scheme>://" or "//" (protocol-relative URL).
// RFC 3986 defines scheme name as a sequence of characters beginning with a letter and followed
// by any combination of letters, digits, plus, period, or hyphen.
return /^([a-z][a-z\d+\-.]*:)?\/\//i.test(url)
}

View File

@@ -0,0 +1,116 @@
type AnyObject = Record<string | number | symbol, any>
type HttpPromise<T> = Promise<HttpResponse<T>>;
type Tasks = UniApp.RequestTask | UniApp.UploadTask | UniApp.DownloadTask
export interface RequestTask {
abort: () => void;
offHeadersReceived: () => void;
onHeadersReceived: () => void;
}
export interface HttpRequestConfig<T = Tasks> {
/** 请求基地址 */
baseURL?: string;
/** 请求服务器接口地址 */
url?: string;
/** 请求查询参数,自动拼接为查询字符串 */
params?: AnyObject;
/** 请求体参数 */
data?: AnyObject;
/** 文件对应的 key */
name?: string;
/** HTTP 请求中其他额外的 form data */
formData?: AnyObject;
/** 要上传文件资源的路径。 */
filePath?: string;
/** 需要上传的文件列表。使用 files 时,filePath 和 name 不生效,App、H5( 2.6.15+) */
files?: Array<{
name?: string;
file?: File;
uri: string;
}>;
/** 要上传的文件对象,仅H5(2.6.15+)支持 */
file?: File;
/** 请求头信息 */
header?: AnyObject;
/** 请求方式 */
method?: "GET" | "POST" | "PUT" | "DELETE" | "CONNECT" | "HEAD" | "OPTIONS" | "TRACE" | "UPLOAD" | "DOWNLOAD";
/** 如果设为 json,会尝试对返回的数据做一次 JSON.parse */
dataType?: string;
/** 设置响应的数据类型,支付宝小程序不支持 */
responseType?: "text" | "arraybuffer";
/** 自定义参数 */
custom?: AnyObject;
/** 超时时间,仅微信小程序(2.10.0)、支付宝小程序支持 */
timeout?: number;
/** DNS解析时优先使用ipv4,仅 App-Android 支持 (HBuilderX 2.8.0+) */
firstIpv4?: boolean;
/** 验证 ssl 证书 仅5+App安卓端支持(HBuilderX 2.3.3+) */
sslVerify?: boolean;
/** 跨域请求时是否携带凭证(cookies)仅H5支持(HBuilderX 2.6.15+) */
withCredentials?: boolean;
/** 返回当前请求的task, options。请勿在此处修改options。 */
getTask?: (task: T, options: HttpRequestConfig<T>) => void;
/** 全局自定义验证器 */
validateStatus?: (statusCode: number) => boolean | void;
}
export interface HttpResponse<T = any> {
config: HttpRequestConfig;
statusCode: number;
cookies: Array<string>;
data: T;
errMsg: string;
header: AnyObject;
}
export interface HttpUploadResponse<T = any> {
config: HttpRequestConfig;
statusCode: number;
data: T;
errMsg: string;
}
export interface HttpDownloadResponse extends HttpResponse {
tempFilePath: string;
}
export interface HttpError {
config: HttpRequestConfig;
statusCode?: number;
cookies?: Array<string>;
data?: any;
errMsg: string;
header?: AnyObject;
}
export interface HttpInterceptorManager<V, E = V> {
use(
onFulfilled?: (config: V) => Promise<V> | V,
onRejected?: (config: E) => Promise<E> | E
): void;
eject(id: number): void;
}
export abstract class HttpRequestAbstract {
constructor(config?: HttpRequestConfig);
config: HttpRequestConfig;
interceptors: {
request: HttpInterceptorManager<HttpRequestConfig, HttpRequestConfig>;
response: HttpInterceptorManager<HttpResponse, HttpError>;
}
middleware<T = any>(config: HttpRequestConfig): HttpPromise<T>;
request<T = any>(config: HttpRequestConfig<UniApp.RequestTask>): HttpPromise<T>;
get<T = any>(url: string, config?: HttpRequestConfig<UniApp.RequestTask>): HttpPromise<T>;
upload<T = any>(url: string, config?: HttpRequestConfig<UniApp.UploadTask>): HttpPromise<T>;
delete<T = any>(url: string, data?: AnyObject, config?: HttpRequestConfig<UniApp.RequestTask>): HttpPromise<T>;
head<T = any>(url: string, data?: AnyObject, config?: HttpRequestConfig<UniApp.RequestTask>): HttpPromise<T>;
post<T = any>(url: string, data?: AnyObject, config?: HttpRequestConfig<UniApp.RequestTask>): HttpPromise<T>;
put<T = any>(url: string, data?: AnyObject, config?: HttpRequestConfig<UniApp.RequestTask>): HttpPromise<T>;
connect<T = any>(url: string, data?: AnyObject, config?: HttpRequestConfig<UniApp.RequestTask>): HttpPromise<T>;
options<T = any>(url: string, data?: AnyObject, config?: HttpRequestConfig<UniApp.RequestTask>): HttpPromise<T>;
trace<T = any>(url: string, data?: AnyObject, config?: HttpRequestConfig<UniApp.RequestTask>): HttpPromise<T>;
download(url: string, config?: HttpRequestConfig<UniApp.DownloadTask>): Promise<HttpDownloadResponse>;
setConfig(onSend: (config: HttpRequestConfig) => HttpRequestConfig): void;
}
declare class HttpRequest extends HttpRequestAbstract { }
export default HttpRequest;

View File

@@ -0,0 +1,3 @@
import Request from './core/Request'
export default Request

View File

@@ -0,0 +1,131 @@
'use strict'
// utils is a library of generic helper functions non-specific to axios
const { toString } = Object.prototype
/**
* Determine if a value is an Array
*
* @param {Object} val The value to test
* @returns {boolean} True if value is an Array, otherwise false
*/
export function isArray(val) {
return toString.call(val) === '[object Array]'
}
/**
* Determine if a value is an Object
*
* @param {Object} val The value to test
* @returns {boolean} True if value is an Object, otherwise false
*/
export function isObject(val) {
return val !== null && typeof val === 'object'
}
/**
* Determine if a value is a Date
*
* @param {Object} val The value to test
* @returns {boolean} True if value is a Date, otherwise false
*/
export function isDate(val) {
return toString.call(val) === '[object Date]'
}
/**
* Determine if a value is a URLSearchParams object
*
* @param {Object} val The value to test
* @returns {boolean} True if value is a URLSearchParams object, otherwise false
*/
export function isURLSearchParams(val) {
return typeof URLSearchParams !== 'undefined' && val instanceof URLSearchParams
}
/**
* Iterate over an Array or an Object invoking a function for each item.
*
* If `obj` is an Array callback will be called passing
* the value, index, and complete array for each item.
*
* If 'obj' is an Object callback will be called passing
* the value, key, and complete object for each property.
*
* @param {Object|Array} obj The object to iterate
* @param {Function} fn The callback to invoke for each item
*/
export function forEach(obj, fn) {
// Don't bother if no value provided
if (obj === null || typeof obj === 'undefined') {
return
}
// Force an array if not already something iterable
if (typeof obj !== 'object') {
/* eslint no-param-reassign:0 */
obj = [obj]
}
if (isArray(obj)) {
// Iterate over array values
for (let i = 0, l = obj.length; i < l; i++) {
fn.call(null, obj[i], i, obj)
}
} else {
// Iterate over object keys
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
fn.call(null, obj[key], key, obj)
}
}
}
}
/**
* 是否为boolean 值
* @param val
* @returns {boolean}
*/
export function isBoolean(val) {
return typeof val === 'boolean'
}
/**
* 是否为真正的对象{} new Object
* @param {any} obj - 检测的对象
* @returns {boolean}
*/
export function isPlainObject(obj) {
return Object.prototype.toString.call(obj) === '[object Object]'
}
/**
* Function equal to merge with the difference being that no reference
* to original objects is kept.
*
* @see merge
* @param {Object} obj1 Object to merge
* @returns {Object} Result of all merge properties
*/
export function deepMerge(/* obj1, obj2, obj3, ... */) {
const result = {}
function assignValue(val, key) {
if (typeof result[key] === 'object' && typeof val === 'object') {
result[key] = deepMerge(result[key], val)
} else if (typeof val === 'object') {
result[key] = deepMerge({}, val)
} else {
result[key] = val
}
}
for (let i = 0, l = arguments.length; i < l; i++) {
forEach(arguments[i], assignValue)
}
return result
}
export function isUndefined(val) {
return typeof val === 'undefined'
}

View File

@@ -0,0 +1,264 @@
/* eslint-disable */
var clone = (function() {
'use strict';
function _instanceof(obj, type) {
return type != null && obj instanceof type;
}
var nativeMap;
try {
nativeMap = Map;
} catch(_) {
// maybe a reference error because no `Map`. Give it a dummy value that no
// value will ever be an instanceof.
nativeMap = function() {};
}
var nativeSet;
try {
nativeSet = Set;
} catch(_) {
nativeSet = function() {};
}
var nativePromise;
try {
nativePromise = Promise;
} catch(_) {
nativePromise = function() {};
}
/**
* Clones (copies) an Object using deep copying.
*
* This function supports circular references by default, but if you are certain
* there are no circular references in your object, you can save some CPU time
* by calling clone(obj, false).
*
* Caution: if `circular` is false and `parent` contains circular references,
* your program may enter an infinite loop and crash.
*
* @param `parent` - the object to be cloned
* @param `circular` - set to true if the object to be cloned may contain
* circular references. (optional - true by default)
* @param `depth` - set to a number if the object is only to be cloned to
* a particular depth. (optional - defaults to Infinity)
* @param `prototype` - sets the prototype to be used when cloning an object.
* (optional - defaults to parent prototype).
* @param `includeNonEnumerable` - set to true if the non-enumerable properties
* should be cloned as well. Non-enumerable properties on the prototype
* chain will be ignored. (optional - false by default)
*/
function clone(parent, circular, depth, prototype, includeNonEnumerable) {
if (typeof circular === 'object') {
depth = circular.depth;
prototype = circular.prototype;
includeNonEnumerable = circular.includeNonEnumerable;
circular = circular.circular;
}
// maintain two arrays for circular references, where corresponding parents
// and children have the same index
var allParents = [];
var allChildren = [];
var useBuffer = typeof Buffer != 'undefined';
if (typeof circular == 'undefined')
circular = true;
if (typeof depth == 'undefined')
depth = Infinity;
// recurse this function so we don't reset allParents and allChildren
function _clone(parent, depth) {
// cloning null always returns null
if (parent === null)
return null;
if (depth === 0)
return parent;
var child;
var proto;
if (typeof parent != 'object') {
return parent;
}
if (_instanceof(parent, nativeMap)) {
child = new nativeMap();
} else if (_instanceof(parent, nativeSet)) {
child = new nativeSet();
} else if (_instanceof(parent, nativePromise)) {
child = new nativePromise(function (resolve, reject) {
parent.then(function(value) {
resolve(_clone(value, depth - 1));
}, function(err) {
reject(_clone(err, depth - 1));
});
});
} else if (clone.__isArray(parent)) {
child = [];
} else if (clone.__isRegExp(parent)) {
child = new RegExp(parent.source, __getRegExpFlags(parent));
if (parent.lastIndex) child.lastIndex = parent.lastIndex;
} else if (clone.__isDate(parent)) {
child = new Date(parent.getTime());
} else if (useBuffer && Buffer.isBuffer(parent)) {
if (Buffer.from) {
// Node.js >= 5.10.0
child = Buffer.from(parent);
} else {
// Older Node.js versions
child = new Buffer(parent.length);
parent.copy(child);
}
return child;
} else if (_instanceof(parent, Error)) {
child = Object.create(parent);
} else {
if (typeof prototype == 'undefined') {
proto = Object.getPrototypeOf(parent);
child = Object.create(proto);
}
else {
child = Object.create(prototype);
proto = prototype;
}
}
if (circular) {
var index = allParents.indexOf(parent);
if (index != -1) {
return allChildren[index];
}
allParents.push(parent);
allChildren.push(child);
}
if (_instanceof(parent, nativeMap)) {
parent.forEach(function(value, key) {
var keyChild = _clone(key, depth - 1);
var valueChild = _clone(value, depth - 1);
child.set(keyChild, valueChild);
});
}
if (_instanceof(parent, nativeSet)) {
parent.forEach(function(value) {
var entryChild = _clone(value, depth - 1);
child.add(entryChild);
});
}
for (var i in parent) {
var attrs = Object.getOwnPropertyDescriptor(parent, i);
if (attrs) {
child[i] = _clone(parent[i], depth - 1);
}
try {
var objProperty = Object.getOwnPropertyDescriptor(parent, i);
if (objProperty.set === 'undefined') {
// no setter defined. Skip cloning this property
continue;
}
child[i] = _clone(parent[i], depth - 1);
} catch(e){
if (e instanceof TypeError) {
// when in strict mode, TypeError will be thrown if child[i] property only has a getter
// we can't do anything about this, other than inform the user that this property cannot be set.
continue
} else if (e instanceof ReferenceError) {
//this may happen in non strict mode
continue
}
}
}
if (Object.getOwnPropertySymbols) {
var symbols = Object.getOwnPropertySymbols(parent);
for (var i = 0; i < symbols.length; i++) {
// Don't need to worry about cloning a symbol because it is a primitive,
// like a number or string.
var symbol = symbols[i];
var descriptor = Object.getOwnPropertyDescriptor(parent, symbol);
if (descriptor && !descriptor.enumerable && !includeNonEnumerable) {
continue;
}
child[symbol] = _clone(parent[symbol], depth - 1);
Object.defineProperty(child, symbol, descriptor);
}
}
if (includeNonEnumerable) {
var allPropertyNames = Object.getOwnPropertyNames(parent);
for (var i = 0; i < allPropertyNames.length; i++) {
var propertyName = allPropertyNames[i];
var descriptor = Object.getOwnPropertyDescriptor(parent, propertyName);
if (descriptor && descriptor.enumerable) {
continue;
}
child[propertyName] = _clone(parent[propertyName], depth - 1);
Object.defineProperty(child, propertyName, descriptor);
}
}
return child;
}
return _clone(parent, depth);
}
/**
* Simple flat clone using prototype, accepts only objects, usefull for property
* override on FLAT configuration object (no nested props).
*
* USE WITH CAUTION! This may not behave as you wish if you do not know how this
* works.
*/
clone.clonePrototype = function clonePrototype(parent) {
if (parent === null)
return null;
var c = function () {};
c.prototype = parent;
return new c();
};
// private utility functions
function __objToStr(o) {
return Object.prototype.toString.call(o);
}
clone.__objToStr = __objToStr;
function __isDate(o) {
return typeof o === 'object' && __objToStr(o) === '[object Date]';
}
clone.__isDate = __isDate;
function __isArray(o) {
return typeof o === 'object' && __objToStr(o) === '[object Array]';
}
clone.__isArray = __isArray;
function __isRegExp(o) {
return typeof o === 'object' && __objToStr(o) === '[object RegExp]';
}
clone.__isRegExp = __isRegExp;
function __getRegExpFlags(re) {
var flags = '';
if (re.global) flags += 'g';
if (re.ignoreCase) flags += 'i';
if (re.multiline) flags += 'm';
return flags;
}
clone.__getRegExpFlags = __getRegExpFlags;
return clone;
})();
export default clone

View File

@@ -0,0 +1,18 @@
import { defineMixin } from '../vue'
export const buttonMixin = defineMixin({
props: {
lang: String,
sessionFrom: String,
sendMessageTitle: String,
sendMessagePath: String,
sendMessageImg: String,
showMessageCard: Boolean,
appParameter: String,
formType: String,
openType: String
}
})
export default buttonMixin

View File

@@ -0,0 +1,313 @@
import { defineMixin } from '../vue'
import { deepMerge, $parent, sleep } from '../function/index'
import test from '../function/test'
import route from '../util/route'
import {
applyNativeThemeUI,
applyNativeThemeUIDeferred,
getThemeCardStyle,
getThemeIsDark,
getThemePageStyle,
getThemeVar,
getThemeVarsForStyle,
syncThemeRuntimeFromStorage
} from '../theme/runtime'
// #ifdef APP-NVUE
// 由于weex为阿里的KPI业绩考核的产物,所以不支持百分比单位,这里需要通过dom查询组件的宽度
const dom = (typeof uni !== 'undefined' && uni && typeof uni.requireNativePlugin === 'function')
? uni.requireNativePlugin('dom')
: null
// #endif
export const mixin = defineMixin({
// 定义每个组件都可能需要用到的外部样式以及类名
props: {
// 每个组件都有的父组件传递的样式,可以为字符串或者对象形式
customStyle: {
type: [Object, String],
default: () => ({})
},
customClass: {
type: String,
default: ''
},
// 跳转的页面路径
url: {
type: String,
default: ''
},
// 页面跳转的类型
linkType: {
type: String,
default: 'navigateTo'
}
},
data() {
return {
__upPageThemeChangeHandler: null,
upThemeVersion: 0
}
},
onLoad() {
// getRect挂载到$u上,因为这方法需要使用in(this),所以无法把它独立成一个单独的文件导出
this.upBindGetRect()
this.upInitThemeVersion()
if (this.upIsPageScope()) {
this.upApplyNativeThemeUI()
if (typeof uni !== 'undefined' && typeof uni.$on === 'function' && !this.__upPageThemeChangeHandler) {
this.__upPageThemeChangeHandler = () => {
this.upApplyNativeThemeUI()
}
uni.$on('uThemeChange', this.__upPageThemeChangeHandler)
}
}
},
onShow() {
if (this.upIsPageScope()) {
this.upApplyNativeThemeUI()
}
},
created() {
// 组件当中,只有created声明周期,为了能在组件使用,故也在created中将方法挂载到$u
this.upBindGetRect()
this.upInitThemeVersion()
if (typeof uni !== 'undefined' && typeof uni.$on === 'function') {
this.__uThemeChangeHandler = (payload = {}) => {
this.upSyncThemeVersion(payload)
this.chacheU = null
if (typeof this.$forceUpdate === 'function') {
this.$forceUpdate()
}
}
uni.$on('uThemeChange', this.__uThemeChangeHandler)
}
},
computed: {
// 在2.x版本中,将会把$u挂载到uni对象下,导致在模板中无法使用uni.$u.xxx形式
// 所以这里通过computed计算属性将其附加到this.$u上,就可以在模板或者js中使用uni.$u.xxx
// 只在nvue环境通过此方式引入完整的$u,其他平台会出现性能问题,非nvue则按需引入(主要原因是props过大)
$u() {
this.upThemeVersion
// #ifndef APP-NVUE
// 在非nvue端,移除props,http,mixin等对象,避免在小程序setData时数据过大影响性能
let mergeU = deepMerge(uni.$u, {
props: undefined,
http: undefined,
mixin: undefined
})
// 缓存结果避免每次计算
if (!this.chacheU) {
this.chacheU = mergeU
}
return this.chacheU
// #endif
// #ifdef APP-NVUE
return uni.$u
// #endif
},
upThemeIsDark() {
this.upThemeVersion
return getThemeIsDark(this.$u)
},
upThemeVars() {
this.upThemeVersion
return getThemeVarsForStyle(this.$u)
},
upThemePageStyle() {
this.upThemeVersion
return getThemePageStyle(this.$u)
},
upThemeCardStyle() {
this.upThemeVersion
return getThemeCardStyle(this.$u)
},
/**
* 生成bem规则类名
* 由于微信小程序,H5,nvue之间绑定class的差异,无法通过:class="[bem()]"的形式进行同用
* 故采用如下折中做法,最后返回的是数组(一般平台)或字符串(支付宝和字节跳动平台),类似['a', 'b', 'c']或'a b c'的形式
* @param {String} name 组件名称
* @param {Array} fixed 一直会存在的类名
* @param {Array} change 会根据变量值为true或者false而出现或者隐藏的类名
* @returns {Array|string}
*/
bem() {
return function (name, fixed, change) {
// 类名前缀
const prefix = `u-${name}--`
const classes = {}
if (fixed) {
fixed.map((item) => {
// 这里的类名,会一直存在
classes[prefix + this[item]] = true
})
}
if (change) {
change.map((item) => {
// 这里的类名,会根据this[item]的值为true或者false,而进行添加或者移除某一个类
this[item] ? (classes[prefix + item] = this[item]) : (delete classes[prefix + item])
})
}
return Object.keys(classes)
// 支付宝,头条小程序无法动态绑定一个数组类名,否则解析出来的结果会带有",",而导致失效
// #ifdef MP-ALIPAY || MP-TOUTIAO || MP-LARK
.join(' ')
// #endif
}
}
},
methods: {
upBindGetRect() {
const upU = this.$u || (typeof uni !== 'undefined' ? uni.$u : null)
if (upU) {
upU.getRect = this.$uGetRect
} else if (typeof uni !== 'undefined') {
uni.$u = {
getRect: this.$uGetRect
}
}
},
upReadThemeVersion() {
return Number((typeof uni !== 'undefined' && uni.$u && uni.$u.theme && uni.$u.theme.version) || 0)
},
upInitThemeVersion() {
const version = this.upReadThemeVersion()
if (version) {
this.upThemeVersion = version
}
},
upSyncThemeVersion(payload = {}) {
const version = Number(payload.version || this.upReadThemeVersion() || 0)
this.upThemeVersion = version || Number(this.upThemeVersion || 0) + 1
},
upIsPageScope() {
return !!(this.$page || this.route || this.$options?.mpType === 'page')
},
upHasProp(propName) {
const vnodeProps = this.$?.vnode?.props || {}
const kebabName = propName.replace(/[A-Z]/g, (s) => `-${s.toLowerCase()}`)
return Object.prototype.hasOwnProperty.call(vnodeProps, propName)
|| Object.prototype.hasOwnProperty.call(vnodeProps, kebabName)
},
upThemeVar(varName, fallbackColor) {
this.upThemeVersion
return getThemeVar(varName, fallbackColor, this.$u)
},
upApplyNativeThemeUI() {
syncThemeRuntimeFromStorage(this.$u)
this.upSyncThemeVersion()
applyNativeThemeUIDeferred(this.$u)
},
// 跳转某一个页面
openPage(urlKey = 'url') {
const url = this[urlKey]
if (url) {
// h5官方回应:发行h5会自动摇树优化,所有使用uni的地方,都会被直接转换成具体的API调用 https://ask.dcloud.net.cn/question/161523?notification_id-1201922__rf-false__item_id-226372
// 使用封装的 route 进行跳转(直接调用方法),不使用 uni 对象
route({ type: this.linkType, url })
// 执行类似uni.navigateTo的方法
// uni[this.linkType]({
// url
// })
}
},
navTo(url = '', linkType = 'navigateTo') {
route({ type: this.linkType, url })
},
// 查询节点信息
// 目前此方法在支付宝小程序中无法获取组件跟接点的尺寸,为支付宝的bug(2020-07-21)
// 解决办法为在组件根部再套一个没有任何作用的view元素
$uGetRect(selector, all) {
return new Promise((resolve) => {
// #ifndef APP-NVUE
uni.createSelectorQuery()
.in(this)[all ? 'selectAll' : 'select'](selector)
.boundingClientRect((rect) => {
if (all && Array.isArray(rect) && rect.length) {
resolve(rect)
}
if (!all && rect) {
resolve(rect)
}
})
.exec()
// #endif
// #ifdef APP-NVUE
sleep(30).then(() => {
let selectorNvue = selector.substring(1) // 去掉开头的#或者.
let selectorRef = this.$refs[selectorNvue]
if (!selectorRef) {
// console.log('不存在元素,请检查是否设置了ref属性' + selectorNvue + '。')
resolve({
with: 0,
height: 0,
left: 0,
right: 0,
top: 0,
bottom: 0
})
}
dom.getComponentRect(selectorRef, res => {
// console.log(res)
resolve(res.size)
})
})
// #endif
})
},
getParentData(parentName = '') {
// 避免在created中去定义parent变量
if (!this.parent) this.parent = {}
// 这里的本质原理是,通过获取父组件实例(也即类似u-radio的父组件u-radio-group的this)
// 将父组件this中对应的参数,赋值给本组件(u-radio的this)的parentData对象中对应的属性
// 之所以需要这么做,是因为所有端中,头条小程序不支持通过this.parent.xxx去监听父组件参数的变化
// 此处并不会自动更新子组件的数据,而是依赖父组件u-radio-group去监听data的变化,手动调用更新子组件的方法去重新获取
this.parent = $parent.call(this, parentName)
if (this.parent.children) {
// 如果父组件的children不存在本组件的实例,才将本实例添加到父组件的children中
this.parent.children.indexOf(this) === -1 && this.parent.children.push(this)
}
if (this.parent && this.parentData) {
// 历遍parentData中的属性,将parent中的同名属性赋值给parentData
Object.keys(this.parentData).map((key) => {
this.parentData[key] = this.parent[key]
})
}
},
// 阻止事件冒泡
preventEvent(e) {
e && typeof (e.stopPropagation) === 'function' && e.stopPropagation()
},
// 空操作
noop(e) {
this.preventEvent(e)
}
},
onReachBottom() {
uni.$emit('uOnReachBottom')
},
beforeUnmount() {
// 判断当前页面是否存在parent和chldren,一般在checkbox和checkbox-group父子联动的场景会有此情况
// 组件销毁时,移除子组件在父组件children数组中的实例,释放资源,避免数据混乱
if (this.parent && test.array(this.parent.children)) {
// 组件销毁时,移除父组件中的children数组中对应的实例
const childrenList = this.parent.children
childrenList.map((child, index) => {
// 如果相等,则移除
if (child === this) {
childrenList.splice(index, 1)
}
})
}
if (typeof uni !== 'undefined' && typeof uni.$off === 'function' && this.__uThemeChangeHandler) {
uni.$off('uThemeChange', this.__uThemeChangeHandler)
this.__uThemeChangeHandler = null
}
if (typeof uni !== 'undefined' && typeof uni.$off === 'function' && this.__upPageThemeChangeHandler) {
uni.$off('uThemeChange', this.__upPageThemeChangeHandler)
this.__upPageThemeChangeHandler = null
}
}
})
export default mixin

View File

@@ -0,0 +1,13 @@
import { defineMixin } from '../vue'
export const mpMixin = defineMixin({
// #ifdef MP-WEIXIN
// 将自定义节点设置成虚拟的,更加接近Vue组件的表现,能更好的使用flex属性
options: {
virtualHost: true
}
// #endif
})
export default mpMixin

View File

@@ -0,0 +1,26 @@
import { defineMixin } from '../vue'
import { queryParams } from '../function/index'
export const mpShare = defineMixin({
data() {
return {
mpShare: {
title: '', // 默认为小程序名称
path: '', // 默认为当前页面路径
imageUrl: '' // 默认为当前页面的截图
}
}
},
async onLoad(options) {
var pages = getCurrentPages();
var page = pages[pages.length - 1];
this.mpShare.path = page.route + queryParams(options);
},
onShareAppMessage(res) {
if (res.from === 'button') {// 来自页面内分享按钮
console.log(res.target)
}
return this.mpShare;
}
})
export default mpShare

View File

@@ -0,0 +1,27 @@
import { defineMixin } from '../vue'
export const openType = defineMixin({
props: {
openType: String
},
methods: {
onGetUserInfo(event) {
this.$emit('getuserinfo', event.detail)
},
onContact(event) {
this.$emit('contact', event.detail)
},
onGetPhoneNumber(event) {
this.$emit('getphonenumber', event.detail)
},
onError(event) {
this.$emit('error', event.detail)
},
onLaunchApp(event) {
this.$emit('launchapp', event.detail)
},
onOpenSetting(event) {
this.$emit('opensetting', event.detail)
}
}
})

View File

@@ -0,0 +1,249 @@
import { defineMixin } from '../vue'
import { addStyle, deepMerge, addUnit, trim } from '../function/index'
export const style = defineMixin({
props: {
// flex排列方式
flexDirection: {
type: String,
default: ''
},
// flex-direction的简写
fd: {
type: String,
default: ''
},
// 展示类型
display: {
type: String,
default: ''
},
// display简写
d: {
type: String,
default: ''
},
// 主轴排列方式
justifyContent: {
type: String,
default: ''
},
// justifyContent的简写
jc: {
type: String,
default: ''
},
// 纵轴排列方式
alignItems: {
type: String,
default: ''
},
// align-items的简写
ai: {
type: String,
default: ''
},
color: {
type: String,
default: ''
},
// color简写
c: {
type: String,
default: ''
},
// 字体大小
fontSize: {
type: [String, Number],
default: 0
},
// font-size简写
fs: {
type: [String, Number],
default: ''
},
margin: {
type: [String, Number],
default: 0
},
// margin简写
m: {
type: [String, Number],
default: 0
},
// margin-top
marginTop: {
type: [String, Number],
default: 0
},
// margin-top简写
mt: {
type: [String, Number],
default: 0
},
// margin-right
marginRight: {
type: [String, Number],
default: 0
},
// margin-right简写
mr: {
type: [String, Number],
default: 0
},
// margin-bottom
marginBottom: {
type: [String, Number],
default: 0
},
// margin-bottom简写
mb: {
type: [String, Number],
default: 0
},
// margin-left
marginLeft: {
type: [String, Number],
default: 0
},
// margin-left简写
ml: {
type: [String, Number],
default: 0
},
// padding-left
paddingLeft: {
type: [String, Number],
default: 0
},
// padding-left简写
pl: {
type: [String, Number],
default: 0
},
// padding-top
paddingTop: {
type: [String, Number],
default: 0
},
// padding-top简写
pt: {
type: [String, Number],
default: 0
},
// padding-right
paddingRight: {
type: [String, Number],
default: 0
},
// padding-right简写
pr: {
type: [String, Number],
default: 0
},
// padding-bottom
paddingBottom: {
type: [String, Number],
default: 0
},
// padding-bottom简写
pb: {
type: [String, Number],
default: 0
},
// border-radius
borderRadius: {
type: [String, Number],
default: 0
},
// border-radius简写
radius: {
type: [String, Number],
default: 0
},
// transform
transform: {
type: String,
default: ''
},
// 定位
position: {
type: String,
default: ''
},
// position简写
pos: {
type: String,
default: ''
},
// 宽度
width: {
type: [String, Number],
default: null
},
// width简写
w: {
type: [String, Number],
default: null
},
// 高度
height: {
type: [String, Number],
default: null
},
// height简写
h: {
type: [String, Number],
default: null
},
top: {
type: [String, Number],
default: 0
},
right: {
type: [String, Number],
default: 0
},
bottom: {
type: [String, Number],
default: 0
},
left: {
type: [String, Number],
default: 0
}
},
computed: {
viewStyle() {
const style = {}
const addStyleTmp = addStyle(this.width || this.w)
&& (style.width = addStyle(this.width || this.w))(this.height || this.h)
&& (style.height = addStyle(this.height || this.h))(this.margin || this.m)
&& (style.margin = addStyle(this.margin || this.m))(this.marginTop || this.mt)
&& (style.marginTop = addStyle(this.marginTop || this.mt))(this.marginRight || this.mr)
&& (style.marginRight = addStyle(this.marginRight || this.mr))(this.marginBottom || this.mb)
&& (style.marginBottom = addStyle(this.marginBottom || this.mb))(this.marginLeft || this.ml)
&& (style.marginLeft = addStyle(this.marginLeft || this.ml))(this.padding || this.p)
&& (style.padding = addStyle(this.padding || this.p))(this.paddingTop || this.pt)
&& (style.paddingTop = addStyle(this.paddingTop || this.pt))(this.paddingRight || this.pr)
&& (style.paddingRight = addStyle(this.paddingRight || this.pr))(this.paddingBottom || this.pb)
&& (style.paddingBottom = addStyle(this.paddingBottom || this.pb))(this.paddingLeft || this.pl)
&& (style.paddingLeft = addStyle(this.paddingLeft || this.pl))(this.color || this.c)
&& (style.color = this.color || this.c)(this.fontSize || this.fs)
&& (style.fontSize = this.fontSize || this.fs)(this.borderRadius || this.radius)
&& (style.borderRadius = this.borderRadius || this.radius)(this.position || this.pos)
&& (this.position = this.position || this.pos)(this.flexDirection || this.fd)
&& (this.flexDirection = this.flexDirection || this.fd)(this.justifyContent || jc)
&& (this.justifyContent = this.justifyContent || jc)(this.alignItems || ai)
&& (this.alignItems = this.alignItems || ai)
return deepMerge(style, addStyleTmp(this.customStyle))
}
},
methods: {
// 获取margin或者padding的单位,比如padding: 0 20转为padding: 0 20px
getUnit(unit = '') {
// 取出两端空格,分隔成数组,再对数组的每个元素添加单位,最后再合并成字符串
return trim(unit).split(' ').map((item) => addUnit(item)).join(' ')
}
}
})

View File

@@ -0,0 +1,61 @@
import { defineMixin } from '../vue'
const MIN_DISTANCE = 10
function getDirection(x, y) {
if (x > y && x > MIN_DISTANCE) {
return 'horizontal'
}
if (y > x && y > MIN_DISTANCE) {
return 'vertical'
}
return ''
}
export const touchMixin = defineMixin({
methods: {
getTouchPoint(e) {
if (!e) {
return {
x: 0,
y: 0
}
} if (e.touches && e.touches[0]) {
return {
x: e.touches[0].pageX,
y: e.touches[0].pageY
}
} if (e.changedTouches && e.changedTouches[0]) {
return {
x: e.changedTouches[0].pageX,
y: e.changedTouches[0].pageY
}
}
return {
x: e.clientX || 0,
y: e.clientY || 0
}
},
resetTouchStatus() {
this.direction = ''
this.deltaX = 0
this.deltaY = 0
this.offsetX = 0
this.offsetY = 0
},
touchStart(event) {
this.resetTouchStatus()
const touch = this.getTouchPoint(event)
this.startX = touch.x
this.startY = touch.y
},
touchMove(event) {
const touch = this.getTouchPoint(event)
this.deltaX = touch.x - this.startX
this.deltaY = touch.y - this.startY
this.offsetX = Math.abs(this.deltaX)
this.offsetY = Math.abs(this.deltaY)
this.direction = this.direction || getDirection(this.offsetX, this.offsetY)
}
}
})

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2024-present, Skiyee (Sky)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,151 @@
import { dirname, relative, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
import process from 'node:process'
import { existsSync, mkdirSync, statSync, writeFileSync } from 'node:fs'
import { createFilter, normalizePath } from 'vite'
import { transformNvuePage, transformPage } from './page.js'
import { rebuildUpApp, registerUpApp } from './root.js'
import { loadPagesJson, normalizePlatformPath, toArray } from './utils.js'
const rootLibPath = normalizePath(dirname(fileURLToPath(import.meta.url)))
export default function UniUpRoot(options = {}) {
const rootOptions = {
enabledVirtualHost: false,
enabledGlobalRef: false,
rootFileName: 'App.up',
autoCreateRootFile: true,
excludePages: [],
...options,
}
const rootFileName = String(rootOptions.rootFileName || 'App.up').replace(/\.vue$/i, '')
const detectProjectRoot = () => {
const cwd = normalizePath(process.env.INIT_CWD || process.cwd())
const envInputDir = process.env.UNI_INPUT_DIR ? normalizePath(process.env.UNI_INPUT_DIR) : ''
const cliRootPath = normalizePath(resolve(cwd, 'src'))
const hbuilderRootPath = cwd
const isPageRoot = (path) => existsSync(resolve(path, 'pages.json'))
if (envInputDir && isPageRoot(envInputDir)) {
const projectType = envInputDir.endsWith('/src') ? 'cli' : 'hbuilder'
return { rootPath: envInputDir, projectType }
}
if (isPageRoot(cliRootPath)) {
return { rootPath: cliRootPath, projectType: 'cli' }
}
if (isPageRoot(hbuilderRootPath)) {
return { rootPath: hbuilderRootPath, projectType: 'hbuilder' }
}
return {
rootPath: envInputDir || cliRootPath,
projectType: envInputDir && !envInputDir.endsWith('/src') ? 'hbuilder' : 'cli',
}
}
const projectInfo = detectProjectRoot()
const rootPath = normalizePath(projectInfo.rootPath)
const appUpPath = normalizePath(resolve(rootPath, `${rootFileName}.vue`))
const rootToastHostPath = normalizePath(resolve(rootLibPath, 'root-toast-host.vue'))
const nvueRootPath = normalizePath(resolve(rootPath, 'uni_modules/uview-plus/libs/root/nvue-root.vue'))
const themeRuntimePath = normalizePath(resolve(rootPath, 'uni_modules/uview-plus/libs/theme/runtime.js'))
const pagesPath = normalizePath(resolve(rootPath, 'pages.json'))
const excludedPaths = toArray(rootOptions.excludePages)
.filter(Boolean)
.map(path => normalizePath(resolve(rootPath, path)))
const mainFiles = [
normalizePath(resolve(rootPath, 'main.ts')),
normalizePath(resolve(rootPath, 'main.js')),
]
const getRelativeImportPath = (fromFile, toFile) => {
let importPath = normalizePath(relative(dirname(fromFile), toFile))
if (!importPath.startsWith('.')) {
importPath = `./${importPath}`
}
return importPath
}
let pagesJson = []
let pagesJsonMtimeMs = 0
let hasPlatformPlugin = false
const ensureRootFile = () => {
if (!rootOptions.autoCreateRootFile) return
if (existsSync(appUpPath)) return
const defaultRootSfc = `<template>
\t<UpRootView />
</template>
`
mkdirSync(dirname(appUpPath), { recursive: true })
writeFileSync(appUpPath, defaultRootSfc, 'utf-8')
}
const refreshPagesJson = () => {
if (!existsSync(pagesPath)) return
const mtimeMs = statSync(pagesPath).mtimeMs
if (mtimeMs === pagesJsonMtimeMs && pagesJson.length) return
pagesJson = loadPagesJson(pagesPath, rootPath)
pagesJsonMtimeMs = mtimeMs
}
return {
name: 'vite-plugin-uni-up-root',
enforce: 'pre',
configResolved({ plugins }) {
hasPlatformPlugin = plugins.some(v => v.name === 'vite-plugin-uni-platform')
},
buildStart() {
ensureRootFile()
refreshPagesJson()
},
async transform(code, id) {
let ms = null
const isSfcBlock = id.includes('?')
const cleanId = normalizePath(id.split('?')[0])
const filterMain = createFilter(mainFiles)
if (filterMain(cleanId)) {
ms = await registerUpApp(code, rootFileName, getRelativeImportPath(cleanId, rootToastHostPath))
}
const filterUpRoot = createFilter(appUpPath)
if (filterUpRoot(cleanId)) {
ms = await rebuildUpApp(code, rootOptions.enabledVirtualHost)
}
refreshPagesJson()
const pageId = hasPlatformPlugin ? normalizePlatformPath(cleanId) : cleanId
const filterPage = createFilter(pagesJson, excludedPaths)
if (!isSfcBlock && filterPage(pageId)) {
if (cleanId.endsWith('.nvue')) {
ms = await transformNvuePage(
code,
getRelativeImportPath(cleanId, nvueRootPath),
getRelativeImportPath(cleanId, themeRuntimePath),
rootOptions.enabledGlobalRef
)
} else {
ms = await transformPage(code, rootOptions.enabledGlobalRef)
}
}
if (ms) {
return {
code: ms.toString(),
map: ms.generateMap({ hires: true }),
}
}
return null
},
}
}

View File

@@ -0,0 +1,72 @@
<template>
<view class="up-nvue-root" :style="rootStyle">
<slot />
</view>
</template>
<script>
import { applyNativeThemeUI, getThemePageStyle, getThemeVarsForStyle, syncThemeRuntimeFromStorage } from '../theme/runtime.js'
export default {
name: 'UpNvueRoot',
data() {
return {
rootStyle: {
...getThemeVarsForStyle(),
...getThemePageStyle()
},
minPageHeight: '0px'
}
},
created() {
this.syncPageHeight()
this.refreshRootStyle()
this.themeChangeHandler = () => {
this.refreshRootStyle()
}
if (typeof uni !== 'undefined' && typeof uni.$on === 'function') {
uni.$on('uThemeChange', this.themeChangeHandler)
}
},
mounted() {
this.refreshRootStyle()
},
beforeUnmount() {
if (this.themeChangeHandler && typeof uni !== 'undefined' && typeof uni.$off === 'function') {
uni.$off('uThemeChange', this.themeChangeHandler)
}
this.themeChangeHandler = null
},
methods: {
syncPageHeight() {
let windowHeight = 0
try {
if (typeof uni !== 'undefined' && typeof uni.getWindowInfo === 'function') {
windowHeight = Number((uni.getWindowInfo() || {}).windowHeight || 0)
} else if (typeof uni !== 'undefined' && typeof uni.getSystemInfoSync === 'function') {
windowHeight = Number((uni.getSystemInfoSync() || {}).windowHeight || 0)
}
} catch (e) {
windowHeight = 0
}
this.minPageHeight = `${windowHeight || 0}px`
},
refreshRootStyle() {
syncThemeRuntimeFromStorage()
this.rootStyle = {
...getThemeVarsForStyle(),
...getThemePageStyle(),
minHeight: this.minPageHeight,
width: '750rpx'
}
applyNativeThemeUI()
}
}
}
</script>
<style>
.up-nvue-root {
width: 750rpx;
}
</style>

View File

@@ -0,0 +1,269 @@
import { MagicString } from 'vue/compiler-sfc'
import { findNode, parseSFC } from './utils.js'
function getPageRootRefSource(sfc, enabledGlobalRef = false) {
const pageTempAttrs = sfc.template?.attrs
if (pageTempAttrs && pageTempAttrs.root) {
return `ref="${pageTempAttrs.root}"`
}
return enabledGlobalRef ? 'ref="uniUpRoot"' : ''
}
function ensureNvueNavigationBar(pageMetaSource) {
const navigationBarSource = '<navigation-bar :front-color="upThemeNavFrontColor" :background-color="upThemeNavBgColor" />'
if (!pageMetaSource) return `<page-meta>${navigationBarSource}</page-meta>`
if (pageMetaSource.indexOf('navigation-bar') > -1 || pageMetaSource.indexOf('NavigationBar') > -1) {
return pageMetaSource
}
return pageMetaSource.replace(/<page-meta([^>]*)>/i, `<page-meta$1>${navigationBarSource}`)
}
function wrapTemplate(ms, sfc, tagName, rootRefSource = '', withNvueNavigationBar = false) {
const pageTempStart = sfc.template?.loc.start.offset
const pageTempEnd = sfc.template?.loc.end.offset
let pageMetaSource = ''
const pageMetaNode = findNode(sfc, 'PageMeta')
if (pageMetaNode) {
pageMetaSource = pageMetaNode.loc.source
const metaTempStart = pageMetaNode.loc.start.offset
const metaTempEnd = pageMetaNode.loc.end.offset
ms.remove(metaTempStart, metaTempEnd)
}
if (withNvueNavigationBar) {
pageMetaSource = ensureNvueNavigationBar(pageMetaSource)
}
if (pageTempStart != null && pageTempEnd != null) {
ms.appendLeft(pageTempStart, `\n${pageMetaSource}\n<${tagName} ${rootRefSource}>`)
ms.appendRight(pageTempEnd, `\n</${tagName}>\n`)
}
}
export async function transformPage(code, enabledGlobalRef = false) {
const sfc = await parseSFC(code)
const ms = new MagicString(code)
wrapTemplate(ms, sfc, 'global-up-root', getPageRootRefSource(sfc, enabledGlobalRef))
return ms
}
function ensureOptionsComponent(ms, scriptContent) {
if (scriptContent.includes('UpNvueRoot')) return
const componentsMatch = scriptContent.match(/components\s*:\s*\{/)
if (componentsMatch) {
ms.appendLeft(componentsMatch.index + componentsMatch[0].length, ' UpNvueRoot,')
return
}
const exportDefaultMatch = scriptContent.match(/export\s+default\s+(?:defineComponent\s*\()?\s*\{/)
if (exportDefaultMatch) {
ms.appendLeft(
exportDefaultMatch.index + exportDefaultMatch[0].length,
'\n components: { UpNvueRoot },'
)
}
}
function ensureOptionsThemeMixin(ms, scriptContent) {
if (scriptContent.includes('__upNvueThemeMixin')) return
const mixinsMatch = scriptContent.match(/mixins\s*:\s*\[/)
if (mixinsMatch) {
ms.appendLeft(mixinsMatch.index + mixinsMatch[0].length, ' __upNvueThemeMixin,')
return
}
const exportDefaultMatch = scriptContent.match(/export\s+default\s+(?:defineComponent\s*\()?\s*\{/)
if (exportDefaultMatch) {
ms.appendLeft(
exportDefaultMatch.index + exportDefaultMatch[0].length,
'\n mixins: [__upNvueThemeMixin],'
)
}
}
function getScriptSetupImports(componentImportPath, runtimeImportPath) {
return `import UpNvueRoot from '${componentImportPath}'
import { computed as __upComputed, onBeforeUnmount as __upOnBeforeUnmount, onMounted as __upOnMounted, ref as __upRef } from 'vue'
import { onShow as __upOnShow } from '@dcloudio/uni-app'
import {
applyNativeThemeUI as __upApplyNativeThemeUI,
applyNativeThemeUIDeferred as __upApplyNativeThemeUIDeferred,
getThemeCardStyle as __upGetThemeCardStyle,
getThemeIsDark as __upGetThemeIsDark,
getThemePageStyle as __upGetThemePageStyle,
getThemeVar as __upThemeVar,
syncThemeRuntimeFromStorage as __upSyncThemeRuntimeFromStorage
} from '${runtimeImportPath}'
const __upThemeVersion = __upRef(0)
let __upThemeChangeHandler = null
const __upReadThemeVersion = () => Number((typeof uni !== 'undefined' && uni.$u && uni.$u.theme && uni.$u.theme.version) || 0)
const __upSyncThemeVersion = (payload = {}) => {
const version = Number(payload.version || __upReadThemeVersion() || 0)
__upThemeVersion.value = version || Number(__upThemeVersion.value || 0) + 1
}
__upOnMounted(() => {
__upSyncThemeRuntimeFromStorage()
__upSyncThemeVersion()
__upApplyNativeThemeUI()
if (typeof uni !== 'undefined' && typeof uni.$on === 'function') {
__upThemeChangeHandler = (payload = {}) => {
__upSyncThemeRuntimeFromStorage()
__upSyncThemeVersion(payload)
__upApplyNativeThemeUI()
}
uni.$on('uThemeChange', __upThemeChangeHandler)
}
})
__upOnShow(() => {
__upSyncThemeRuntimeFromStorage()
__upSyncThemeVersion()
__upApplyNativeThemeUIDeferred()
})
__upOnBeforeUnmount(() => {
if (typeof uni !== 'undefined' && typeof uni.$off === 'function' && __upThemeChangeHandler) {
uni.$off('uThemeChange', __upThemeChangeHandler)
__upThemeChangeHandler = null
}
})
const upThemeVar = (varName, fallbackColor) => {
__upThemeVersion.value
return __upThemeVar(varName, fallbackColor)
}
const upThemeCardStyle = __upComputed(() => {
__upThemeVersion.value
return __upGetThemeCardStyle()
})
const upThemePageStyle = __upComputed(() => {
__upThemeVersion.value
return __upGetThemePageStyle()
})
const upThemeIsDark = __upComputed(() => {
__upThemeVersion.value
return __upGetThemeIsDark()
})
const upThemeNavFrontColor = __upComputed(() => {
__upThemeVersion.value
return __upGetThemeIsDark() ? '#ffffff' : '#000000'
})
const upThemeNavBgColor = __upComputed(() => {
__upThemeVersion.value
return __upThemeVar('--up-navbar-bg-color', __upGetThemeIsDark() ? '#1c1c1e' : '#ffffff')
})
`
}
function getOptionsImports(componentImportPath, runtimeImportPath) {
return `import UpNvueRoot from '${componentImportPath}'
import {
applyNativeThemeUI as __upApplyNativeThemeUI,
applyNativeThemeUIDeferred as __upApplyNativeThemeUIDeferred,
getThemeCardStyle as __upGetThemeCardStyle,
getThemeIsDark as __upGetThemeIsDark,
getThemePageStyle as __upGetThemePageStyle,
getThemeVar as __upThemeVar,
syncThemeRuntimeFromStorage as __upSyncThemeRuntimeFromStorage
} from '${runtimeImportPath}'
const __upNvueThemeMixin = {
data() {
return {
__upNvueThemeVersion: 0,
__upNvueThemeChangeHandler: null
}
},
created() {
__upSyncThemeRuntimeFromStorage()
this.__upSyncNvueThemeVersion()
__upApplyNativeThemeUI()
if (typeof uni !== 'undefined' && typeof uni.$on === 'function') {
this.__upNvueThemeChangeHandler = (payload = {}) => {
__upSyncThemeRuntimeFromStorage()
this.__upSyncNvueThemeVersion(payload)
__upApplyNativeThemeUI()
}
uni.$on('uThemeChange', this.__upNvueThemeChangeHandler)
}
},
onShow() {
__upSyncThemeRuntimeFromStorage()
this.__upSyncNvueThemeVersion()
__upApplyNativeThemeUIDeferred()
},
beforeUnmount() {
if (typeof uni !== 'undefined' && typeof uni.$off === 'function' && this.__upNvueThemeChangeHandler) {
uni.$off('uThemeChange', this.__upNvueThemeChangeHandler)
this.__upNvueThemeChangeHandler = null
}
},
computed: {
upThemeCardStyle() {
this.__upNvueThemeVersion
return __upGetThemeCardStyle()
},
upThemePageStyle() {
this.__upNvueThemeVersion
return __upGetThemePageStyle()
},
upThemeIsDark() {
this.__upNvueThemeVersion
return __upGetThemeIsDark()
},
upThemeNavFrontColor() {
this.__upNvueThemeVersion
return __upGetThemeIsDark() ? '#ffffff' : '#000000'
},
upThemeNavBgColor() {
this.__upNvueThemeVersion
return __upThemeVar('--up-navbar-bg-color', __upGetThemeIsDark() ? '#1c1c1e' : '#ffffff')
}
},
methods: {
__upReadNvueThemeVersion() {
return Number((typeof uni !== 'undefined' && uni.$u && uni.$u.theme && uni.$u.theme.version) || 0)
},
__upSyncNvueThemeVersion(payload = {}) {
const version = Number(payload.version || this.__upReadNvueThemeVersion() || 0)
this.__upNvueThemeVersion = version || Number(this.__upNvueThemeVersion || 0) + 1
},
upThemeVar(varName, fallbackColor) {
this.__upNvueThemeVersion
return __upThemeVar(varName, fallbackColor)
}
}
}
`
}
export async function transformNvuePage(
code,
componentImportPath,
runtimeImportPath,
enabledGlobalRef = false
) {
const sfc = await parseSFC(code)
const ms = new MagicString(code)
wrapTemplate(ms, sfc, 'UpNvueRoot', getPageRootRefSource(sfc, enabledGlobalRef), true)
if (sfc.scriptSetup) {
ms.appendLeft(sfc.scriptSetup.loc.start.offset, getScriptSetupImports(componentImportPath, runtimeImportPath))
} else if (sfc.script) {
ms.appendLeft(sfc.script.loc.start.offset, getOptionsImports(componentImportPath, runtimeImportPath))
ensureOptionsComponent(ms, sfc.script.content)
ensureOptionsThemeMixin(ms, sfc.script.content)
} else {
ms.append(
`\n<script>\n${getOptionsImports(componentImportPath, runtimeImportPath)}export default {\n components: { UpNvueRoot },\n mixins: [__upNvueThemeMixin]\n}\n</script>\n`
)
}
return ms
}

View File

@@ -0,0 +1,31 @@
<template>
<up-toast ref="upGlobalToastRef" />
<up-notify ref="upGlobalNotifyRef" />
</template>
<script setup>
import { onBeforeUnmount, onMounted, ref } from 'vue'
const upGlobalToastRef = ref(null)
const upGlobalNotifyRef = ref(null)
onMounted(() => {
if (typeof uni === 'undefined' || !uni.$u) return
if (typeof uni.$u.setRootToastRef === 'function') {
uni.$u.setRootToastRef(upGlobalToastRef.value)
}
if (typeof uni.$u.setRootNotifyRef === 'function') {
uni.$u.setRootNotifyRef(upGlobalNotifyRef.value)
}
})
onBeforeUnmount(() => {
if (typeof uni === 'undefined' || !uni.$u) return
if (typeof uni.$u.setRootToastRef === 'function') {
uni.$u.setRootToastRef(null)
}
if (typeof uni.$u.setRootNotifyRef === 'function') {
uni.$u.setRootNotifyRef(null)
}
})
</script>

View File

@@ -0,0 +1,44 @@
import { MagicString } from 'vue/compiler-sfc'
import { parseSFC } from './utils.js'
export async function registerUpApp(
code,
fileName = 'App.up',
rootToastHostPath = './uni_modules/uview-plus/libs/root/root-toast-host.vue'
) {
const ms = new MagicString(code)
const importCode = `import GlobalUpRoot from "./${fileName}.vue";
import UpRootToastHost from "${rootToastHostPath}";`
const vueUseComponentCode = 'app.component("global-up-root", GlobalUpRoot);\napp.component("ku-root-toast-host", UpRootToastHost);'
ms.prepend(`${importCode}\n`).replace(
/(createApp[\s\S]*?)(return\s\{\s*app)/,
`$1${vueUseComponentCode}\n$2`,
)
return ms
}
export async function rebuildUpApp(code, enabledVirtualHost = false) {
const ms = new MagicString(code)
const rootTagNameRE = /<(UpRootView|up-root-view)(?:\s*\/>|><\/\1>)/
ms.replace(rootTagNameRE, '<slot />\n <ku-root-toast-host />')
if (enabledVirtualHost) {
const sfc = await parseSFC(code)
if (sfc.script) {
return ms
}
const langType = sfc.scriptSetup?.lang
ms.append(`<script ${langType ? `lang="${langType}"` : ''}>
export default {
options: {
virtualHost: true,
}
}\n</script>`)
}
return ms
}

View File

@@ -0,0 +1,11 @@
// Compatibility shim for stale incremental build caches.
// New root integration no longer depends on this file.
export function createGlobalUpRoot(AppRootComponent) {
return AppRootComponent
}
export default {
createGlobalUpRoot,
}

View File

@@ -0,0 +1,115 @@
import { existsSync, readFileSync } from 'node:fs'
import { extname, join } from 'node:path'
import process from 'node:process'
import { parse as VueParser } from 'vue/compiler-sfc'
import { normalizePath } from 'vite'
function stripJsonComments(jsonText) {
return jsonText
.replace(/\/\*[\s\S]*?\*\//g, '')
.replace(/(^|[^:\\])\/\/.*$/gm, '$1')
}
function parseJsonc(jsonText) {
const withoutComments = stripJsonComments(jsonText)
const withoutTrailingComma = withoutComments.replace(/,\s*([}\]])/g, '$1')
return JSON.parse(withoutTrailingComma)
}
export async function parseSFC(code) {
try {
return VueParser(code, { pad: 'space' }).descriptor
} catch {
throw new Error('[@up-root] Vue version must support compiler-sfc parser.')
}
}
const PAGE_FILE_EXTS = ['.vue', '.nvue', '.uvue']
export function formatPagePath(root, path) {
const joinedPath = join(root, path)
const pathExt = extname(joinedPath)
if (pathExt) {
return normalizePath(joinedPath)
}
const pageFilePath = PAGE_FILE_EXTS
.map(fileExt => `${joinedPath}${fileExt}`)
.find(filePath => existsSync(filePath))
return normalizePath(pageFilePath || `${joinedPath}.vue`)
}
export function loadPagesJson(path, rootPath) {
const pagesJsonRaw = readFileSync(path, 'utf-8')
const parsed = parseJsonc(pagesJsonRaw) || {}
const pages = parsed.pages || []
const subPackages = parsed.subPackages || []
return [
...pages.map((page) => formatPagePath(rootPath, page.path)),
...subPackages
.map(({ pages: subPages = [], root = '' }) => {
return subPages.map((page) => formatPagePath(join(rootPath, root), page.path))
})
.flat(),
]
}
export function toKebabCase(str) {
return str
.replace(/([a-z])([A-Z])/g, '$1-$2')
.replace(/[_\s]+/g, '-')
.toLowerCase()
}
export function toPascalCase(str) {
return str
.replace(/(^\w|-+\w)/g, (match) => match.toUpperCase().replace(/-/g, ''))
}
export function findNode(sfc, rawTagName) {
const templateSource = sfc.template?.content
if (!templateSource) return
let tagName = ''
if (templateSource.includes(`<${toKebabCase(rawTagName)}`)) {
tagName = toKebabCase(rawTagName)
} else if (templateSource.includes(`<${toPascalCase(rawTagName)}`)) {
tagName = toPascalCase(rawTagName)
}
if (!tagName) return
const nodeAst = sfc.template?.ast
if (!nodeAst) return
const traverse = (nodes) => {
for (const node of nodes) {
if (node.type === 1) {
if (node.tag === tagName) return node
if (node.children?.length) {
const found = traverse(node.children)
if (found) return found
}
}
}
}
return traverse(nodeAst.children)
}
const platform = process.env.UNI_PLATFORM
export function normalizePlatformPath(id) {
const idExt = extname(id)
if (idExt !== '.vue') return id
if (!id.includes(`.${platform}.`)) return id
return id.replace(`.${platform}.`, '.')
}
export function toArray(value) {
if (!value) return []
return Array.isArray(value) ? value : [value]
}

View File

@@ -0,0 +1,440 @@
const THEME_MODE_STORAGE_KEY = 'u-theme-mode'
const FALLBACK_THEME_VARS = {
light: {
'--up-main-color': 'var(--up-light-main-color, #303133)',
'--up-content-color': 'var(--up-light-content-color, #606266)',
'--up-tips-color': 'var(--up-light-tips-color, #909193)',
'--up-light-color': 'var(--up-light-light-color, #c0c4cc)',
'--up-border-color': 'var(--up-light-border-color, #dadbde)',
'--up-bg-color': 'var(--up-light-bg-color, #f3f4f6)',
'--up-hover-bg-color': '#e7ebf0',
'--up-page-bg-color': '#f3f4f6',
'--up-card-bg-color': '#ffffff',
'--up-navbar-bg-color': '#ffffff',
'--up-table2-header-bg-color': '#f5f7fa',
'--up-table2-zebra-bg-color': '#fafafa',
'--up-table2-highlight-bg-color': '#f5f7fa',
'--up-gap-bg-color': '#f3f4f6',
'--up-skeleton-bg-color': '#f1f2f4',
'--up-skeleton-shimmer-color': '#e6e6e6',
'--up-swipe-action-button-bg-color': '#c7c6cd',
'--up-index-list-indicator-bg-color': '#c9c9c9',
'--up-calendar-month-mark-color': 'rgba(231, 232, 234, 0.83)',
'--up-disabled-color': 'var(--up-light-disabled-color, #c8c9cc)',
'--up-primary': 'var(--up-light-primary, #3c9cff)',
'--up-primary-dark': 'var(--up-light-primary-dark, #398ade)',
'--up-primary-disabled': 'var(--up-light-primary-disabled, #9acafc)',
'--up-primary-light': 'var(--up-light-primary-light, #ecf5ff)',
'--up-warning': 'var(--up-light-warning, #f9ae3d)',
'--up-warning-dark': 'var(--up-light-warning-dark, #f1a532)',
'--up-warning-disabled': 'var(--up-light-warning-disabled, #f9d39b)',
'--up-warning-light': 'var(--up-light-warning-light, #fdf6ec)',
'--up-success': 'var(--up-light-success, #5ac725)',
'--up-success-dark': 'var(--up-light-success-dark, #53c21d)',
'--up-success-disabled': 'var(--up-light-success-disabled, #a9e08f)',
'--up-success-light': 'var(--up-light-success-light, #f5fff0)',
'--up-error': 'var(--up-light-error, #f56c6c)',
'--up-error-dark': 'var(--up-light-error-dark, #e45656)',
'--up-error-disabled': 'var(--up-light-error-disabled, #f7b2b2)',
'--up-error-light': 'var(--up-light-error-light, #fef0f0)',
'--up-info': 'var(--up-light-info, #909399)',
'--up-info-dark': 'var(--up-light-info-dark, #767a82)',
'--up-info-disabled': 'var(--up-light-info-disabled, #c4c6c9)',
'--up-info-light': 'var(--up-light-info-light, #f4f4f5)'
},
dark: {
'--up-main-color': '#f5f5f5',
'--up-content-color': '#d1d5db',
'--up-tips-color': '#9ca3af',
'--up-light-color': '#6b7280',
'--up-border-color': '#3a3a3c',
'--up-bg-color': '#1f1f1f',
'--up-hover-bg-color': '#343741',
'--up-page-bg-color': '#1f1f1f',
'--up-card-bg-color': '#1c1c1e',
'--up-navbar-bg-color': '#1c1c1e',
'--up-table2-header-bg-color': '#2a2d33',
'--up-table2-zebra-bg-color': '#23262b',
'--up-table2-highlight-bg-color': '#2f3440',
'--up-gap-bg-color': '#111111',
'--up-skeleton-bg-color': '#2f3135',
'--up-skeleton-shimmer-color': 'rgba(255, 255, 255, 0.12)',
'--up-swipe-action-button-bg-color': '#4b5563',
'--up-index-list-indicator-bg-color': '#4b5563',
'--up-calendar-month-mark-color': 'rgba(255, 255, 255, 0.04)',
'--up-disabled-color': '#4b5563',
'--up-primary': '#3c9cff',
'--up-primary-dark': '#5aa8ff',
'--up-primary-disabled': '#4c6f92',
'--up-primary-light': '#10243a',
'--up-warning': '#f9ae3d',
'--up-warning-dark': '#ffbf66',
'--up-warning-disabled': '#8a6a3a',
'--up-warning-light': '#3d2f1b',
'--up-success': '#5ac725',
'--up-success-dark': '#7ad94b',
'--up-success-disabled': '#5f7f4f',
'--up-success-light': '#1f3316',
'--up-error': '#f56c6c',
'--up-error-dark': '#ff8a8a',
'--up-error-disabled': '#8d5858',
'--up-error-light': '#3a2222',
'--up-info': '#909399',
'--up-info-dark': '#b0b3b8',
'--up-info-disabled': '#5f6368',
'--up-info-light': '#2f3238'
}
}
const THEME_COLOR_SYNC_MAP = {
'--up-main-color': 'mainColor',
'--up-content-color': 'contentColor',
'--up-tips-color': 'tipsColor',
'--up-light-color': 'lightColor',
'--up-border-color': 'borderColor',
'--up-bg-color': 'bgColor',
'--up-disabled-color': 'disabledColor',
'--up-primary': 'primary',
'--up-primary-dark': 'primaryDark',
'--up-primary-disabled': 'primaryDisabled',
'--up-primary-light': 'primaryLight',
'--up-warning': 'warning',
'--up-warning-dark': 'warningDark',
'--up-warning-disabled': 'warningDisabled',
'--up-warning-light': 'warningLight',
'--up-success': 'success',
'--up-success-dark': 'successDark',
'--up-success-disabled': 'successDisabled',
'--up-success-light': 'successLight',
'--up-error': 'error',
'--up-error-dark': 'errorDark',
'--up-error-disabled': 'errorDisabled',
'--up-error-light': 'errorLight',
'--up-info': 'info',
'--up-info-dark': 'infoDark',
'--up-info-disabled': 'infoDisabled',
'--up-info-light': 'infoLight'
}
function buildFallbackAliasVars(vars) {
const aliasVars = {}
Object.keys(vars).forEach((key) => {
if (typeof key === 'string' && key.indexOf('--up-') === 0) {
aliasVars[key.replace('--up-', '--u-')] = vars[key]
}
})
return aliasVars
}
function getRuntimeU(upU) {
if (upU) return upU
if (typeof uni !== 'undefined') return uni.$u
return null
}
function normalizeRuntimeRoute(route) {
if (typeof route !== 'string') return ''
return route.replace(/^\//, '').split('?')[0]
}
function getCurrentRuntimeRoute() {
try {
if (typeof getCurrentPages !== 'function') return ''
const pages = getCurrentPages()
if (!Array.isArray(pages) || pages.length === 0) return ''
const page = pages[pages.length - 1] || {}
return normalizeRuntimeRoute(page.route || page.path || '')
} catch (e) {}
return ''
}
function getRuntimeTabBarRoutes() {
const routes = []
try {
const runtimeConfig = typeof __uniConfig !== 'undefined' ? __uniConfig : null
const tabBarList = runtimeConfig?.tabBar?.list
if (Array.isArray(tabBarList)) {
tabBarList.forEach((item) => {
const route = normalizeRuntimeRoute(item?.pagePath || '')
if (route) routes.push(route)
})
}
} catch (e) {}
return routes
}
function hasActiveRuntimePage() {
try {
if (typeof getCurrentPages === 'function') {
const pages = getCurrentPages()
return Array.isArray(pages) && pages.length > 0
}
} catch (e) {}
return false
}
function trySetNavigationBarColor(options) {
if (typeof uni === 'undefined' || typeof uni.setNavigationBarColor !== 'function') return
if (!hasActiveRuntimePage()) return
try {
const result = uni.setNavigationBarColor(options)
if (result && typeof result.catch === 'function') {
result.catch(() => {})
}
} catch (e) {}
}
export function isTabBarPage() {
const route = getCurrentRuntimeRoute()
if (!route) return false
const tabBarRoutes = getRuntimeTabBarRoutes()
if (!tabBarRoutes.length) return false
return tabBarRoutes.includes(route)
}
export function trySetTabBarStyle(options) {
if (typeof uni === 'undefined' || typeof uni.setTabBarStyle !== 'function') return
if (!isTabBarPage()) return
try {
const result = uni.setTabBarStyle(options)
if (result && typeof result.catch === 'function') {
result.catch(() => {})
}
} catch (e) {}
}
function normalizeThemeMode(theme = 'light') {
return theme === 'dark' ? 'dark' : 'light'
}
function normalizeThemePreference(mode = 'system') {
return mode === 'dark' || mode === 'light' ? mode : 'system'
}
function getFallbackSystemTheme() {
let theme = 'light'
try {
if (typeof uni !== 'undefined' && typeof uni.getAppBaseInfo === 'function') {
const appBaseInfo = uni.getAppBaseInfo() || {}
if (appBaseInfo.theme) theme = appBaseInfo.theme
}
if (typeof uni !== 'undefined' && typeof uni.getSystemInfoSync === 'function') {
const systemInfo = uni.getSystemInfoSync() || {}
if (systemInfo.theme) theme = systemInfo.theme
}
} catch (e) {
theme = 'light'
}
return normalizeThemeMode(theme)
}
function getFallbackThemePreference() {
try {
if (typeof uni !== 'undefined' && typeof uni.getStorageSync === 'function') {
const preference = uni.getStorageSync(THEME_MODE_STORAGE_KEY)
return normalizeThemePreference(preference)
}
} catch (e) {}
return 'system'
}
function getFallbackThemeMode() {
const preference = getFallbackThemePreference()
if (preference === 'dark' || preference === 'light') return preference
return getFallbackSystemTheme()
}
function getFallbackThemeVarsByMode(mode) {
const vars = FALLBACK_THEME_VARS[normalizeThemeMode(mode)] || FALLBACK_THEME_VARS.light
return {
...vars,
...buildFallbackAliasVars(vars)
}
}
function getFallbackThemeVars(upU) {
const mode = getThemeIsDark(upU) ? 'dark' : 'light'
return getFallbackThemeVarsByMode(mode)
}
function syncRuntimeColor(runtimeU, vars) {
if (!runtimeU || !runtimeU.color) return
Object.keys(THEME_COLOR_SYNC_MAP).forEach((token) => {
const field = THEME_COLOR_SYNC_MAP[token]
runtimeU.color[field] = vars[token]
})
}
export function syncThemeRuntimeFromStorage(upU) {
const runtimeU = getRuntimeU(upU)
if (!runtimeU || !runtimeU.theme) return runtimeU?.theme
const preference = getFallbackThemePreference()
const mode = preference === 'system' ? getFallbackSystemTheme() : preference
const vars = getFallbackThemeVarsByMode(mode)
const shouldUpdate = runtimeU.theme.preference !== preference || runtimeU.theme.mode !== mode
if (shouldUpdate && typeof runtimeU.setThemePreference === 'function') {
return runtimeU.setThemePreference(preference) || runtimeU.theme
}
runtimeU.theme.preference = preference
runtimeU.theme.mode = mode
runtimeU.theme.vars = {
...vars,
...(runtimeU.theme.vars && !shouldUpdate ? runtimeU.theme.vars : {})
}
if (shouldUpdate) {
runtimeU.theme.version = Number(runtimeU.theme.version || 0) + 1
}
syncRuntimeColor(runtimeU, runtimeU.theme.vars)
return runtimeU.theme
}
export function getThemeIsDark(upU) {
const runtimeMode = getRuntimeU(upU)?.theme?.mode
if (runtimeMode) return runtimeMode === 'dark'
return getFallbackThemeMode() === 'dark'
}
export function getThemeVarsForStyle(upU) {
const runtimeU = getRuntimeU(upU)
if (runtimeU && typeof runtimeU.getThemeVars === 'function') {
return runtimeU.getThemeVars()
}
return getFallbackThemeVars(runtimeU)
}
export function getThemeVar(varName, fallbackColor, upU) {
const runtimeU = getRuntimeU(upU)
const themeVars = runtimeU?.theme?.vars
if (themeVars && Object.prototype.hasOwnProperty.call(themeVars, varName)) {
return themeVars[varName]
}
if (typeof varName === 'string') {
const aliasVarName = varName.indexOf('--up-') === 0
? varName.replace('--up-', '--u-')
: (varName.indexOf('--u-') === 0 ? varName.replace('--u-', '--up-') : '')
if (aliasVarName && themeVars && Object.prototype.hasOwnProperty.call(themeVars, aliasVarName)) {
return themeVars[aliasVarName]
}
const runtimeColorMap = runtimeU?.config?.color || {}
const colorTokenKey = varName.indexOf('--') === 0 ? varName.slice(2) : varName
if (Object.prototype.hasOwnProperty.call(runtimeColorMap, colorTokenKey)) {
return runtimeColorMap[colorTokenKey]
}
const aliasColorTokenKey = colorTokenKey.indexOf('up-') === 0
? colorTokenKey.replace('up-', 'u-')
: (colorTokenKey.indexOf('u-') === 0 ? colorTokenKey.replace('u-', 'up-') : '')
if (aliasColorTokenKey && Object.prototype.hasOwnProperty.call(runtimeColorMap, aliasColorTokenKey)) {
return runtimeColorMap[aliasColorTokenKey]
}
}
if (runtimeU && typeof runtimeU.getThemeVars === 'function') {
const vars = runtimeU.getThemeVars()
if (vars && Object.prototype.hasOwnProperty.call(vars, varName)) {
return vars[varName]
}
}
const fallbackVars = getFallbackThemeVars(runtimeU)
if (fallbackVars && Object.prototype.hasOwnProperty.call(fallbackVars, varName)) {
return fallbackVars[varName]
}
return typeof fallbackColor !== 'undefined' ? fallbackColor : ''
}
export function getThemeCssVar(varName, fallbackColor) {
if (typeof fallbackColor === 'undefined') {
return `var(${varName})`
}
return `var(${varName}, ${fallbackColor})`
}
export function getThemePageStyle(upU, preferCssVars = false) {
const runtimeU = getRuntimeU(upU)
const isDark = getThemeIsDark(runtimeU)
const fallbackBg = isDark ? '#1f1f1f' : (runtimeU?.color?.bgColor || '#f3f4f6')
if (preferCssVars) {
return {
...getThemeVarsForStyle(runtimeU),
minHeight: '100vh',
backgroundColor: `var(--up-page-bg-color, var(--up-bg-color, ${fallbackBg}))`
}
}
return {
backgroundColor: getThemeVar(
'--up-page-bg-color',
getThemeVar('--up-bg-color', fallbackBg, runtimeU),
runtimeU
)
}
}
export function getThemeCardStyle(upU, preferCssVars = false) {
const runtimeU = getRuntimeU(upU)
const isDark = getThemeIsDark(runtimeU)
const fallbackCard = isDark ? '#1c1c1e' : '#ffffff'
const fallbackBorder = runtimeU?.color?.borderColor || '#dadbde'
if (preferCssVars) {
return {
backgroundColor: `var(--up-card-bg-color, ${fallbackCard})`,
borderColor: `var(--up-border-color, ${fallbackBorder})`
}
}
return {
backgroundColor: getThemeVar('--up-card-bg-color', fallbackCard, runtimeU),
borderColor: getThemeVar('--up-border-color', fallbackBorder, runtimeU)
}
}
export function getThemeTabBarStyle(upU) {
const runtimeU = getRuntimeU(upU)
const isDark = getThemeIsDark(runtimeU)
return {
color: isDark ? '#8e8e93' : '#909399',
selectedColor: isDark ? '#f2f2f7' : '#303133',
backgroundColor: isDark ? '#111111' : '#ffffff',
borderStyle: isDark ? 'white' : 'black'
}
}
export function applyNativeThemeUI(upU) {
if (typeof uni === 'undefined') return
const runtimeU = getRuntimeU(upU)
if (runtimeU?.config?.nativeThemeSync !== true) return
const isDark = getThemeIsDark(runtimeU)
const fallbackBg = isDark ? '#1f1f1f' : (runtimeU?.color?.bgColor || '#f3f4f6')
const pageBg = getThemeVar(
'--up-page-bg-color',
getThemeVar('--up-bg-color', fallbackBg, runtimeU),
runtimeU
)
const navBg = getThemeVar(
'--up-navbar-bg-color',
isDark ? '#1c1c1e' : '#ffffff',
runtimeU
)
trySetNavigationBarColor({
frontColor: isDark ? '#ffffff' : '#000000',
backgroundColor: navBg,
animation: {
duration: 0,
timingFunc: 'linear'
}
})
if (typeof uni.setBackgroundColor === 'function') {
uni.setBackgroundColor({
backgroundColor: pageBg,
backgroundColorTop: pageBg,
backgroundColorBottom: pageBg
})
}
trySetTabBarStyle(getThemeTabBarStyle(runtimeU))
}
export function applyNativeThemeUIDeferred(upU, delay = 30) {
applyNativeThemeUI(upU)
if (typeof setTimeout === 'function') {
setTimeout(() => {
applyNativeThemeUI(upU)
}, delay)
}
}

View File

@@ -0,0 +1,681 @@
import config from '../config/config.js'
import color from '../config/color.js'
import index from '../function/index.js'
import { trySetTabBarStyle } from './runtime.js'
const DEFAULT_LIGHT_THEME_COLORS = Object.freeze({
primary: '#3c9cff',
info: '#909399',
warning: '#f9ae3d',
error: '#f56c6c',
success: '#5ac725',
mainColor: '#303133',
contentColor: '#606266',
tipsColor: '#909193',
lightColor: '#c0c4cc',
borderColor: '#dadbde',
bgColor: '#f3f4f6',
disabledColor: '#c8c9cc',
primaryDark: '#398ade',
primaryDisabled: '#9acafc',
primaryLight: '#ecf5ff',
warningDark: '#f1a532',
warningDisabled: '#f9d39b',
warningLight: '#fdf6ec',
successDark: '#53c21d',
successDisabled: '#a9e08f',
successLight: '#f5fff0',
errorDark: '#e45656',
errorDisabled: '#f7b2b2',
errorLight: '#fef0f0',
infoDark: '#767a82',
infoDisabled: '#c4c6c9',
infoLight: '#f4f4f5'
})
const DEFAULT_DARK_THEME_COLORS = Object.freeze({
primary: '#3c9cff',
info: '#909399',
warning: '#f9ae3d',
error: '#f56c6c',
success: '#5ac725',
mainColor: '#f5f5f5',
contentColor: '#d1d5db',
tipsColor: '#9ca3af',
lightColor: '#6b7280',
borderColor: '#3a3a3c',
bgColor: '#1f1f1f',
disabledColor: '#4b5563',
primaryDark: '#5aa8ff',
primaryDisabled: '#4c6f92',
primaryLight: '#10243a',
warningDark: '#ffbf66',
warningDisabled: '#8a6a3a',
warningLight: '#3d2f1b',
successDark: '#7ad94b',
successDisabled: '#5f7f4f',
successLight: '#1f3316',
errorDark: '#ff8a8a',
errorDisabled: '#8d5858',
errorLight: '#3a2222',
infoDark: '#b0b3b8',
infoDisabled: '#5f6368',
infoLight: '#2f3238'
})
const DEFAULT_THEME_EXTRA_VARS = Object.freeze({
light: Object.freeze({
'--up-table2-header-bg-color': '#f5f7fa',
'--up-table2-zebra-bg-color': '#fafafa',
'--up-table2-highlight-bg-color': '#f5f7fa',
'--up-gap-bg-color': '#f3f4f6',
'--up-skeleton-bg-color': '#f1f2f4',
'--up-skeleton-shimmer-color': '#e6e6e6',
'--up-swipe-action-button-bg-color': '#c7c6cd',
'--up-index-list-indicator-bg-color': '#c9c9c9',
'--up-calendar-month-mark-color': 'rgba(231, 232, 234, 0.83)'
}),
dark: Object.freeze({
'--up-table2-header-bg-color': '#2a2d33',
'--up-table2-zebra-bg-color': '#23262b',
'--up-table2-highlight-bg-color': '#2f3440',
'--up-gap-bg-color': '#111111',
'--up-skeleton-bg-color': '#2f3135',
'--up-skeleton-shimmer-color': 'rgba(255, 255, 255, 0.12)',
'--up-swipe-action-button-bg-color': '#4b5563',
'--up-index-list-indicator-bg-color': '#4b5563',
'--up-calendar-month-mark-color': 'rgba(255, 255, 255, 0.04)'
})
})
export const themeState = {
preference: 'system',
mode: 'light',
version: 0,
vars: {}
}
const THEME_MODE_STORAGE_KEY = 'u-theme-mode'
const THEME_MODE_SYSTEM = 'system'
const THEME_MODE_MANUAL = ['light', 'dark']
const LIGHT_THEME_TOKEN_FIELD_MAP = Object.freeze({
'primary': 'primary',
'primary-dark': 'primaryDark',
'primary-disabled': 'primaryDisabled',
'primary-light': 'primaryLight',
'warning': 'warning',
'warning-dark': 'warningDark',
'warning-disabled': 'warningDisabled',
'warning-light': 'warningLight',
'success': 'success',
'success-dark': 'successDark',
'success-disabled': 'successDisabled',
'success-light': 'successLight',
'error': 'error',
'error-dark': 'errorDark',
'error-disabled': 'errorDisabled',
'error-light': 'errorLight',
'info': 'info',
'info-dark': 'infoDark',
'info-disabled': 'infoDisabled',
'info-light': 'infoLight',
'main-color': 'mainColor',
'content-color': 'contentColor',
'tips-color': 'tipsColor',
'light-color': 'lightColor',
'border-color': 'borderColor',
'bg-color': 'bgColor',
'disabled-color': 'disabledColor'
})
const LIGHT_THEME_FIELD_TOKEN_MAP = Object.freeze(
Object.fromEntries(
Object.entries(LIGHT_THEME_TOKEN_FIELD_MAP).map(([token, field]) => [field, token])
)
)
const runtimeThemeOverrideState = {
color: Object.create(null),
configColor: Object.create(null)
}
let cachedLightThemeColors = null
let hasRegisterThemeListener = false
let currentThemePreference = THEME_MODE_SYSTEM
function normalizeThemeMode(theme = 'light') {
return theme === 'dark' ? 'dark' : 'light'
}
function normalizeThemePreference(mode = THEME_MODE_SYSTEM) {
if (THEME_MODE_MANUAL.includes(mode)) return mode
return THEME_MODE_SYSTEM
}
function getLightBridgeVar(token, fallback) {
return `var(--up-light-${token}, ${fallback})`
}
function clearOverrideBucket(bucket) {
Object.keys(bucket).forEach((key) => {
delete bucket[key]
})
}
function normalizeLightThemeToken(token = '') {
if (typeof token !== 'string') return ''
if (token.indexOf('up-') === 0) return token.slice(3)
if (token.indexOf('u-') === 0) return token.slice(2)
return token
}
function isLightThemeConfigColorKey(token = '') {
return token.indexOf('up-') === 0 || token.indexOf('u-') === 0
}
export function syncThemeColorOverrideState({
color: colorOverrides,
configColor: configColorOverrides,
reset = false
} = {}) {
if (reset) {
clearOverrideBucket(runtimeThemeOverrideState.color)
clearOverrideBucket(runtimeThemeOverrideState.configColor)
}
if (colorOverrides && typeof colorOverrides === 'object') {
Object.keys(LIGHT_THEME_FIELD_TOKEN_MAP).forEach((field) => {
if (!Object.prototype.hasOwnProperty.call(colorOverrides, field)) return
const value = colorOverrides[field]
if (typeof value === 'string' && value) {
runtimeThemeOverrideState.color[field] = true
return
}
delete runtimeThemeOverrideState.color[field]
})
}
if (configColorOverrides && typeof configColorOverrides === 'object') {
Object.keys(configColorOverrides).forEach((key) => {
const token = normalizeLightThemeToken(key)
if (!Object.prototype.hasOwnProperty.call(LIGHT_THEME_TOKEN_FIELD_MAP, token)) return
const value = configColorOverrides[key]
if (typeof value === 'string' && value) {
const overrideKey = isLightThemeConfigColorKey(key) ? key : `up-${token}`
runtimeThemeOverrideState.configColor[overrideKey] = true
return
}
delete runtimeThemeOverrideState.configColor[key]
delete runtimeThemeOverrideState.configColor[`u-${token}`]
delete runtimeThemeOverrideState.configColor[`up-${token}`]
})
}
}
function getExplicitRuntimeColorValue(token, runtimeColorMap = {}) {
const field = LIGHT_THEME_TOKEN_FIELD_MAP[token]
if (!field) return ''
if (runtimeThemeOverrideState.color[field]) {
const value = color[field]
if (typeof value === 'string' && value) return value
}
const upKey = `up-${token}`
const uKey = `u-${token}`
if (!runtimeThemeOverrideState.configColor[upKey] && !runtimeThemeOverrideState.configColor[uKey]) return ''
const upValue = runtimeColorMap[upKey]
const uValue = runtimeColorMap[uKey]
if (runtimeThemeOverrideState.configColor[upKey] && typeof upValue === 'string' && upValue) return upValue
if (runtimeThemeOverrideState.configColor[uKey] && typeof uValue === 'string' && uValue) return uValue
return ''
}
function readThemePreferenceFromStorage() {
try {
if (typeof uni !== 'undefined' && typeof uni.getStorageSync === 'function') {
const mode = uni.getStorageSync(THEME_MODE_STORAGE_KEY)
return normalizeThemePreference(mode)
}
} catch (e) {}
return THEME_MODE_SYSTEM
}
function writeThemePreferenceToStorage(mode) {
try {
if (typeof uni !== 'undefined' && typeof uni.setStorageSync === 'function') {
uni.setStorageSync(THEME_MODE_STORAGE_KEY, mode)
}
} catch (e) {}
}
export function getSystemTheme() {
let theme = 'light'
try {
if (typeof uni !== 'undefined' && typeof uni.getAppBaseInfo === 'function') {
const appBaseInfo = uni.getAppBaseInfo() || {}
if (appBaseInfo.theme) {
theme = appBaseInfo.theme
}
}
if (typeof uni !== 'undefined' && typeof uni.getSystemInfoSync === 'function') {
const systemInfo = uni.getSystemInfoSync() || {}
if (systemInfo.theme) {
theme = systemInfo.theme
}
}
} catch (e) {
theme = 'light'
}
return normalizeThemeMode(theme)
}
function getCurrentLightThemeColors() {
const runtimeColorMap = config.color || {}
const lightThemeColors = {
...DEFAULT_LIGHT_THEME_COLORS
}
Object.keys(LIGHT_THEME_TOKEN_FIELD_MAP).forEach((token) => {
const explicitValue = getExplicitRuntimeColorValue(token, runtimeColorMap)
if (!explicitValue) return
lightThemeColors[LIGHT_THEME_TOKEN_FIELD_MAP[token]] = explicitValue
})
return lightThemeColors
}
function getThemeColorsByMode(mode) {
if (!cachedLightThemeColors) {
cachedLightThemeColors = getCurrentLightThemeColors()
}
const themeMode = normalizeThemeMode(mode)
if (themeMode === 'dark') {
return {
...DEFAULT_DARK_THEME_COLORS,
primary: cachedLightThemeColors.primary,
info: cachedLightThemeColors.info,
warning: cachedLightThemeColors.warning,
error: cachedLightThemeColors.error,
success: cachedLightThemeColors.success
}
}
return {
...cachedLightThemeColors
}
}
function buildConfigColorMap(themeColors) {
return {
'u-primary': themeColors.primary,
'u-primary-dark': themeColors.primaryDark,
'u-primary-disabled': themeColors.primaryDisabled,
'u-primary-light': themeColors.primaryLight,
'u-warning': themeColors.warning,
'u-warning-dark': themeColors.warningDark,
'u-warning-disabled': themeColors.warningDisabled,
'u-warning-light': themeColors.warningLight,
'u-success': themeColors.success,
'u-success-dark': themeColors.successDark,
'u-success-disabled': themeColors.successDisabled,
'u-success-light': themeColors.successLight,
'u-error': themeColors.error,
'u-error-dark': themeColors.errorDark,
'u-error-disabled': themeColors.errorDisabled,
'u-error-light': themeColors.errorLight,
'u-info': themeColors.info,
'u-info-dark': themeColors.infoDark,
'u-info-disabled': themeColors.infoDisabled,
'u-info-light': themeColors.infoLight,
'u-main-color': themeColors.mainColor,
'u-content-color': themeColors.contentColor,
'u-tips-color': themeColors.tipsColor,
'u-light-color': themeColors.lightColor,
'u-border-color': themeColors.borderColor,
'u-bg-color': themeColors.bgColor,
'u-disabled-color': themeColors.disabledColor,
'up-primary': themeColors.primary,
'up-primary-dark': themeColors.primaryDark,
'up-primary-disabled': themeColors.primaryDisabled,
'up-primary-light': themeColors.primaryLight,
'up-warning': themeColors.warning,
'up-warning-dark': themeColors.warningDark,
'up-warning-disabled': themeColors.warningDisabled,
'up-warning-light': themeColors.warningLight,
'up-success': themeColors.success,
'up-success-dark': themeColors.successDark,
'up-success-disabled': themeColors.successDisabled,
'up-success-light': themeColors.successLight,
'up-error': themeColors.error,
'up-error-dark': themeColors.errorDark,
'up-error-disabled': themeColors.errorDisabled,
'up-error-light': themeColors.errorLight,
'up-info': themeColors.info,
'up-info-dark': themeColors.infoDark,
'up-info-disabled': themeColors.infoDisabled,
'up-info-light': themeColors.infoLight,
'up-main-color': themeColors.mainColor,
'up-content-color': themeColors.contentColor,
'up-tips-color': themeColors.tipsColor,
'up-light-color': themeColors.lightColor,
'up-border-color': themeColors.borderColor,
'up-bg-color': themeColors.bgColor,
'up-disabled-color': themeColors.disabledColor
}
}
function buildAliasCssVars(vars = {}) {
const aliasVars = {}
Object.keys(vars).forEach((key) => {
if (typeof key !== 'string') return
if (key.indexOf('--up-') === 0) {
aliasVars[key.replace('--up-', '--u-')] = vars[key]
return
}
if (key.indexOf('--u-') === 0) {
aliasVars[key.replace('--u-', '--up-')] = vars[key]
}
})
return aliasVars
}
function buildThemeCssVars(themeColors, mode = 'light') {
const themeMode = normalizeThemeMode(mode)
const isDark = themeMode === 'dark'
const useBridge = !isDark
const runtimeColorMap = config.color || {}
const defaultExtraVars = DEFAULT_THEME_EXTRA_VARS[themeMode] || DEFAULT_THEME_EXTRA_VARS.light
const pageBgColor = themeColors.bgColor || (isDark ? '#1f1f1f' : '#f3f4f6')
const hoverBgColor = runtimeColorMap['up-hover-bg-color']
|| runtimeColorMap['u-hover-bg-color']
|| (isDark ? '#343741' : '#e7ebf0')
const navbarBgColor = runtimeColorMap['up-navbar-bg-color']
|| runtimeColorMap['u-navbar-bg-color']
|| (isDark ? '#1c1c1e' : '#ffffff')
const resolveLightTokenValue = (token, fallback) => {
if (!useBridge) return fallback
const explicitValue = getExplicitRuntimeColorValue(token, runtimeColorMap)
return explicitValue || getLightBridgeVar(token, fallback)
}
const resolvedMainColor = resolveLightTokenValue('main-color', themeColors.mainColor)
const resolvedContentColor = resolveLightTokenValue('content-color', themeColors.contentColor)
const resolvedTipsColor = resolveLightTokenValue('tips-color', themeColors.tipsColor)
const resolvedLightColor = resolveLightTokenValue('light-color', themeColors.lightColor)
const resolvedBorderColor = resolveLightTokenValue('border-color', themeColors.borderColor)
const resolvedBgColor = resolveLightTokenValue('bg-color', themeColors.bgColor)
const resolvedDisabledColor = resolveLightTokenValue('disabled-color', themeColors.disabledColor)
const resolvedPrimary = resolveLightTokenValue('primary', themeColors.primary)
const resolvedPrimaryDark = resolveLightTokenValue('primary-dark', themeColors.primaryDark)
const resolvedPrimaryDisabled = resolveLightTokenValue('primary-disabled', themeColors.primaryDisabled)
const resolvedPrimaryLight = resolveLightTokenValue('primary-light', themeColors.primaryLight)
const resolvedWarning = resolveLightTokenValue('warning', themeColors.warning)
const resolvedWarningDark = resolveLightTokenValue('warning-dark', themeColors.warningDark)
const resolvedWarningDisabled = resolveLightTokenValue('warning-disabled', themeColors.warningDisabled)
const resolvedWarningLight = resolveLightTokenValue('warning-light', themeColors.warningLight)
const resolvedSuccess = resolveLightTokenValue('success', themeColors.success)
const resolvedSuccessDark = resolveLightTokenValue('success-dark', themeColors.successDark)
const resolvedSuccessDisabled = resolveLightTokenValue('success-disabled', themeColors.successDisabled)
const resolvedSuccessLight = resolveLightTokenValue('success-light', themeColors.successLight)
const resolvedError = resolveLightTokenValue('error', themeColors.error)
const resolvedErrorDark = resolveLightTokenValue('error-dark', themeColors.errorDark)
const resolvedErrorDisabled = resolveLightTokenValue('error-disabled', themeColors.errorDisabled)
const resolvedErrorLight = resolveLightTokenValue('error-light', themeColors.errorLight)
const resolvedInfo = resolveLightTokenValue('info', themeColors.info)
const resolvedInfoDark = resolveLightTokenValue('info-dark', themeColors.infoDark)
const resolvedInfoDisabled = resolveLightTokenValue('info-disabled', themeColors.infoDisabled)
const resolvedInfoLight = resolveLightTokenValue('info-light', themeColors.infoLight)
const coreVars = {
'--u-main-color': resolvedMainColor,
'--u-content-color': resolvedContentColor,
'--u-tips-color': resolvedTipsColor,
'--u-light-color': resolvedLightColor,
'--u-border-color': resolvedBorderColor,
'--u-bg-color': resolvedBgColor,
'--u-hover-bg-color': hoverBgColor,
'--u-disabled-color': resolvedDisabledColor,
'--u-primary': resolvedPrimary,
'--u-primary-dark': resolvedPrimaryDark,
'--u-primary-disabled': resolvedPrimaryDisabled,
'--u-primary-light': resolvedPrimaryLight,
'--u-warning': resolvedWarning,
'--u-warning-dark': resolvedWarningDark,
'--u-warning-disabled': resolvedWarningDisabled,
'--u-warning-light': resolvedWarningLight,
'--u-success': resolvedSuccess,
'--u-success-dark': resolvedSuccessDark,
'--u-success-disabled': resolvedSuccessDisabled,
'--u-success-light': resolvedSuccessLight,
'--u-error': resolvedError,
'--u-error-dark': resolvedErrorDark,
'--u-error-disabled': resolvedErrorDisabled,
'--u-error-light': resolvedErrorLight,
'--u-info': resolvedInfo,
'--u-info-dark': resolvedInfoDark,
'--u-info-disabled': resolvedInfoDisabled,
'--u-info-light': resolvedInfoLight,
'--up-main-color': resolvedMainColor,
'--up-content-color': resolvedContentColor,
'--up-tips-color': resolvedTipsColor,
'--up-light-color': resolvedLightColor,
'--up-border-color': resolvedBorderColor,
'--up-bg-color': resolvedBgColor,
'--up-hover-bg-color': hoverBgColor,
'--up-disabled-color': resolvedDisabledColor,
'--up-primary': resolvedPrimary,
'--up-primary-dark': resolvedPrimaryDark,
'--up-primary-disabled': resolvedPrimaryDisabled,
'--up-primary-light': resolvedPrimaryLight,
'--up-warning': resolvedWarning,
'--up-warning-dark': resolvedWarningDark,
'--up-warning-disabled': resolvedWarningDisabled,
'--up-warning-light': resolvedWarningLight,
'--up-success': resolvedSuccess,
'--up-success-dark': resolvedSuccessDark,
'--up-success-disabled': resolvedSuccessDisabled,
'--up-success-light': resolvedSuccessLight,
'--up-error': resolvedError,
'--up-error-dark': resolvedErrorDark,
'--up-error-disabled': resolvedErrorDisabled,
'--up-error-light': resolvedErrorLight,
'--up-info': resolvedInfo,
'--up-info-dark': resolvedInfoDark,
'--up-info-disabled': resolvedInfoDisabled,
'--up-info-light': resolvedInfoLight,
'--up-page-bg-color': pageBgColor,
'--up-card-bg-color': isDark ? '#1c1c1e' : '#ffffff',
'--up-navbar-bg-color': navbarBgColor
}
const extraVars = {}
Object.keys(runtimeColorMap).forEach((key) => {
if (typeof key !== 'string') return
const isThemeToken = key.indexOf('up-') === 0 || key.indexOf('u-') === 0
if (!isThemeToken) return
const cssVarName = `--${key}`
if (Object.prototype.hasOwnProperty.call(coreVars, cssVarName)) return
const value = runtimeColorMap[key]
if (typeof value === 'string' && value) {
extraVars[cssVarName] = value
}
})
return {
...coreVars,
...defaultExtraVars,
...buildAliasCssVars(defaultExtraVars),
...extraVars,
...buildAliasCssVars(extraVars)
}
}
export function getThemeVars(mode) {
if (mode) {
return buildThemeCssVars(getThemeColorsByMode(mode), mode)
}
if (themeState.vars && Object.keys(themeState.vars).length > 0) {
return { ...themeState.vars }
}
return buildThemeCssVars(getThemeColorsByMode(themeState.mode), themeState.mode)
}
function syncThemeToH5(mode) {
// #ifdef H5
if (typeof document !== 'undefined' && document.documentElement) {
document.documentElement.setAttribute('data-up-theme', mode)
}
// #endif
}
function hasActiveRuntimePage() {
try {
if (typeof getCurrentPages === 'function') {
const pages = getCurrentPages()
return Array.isArray(pages) && pages.length > 0
}
} catch (e) {}
return false
}
function trySetNavigationBarColor(options) {
if (typeof uni === 'undefined' || typeof uni.setNavigationBarColor !== 'function') return
if (!hasActiveRuntimePage()) return
try {
const result = uni.setNavigationBarColor(options)
if (result && typeof result.catch === 'function') {
result.catch(() => {})
}
} catch (e) {}
}
function applyNativeThemeUI(mode, themeColors, themeVars = {}) {
if (typeof uni === 'undefined') return
if (config.nativeThemeSync !== true) return
const isDark = normalizeThemeMode(mode) === 'dark'
const pageBg = themeColors?.bgColor || (isDark ? '#1f1f1f' : '#f3f4f6')
const navBg = themeVars?.['--up-navbar-bg-color']
|| themeVars?.['--u-navbar-bg-color']
|| config.color?.['up-navbar-bg-color']
|| config.color?.['u-navbar-bg-color']
|| (isDark ? '#1c1c1e' : '#ffffff')
trySetNavigationBarColor({
frontColor: isDark ? '#ffffff' : '#000000',
backgroundColor: navBg,
animation: {
duration: 0,
timingFunc: 'linear'
}
})
if (typeof uni.setBackgroundColor === 'function') {
uni.setBackgroundColor({
backgroundColor: pageBg,
backgroundColorTop: pageBg,
backgroundColorBottom: pageBg
})
}
trySetTabBarStyle({
color: isDark ? '#8e8e93' : '#909399',
selectedColor: isDark ? '#f2f2f7' : '#303133',
backgroundColor: isDark ? '#111111' : '#ffffff',
borderStyle: isDark ? 'white' : 'black'
})
}
function applyTheme(mode = 'light') {
const themeMode = normalizeThemeMode(mode)
const themeColors = getThemeColorsByMode(themeMode)
const themeVars = buildThemeCssVars(themeColors, themeMode)
index.shallowMerge(color, {
primary: themeColors.primary,
primaryDark: themeColors.primaryDark,
primaryDisabled: themeColors.primaryDisabled,
primaryLight: themeColors.primaryLight,
info: themeColors.info,
infoDark: themeColors.infoDark,
infoDisabled: themeColors.infoDisabled,
infoLight: themeColors.infoLight,
default: themeColors.info,
warning: themeColors.warning,
warningDark: themeColors.warningDark,
warningDisabled: themeColors.warningDisabled,
warningLight: themeColors.warningLight,
error: themeColors.error,
errorDark: themeColors.errorDark,
errorDisabled: themeColors.errorDisabled,
errorLight: themeColors.errorLight,
success: themeColors.success,
successDark: themeColors.successDark,
successDisabled: themeColors.successDisabled,
successLight: themeColors.successLight,
mainColor: themeColors.mainColor,
contentColor: themeColors.contentColor,
tipsColor: themeColors.tipsColor,
lightColor: themeColors.lightColor,
borderColor: themeColors.borderColor,
bgColor: themeColors.bgColor,
disabledColor: themeColors.disabledColor
})
index.shallowMerge(config.color, buildConfigColorMap(themeColors))
config.themeMode = themeMode
themeState.preference = currentThemePreference
themeState.mode = themeMode
themeState.vars = { ...themeVars }
themeState.version = Number(themeState.version || 0) + 1
syncThemeToH5(themeMode)
applyNativeThemeUI(themeMode, themeColors, themeVars)
if (typeof uni !== 'undefined' && uni.$u && uni.$u.theme) {
uni.$u.theme.mode = themeState.mode
if (Object.prototype.hasOwnProperty.call(uni.$u.theme, 'colors')) {
delete uni.$u.theme.colors
}
uni.$u.theme.vars = { ...themeState.vars }
uni.$u.theme.version = themeState.version
}
if (typeof uni !== 'undefined' && typeof uni.$emit === 'function') {
uni.$emit('uThemeChange', {
mode: themeState.mode,
colors: { ...themeColors },
version: themeState.version,
vars: { ...themeState.vars }
})
}
return themeState
}
export function setTheme(mode = 'light') {
currentThemePreference = normalizeThemeMode(mode)
writeThemePreferenceToStorage(currentThemePreference)
return applyTheme(currentThemePreference)
}
export function setThemePreference(mode = THEME_MODE_SYSTEM) {
currentThemePreference = normalizeThemePreference(mode)
writeThemePreferenceToStorage(currentThemePreference)
if (currentThemePreference === THEME_MODE_SYSTEM) {
return applyTheme(getSystemTheme())
}
return applyTheme(currentThemePreference)
}
export function getThemePreference() {
return currentThemePreference
}
export function refreshThemeFromConfig() {
cachedLightThemeColors = getCurrentLightThemeColors()
if (themeState.version > 0) {
applyTheme(themeState.mode)
}
}
export function initThemeSystem() {
if (typeof uni === 'undefined') return
if (!cachedLightThemeColors) {
cachedLightThemeColors = getCurrentLightThemeColors()
}
currentThemePreference = readThemePreferenceFromStorage()
if (currentThemePreference === THEME_MODE_SYSTEM) {
applyTheme(getSystemTheme())
} else {
applyTheme(currentThemePreference)
}
if (!hasRegisterThemeListener && typeof uni.onThemeChange === 'function') {
uni.onThemeChange((res = {}) => {
if (currentThemePreference === THEME_MODE_SYSTEM) {
applyTheme(res.theme)
}
})
hasRegisterThemeListener = true
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,546 @@
/**
* @1900-2100区间内的公历、农历互转
* @charset UTF-8
* @github https://github.com/jjonline/calendar.js
* @Author Jea杨(JJonline@JJonline.Cn)
* @Time 2014-7-21
* @Time 2016-8-13 Fixed 2033hex、Attribution Annals
* @Time 2016-9-25 Fixed lunar LeapMonth Param Bug
* @Time 2017-7-24 Fixed use getTerm Func Param Error.use solar year,NOT lunar year
* @Version 1.0.3
* @公历转农历:calendar.solar2lunar(1987,11,01); //[you can ignore params of prefix 0]
* @农历转公历:calendar.lunar2solar(1987,09,10); //[you can ignore params of prefix 0]
*/
/* eslint-disable */
var Calendar = {
/**
* 农历1900-2100的润大小信息表
* @Array Of Property
* @return Hex
*/
lunarInfo: [0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, // 1900-1909
0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, // 1910-1919
0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, // 1920-1929
0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, // 1930-1939
0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, // 1940-1949
0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0, 0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0, // 1950-1959
0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, // 1960-1969
0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0, 0x195a6, // 1970-1979
0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, // 1980-1989
0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x05ac0, 0x0ab60, 0x096d5, 0x092e0, // 1990-1999
0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, // 2000-2009
0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, // 2010-2019
0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, // 2020-2029
0x05aa0, 0x076a3, 0x096d0, 0x04afb, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, // 2030-2039
0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, // 2040-2049
/** Add By JJonline@JJonline.Cn**/
0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0, // 2050-2059
0x0a2e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4, // 2060-2069
0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0, // 2070-2079
0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160, // 2080-2089
0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252, // 2090-2099
0x0d520], // 2100
/**
* 公历每个月份的天数普通表
* @Array Of Property
* @return Number
*/
solarMonth: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
/**
* 天干地支之天干速查表
* @Array Of Property trans["甲","乙","丙","丁","戊","己","庚","辛","壬","癸"]
* @return Cn string
*/
Gan: ['\u7532', '\u4e59', '\u4e19', '\u4e01', '\u620a', '\u5df1', '\u5e9a', '\u8f9b', '\u58ec', '\u7678'],
/**
* 天干地支之地支速查表
* @Array Of Property
* @trans["子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"]
* @return Cn string
*/
Zhi: ['\u5b50', '\u4e11', '\u5bc5', '\u536f', '\u8fb0', '\u5df3', '\u5348', '\u672a', '\u7533', '\u9149', '\u620c', '\u4ea5'],
/**
* 天干地支之地支速查表<=>生肖
* @Array Of Property
* @trans["鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"]
* @return Cn string
*/
Animals: ['\u9f20', '\u725b', '\u864e', '\u5154', '\u9f99', '\u86c7', '\u9a6c', '\u7f8a', '\u7334', '\u9e21', '\u72d7', '\u732a'],
/**
* 24节气速查表
* @Array Of Property
* @trans["小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"]
* @return Cn string
*/
solarTerm: ['\u5c0f\u5bd2', '\u5927\u5bd2', '\u7acb\u6625', '\u96e8\u6c34', '\u60ca\u86f0', '\u6625\u5206', '\u6e05\u660e', '\u8c37\u96e8', '\u7acb\u590f', '\u5c0f\u6ee1', '\u8292\u79cd', '\u590f\u81f3', '\u5c0f\u6691', '\u5927\u6691', '\u7acb\u79cb', '\u5904\u6691', '\u767d\u9732', '\u79cb\u5206', '\u5bd2\u9732', '\u971c\u964d', '\u7acb\u51ac', '\u5c0f\u96ea', '\u5927\u96ea', '\u51ac\u81f3'],
/**
* 1900-2100各年的24节气日期速查表
* @Array Of Property
* @return 0x string For splice
*/
sTermInfo: ['9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f',
'97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
'97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa',
'97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f',
'b027097bd097c36b0b6fc9274c91aa', '9778397bd19801ec9210c965cc920e', '97b6b97bd19801ec95f8c965cc920f',
'97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd197c36c9210c9274c91aa',
'97b6b97bd19801ec95f8c965cc920e', '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2',
'9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec95f8c965cc920e', '97bcf97c3598082c95f8e1cfcc920f',
'97bd097bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e',
'97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
'97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722',
'9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f',
'97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
'97bcf97c359801ec95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
'97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd097bd07f595b0b6fc920fb0722',
'9778397bd097c36b0b6fc9210c8dc2', '9778397bd19801ec9210c9274c920e', '97b6b97bd19801ec95f8c965cc920f',
'97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
'97b6b97bd19801ec95f8c965cc920f', '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
'9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bd07f1487f595b0b0bc920fb0722',
'7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
'97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
'97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
'9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f531b0b0bb0b6fb0722',
'7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
'97bcf7f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
'97b6b97bd19801ec9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
'9778397bd097c36b0b6fc9210c91aa', '97b6b97bd197c36c9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722',
'7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
'97b6b7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
'9778397bd097c36b0b70c9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
'7f0e397bd097c35b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
'7f0e27f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
'97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
'9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
'7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
'97b6b7f0e47f531b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
'9778397bd097c36b0b6fc9210c91aa', '97b6b7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
'7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '977837f0e37f149b0723b0787b0721',
'7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c35b0b6fc9210c8dc2',
'977837f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
'7f0e397bd097c35b0b6fc9210c8dc2', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '977837f0e37f14998082b0787b06bd',
'7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
'977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
'7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd',
'7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
'977837f0e37f14998082b0723b06bd', '7f07e7f0e37f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
'7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b0721',
'7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f595b0b0bb0b6fb0722', '7f0e37f0e37f14898082b0723b02d5',
'7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f531b0b0bb0b6fb0722',
'7f0e37f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
'7f0e37f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
'7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35',
'7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
'7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f149b0723b0787b0721',
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0723b06bd',
'7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', '7f0e37f0e366aa89801eb072297c35',
'7ec967f0e37f14998082b0723b06bd', '7f07e7f0e37f14998083b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
'7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14898082b0723b02d5', '7f07e7f0e37f14998082b0787b0721',
'7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66aa89801e9808297c35', '665f67f0e37f14898082b0723b02d5',
'7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66a449801e9808297c35',
'665f67f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
'7f0e36665b66a449801e9808297c35', '665f67f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
'7f07e7f0e47f531b0723b0b6fb0721', '7f0e26665b66a449801e9808297c35', '665f67f0e37f1489801eb072297c35',
'7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722'],
/**
* 数字转中文速查表
* @Array Of Property
* @trans ['日','一','二','三','四','五','六','七','八','九','十']
* @return Cn string
*/
nStr1: ['\u65e5', '\u4e00', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341'],
/**
* 日期转农历称呼速查表
* @Array Of Property
* @trans ['初','十','廿','卅']
* @return Cn string
*/
nStr2: ['\u521d', '\u5341', '\u5eff', '\u5345'],
/**
* 月份转农历称呼速查表
* @Array Of Property
* @trans ['正','一','二','三','四','五','六','七','八','九','十','冬','腊']
* @return Cn string
*/
nStr3: ['\u6b63', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341', '\u51ac', '\u814a'],
/**
* 返回农历y年一整年的总天数
* @param lunar Year
* @return Number
* @eg:var count = calendar.lYearDays(1987) ;//count=387
*/
lYearDays: function (y) {
var i; var sum = 348
for (i = 0x8000; i > 0x8; i >>= 1) { sum += (this.lunarInfo[y - 1900] & i) ? 1 : 0 }
return (sum + this.leapDays(y))
},
/**
* 返回农历y年闰月是哪个月;若y年没有闰月 则返回0
* @param lunar Year
* @return Number (0-12)
* @eg:var leapMonth = calendar.leapMonth(1987) ;//leapMonth=6
*/
leapMonth: function (y) { // 闰字编码 \u95f0
return (this.lunarInfo[y - 1900] & 0xf)
},
/**
* 返回农历y年闰月的天数 若该年没有闰月则返回0
* @param lunar Year
* @return Number (0、29、30)
* @eg:var leapMonthDay = calendar.leapDays(1987) ;//leapMonthDay=29
*/
leapDays: function (y) {
if (this.leapMonth(y)) {
return ((this.lunarInfo[y - 1900] & 0x10000) ? 30 : 29)
}
return (0)
},
/**
* 返回农历y年m月(非闰月)的总天数,计算m为闰月时的天数请使用leapDays方法
* @param lunar Year
* @return Number (-1、29、30)
* @eg:var MonthDay = calendar.monthDays(1987,9) ;//MonthDay=29
*/
monthDays: function (y, m) {
if (m > 12 || m < 1) { return -1 }// 月份参数从1至12,参数错误返回-1
return ((this.lunarInfo[y - 1900] & (0x10000 >> m)) ? 30 : 29)
},
/**
* 返回公历(!)y年m月的天数
* @param solar Year
* @return Number (-1、28、29、30、31)
* @eg:var solarMonthDay = calendar.leapDays(1987) ;//solarMonthDay=30
*/
solarDays: function (y, m) {
if (m > 12 || m < 1) { return -1 } // 若参数错误 返回-1
var ms = m - 1
if (ms == 1) { // 2月份的闰平规律测算后确认返回28或29
return (((y % 4 == 0) && (y % 100 != 0) || (y % 400 == 0)) ? 29 : 28)
} else {
return (this.solarMonth[ms])
}
},
/**
* 农历年份转换为干支纪年
* @param lYear 农历年的年份数
* @return Cn string
*/
toGanZhiYear: function (lYear) {
var ganKey = (lYear - 3) % 10
var zhiKey = (lYear - 3) % 12
if (ganKey == 0) ganKey = 10// 如果余数为0则为最后一个天干
if (zhiKey == 0) zhiKey = 12// 如果余数为0则为最后一个地支
return this.Gan[ganKey - 1] + this.Zhi[zhiKey - 1]
},
/**
* 公历月、日判断所属星座
* @param cMonth [description]
* @param cDay [description]
* @return Cn string
*/
toAstro: function (cMonth, cDay) {
var s = '\u9b54\u7faf\u6c34\u74f6\u53cc\u9c7c\u767d\u7f8a\u91d1\u725b\u53cc\u5b50\u5de8\u87f9\u72ee\u5b50\u5904\u5973\u5929\u79e4\u5929\u874e\u5c04\u624b\u9b54\u7faf'
var arr = [20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22]
return s.substr(cMonth * 2 - (cDay < arr[cMonth - 1] ? 2 : 0), 2) + '\u5ea7'// 座
},
/**
* 传入offset偏移量返回干支
* @param offset 相对甲子的偏移量
* @return Cn string
*/
toGanZhi: function (offset) {
return this.Gan[offset % 10] + this.Zhi[offset % 12]
},
/**
* 传入公历(!)y年获得该年第n个节气的公历日期
* @param y公历年(1900-2100);n二十四节气中的第几个节气(1~24);从n=1(小寒)算起
* @return day Number
* @eg:var _24 = calendar.getTerm(1987,3) ;//_24=4;意即1987年2月4日立春
*/
getTerm: function (y, n) {
if (y < 1900 || y > 2100) { return -1 }
if (n < 1 || n > 24) { return -1 }
var _table = this.sTermInfo[y - 1900]
var _info = [
parseInt('0x' + _table.substr(0, 5)).toString(),
parseInt('0x' + _table.substr(5, 5)).toString(),
parseInt('0x' + _table.substr(10, 5)).toString(),
parseInt('0x' + _table.substr(15, 5)).toString(),
parseInt('0x' + _table.substr(20, 5)).toString(),
parseInt('0x' + _table.substr(25, 5)).toString()
]
var _calday = [
_info[0].substr(0, 1),
_info[0].substr(1, 2),
_info[0].substr(3, 1),
_info[0].substr(4, 2),
_info[1].substr(0, 1),
_info[1].substr(1, 2),
_info[1].substr(3, 1),
_info[1].substr(4, 2),
_info[2].substr(0, 1),
_info[2].substr(1, 2),
_info[2].substr(3, 1),
_info[2].substr(4, 2),
_info[3].substr(0, 1),
_info[3].substr(1, 2),
_info[3].substr(3, 1),
_info[3].substr(4, 2),
_info[4].substr(0, 1),
_info[4].substr(1, 2),
_info[4].substr(3, 1),
_info[4].substr(4, 2),
_info[5].substr(0, 1),
_info[5].substr(1, 2),
_info[5].substr(3, 1),
_info[5].substr(4, 2)
]
return parseInt(_calday[n - 1])
},
/**
* 传入农历数字月份返回汉语通俗表示法
* @param lunar month
* @return Cn string
* @eg:var cnMonth = calendar.toChinaMonth(12) ;//cnMonth='腊月'
*/
toChinaMonth: function (m) { // 月 => \u6708
if (m > 12 || m < 1) { return -1 } // 若参数错误 返回-1
var s = this.nStr3[m - 1]
s += '\u6708'// 加上月字
return s
},
/**
* 传入农历日期数字返回汉字表示法
* @param lunar day
* @return Cn string
* @eg:var cnDay = calendar.toChinaDay(21) ;//cnMonth='廿一'
*/
toChinaDay: function (d) { // 日 => \u65e5
var s
switch (d) {
case 10:
s = '\u521d\u5341'; break
case 20:
s = '\u4e8c\u5341'; break
break
case 30:
s = '\u4e09\u5341'; break
break
default:
s = this.nStr2[Math.floor(d / 10)]
s += this.nStr1[d % 10]
}
return (s)
},
/**
* 年份转生肖[!仅能大致转换] => 精确划分生肖分界线是“立春”
* @param y year
* @return Cn string
* @eg:var animal = calendar.getAnimal(1987) ;//animal='兔'
*/
getAnimal: function (y) {
return this.Animals[(y - 4) % 12]
},
/**
* 传入阳历年月日获得详细的公历、农历object信息 <=>JSON
* @param y solar year
* @param m solar month
* @param d solar day
* @return JSON object
* @eg:console.log(calendar.solar2lunar(1987,11,01));
*/
solar2lunar: function (y, m, d) { // 参数区间1900.1.31~2100.12.31
// 年份限定、上限
if (y < 1900 || y > 2100) {
return -1// undefined转换为数字变为NaN
}
// 公历传参最下限
if (y == 1900 && m == 1 && d < 31) {
return -1
}
// 未传参 获得当天
if (!y) {
var objDate = new Date()
} else {
var objDate = new Date(y, parseInt(m) - 1, d)
}
var i; var leap = 0; var temp = 0
// 修正ymd参数
var y = objDate.getFullYear()
var m = objDate.getMonth() + 1
var d = objDate.getDate()
var offset = (Date.UTC(objDate.getFullYear(), objDate.getMonth(), objDate.getDate()) - Date.UTC(1900, 0, 31)) / 86400000
for (i = 1900; i < 2101 && offset > 0; i++) {
temp = this.lYearDays(i)
offset -= temp
}
if (offset < 0) {
offset += temp; i--
}
// 是否今天
var isTodayObj = new Date()
var isToday = false
if (isTodayObj.getFullYear() == y && isTodayObj.getMonth() + 1 == m && isTodayObj.getDate() == d) {
isToday = true
}
// 星期几
var nWeek = objDate.getDay()
var cWeek = this.nStr1[nWeek]
// 数字表示周几顺应天朝周一开始的惯例
if (nWeek == 0) {
nWeek = 7
}
// 农历年
var year = i
var leap = this.leapMonth(i) // 闰哪个月
var isLeap = false
// 效验闰月
for (i = 1; i < 13 && offset > 0; i++) {
// 闰月
if (leap > 0 && i == (leap + 1) && isLeap == false) {
--i
isLeap = true; temp = this.leapDays(year) // 计算农历闰月天数
} else {
temp = this.monthDays(year, i)// 计算农历普通月天数
}
// 解除闰月
if (isLeap == true && i == (leap + 1)) { isLeap = false }
offset -= temp
}
// 闰月导致数组下标重叠取反
if (offset == 0 && leap > 0 && i == leap + 1) {
if (isLeap) {
isLeap = false
} else {
isLeap = true; --i
}
}
if (offset < 0) {
offset += temp; --i
}
// 农历月
var month = i
// 农历日
var day = offset + 1
// 天干地支处理
var sm = m - 1
var gzY = this.toGanZhiYear(year)
// 当月的两个节气
// bugfix-2017-7-24 11:03:38 use lunar Year Param `y` Not `year`
var firstNode = this.getTerm(y, (m * 2 - 1))// 返回当月「节」为几日开始
var secondNode = this.getTerm(y, (m * 2))// 返回当月「节」为几日开始
// 依据12节气修正干支月
var gzM = this.toGanZhi((y - 1900) * 12 + m + 11)
if (d >= firstNode) {
gzM = this.toGanZhi((y - 1900) * 12 + m + 12)
}
// 传入的日期的节气与否
var isTerm = false
var Term = null
if (firstNode == d) {
isTerm = true
Term = this.solarTerm[m * 2 - 2]
}
if (secondNode == d) {
isTerm = true
Term = this.solarTerm[m * 2 - 1]
}
// 日柱 当月一日与 1900/1/1 相差天数
var dayCyclical = Date.UTC(y, sm, 1, 0, 0, 0, 0) / 86400000 + 25567 + 10
var gzD = this.toGanZhi(dayCyclical + d - 1)
// 该日期所属的星座
var astro = this.toAstro(m, d)
return { 'lYear': year, 'lMonth': month, 'lDay': day, 'Animal': this.getAnimal(year), 'IMonthCn': (isLeap ? '\u95f0' : '') + this.toChinaMonth(month), 'IDayCn': this.toChinaDay(day), 'cYear': y, 'cMonth': m, 'cDay': d, 'gzYear': gzY, 'gzMonth': gzM, 'gzDay': gzD, 'isToday': isToday, 'isLeap': isLeap, 'nWeek': nWeek, 'ncWeek': '\u661f\u671f' + cWeek, 'isTerm': isTerm, 'Term': Term, 'astro': astro }
},
/**
* 传入农历年月日以及传入的月份是否闰月获得详细的公历、农历object信息 <=>JSON
* @param y lunar year
* @param m lunar month
* @param d lunar day
* @param isLeapMonth lunar month is leap or not.[如果是农历闰月第四个参数赋值true即可]
* @return JSON object
* @eg:console.log(calendar.lunar2solar(1987,9,10));
*/
lunar2solar: function (y, m, d, isLeapMonth) { // 参数区间1900.1.31~2100.12.1
var isLeapMonth = !!isLeapMonth
var leapOffset = 0
var leapMonth = this.leapMonth(y)
var leapDay = this.leapDays(y)
if (isLeapMonth && (leapMonth != m)) { return -1 }// 传参要求计算该闰月公历 但该年得出的闰月与传参的月份并不同
if (y == 2100 && m == 12 && d > 1 || y == 1900 && m == 1 && d < 31) { return -1 }// 超出了最大极限值
var day = this.monthDays(y, m)
var _day = day
// bugFix 2016-9-25
// if month is leap, _day use leapDays method
if (isLeapMonth) {
_day = this.leapDays(y, m)
}
if (y < 1900 || y > 2100 || d > _day) { return -1 }// 参数合法性效验
// 计算农历的时间差
var offset = 0
for (var i = 1900; i < y; i++) {
offset += this.lYearDays(i)
}
var leap = 0; var isAdd = false
for (var i = 1; i < m; i++) {
leap = this.leapMonth(y)
if (!isAdd) { // 处理闰月
if (leap <= i && leap > 0) {
offset += this.leapDays(y); isAdd = true
}
}
offset += this.monthDays(y, i)
}
// 转换闰月农历 需补充该年闰月的前一个月的时差
if (isLeapMonth) { offset += day }
// 1900年农历正月一日的公历时间为1900年1月30日0时0分0秒(该时间也是本农历的最开始起始点)
var stmap = Date.UTC(1900, 1, 30, 0, 0, 0)
var calObj = new Date((offset + d - 31) * 86400000 + stmap)
var cY = calObj.getUTCFullYear()
var cM = calObj.getUTCMonth() + 1
var cD = calObj.getUTCDate()
return this.solar2lunar(cY, cM, cD)
}
}
export default Calendar

View File

@@ -0,0 +1,51 @@
/**
* 递归使用 call 方式this指向
* @param componentName // 需要找的组件的名称
* @param eventName // 事件名称
* @param params // 需要传递的参数
*/
function broadcast(componentName, eventName, params) {
// 循环子节点找到名称一样的子节点 否则 递归 当前子节点
this.$children.map((child) => {
if (componentName === child.$options.name) {
child.$emit.apply(child, [eventName].concat(params))
} else {
broadcast.apply(child, [componentName, eventName].concat(params))
}
})
}
export default {
methods: {
/**
* 派发 (向上查找) (一个)
* @param componentName // 需要找的组件的名称
* @param eventName // 事件名称
* @param params // 需要传递的参数
*/
dispatch(componentName, eventName, params) {
let parent = this.$parent || this.$root// $parent 找到最近的父节点 $root 根节点
let { name } = parent.$options // 获取当前组件实例的name
// 如果当前有节点 && 当前没名称 且 当前名称等于需要传进来的名称的时候就去查找当前的节点
// 循环出当前名称的一样的组件实例
while (parent && (!name || name !== componentName)) {
parent = parent.$parent
if (parent) {
name = parent.$options.name
}
}
// 有节点表示当前找到了name一样的实例
if (parent) {
parent.$emit.apply(parent, [eventName].concat(params))
}
},
/**
* 广播 (向下查找) (广播多个)
* @param componentName // 需要找的组件的名称
* @param eventName // 事件名称
* @param params // 需要传递的参数
*/
broadcast(componentName, eventName, params) {
broadcast.call(this, componentName, eventName, params)
}
}
}

View File

@@ -0,0 +1,242 @@
const isWeex = typeof WXEnvironment !== 'undefined';
const isWeexIOS = isWeex && /ios/i.test(WXEnvironment.platform);
const isWeexAndroid = isWeex && !isWeexIOS;
import GLmethod from '../context-webgl/GLmethod';
const GCanvasModule =
(typeof weex !== 'undefined' && weex.requireModule) ? (weex.requireModule('gcanvas')) :
(typeof __weex_require__ !== 'undefined') ? (__weex_require__('@weex-module/gcanvas')) : {};
let isDebugging = false;
let isComboDisabled = false;
const logCommand = (function () {
const methodQuery = [];
Object.keys(GLmethod).forEach(key => {
methodQuery[GLmethod[key]] = key;
})
const queryMethod = (id) => {
return methodQuery[parseInt(id)] || 'NotFoundMethod';
}
const logCommand = (id, cmds) => {
const mId = cmds.split(',')[0];
console.log(`=== callNative - componentId:${id}; method: ${mName}; cmds: ${cmds}`);
}
return logCommand;
})();
function joinArray(arr, sep) {
let res = '';
for (let i = 0; i < arr.length; i++) {
if (i !== 0) {
res += sep;
}
res += arr[i];
}
return res;
}
const commandsCache = {}
const GBridge = {
callEnable: (ref, configArray) => {
commandsCache[ref] = [];
return GCanvasModule.enable({
componentId: ref,
config: configArray
});
},
callEnableDebug: () => {
isDebugging = true;
},
callEnableDisableCombo: () => {
isComboDisabled = true;
},
callSetContextType: function (componentId, context_type) {
GCanvasModule.setContextType(context_type, componentId);
},
callReset: function(id){
GCanvasModule.resetComponent && canvasModule.resetComponent(componentId);
},
render: isWeexIOS ? function (componentId) {
return GCanvasModule.extendCallNative({
contextId: componentId,
type: 0x60000001
});
} : function (componentId) {
return callGCanvasLinkNative(componentId, 0x60000001, 'render');
},
render2d: isWeexIOS ? function (componentId, commands, callback) {
if (isDebugging) {
console.log('>>> >>> render2d ===');
console.log('>>> commands: ' + commands);
}
GCanvasModule.render([commands, callback?true:false], componentId, callback);
} : function (componentId, commands,callback) {
if (isDebugging) {
console.log('>>> >>> render2d ===');
console.log('>>> commands: ' + commands);
}
callGCanvasLinkNative(componentId, 0x20000001, commands);
if(callback){
callback();
}
},
callExtendCallNative: isWeexIOS ? function (componentId, cmdArgs) {
throw 'should not be here anymore ' + cmdArgs;
} : function (componentId, cmdArgs) {
throw 'should not be here anymore ' + cmdArgs;
},
flushNative: isWeexIOS ? function (componentId) {
const cmdArgs = joinArray(commandsCache[componentId], ';');
commandsCache[componentId] = [];
if (isDebugging) {
console.log('>>> >>> flush native ===');
console.log('>>> commands: ' + cmdArgs);
}
const result = GCanvasModule.extendCallNative({
"contextId": componentId,
"type": 0x60000000,
"args": cmdArgs
});
const res = result && result.result;
if (isDebugging) {
console.log('>>> result: ' + res);
}
return res;
} : function (componentId) {
const cmdArgs = joinArray(commandsCache[componentId], ';');
commandsCache[componentId] = [];
if (isDebugging) {
console.log('>>> >>> flush native ===');
console.log('>>> commands: ' + cmdArgs);
}
const result = callGCanvasLinkNative(componentId, 0x60000000, cmdArgs);
if (isDebugging) {
console.log('>>> result: ' + result);
}
return result;
},
callNative: function (componentId, cmdArgs, cache) {
if (isDebugging) {
logCommand(componentId, cmdArgs);
}
commandsCache[componentId].push(cmdArgs);
if (!cache || isComboDisabled) {
return GBridge.flushNative(componentId);
} else {
return undefined;
}
},
texImage2D(componentId, ...args) {
if (isWeexIOS) {
if (args.length === 6) {
const [target, level, internalformat, format, type, image] = args;
GBridge.callNative(
componentId,
GLmethod.texImage2D + ',' + 6 + ',' + target + ',' + level + ',' + internalformat + ',' + format + ',' + type + ',' + image.src
)
} else if (args.length === 9) {
const [target, level, internalformat, width, height, border, format, type, image] = args;
GBridge.callNative(
componentId,
GLmethod.texImage2D + ',' + 9 + ',' + target + ',' + level + ',' + internalformat + ',' + width + ',' + height + ',' + border + ',' +
+ format + ',' + type + ',' + (image ? image.src : 0)
)
}
} else if (isWeexAndroid) {
if (args.length === 6) {
const [target, level, internalformat, format, type, image] = args;
GCanvasModule.texImage2D(componentId, target, level, internalformat, format, type, image.src);
} else if (args.length === 9) {
const [target, level, internalformat, width, height, border, format, type, image] = args;
GCanvasModule.texImage2D(componentId, target, level, internalformat, width, height, border, format, type, (image ? image.src : 0));
}
}
},
texSubImage2D(componentId, target, level, xoffset, yoffset, format, type, image) {
if (isWeexIOS) {
if (arguments.length === 8) {
GBridge.callNative(
componentId,
GLmethod.texSubImage2D + ',' + 6 + ',' + target + ',' + level + ',' + xoffset + ',' + yoffset, + ',' + format + ',' + type + ',' + image.src
)
}
} else if (isWeexAndroid) {
GCanvasModule.texSubImage2D(componentId, target, level, xoffset, yoffset, format, type, image.src);
}
},
bindImageTexture(componentId, src, imageId) {
GCanvasModule.bindImageTexture([src, imageId], componentId);
},
perloadImage([url, id], callback) {
console.log('********************asda**********')
GCanvasModule.preLoadImage([url, id], function (image) {
console.log('********************asda2**********')
image.url = url;
image.id = id;
callback(image);
});
},
measureText(text, fontStyle, componentId) {
return GCanvasModule.measureText([text, fontStyle], componentId);
},
getImageData (componentId, x, y, w, h, callback) {
GCanvasModule.getImageData([x, y,w,h],componentId,callback);
},
putImageData (componentId, data, x, y, w, h, callback) {
GCanvasModule.putImageData([x, y,w,h,data],componentId,callback);
},
toTempFilePath(componentId, x, y, width, height, destWidth, destHeight, fileType, quality, callback){
GCanvasModule.toTempFilePath([x, y, width,height, destWidth, destHeight, fileType, quality], componentId, callback);
}
}
export default GBridge;

View File

@@ -0,0 +1,18 @@
class FillStyleLinearGradient {
constructor(x0, y0, x1, y1) {
this._start_pos = { _x: x0, _y: y0 };
this._end_pos = { _x: x1, _y: y1 };
this._stop_count = 0;
this._stops = [0, 0, 0, 0, 0];
}
addColorStop = function (pos, color) {
if (this._stop_count < 5 && 0.0 <= pos && pos <= 1.0) {
this._stops[this._stop_count] = { _pos: pos, _color: color };
this._stop_count++;
}
}
}
export default FillStyleLinearGradient;

View File

@@ -0,0 +1,8 @@
class FillStylePattern {
constructor(img, pattern) {
this._style = pattern;
this._img = img;
}
}
export default FillStylePattern;

View File

@@ -0,0 +1,17 @@
class FillStyleRadialGradient {
constructor(x0, y0, r0, x1, y1, r1) {
this._start_pos = { _x: x0, _y: y0, _r: r0 };
this._end_pos = { _x: x1, _y: y1, _r: r1 };
this._stop_count = 0;
this._stops = [0, 0, 0, 0, 0];
}
addColorStop(pos, color) {
if (this._stop_count < 5 && 0.0 <= pos && pos <= 1.0) {
this._stops[this._stop_count] = { _pos: pos, _color: color };
this._stop_count++;
}
}
}
export default FillStyleRadialGradient;

View File

@@ -0,0 +1,666 @@
import FillStylePattern from './FillStylePattern';
import FillStyleLinearGradient from './FillStyleLinearGradient';
import FillStyleRadialGradient from './FillStyleRadialGradient';
import GImage from '../env/image.js';
import {
ArrayBufferToBase64,
Base64ToUint8ClampedArray
} from '../env/tool.js';
export default class CanvasRenderingContext2D {
_drawCommands = '';
_globalAlpha = 1.0;
_fillStyle = 'rgb(0,0,0)';
_strokeStyle = 'rgb(0,0,0)';
_lineWidth = 1;
_lineCap = 'butt';
_lineJoin = 'miter';
_miterLimit = 10;
_globalCompositeOperation = 'source-over';
_textAlign = 'start';
_textBaseline = 'alphabetic';
_font = '10px sans-serif';
_savedGlobalAlpha = [];
timer = null;
componentId = null;
_notCommitDrawImageCache = [];
_needRedrawImageCache = [];
_redrawCommands = '';
_autoSaveContext = true;
// _imageMap = new GHashMap();
// _textureMap = new GHashMap();
constructor() {
this.className = 'CanvasRenderingContext2D';
//this.save()
}
setFillStyle(value) {
this.fillStyle = value;
}
set fillStyle(value) {
this._fillStyle = value;
if (typeof(value) == 'string') {
this._drawCommands = this._drawCommands.concat("F" + value + ";");
} else if (value instanceof FillStylePattern) {
const image = value._img;
if (!image.complete) {
image.onload = () => {
var index = this._needRedrawImageCache.indexOf(image);
if (index > -1) {
this._needRedrawImageCache.splice(index, 1);
CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
this._redrawflush(true);
}
}
this._notCommitDrawImageCache.push(image);
} else {
CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
}
//CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
this._drawCommands = this._drawCommands.concat("G" + image._id + "," + value._style + ";");
} else if (value instanceof FillStyleLinearGradient) {
var command = "D" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," +
value._end_pos._x.toFixed(2) + "," + value._end_pos._y.toFixed(2) + "," +
value._stop_count;
for (var i = 0; i < value._stop_count; ++i) {
command += ("," + value._stops[i]._pos + "," + value._stops[i]._color);
}
this._drawCommands = this._drawCommands.concat(command + ";");
} else if (value instanceof FillStyleRadialGradient) {
var command = "H" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," + value._start_pos._r
.toFixed(2) + "," +
value._end_pos._x.toFixed(2) + "," + value._end_pos._y.toFixed(2) + "," + value._end_pos._r.toFixed(2) + "," +
value._stop_count;
for (var i = 0; i < value._stop_count; ++i) {
command += ("," + value._stops[i]._pos + "," + value._stops[i]._color);
}
this._drawCommands = this._drawCommands.concat(command + ";");
}
}
get fillStyle() {
return this._fillStyle;
}
get globalAlpha() {
return this._globalAlpha;
}
setGlobalAlpha(value) {
this.globalAlpha = value;
}
set globalAlpha(value) {
this._globalAlpha = value;
this._drawCommands = this._drawCommands.concat("a" + value.toFixed(2) + ";");
}
get strokeStyle() {
return this._strokeStyle;
}
setStrokeStyle(value) {
this.strokeStyle = value;
}
set strokeStyle(value) {
this._strokeStyle = value;
if (typeof(value) == 'string') {
this._drawCommands = this._drawCommands.concat("S" + value + ";");
} else if (value instanceof FillStylePattern) {
CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
this._drawCommands = this._drawCommands.concat("G" + image._id + "," + value._style + ";");
} else if (value instanceof FillStyleLinearGradient) {
var command = "D" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," +
value._end_pos._x.toFixed(2) + "," + value._end_pos._y.toFixed(2) + "," +
value._stop_count;
for (var i = 0; i < value._stop_count; ++i) {
command += ("," + value._stops[i]._pos + "," + value._stops[i]._color);
}
this._drawCommands = this._drawCommands.concat(command + ";");
} else if (value instanceof FillStyleRadialGradient) {
var command = "H" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," + value._start_pos._r
.toFixed(2) + "," +
value._end_pos._x.toFixed(2) + "," + value._end_pos._y + ",".toFixed(2) + value._end_pos._r.toFixed(2) + "," +
value._stop_count;
for (var i = 0; i < value._stop_count; ++i) {
command += ("," + value._stops[i]._pos + "," + value._stops[i]._color);
}
this._drawCommands = this._drawCommands.concat(command + ";");
}
}
get lineWidth() {
return this._lineWidth;
}
setLineWidth(value) {
this.lineWidth = value;
}
set lineWidth(value) {
this._lineWidth = value;
this._drawCommands = this._drawCommands.concat("W" + value + ";");
}
get lineCap() {
return this._lineCap;
}
setLineCap(value) {
this.lineCap = value;
}
set lineCap(value) {
this._lineCap = value;
this._drawCommands = this._drawCommands.concat("C" + value + ";");
}
get lineJoin() {
return this._lineJoin;
}
setLineJoin(value) {
this.lineJoin = value
}
set lineJoin(value) {
this._lineJoin = value;
this._drawCommands = this._drawCommands.concat("J" + value + ";");
}
get miterLimit() {
return this._miterLimit;
}
setMiterLimit(value) {
this.miterLimit = value
}
set miterLimit(value) {
this._miterLimit = value;
this._drawCommands = this._drawCommands.concat("M" + value + ";");
}
get globalCompositeOperation() {
return this._globalCompositeOperation;
}
set globalCompositeOperation(value) {
this._globalCompositeOperation = value;
let mode = 0;
switch (value) {
case "source-over":
mode = 0;
break;
case "source-atop":
mode = 5;
break;
case "source-in":
mode = 0;
break;
case "source-out":
mode = 2;
break;
case "destination-over":
mode = 4;
break;
case "destination-atop":
mode = 4;
break;
case "destination-in":
mode = 4;
break;
case "destination-out":
mode = 3;
break;
case "lighter":
mode = 1;
break;
case "copy":
mode = 2;
break;
case "xor":
mode = 6;
break;
default:
mode = 0;
}
this._drawCommands = this._drawCommands.concat("B" + mode + ";");
}
get textAlign() {
return this._textAlign;
}
setTextAlign(value) {
this.textAlign = value
}
set textAlign(value) {
this._textAlign = value;
let Align = 0;
switch (value) {
case "start":
Align = 0;
break;
case "end":
Align = 1;
break;
case "left":
Align = 2;
break;
case "center":
Align = 3;
break;
case "right":
Align = 4;
break;
default:
Align = 0;
}
this._drawCommands = this._drawCommands.concat("A" + Align + ";");
}
get textBaseline() {
return this._textBaseline;
}
setTextBaseline(value) {
this.textBaseline = value
}
set textBaseline(value) {
this._textBaseline = value;
let baseline = 0;
switch (value) {
case "alphabetic":
baseline = 0;
break;
case "middle":
baseline = 1;
break;
case "top":
baseline = 2;
break;
case "hanging":
baseline = 3;
break;
case "bottom":
baseline = 4;
break;
case "ideographic":
baseline = 5;
break;
default:
baseline = 0;
break;
}
this._drawCommands = this._drawCommands.concat("E" + baseline + ";");
}
get font() {
return this._font;
}
setFontSize(size) {
var str = this._font;
var strs = str.trim().split(/\s+/);
for (var i = 0; i < strs.length; i++) {
var values = ["normal", "italic", "oblique", "normal", "small-caps", "normal", "bold",
"bolder", "lighter", "100", "200", "300", "400", "500", "600", "700", "800", "900",
"normal", "ultra-condensed", "extra-condensed", "condensed", "semi-condensed",
"semi-expanded", "expanded", "extra-expanded", "ultra-expanded"
];
if (-1 == values.indexOf(strs[i].trim())) {
if (typeof size === 'string') {
strs[i] = size;
} else if (typeof size === 'number') {
strs[i] = String(size) + 'px';
}
break;
}
}
this.font = strs.join(" ");
}
set font(value) {
this._font = value;
this._drawCommands = this._drawCommands.concat("j" + value + ";");
}
setTransform(a, b, c, d, tx, ty) {
this._drawCommands = this._drawCommands.concat("t" +
(a === 1 ? "1" : a.toFixed(2)) + "," +
(b === 0 ? "0" : b.toFixed(2)) + "," +
(c === 0 ? "0" : c.toFixed(2)) + "," +
(d === 1 ? "1" : d.toFixed(2)) + "," + tx.toFixed(2) + "," + ty.toFixed(2) + ";");
}
transform(a, b, c, d, tx, ty) {
this._drawCommands = this._drawCommands.concat("f" +
(a === 1 ? "1" : a.toFixed(2)) + "," +
(b === 0 ? "0" : b.toFixed(2)) + "," +
(c === 0 ? "0" : c.toFixed(2)) + "," +
(d === 1 ? "1" : d.toFixed(2)) + "," + tx + "," + ty + ";");
}
resetTransform() {
this._drawCommands = this._drawCommands.concat("m;");
}
scale(a, d) {
this._drawCommands = this._drawCommands.concat("k" + a.toFixed(2) + "," +
d.toFixed(2) + ";");
}
rotate(angle) {
this._drawCommands = this._drawCommands
.concat("r" + angle.toFixed(6) + ";");
}
translate(tx, ty) {
this._drawCommands = this._drawCommands.concat("l" + tx.toFixed(2) + "," + ty.toFixed(2) + ";");
}
save() {
this._savedGlobalAlpha.push(this._globalAlpha);
this._drawCommands = this._drawCommands.concat("v;");
}
restore() {
this._drawCommands = this._drawCommands.concat("e;");
this._globalAlpha = this._savedGlobalAlpha.pop();
}
createPattern(img, pattern) {
if (typeof img === 'string') {
var imgObj = new GImage();
imgObj.src = img;
img = imgObj;
}
return new FillStylePattern(img, pattern);
}
createLinearGradient(x0, y0, x1, y1) {
return new FillStyleLinearGradient(x0, y0, x1, y1);
}
createRadialGradient = function(x0, y0, r0, x1, y1, r1) {
return new FillStyleRadialGradient(x0, y0, r0, x1, y1, r1);
};
createCircularGradient = function(x0, y0, r0) {
return new FillStyleRadialGradient(x0, y0, 0, x0, y0, r0);
};
strokeRect(x, y, w, h) {
this._drawCommands = this._drawCommands.concat("s" + x + "," + y + "," + w + "," + h + ";");
}
clearRect(x, y, w, h) {
this._drawCommands = this._drawCommands.concat("c" + x + "," + y + "," + w +
"," + h + ";");
}
clip() {
this._drawCommands = this._drawCommands.concat("p;");
}
resetClip() {
this._drawCommands = this._drawCommands.concat("q;");
}
closePath() {
this._drawCommands = this._drawCommands.concat("o;");
}
moveTo(x, y) {
this._drawCommands = this._drawCommands.concat("g" + x.toFixed(2) + "," + y.toFixed(2) + ";");
}
lineTo(x, y) {
this._drawCommands = this._drawCommands.concat("i" + x.toFixed(2) + "," + y.toFixed(2) + ";");
}
quadraticCurveTo = function(cpx, cpy, x, y) {
this._drawCommands = this._drawCommands.concat("u" + cpx + "," + cpy + "," + x + "," + y + ";");
}
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y, ) {
this._drawCommands = this._drawCommands.concat(
"z" + cp1x.toFixed(2) + "," + cp1y.toFixed(2) + "," + cp2x.toFixed(2) + "," + cp2y.toFixed(2) + "," +
x.toFixed(2) + "," + y.toFixed(2) + ";");
}
arcTo(x1, y1, x2, y2, radius) {
this._drawCommands = this._drawCommands.concat("h" + x1 + "," + y1 + "," + x2 + "," + y2 + "," + radius + ";");
}
beginPath() {
this._drawCommands = this._drawCommands.concat("b;");
}
fillRect(x, y, w, h) {
this._drawCommands = this._drawCommands.concat("n" + x + "," + y + "," + w +
"," + h + ";");
}
rect(x, y, w, h) {
this._drawCommands = this._drawCommands.concat("w" + x + "," + y + "," + w + "," + h + ";");
}
fill() {
this._drawCommands = this._drawCommands.concat("L;");
}
stroke(path) {
this._drawCommands = this._drawCommands.concat("x;");
}
arc(x, y, radius, startAngle, endAngle, anticlockwise) {
let ianticlockwise = 0;
if (anticlockwise) {
ianticlockwise = 1;
}
this._drawCommands = this._drawCommands.concat(
"y" + x.toFixed(2) + "," + y.toFixed(2) + "," +
radius.toFixed(2) + "," + startAngle + "," + endAngle + "," + ianticlockwise +
";"
);
}
fillText(text, x, y) {
let tmptext = text.replace(/!/g, "!!");
tmptext = tmptext.replace(/,/g, "!,");
tmptext = tmptext.replace(/;/g, "!;");
this._drawCommands = this._drawCommands.concat("T" + tmptext + "," + x + "," + y + ",0.0;");
}
strokeText = function(text, x, y) {
let tmptext = text.replace(/!/g, "!!");
tmptext = tmptext.replace(/,/g, "!,");
tmptext = tmptext.replace(/;/g, "!;");
this._drawCommands = this._drawCommands.concat("U" + tmptext + "," + x + "," + y + ",0.0;");
}
measureText(text) {
return CanvasRenderingContext2D.GBridge.measureText(text, this.font, this.componentId);
}
isPointInPath = function(x, y) {
throw new Error('GCanvas not supported yet');
}
drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh) {
if (typeof image === 'string') {
var imgObj = new GImage();
imgObj.src = image;
image = imgObj;
}
if (image instanceof GImage) {
if (!image.complete) {
imgObj.onload = () => {
var index = this._needRedrawImageCache.indexOf(image);
if (index > -1) {
this._needRedrawImageCache.splice(index, 1);
CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
this._redrawflush(true);
}
}
this._notCommitDrawImageCache.push(image);
} else {
CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id);
}
var srcArgs = [image, sx, sy, sw, sh, dx, dy, dw, dh];
var args = [];
for (var arg in srcArgs) {
if (typeof(srcArgs[arg]) != 'undefined') {
args.push(srcArgs[arg]);
}
}
this.__drawImage.apply(this, args);
//this.__drawImage(image,sx, sy, sw, sh, dx, dy, dw, dh);
}
}
__drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh) {
const numArgs = arguments.length;
function drawImageCommands() {
if (numArgs === 3) {
const x = parseFloat(sx) || 0.0;
const y = parseFloat(sy) || 0.0;
return ("d" + image._id + ",0,0," +
image.width + "," + image.height + "," +
x + "," + y + "," + image.width + "," + image.height + ";");
} else if (numArgs === 5) {
const x = parseFloat(sx) || 0.0;
const y = parseFloat(sy) || 0.0;
const width = parseInt(sw) || image.width;
const height = parseInt(sh) || image.height;
return ("d" + image._id + ",0,0," +
image.width + "," + image.height + "," +
x + "," + y + "," + width + "," + height + ";");
} else if (numArgs === 9) {
sx = parseFloat(sx) || 0.0;
sy = parseFloat(sy) || 0.0;
sw = parseInt(sw) || image.width;
sh = parseInt(sh) || image.height;
dx = parseFloat(dx) || 0.0;
dy = parseFloat(dy) || 0.0;
dw = parseInt(dw) || image.width;
dh = parseInt(dh) || image.height;
return ("d" + image._id + "," +
sx + "," + sy + "," + sw + "," + sh + "," +
dx + "," + dy + "," + dw + "," + dh + ";");
}
}
this._drawCommands += drawImageCommands();
}
_flush(reserve, callback) {
const commands = this._drawCommands;
this._drawCommands = '';
CanvasRenderingContext2D.GBridge.render2d(this.componentId, commands, callback);
this._needRender = false;
}
_redrawflush(reserve, callback) {
const commands = this._redrawCommands;
CanvasRenderingContext2D.GBridge.render2d(this.componentId, commands, callback);
if (this._needRedrawImageCache.length == 0) {
this._redrawCommands = '';
}
}
draw(reserve, callback) {
if (!reserve) {
this._globalAlpha = this._savedGlobalAlpha.pop();
this._savedGlobalAlpha.push(this._globalAlpha);
this._redrawCommands = this._drawCommands;
this._needRedrawImageCache = this._notCommitDrawImageCache;
if (this._autoSaveContext) {
this._drawCommands = ("v;" + this._drawCommands);
this._autoSaveContext = false;
} else {
this._drawCommands = ("e;X;v;" + this._drawCommands);
}
} else {
this._needRedrawImageCache = this._needRedrawImageCache.concat(this._notCommitDrawImageCache);
this._redrawCommands += this._drawCommands;
if (this._autoSaveContext) {
this._drawCommands = ("v;" + this._drawCommands);
this._autoSaveContext = false;
}
}
this._notCommitDrawImageCache = [];
if (this._flush) {
this._flush(reserve, callback);
}
}
getImageData(x, y, w, h, callback) {
CanvasRenderingContext2D.GBridge.getImageData(this.componentId, x, y, w, h, function(res) {
res.data = Base64ToUint8ClampedArray(res.data);
if (typeof(callback) == 'function') {
callback(res);
}
});
}
putImageData(data, x, y, w, h, callback) {
if (data instanceof Uint8ClampedArray) {
data = ArrayBufferToBase64(data);
CanvasRenderingContext2D.GBridge.putImageData(this.componentId, data, x, y, w, h, function(res) {
if (typeof(callback) == 'function') {
callback(res);
}
});
}
}
toTempFilePath(x, y, width, height, destWidth, destHeight, fileType, quality, callback) {
CanvasRenderingContext2D.GBridge.toTempFilePath(this.componentId, x, y, width, height, destWidth, destHeight,
fileType, quality,
function(res) {
if (typeof(callback) == 'function') {
callback(res);
}
});
}
}

View File

@@ -0,0 +1,11 @@
export default class WebGLActiveInfo {
className = 'WebGLActiveInfo';
constructor({
type, name, size
}) {
this.type = type;
this.name = name;
this.size = size;
}
}

View File

@@ -0,0 +1,21 @@
import {getTransferedObjectUUID} from './classUtils';
const name = 'WebGLBuffer';
function uuid(id) {
return getTransferedObjectUUID(name, id);
}
export default class WebGLBuffer {
className = name;
constructor(id) {
this.id = id;
}
static uuid = uuid;
uuid() {
return uuid(this.id);
}
}

View File

@@ -0,0 +1,21 @@
import {getTransferedObjectUUID} from './classUtils';
const name = 'WebGLFrameBuffer';
function uuid(id) {
return getTransferedObjectUUID(name, id);
}
export default class WebGLFramebuffer {
className = name;
constructor(id) {
this.id = id;
}
static uuid = uuid;
uuid() {
return uuid(this.id);
}
}

View File

@@ -0,0 +1,298 @@
export default {
"DEPTH_BUFFER_BIT": 256,
"STENCIL_BUFFER_BIT": 1024,
"COLOR_BUFFER_BIT": 16384,
"POINTS": 0,
"LINES": 1,
"LINE_LOOP": 2,
"LINE_STRIP": 3,
"TRIANGLES": 4,
"TRIANGLE_STRIP": 5,
"TRIANGLE_FAN": 6,
"ZERO": 0,
"ONE": 1,
"SRC_COLOR": 768,
"ONE_MINUS_SRC_COLOR": 769,
"SRC_ALPHA": 770,
"ONE_MINUS_SRC_ALPHA": 771,
"DST_ALPHA": 772,
"ONE_MINUS_DST_ALPHA": 773,
"DST_COLOR": 774,
"ONE_MINUS_DST_COLOR": 775,
"SRC_ALPHA_SATURATE": 776,
"FUNC_ADD": 32774,
"BLEND_EQUATION": 32777,
"BLEND_EQUATION_RGB": 32777,
"BLEND_EQUATION_ALPHA": 34877,
"FUNC_SUBTRACT": 32778,
"FUNC_REVERSE_SUBTRACT": 32779,
"BLEND_DST_RGB": 32968,
"BLEND_SRC_RGB": 32969,
"BLEND_DST_ALPHA": 32970,
"BLEND_SRC_ALPHA": 32971,
"CONSTANT_COLOR": 32769,
"ONE_MINUS_CONSTANT_COLOR": 32770,
"CONSTANT_ALPHA": 32771,
"ONE_MINUS_CONSTANT_ALPHA": 32772,
"BLEND_COLOR": 32773,
"ARRAY_BUFFER": 34962,
"ELEMENT_ARRAY_BUFFER": 34963,
"ARRAY_BUFFER_BINDING": 34964,
"ELEMENT_ARRAY_BUFFER_BINDING": 34965,
"STREAM_DRAW": 35040,
"STATIC_DRAW": 35044,
"DYNAMIC_DRAW": 35048,
"BUFFER_SIZE": 34660,
"BUFFER_USAGE": 34661,
"CURRENT_VERTEX_ATTRIB": 34342,
"FRONT": 1028,
"BACK": 1029,
"FRONT_AND_BACK": 1032,
"TEXTURE_2D": 3553,
"CULL_FACE": 2884,
"BLEND": 3042,
"DITHER": 3024,
"STENCIL_TEST": 2960,
"DEPTH_TEST": 2929,
"SCISSOR_TEST": 3089,
"POLYGON_OFFSET_FILL": 32823,
"SAMPLE_ALPHA_TO_COVERAGE": 32926,
"SAMPLE_COVERAGE": 32928,
"NO_ERROR": 0,
"INVALID_ENUM": 1280,
"INVALID_VALUE": 1281,
"INVALID_OPERATION": 1282,
"OUT_OF_MEMORY": 1285,
"CW": 2304,
"CCW": 2305,
"LINE_WIDTH": 2849,
"ALIASED_POINT_SIZE_RANGE": 33901,
"ALIASED_LINE_WIDTH_RANGE": 33902,
"CULL_FACE_MODE": 2885,
"FRONT_FACE": 2886,
"DEPTH_RANGE": 2928,
"DEPTH_WRITEMASK": 2930,
"DEPTH_CLEAR_VALUE": 2931,
"DEPTH_FUNC": 2932,
"STENCIL_CLEAR_VALUE": 2961,
"STENCIL_FUNC": 2962,
"STENCIL_FAIL": 2964,
"STENCIL_PASS_DEPTH_FAIL": 2965,
"STENCIL_PASS_DEPTH_PASS": 2966,
"STENCIL_REF": 2967,
"STENCIL_VALUE_MASK": 2963,
"STENCIL_WRITEMASK": 2968,
"STENCIL_BACK_FUNC": 34816,
"STENCIL_BACK_FAIL": 34817,
"STENCIL_BACK_PASS_DEPTH_FAIL": 34818,
"STENCIL_BACK_PASS_DEPTH_PASS": 34819,
"STENCIL_BACK_REF": 36003,
"STENCIL_BACK_VALUE_MASK": 36004,
"STENCIL_BACK_WRITEMASK": 36005,
"VIEWPORT": 2978,
"SCISSOR_BOX": 3088,
"COLOR_CLEAR_VALUE": 3106,
"COLOR_WRITEMASK": 3107,
"UNPACK_ALIGNMENT": 3317,
"PACK_ALIGNMENT": 3333,
"MAX_TEXTURE_SIZE": 3379,
"MAX_VIEWPORT_DIMS": 3386,
"SUBPIXEL_BITS": 3408,
"RED_BITS": 3410,
"GREEN_BITS": 3411,
"BLUE_BITS": 3412,
"ALPHA_BITS": 3413,
"DEPTH_BITS": 3414,
"STENCIL_BITS": 3415,
"POLYGON_OFFSET_UNITS": 10752,
"POLYGON_OFFSET_FACTOR": 32824,
"TEXTURE_BINDING_2D": 32873,
"SAMPLE_BUFFERS": 32936,
"SAMPLES": 32937,
"SAMPLE_COVERAGE_VALUE": 32938,
"SAMPLE_COVERAGE_INVERT": 32939,
"COMPRESSED_TEXTURE_FORMATS": 34467,
"DONT_CARE": 4352,
"FASTEST": 4353,
"NICEST": 4354,
"GENERATE_MIPMAP_HINT": 33170,
"BYTE": 5120,
"UNSIGNED_BYTE": 5121,
"SHORT": 5122,
"UNSIGNED_SHORT": 5123,
"INT": 5124,
"UNSIGNED_INT": 5125,
"FLOAT": 5126,
"DEPTH_COMPONENT": 6402,
"ALPHA": 6406,
"RGB": 6407,
"RGBA": 6408,
"LUMINANCE": 6409,
"LUMINANCE_ALPHA": 6410,
"UNSIGNED_SHORT_4_4_4_4": 32819,
"UNSIGNED_SHORT_5_5_5_1": 32820,
"UNSIGNED_SHORT_5_6_5": 33635,
"FRAGMENT_SHADER": 35632,
"VERTEX_SHADER": 35633,
"MAX_VERTEX_ATTRIBS": 34921,
"MAX_VERTEX_UNIFORM_VECTORS": 36347,
"MAX_VARYING_VECTORS": 36348,
"MAX_COMBINED_TEXTURE_IMAGE_UNITS": 35661,
"MAX_VERTEX_TEXTURE_IMAGE_UNITS": 35660,
"MAX_TEXTURE_IMAGE_UNITS": 34930,
"MAX_FRAGMENT_UNIFORM_VECTORS": 36349,
"SHADER_TYPE": 35663,
"DELETE_STATUS": 35712,
"LINK_STATUS": 35714,
"VALIDATE_STATUS": 35715,
"ATTACHED_SHADERS": 35717,
"ACTIVE_UNIFORMS": 35718,
"ACTIVE_ATTRIBUTES": 35721,
"SHADING_LANGUAGE_VERSION": 35724,
"CURRENT_PROGRAM": 35725,
"NEVER": 512,
"LESS": 513,
"EQUAL": 514,
"LEQUAL": 515,
"GREATER": 516,
"NOTEQUAL": 517,
"GEQUAL": 518,
"ALWAYS": 519,
"KEEP": 7680,
"REPLACE": 7681,
"INCR": 7682,
"DECR": 7683,
"INVERT": 5386,
"INCR_WRAP": 34055,
"DECR_WRAP": 34056,
"VENDOR": 7936,
"RENDERER": 7937,
"VERSION": 7938,
"NEAREST": 9728,
"LINEAR": 9729,
"NEAREST_MIPMAP_NEAREST": 9984,
"LINEAR_MIPMAP_NEAREST": 9985,
"NEAREST_MIPMAP_LINEAR": 9986,
"LINEAR_MIPMAP_LINEAR": 9987,
"TEXTURE_MAG_FILTER": 10240,
"TEXTURE_MIN_FILTER": 10241,
"TEXTURE_WRAP_S": 10242,
"TEXTURE_WRAP_T": 10243,
"TEXTURE": 5890,
"TEXTURE_CUBE_MAP": 34067,
"TEXTURE_BINDING_CUBE_MAP": 34068,
"TEXTURE_CUBE_MAP_POSITIVE_X": 34069,
"TEXTURE_CUBE_MAP_NEGATIVE_X": 34070,
"TEXTURE_CUBE_MAP_POSITIVE_Y": 34071,
"TEXTURE_CUBE_MAP_NEGATIVE_Y": 34072,
"TEXTURE_CUBE_MAP_POSITIVE_Z": 34073,
"TEXTURE_CUBE_MAP_NEGATIVE_Z": 34074,
"MAX_CUBE_MAP_TEXTURE_SIZE": 34076,
"TEXTURE0": 33984,
"TEXTURE1": 33985,
"TEXTURE2": 33986,
"TEXTURE3": 33987,
"TEXTURE4": 33988,
"TEXTURE5": 33989,
"TEXTURE6": 33990,
"TEXTURE7": 33991,
"TEXTURE8": 33992,
"TEXTURE9": 33993,
"TEXTURE10": 33994,
"TEXTURE11": 33995,
"TEXTURE12": 33996,
"TEXTURE13": 33997,
"TEXTURE14": 33998,
"TEXTURE15": 33999,
"TEXTURE16": 34000,
"TEXTURE17": 34001,
"TEXTURE18": 34002,
"TEXTURE19": 34003,
"TEXTURE20": 34004,
"TEXTURE21": 34005,
"TEXTURE22": 34006,
"TEXTURE23": 34007,
"TEXTURE24": 34008,
"TEXTURE25": 34009,
"TEXTURE26": 34010,
"TEXTURE27": 34011,
"TEXTURE28": 34012,
"TEXTURE29": 34013,
"TEXTURE30": 34014,
"TEXTURE31": 34015,
"ACTIVE_TEXTURE": 34016,
"REPEAT": 10497,
"CLAMP_TO_EDGE": 33071,
"MIRRORED_REPEAT": 33648,
"FLOAT_VEC2": 35664,
"FLOAT_VEC3": 35665,
"FLOAT_VEC4": 35666,
"INT_VEC2": 35667,
"INT_VEC3": 35668,
"INT_VEC4": 35669,
"BOOL": 35670,
"BOOL_VEC2": 35671,
"BOOL_VEC3": 35672,
"BOOL_VEC4": 35673,
"FLOAT_MAT2": 35674,
"FLOAT_MAT3": 35675,
"FLOAT_MAT4": 35676,
"SAMPLER_2D": 35678,
"SAMPLER_CUBE": 35680,
"VERTEX_ATTRIB_ARRAY_ENABLED": 34338,
"VERTEX_ATTRIB_ARRAY_SIZE": 34339,
"VERTEX_ATTRIB_ARRAY_STRIDE": 34340,
"VERTEX_ATTRIB_ARRAY_TYPE": 34341,
"VERTEX_ATTRIB_ARRAY_NORMALIZED": 34922,
"VERTEX_ATTRIB_ARRAY_POINTER": 34373,
"VERTEX_ATTRIB_ARRAY_BUFFER_BINDING": 34975,
"IMPLEMENTATION_COLOR_READ_TYPE": 35738,
"IMPLEMENTATION_COLOR_READ_FORMAT": 35739,
"COMPILE_STATUS": 35713,
"LOW_FLOAT": 36336,
"MEDIUM_FLOAT": 36337,
"HIGH_FLOAT": 36338,
"LOW_INT": 36339,
"MEDIUM_INT": 36340,
"HIGH_INT": 36341,
"FRAMEBUFFER": 36160,
"RENDERBUFFER": 36161,
"RGBA4": 32854,
"RGB5_A1": 32855,
"RGB565": 36194,
"DEPTH_COMPONENT16": 33189,
"STENCIL_INDEX8": 36168,
"DEPTH_STENCIL": 34041,
"RENDERBUFFER_WIDTH": 36162,
"RENDERBUFFER_HEIGHT": 36163,
"RENDERBUFFER_INTERNAL_FORMAT": 36164,
"RENDERBUFFER_RED_SIZE": 36176,
"RENDERBUFFER_GREEN_SIZE": 36177,
"RENDERBUFFER_BLUE_SIZE": 36178,
"RENDERBUFFER_ALPHA_SIZE": 36179,
"RENDERBUFFER_DEPTH_SIZE": 36180,
"RENDERBUFFER_STENCIL_SIZE": 36181,
"FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE": 36048,
"FRAMEBUFFER_ATTACHMENT_OBJECT_NAME": 36049,
"FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL": 36050,
"FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE": 36051,
"COLOR_ATTACHMENT0": 36064,
"DEPTH_ATTACHMENT": 36096,
"STENCIL_ATTACHMENT": 36128,
"DEPTH_STENCIL_ATTACHMENT": 33306,
"NONE": 0,
"FRAMEBUFFER_COMPLETE": 36053,
"FRAMEBUFFER_INCOMPLETE_ATTACHMENT": 36054,
"FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT": 36055,
"FRAMEBUFFER_INCOMPLETE_DIMENSIONS": 36057,
"FRAMEBUFFER_UNSUPPORTED": 36061,
"FRAMEBUFFER_BINDING": 36006,
"RENDERBUFFER_BINDING": 36007,
"MAX_RENDERBUFFER_SIZE": 34024,
"INVALID_FRAMEBUFFER_OPERATION": 1286,
"UNPACK_FLIP_Y_WEBGL": 37440,
"UNPACK_PREMULTIPLY_ALPHA_WEBGL": 37441,
"CONTEXT_LOST_WEBGL": 37442,
"UNPACK_COLORSPACE_CONVERSION_WEBGL": 37443,
"BROWSER_DEFAULT_WEBGL": 37444
};

View File

@@ -0,0 +1,142 @@
let i = 1;
const GLmethod = {};
GLmethod.activeTexture = i++; //1
GLmethod.attachShader = i++;
GLmethod.bindAttribLocation = i++;
GLmethod.bindBuffer = i++;
GLmethod.bindFramebuffer = i++;
GLmethod.bindRenderbuffer = i++;
GLmethod.bindTexture = i++;
GLmethod.blendColor = i++;
GLmethod.blendEquation = i++;
GLmethod.blendEquationSeparate = i++; //10
GLmethod.blendFunc = i++;
GLmethod.blendFuncSeparate = i++;
GLmethod.bufferData = i++;
GLmethod.bufferSubData = i++;
GLmethod.checkFramebufferStatus = i++;
GLmethod.clear = i++;
GLmethod.clearColor = i++;
GLmethod.clearDepth = i++;
GLmethod.clearStencil = i++;
GLmethod.colorMask = i++; //20
GLmethod.compileShader = i++;
GLmethod.compressedTexImage2D = i++;
GLmethod.compressedTexSubImage2D = i++;
GLmethod.copyTexImage2D = i++;
GLmethod.copyTexSubImage2D = i++;
GLmethod.createBuffer = i++;
GLmethod.createFramebuffer = i++;
GLmethod.createProgram = i++;
GLmethod.createRenderbuffer = i++;
GLmethod.createShader = i++; //30
GLmethod.createTexture = i++;
GLmethod.cullFace = i++;
GLmethod.deleteBuffer = i++;
GLmethod.deleteFramebuffer = i++;
GLmethod.deleteProgram = i++;
GLmethod.deleteRenderbuffer = i++;
GLmethod.deleteShader = i++;
GLmethod.deleteTexture = i++;
GLmethod.depthFunc = i++;
GLmethod.depthMask = i++; //40
GLmethod.depthRange = i++;
GLmethod.detachShader = i++;
GLmethod.disable = i++;
GLmethod.disableVertexAttribArray = i++;
GLmethod.drawArrays = i++;
GLmethod.drawArraysInstancedANGLE = i++;
GLmethod.drawElements = i++;
GLmethod.drawElementsInstancedANGLE = i++;
GLmethod.enable = i++;
GLmethod.enableVertexAttribArray = i++; //50
GLmethod.flush = i++;
GLmethod.framebufferRenderbuffer = i++;
GLmethod.framebufferTexture2D = i++;
GLmethod.frontFace = i++;
GLmethod.generateMipmap = i++;
GLmethod.getActiveAttrib = i++;
GLmethod.getActiveUniform = i++;
GLmethod.getAttachedShaders = i++;
GLmethod.getAttribLocation = i++;
GLmethod.getBufferParameter = i++; //60
GLmethod.getContextAttributes = i++;
GLmethod.getError = i++;
GLmethod.getExtension = i++;
GLmethod.getFramebufferAttachmentParameter = i++;
GLmethod.getParameter = i++;
GLmethod.getProgramInfoLog = i++;
GLmethod.getProgramParameter = i++;
GLmethod.getRenderbufferParameter = i++;
GLmethod.getShaderInfoLog = i++;
GLmethod.getShaderParameter = i++; //70
GLmethod.getShaderPrecisionFormat = i++;
GLmethod.getShaderSource = i++;
GLmethod.getSupportedExtensions = i++;
GLmethod.getTexParameter = i++;
GLmethod.getUniform = i++;
GLmethod.getUniformLocation = i++;
GLmethod.getVertexAttrib = i++;
GLmethod.getVertexAttribOffset = i++;
GLmethod.isBuffer = i++;
GLmethod.isContextLost = i++; //80
GLmethod.isEnabled = i++;
GLmethod.isFramebuffer = i++;
GLmethod.isProgram = i++;
GLmethod.isRenderbuffer = i++;
GLmethod.isShader = i++;
GLmethod.isTexture = i++;
GLmethod.lineWidth = i++;
GLmethod.linkProgram = i++;
GLmethod.pixelStorei = i++;
GLmethod.polygonOffset = i++; //90
GLmethod.readPixels = i++;
GLmethod.renderbufferStorage = i++;
GLmethod.sampleCoverage = i++;
GLmethod.scissor = i++;
GLmethod.shaderSource = i++;
GLmethod.stencilFunc = i++;
GLmethod.stencilFuncSeparate = i++;
GLmethod.stencilMask = i++;
GLmethod.stencilMaskSeparate = i++;
GLmethod.stencilOp = i++; //100
GLmethod.stencilOpSeparate = i++;
GLmethod.texImage2D = i++;
GLmethod.texParameterf = i++;
GLmethod.texParameteri = i++;
GLmethod.texSubImage2D = i++;
GLmethod.uniform1f = i++;
GLmethod.uniform1fv = i++;
GLmethod.uniform1i = i++;
GLmethod.uniform1iv = i++;
GLmethod.uniform2f = i++; //110
GLmethod.uniform2fv = i++;
GLmethod.uniform2i = i++;
GLmethod.uniform2iv = i++;
GLmethod.uniform3f = i++;
GLmethod.uniform3fv = i++;
GLmethod.uniform3i = i++;
GLmethod.uniform3iv = i++;
GLmethod.uniform4f = i++;
GLmethod.uniform4fv = i++;
GLmethod.uniform4i = i++; //120
GLmethod.uniform4iv = i++;
GLmethod.uniformMatrix2fv = i++;
GLmethod.uniformMatrix3fv = i++;
GLmethod.uniformMatrix4fv = i++;
GLmethod.useProgram = i++;
GLmethod.validateProgram = i++;
GLmethod.vertexAttrib1f = i++; //new
GLmethod.vertexAttrib2f = i++; //new
GLmethod.vertexAttrib3f = i++; //new
GLmethod.vertexAttrib4f = i++; //new //130
GLmethod.vertexAttrib1fv = i++; //new
GLmethod.vertexAttrib2fv = i++; //new
GLmethod.vertexAttrib3fv = i++; //new
GLmethod.vertexAttrib4fv = i++; //new
GLmethod.vertexAttribPointer = i++;
GLmethod.viewport = i++;
export default GLmethod;

View File

@@ -0,0 +1,23 @@
const GLtype = {};
[
"GLbitfield",
"GLboolean",
"GLbyte",
"GLclampf",
"GLenum",
"GLfloat",
"GLint",
"GLintptr",
"GLsizei",
"GLsizeiptr",
"GLshort",
"GLubyte",
"GLuint",
"GLushort"
].sort().map((typeName, i) => GLtype[typeName] = 1 >> (i + 1));
export default GLtype;

View File

@@ -0,0 +1,21 @@
import {getTransferedObjectUUID} from './classUtils';
const name = 'WebGLProgram';
function uuid(id) {
return getTransferedObjectUUID(name, id);
}
export default class WebGLProgram {
className = name;
constructor(id) {
this.id = id;
}
static uuid = uuid;
uuid() {
return uuid(this.id);
}
}

View File

@@ -0,0 +1,21 @@
import {getTransferedObjectUUID} from './classUtils';
const name = 'WebGLRenderBuffer';
function uuid(id) {
return getTransferedObjectUUID(name, id);
}
export default class WebGLRenderbuffer {
className = name;
constructor(id) {
this.id = id;
}
static uuid = uuid;
uuid() {
return uuid(this.id);
}
}

View File

@@ -0,0 +1,22 @@
import {getTransferedObjectUUID} from './classUtils';
const name = 'WebGLShader';
function uuid(id) {
return getTransferedObjectUUID(name, id);
}
export default class WebGLShader {
className = name;
constructor(id, type) {
this.id = id;
this.type = type;
}
static uuid = uuid;
uuid() {
return uuid(this.id);
}
}

View File

@@ -0,0 +1,11 @@
export default class WebGLShaderPrecisionFormat {
className = 'WebGLShaderPrecisionFormat';
constructor({
rangeMin, rangeMax, precision
}) {
this.rangeMin = rangeMin;
this.rangeMax = rangeMax;
this.precision = precision;
}
}

View File

@@ -0,0 +1,22 @@
import {getTransferedObjectUUID} from './classUtils';
const name = 'WebGLTexture';
function uuid(id) {
return getTransferedObjectUUID(name, id);
}
export default class WebGLTexture {
className = name;
constructor(id, type) {
this.id = id;
this.type = type;
}
static uuid = uuid;
uuid() {
return uuid(this.id);
}
}

View File

@@ -0,0 +1,22 @@
import {getTransferedObjectUUID} from './classUtils';
const name = 'WebGLUniformLocation';
function uuid(id) {
return getTransferedObjectUUID(name, id);
}
export default class WebGLUniformLocation {
className = name;
constructor(id, type) {
this.id = id;
this.type = type;
}
static uuid = uuid;
uuid() {
return uuid(this.id);
}
}

View File

@@ -0,0 +1,3 @@
export function getTransferedObjectUUID(name, id) {
return `${name.toLowerCase()}-${id}`;
}

View File

@@ -0,0 +1,74 @@
import GContext2D from '../context-2d/RenderingContext';
import GContextWebGL from '../context-webgl/RenderingContext';
export default class GCanvas {
// static GBridge = null;
id = null;
_needRender = true;
constructor(id, { disableAutoSwap }) {
this.id = id;
this._disableAutoSwap = disableAutoSwap;
if (disableAutoSwap) {
this._swapBuffers = () => {
GCanvas.GBridge.render(this.id);
}
}
}
getContext(type) {
let context = null;
if (type.match(/webgl/i)) {
context = new GContextWebGL(this);
context.componentId = this.id;
if (!this._disableAutoSwap) {
const render = () => {
if (this._needRender) {
GCanvas.GBridge.render(this.id);
this._needRender = false;
}
}
setInterval(render, 16);
}
GCanvas.GBridge.callSetContextType(this.id, 1); // 0 for 2d; 1 for webgl
} else if (type.match(/2d/i)) {
context = new GContext2D(this);
context.componentId = this.id;
// const render = ( callback ) => {
//
// const commands = context._drawCommands;
// context._drawCommands = '';
//
// GCanvas.GBridge.render2d(this.id, commands, callback);
// this._needRender = false;
// }
// //draw方法触发
// context._flush = render;
// //setInterval(render, 16);
GCanvas.GBridge.callSetContextType(this.id, 0);
} else {
throw new Error('not supported context ' + type);
}
return context;
}
reset() {
GCanvas.GBridge.callReset(this.id);
}
}

View File

@@ -0,0 +1,104 @@
let incId = 1;
import GBridge from '../bridge/bridge-weex.js'
const noop = function () { };
class GImage {
static GBridge = null;
constructor() {
this._id = incId++;
this._width = 0;
this._height = 0;
this._src = undefined;
this._onload = noop;
this._onerror = noop;
this.complete = false;
}
get width() {
return this._width;
}
set width(v) {
this._width = v;
}
get height() {
return this._height;
}
set height(v) {
this._height = v;
}
get src() {
return this._src;
}
set src(v) {
if (v.startsWith('//')) {
v = 'http:' + v;
}
this._src = v;
try {
GBridge.perloadImage([this._src, this._id], (data) => {
if (process.env.NODE_ENV === 'development') {
console.log('****GBridge.perloadImage****')
}
if (typeof data === 'string') {
data = JSON.parse(data);
}
if (data.error) {
var evt = { type: 'error', target: this };
this.onerror(evt);
} else {
this.complete = true;
this.width = typeof data.width === 'number' ? data.width : 0;
this.height = typeof data.height === 'number' ? data.height : 0;
var evt = { type: 'load', target: this };
this.onload(evt);
}
});
} catch (error) {
console.log('perloadImage fail', error)
}
}
addEventListener(name, listener) {
if (name === 'load') {
this.onload = listener;
} else if (name === 'error') {
this.onerror = listener;
}
}
removeEventListener(name, listener) {
if (name === 'load') {
this.onload = noop;
} else if (name === 'error') {
this.onerror = noop;
}
}
get onload() {
return this._onload;
}
set onload(v) {
this._onload = v;
}
get onerror() {
return this._onerror;
}
set onerror(v) {
this._onerror = v;
}
}
export default GImage;

View File

@@ -0,0 +1,24 @@
export function ArrayBufferToBase64 (buffer) {
var binary = '';
var bytes = new Uint8ClampedArray(buffer);
for (var len = bytes.byteLength, i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return btoa(binary);
}
export function Base64ToUint8ClampedArray(base64String) {
const padding = '='.repeat((4 - base64String.length % 4) % 4);
const base64 = (base64String + padding)
.replace(/\-/g, '+')
.replace(/_/g, '/');
const rawData = atob(base64);
const outputArray = new Uint8ClampedArray(rawData.length);
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}

View File

@@ -0,0 +1,39 @@
import GCanvas from './env/canvas';
import GImage from './env/image';
import GWebGLRenderingContext from './context-webgl/RenderingContext';
import GContext2D from './context-2d/RenderingContext';
import GBridgeWeex from './bridge/bridge-weex';
export let Image = GImage;
export let WeexBridge = GBridgeWeex;
export function enable(el, { bridge, debug, disableAutoSwap, disableComboCommands } = {}) {
const GBridge = GImage.GBridge = GCanvas.GBridge = GWebGLRenderingContext.GBridge = GContext2D.GBridge = bridge;
GBridge.callEnable(el.ref, [
0, // renderMode: 0--RENDERMODE_WHEN_DIRTY, 1--RENDERMODE_CONTINUOUSLY
-1, // hybridLayerType: 0--LAYER_TYPE_NONE 1--LAYER_TYPE_SOFTWARE 2--LAYER_TYPE_HARDWARE
false, // supportScroll
false, // newCanvasMode
1, // compatible
'white',// clearColor
false // sameLevel: newCanvasMode = true && true => GCanvasView and Webview is same level
]);
if (debug === true) {
GBridge.callEnableDebug();
}
if (disableComboCommands) {
GBridge.callEnableDisableCombo();
}
var canvas = new GCanvas(el.ref, { disableAutoSwap });
canvas.width = el.style.width;
canvas.height = el.style.height;
return canvas;
};

View File

@@ -0,0 +1,124 @@
/**
* 路由跳转方法,该方法相对于直接使用uni.xxx的好处是使用更加简单快捷
* 并且带有路由拦截功能
*/
import { queryParams, deepMerge, page } from '../function/index';
class Router {
constructor() {
// 原始属性定义
this.config = {
type: 'navigateTo',
url: '',
delta: 1, // navigateBack页面后退时,回退的层数
params: {}, // 传递的参数
animationType: 'pop-in', // 窗口动画,只在APP有效
animationDuration: 300, // 窗口动画持续时间,单位毫秒,只在APP有效
intercept: false // 是否需要拦截
}
// 因为route方法是需要对外赋值给另外的对象使用,同时route内部有使用this,会导致route失去上下文
// 这里在构造函数中进行this绑定
this.route = this.route.bind(this)
}
// 判断url前面是否有"/",如果没有则加上,否则无法跳转
addRootPath(url) {
return url[0] === '/' ? url : `/${url}`
}
// 整合路由参数
mixinParam(url, params) {
url = url && this.addRootPath(url)
// 使用正则匹配,主要依据是判断是否有"/","?","="等,如“/page/index/index?name=mary"
// 如果有url中有get参数,转换后无需带上"?"
let query = ''
if (/.*\/.*\?.*=.*/.test(url)) {
// object对象转为get类型的参数
query = queryParams(params, false)
// 因为已有get参数,所以后面拼接的参数需要带上"&"隔开
return url += `&${query}`
}
// 直接拼接参数,因为此处url中没有后面的query参数,也就没有"?/&"之类的符号
query = queryParams(params)
return url += query
}
// 对外的方法名称
async route(options = {}, params = {}) {
// 合并用户的配置和内部的默认配置
let mergeConfig = {}
if (typeof options === 'string') {
// 如果options为字符串,则为route(url, params)的形式
mergeConfig.url = this.mixinParam(options, params)
mergeConfig.type = 'navigateTo'
} else {
mergeConfig = deepMerge(this.config, options)
// 否则正常使用mergeConfig中的url和params进行拼接
mergeConfig.url = this.mixinParam(options.url, options.params)
}
// 如果本次跳转的路径和本页面路径一致,不执行跳转,防止用户快速点击跳转按钮,造成多次跳转同一个页面的问题
if (mergeConfig.url === page()) return
if (params.intercept) {
this.config.intercept = params.intercept
}
// params参数也带给拦截器
mergeConfig.params = params
// 合并内外部参数
mergeConfig = deepMerge(this.config, mergeConfig)
// 判断用户是否定义了拦截器
if (typeof uni.$u.routeIntercept === 'function') {
// 定一个promise,根据用户执行resolve(true)或者resolve(false)来决定是否进行路由跳转
const isNext = await new Promise((resolve, reject) => {
uni.$u.routeIntercept(mergeConfig, resolve)
})
// 如果isNext为true,则执行路由跳转
isNext && this.openPage(mergeConfig)
} else {
this.openPage(mergeConfig)
}
}
// 执行路由跳转
openPage(config) {
// 解构参数
const {
url,
type,
delta,
animationType,
animationDuration
} = config
if (config.type == 'navigateTo' || config.type == 'to') {
uni.navigateTo({
url,
animationType,
animationDuration
})
}
if (config.type == 'redirectTo' || config.type == 'redirect') {
uni.redirectTo({
url
})
}
if (config.type == 'switchTab' || config.type == 'tab') {
uni.switchTab({
url
})
}
if (config.type == 'reLaunch' || config.type == 'launch') {
uni.reLaunch({
url
})
}
if (config.type == 'navigateBack' || config.type == 'back') {
uni.navigateBack({
delta
})
}
}
}
export default (new Router()).route

View File

@@ -0,0 +1,3 @@
export const defineMixin = (options) => {
return options
}