提交 123cd46e authored 作者: 刘旭's avatar 刘旭

剩余下单页面

上级 5484b168
......@@ -16,6 +16,7 @@
"@dcloudio/uni-components": "3.0.0-alpha-3050320220729001",
"@dcloudio/uni-h5": "3.0.0-alpha-3050320220729001",
"@dcloudio/uni-mp-weixin": "3.0.0-alpha-3050320220729001",
"lodash": "^4.17.21",
"node-sass": "^7.0.1",
"pinia": "^2.0.21",
"vue": "^3.2.37",
......
import { request } from '@/utils/request';
// 购物车初始数据
export const getCartIndex = () => request('/wx/cart/index', 'GET');
// 选择或取消商品
export const cartChecked = (data: any) => request('/wx/cart/checked', 'POST', data)
// 删除商品
export const cartDelete = (data: any) => request('/wx/cart/delete', 'POST', data)
// 更新商品
export const cartUpdate= (data: any) => request('/wx/cart/update', 'POST', data)
\ No newline at end of file
import { request } from '@/utils/request';
// 分类初始数据 /wx/catalog/index
export const getCatalogIndex = () => request('/wx/catalog/index', 'GET');
// 分类数据
export const getCatalogCurrent = (data: any) => request('/wx/catalog/current', 'GET', data);
// 分类详情数据
export const getGoodsCategory = (data: any) => request('/wx/goods/category', 'GET', data);
// 分类详情数据列表
export const getGoodsList = (data: any) => request('/wx/goods/list', 'GET', data);
import { request } from '@/utils/request';
// 主页数据
export const homeIndex = () => request('/wx/home/index', 'GET');
// 商品详情
export const indexDetails = (data: any) => request('/wx/goods/detail', 'GET', data);
// 加入购物车
export const addCart = (data: any) => request('/wx/cart/add', 'POST', data)
\ No newline at end of file
import { request } from '@/utils/request'
// 登录
export const login = (data: any) => request('/wx/auth/login', 'POST', data)
\ No newline at end of file
<template>
<view style="margin-bottom: 20rpx;">
<view class="login-input">
<view :class="'iconfont ' + inputData.iconfont + ' login-icon'"></view>
<input
:type="inputData?.type"
:placeholder="inputData.placeholder"
:password="inputData?.password"
class="input-text"
v-model="inputData.inputValue"
@blur="handleValue"
/>
<text class="getcode" v-if="inputData.checkType === 'code'">获取验证码</text>
</view>
<text class="check" v-if="inputData.check">{{ inputData.checkContent }}</text>
</view>
</template>
<script setup lang="ts">
let props = defineProps({
inputData: Object
});
let emits = defineEmits(['hangleInput']);
let handleValue = (Value: any) => {
emits('hangleInput', Value.detail.value, props.inputData?.checkType);
};
</script>
<style lang="scss" scoped>
.login-input {
display: flex;
flex-direction: inherit;
border: 1px solid #ccc;
border-radius: 50rpx;
width: 560rpx;
height: 70rpx;
.login-icon {
line-height: 70rpx;
margin: 0 15rpx;
font-size: 42rpx;
color: #c7c7c7;
}
.input-text {
height: 100%;
line-height: 70rpx;
flex: 1 1 auto;
}
.getcode {
height: 100%;
width: 144rpx;
font-size: 24rpx;
color: #c7c7c7;
line-height: 70rpx;
}
}
.check {
font-size: 24rpx;
color: red;
margin: 0 0 10rpx 21rpx;
}
</style>
......@@ -28,9 +28,15 @@
"navigationBarTitleText": "聊天窗口"
}
}, {
"path": "pages/productLine/productLine",
"style": {
"navigationBarTitleText": "产品线"
}
}, {
"path": "pages/cart/index",
"style": {
"navigationBarTitleText": "购物车"
"navigationBarTitleText": "购物车",
"navigationStyle": "custom"
}
}, {
"path": "pages/goods/index",
......@@ -47,6 +53,18 @@
"style": {
"navigationBarTitleText": "我的订单"
}
}, {
"path": "pages/login/login",
"style": {
"navigationBarTitleText": "登录"
}
}, {
"path": "pages/category/items",
"style": {
"navigationBarTitleText": "",
"navigationBarBackgroundColor": "#fff",
"onReachBottomDistance": 55
}
}
],
"tabBar": {
......@@ -55,8 +73,7 @@
"backgroundColor": "#fff",
"borderStyle": "white",
"height": "50px",
"list": [
{
"list": [{
"pagePath": "pages/index/index",
"iconPath": "/static/tabbar/home.png",
"selectedIconPath": "/static/tabbar/home_fill.png",
......@@ -69,10 +86,10 @@
"text": "分类"
},
{
"pagePath": "pages/message/index",
"pagePath": "pages/productLine/productLine",
"iconPath": "/static/tabbar/message.png",
"selectedIconPath": "/static/tabbar/message_fill.png",
"text": "消息"
"text": "产品线"
},
{
"pagePath": "pages/cart/index",
......
<template>
<view class="cart-container">
<view class="cart-item" v-for="(item, index) in cartList" :key="index">
<view class="item-infos">
<view class="item-title">
<view class="item-checkbox">
<checkbox-group @change="selectAll(item)">
<label>
<checkbox class="all-select" :checked="item.allChecked"/>
</label>
</checkbox-group>
<u-navbar :is-back="false" title="">
<template #right>
<text style="margin-right: 30rpx;" @tap="tapDel">{{ administration }}</text>
</template>
</u-navbar>
<view v-if="cartList.length > 0" style="width: 100%; display:flex; margin-top: 10rpx;">
<u-checkbox-group @change="checkboxGroupChange" style="width: 100%; display:flex">
<block v-for="(item, index) in cartList" :key="item.id">
<view class="group-item">
<view class="item">
<u-checkbox
:name="item.id"
v-model="item.checked"
shape="circle"
></u-checkbox>
<u-image
width="140rpx"
height="200rpx"
:src="item.picUrl"
class="img"
></u-image>
<view class="details">
<view>{{ item.goodsName }}</view>
<view
class="tag"
v-for="(item1, index1) in item.specifications.length"
:key="index1"
>
<u-tag
:text="item.specifications[index1]"
type="info"
size="mini"
style="margin-right: 2rpx;"
/>
</view>
<text>{{ item.shopName }}</text>
<view style="font-weight: bold;">¥{{ item.price }}</view>
</view>
<view v-for="(goodsItem, goodsIndex) in item.goodsList" :key="goodsIndex">
<uni-swipe-action style="width: 100%">
<uni-swipe-action-item
:right-options="options"
:key="goodsItem.id"
@click="bindClick">
<view class="item-detail">
<view class="item-checkbox">
<checkbox-group @change="selected(goodsItem, item)">
<label>
<checkbox class="item-select" :checked="goodsItem.checked"/>
</label>
</checkbox-group>
</view>
<view class="goods-img">
<image :src="goodsItem.img"/>
<view v-if="delCircle" class="circle" @tap="deleteCart(index)">
<view class="horizontal"></view>
</view>
<view class="goods-detail">
<view class="goods-title">
<text>{{ goodsItem.title }}</text>
</view>
<view class="goods-price-count">
<text class="goods-price">
<text class="unit"></text>
<text class="price">{{ goodsItem.price }}</text>
</text>
<view class="goods-count">
<uni-number-box
:value="goodsItem.selectCount"
<view v-else class="number-box">
<u-number-box
v-model="item.number"
:min="1"
:max="99"
@change="($value: number) => { changeBuyNum($value, goodsItem);}"/>
</view>
</view>
</view>
disabled-input
@change="valChange($event, item)"
></u-number-box>
</view>
</uni-swipe-action-item>
</uni-swipe-action>
</view>
</block>
</u-checkbox-group>
</view>
<view v-else style="margin-top: 200rpx;"><u-empty text="购物车为空" mode="car" /></view>
<view class="footer">
<view class="left">
<u-checkbox-group>
<u-checkbox v-model="checkedAll" @tap="checkboxChange" shape="circle" name="全选">
全选
</u-checkbox>
</u-checkbox-group>
</view>
<view class="bottom-bar">
<view class="bottom-left">
<view class="total-price-box">
<text>合计:</text>
<text class="goods-price">
<text class="unit"></text>
<text class="price">{{totalAmount}}</text>
<view class="right">
<text v-show="!delCircle">总计:</text>
<text v-show="!delCircle" style="color: red; font-size: 40rpx;">
¥{{ totalPrice }}
</text>
<u-button
shape="circle"
size="medium"
hover-class="#f32329"
style="background-color: #f32329; margin-left: 20rpx; color: #fff;"
@tap="tapOptions"
>
{{ !delCircle ? '结算' : '删除' }}
</u-button>
</view>
</view>
<view class="bottom-right">
<text>结算</text>
</view>
</view>
</view>
<!-- 删除模态框 -->
<u-modal
v-model="showModel.show"
:content="showModel.content"
:title="showModel.title"
show-cancel-button
async-close
:cancel-text="showModel.cancelText"
@confirm="onConfirm"
></u-modal>
</template>
<script lang="ts" setup>
import {reactive, ref, computed} from "vue";
import {CartItem} from "@/types/cart";
import {CartGoodsItem, GoodsItem} from "@/types/goods";
import { ref, reactive } from 'vue';
import { getCartIndex, cartChecked, cartDelete, cartUpdate } from '@/api/cart';
import { toLogin } from '@/utils/auth';
import { onShow } from '@dcloudio/uni-app';
import _ from 'lodash';
const cartList: CartItem[] = reactive([
{
cartId: 1,
shopName: 'XXX旗舰店',
goodsList: [
{
id: 1,
title: 'XXXXXXXXX',
img: 'https://bytelibs-dev.oss-cn-beijing.aliyuncs.com/image/goods/goods_1.jpg',
price: '5500.00',
sales: '1000',
selectCount: 1
}, {
id: 2,
title: 'XXXXXXXXX',
img: 'https://bytelibs-dev.oss-cn-beijing.aliyuncs.com/image/goods/goods_2.jpg',
price: '5500.00',
sales: '1000',
selectCount: 1
}
]
}, {
cartId: 2,
shopName: 'XXX旗舰店',
goodsList: [
{
id: 1,
title: 'XXXXXXXXX',
img: 'https://bytelibs-dev.oss-cn-beijing.aliyuncs.com/image/goods/goods_3.jpg',
price: '5500.00',
sales: '1000',
selectCount: 1
}
]
}
])
const cartList = ref([] as any); // 购物车数据
const checkedAll = ref(false); // 全选checkbox
const allGoods = ref(); // 购物车列表id
const checkedGoods = ref(); // 购物车列表check为true id
const totalPrice = ref(); // 总价
const delCircle = ref(false); // 控制删除与管理
const administration = ref('管理');
const delProductIds = ref([] as any); // 删除id
const showModel = reactive({
title: '',
show: false,
content: '确认删除所选商品吗',
cancelText: '再想想',
}); // model元素
const options = ref([
{
text: '删除',
style: {
backgroundColor: '#F56C6C'
// 管理
const tapDel = () => {
if (delCircle.value) {
initCartIndex();
delCircle.value = false;
administration.value = '管理';
} else {
delCircle.value = true;
administration.value = '退出管理';
}
}
])
};
const bindClick = (e: any) => {
console.log(e);
uni.showToast({
title: `点击了${e.position === 'left' ? '左侧' : '右侧'} ${e.content.text}按钮`,
icon: 'none'
// 点击购物车列表checkbox
const checkboxGroupChange = (e: any) => {
let addProductIds: any = [];
_.each(e, (v: any) => {
let productId = _.find(cartList.value, (result: any) => {
return result.id === v;
}).productId;
if (productId == undefined) initCartIndex();
addProductIds.push(productId);
});
}
const selectAll = (item: CartItem) => {
if (undefined === item.allChecked) {
item.allChecked = false
}
item.allChecked = !item.allChecked
item.goodsList.forEach(goods => {
goods.checked = item.allChecked;
})
}
const selected = (item: CartGoodsItem, cartItem: CartItem) => {
item.checked = !item.checked
let newArr: GoodsItem[] = cartItem.goodsList.filter(i => (i.checked === true))
cartItem.allChecked = newArr.length === cartItem.goodsList.length;
}
const changeBuyNum = (value: number, goodsItem: CartGoodsItem) => {
goodsItem.selectCount = value;
}
const totalAmount = computed(() => {
let totalAmount = 0;
cartList.forEach(cartItem => {
cartItem.goodsList.filter(goodsItem => (goodsItem.checked === true)).forEach(item => {
totalAmount = totalAmount + Number.parseFloat(item.price) * item.selectCount
})
})
return totalAmount.toFixed(2)
})
// 取消checkedbox
let delProductIds: any = [];
_.each(_.difference(allGoods.value, e), (v: any) => {
let productId = _.find(cartList.value, (result: any) => {
return result.id === v;
}).productId;
delProductIds.push(productId);
});
</script>
if (addProductIds.length > 0) initCartChecked(1, addProductIds);
<style lang="scss" scoped>
.cart-container {
.cart-item {
margin: 20rpx;
border-radius: 20rpx;
background-color: #FFFFFF;
if (delProductIds.length > 0) initCartChecked(0, delProductIds);
.item-infos {
padding: 20rpx;
//margin-left: 60rpx;
.item-title {
display: flex;
if (e.length === allGoods.value.length) checkedAll.value = true;
else checkedAll.value = false;
};
.item-checkbox {
.all-select {
transform: scale(0.7);
}
}
// 单个删除
const deleteCart = (index: number) => {
delProductIds.value.push(cartList.value[index].productId);
console.log(delProductIds.value);
showModel.show = true;
};
//margin-left: 60rpx;
// 批量删除
const tapOptions = () => {
if(delCircle.value) {
console.log('删除');
delProductIds.value = [];
_.each(checkedGoods.value, (id: any) => {
delProductIds.value.push(
_.find(cartList.value, (vv: any) => {
return id === vv.id;
}).productId
);
});
showModel.show = true;
} else {
}
.item-detail {
display: flex;
padding-top: 10rpx;
padding-bottom: 10rpx;
//line-height: 88rpx;
align-items: center;
};
.item-checkbox {
.item-select {
transform: scale(0.7);
// 确认删除
const onConfirm = () => {
if (delProductIds.value) {
if (delProductIds.value.length === 1) {
cartDelete({ productIds: delProductIds.value }).then((res: any) => {
delProductIds.value = [];
cartList.value = res.data.data.cartList;
allGoods.value = getAllList();
checkedGoods.value = getCheckedList(cartList.value);
totalPrice.value = res.data.data.cartTotal.checkedGoodsAmount.toFixed(2);
showModel.show = false;
});
} else {
cartDelete({ productIds: delProductIds.value }).then((res: any) => {
delProductIds.value = [];
cartList.value = res.data.data.cartList;
allGoods.value = getAllList();
checkedGoods.value = getCheckedList(cartList.value);
totalPrice.value = res.data.data.cartTotal.checkedGoodsAmount.toFixed(2);
// 批量删除后,check的name属性没有更新,需要刷新当前页面
uni.reLaunch({ url: '../cart/index' });
showModel.show = false;
});
}
}
};
.goods-img {
flex: 0;
image {
width: 100rpx;
height: 100rpx;
border-radius: 15rpx;
}
// 是否全选
const checkboxChange = () => {
let productIds: any = [];
_.each(cartList.value, (v: any) => {
productIds.push(v.productId);
});
if (checkedAll.value) {
initCartChecked(1, productIds);
checkedAll.value = true;
} else {
initCartChecked(0, productIds);
checkedAll.value = false;
}
};
.goods-detail {
//display: flex;
flex: auto;
padding-left: 40rpx;
.goods-title {
// 商品数量变化
const valChange = (e: any, item: any) => {
cartUpdate({
number: e.value,
goodsId: item.goodsId,
id: item.id,
productId: item.productId,
}).then((res: any) => {
initCartIndex();
console.log(res);
});
};
}
// 初始化数据
const initCartIndex = () => {
toLogin();
getCartIndex().then((res: any) => {
cartList.value = res.data.data.cartList;
totalPrice.value = res.data.data.cartTotal.checkedGoodsAmount.toFixed(2);
allGoods.value = getAllList();
checkedGoods.value = getCheckedList(cartList.value);
let sort = 0;
cartList.value.map((item: any) => {
if (!item.checked) sort += 1;
});
if (sort === 0) checkedAll.value = true;
else checkedAll.value = false;
sort = 0;
console.log('购物车数据', cartList.value);
});
};
.goods-price-count {
display: flex;
// 点击复选框操作
const initCartChecked = (isChecked: number, productIds: any) => {
cartChecked({ isChecked, productIds }).then((res: any) => {
totalPrice.value = res.data.data.cartTotal.checkedGoodsAmount.toFixed(2);
cartList.value = res.data.data.cartList;
allGoods.value = getAllList();
checkedGoods.value = getCheckedList(cartList.value);
});
};
.goods-price {
color: #dd524d;
margin-top: 10rpx;
//position: absolute;
display: flex;
flex: auto;
// 获取所有的id
const getAllList = () => {
let result: any = [];
_.each(cartList.value, (v: any) => {
result.push(v.id);
});
return result;
};
.unit {
font-size: 10px;
// 获取check为true的id
const getCheckedList = (goods: any) => {
let result: any = [];
_.each(goods, (v: any) => {
if (v.checked) {
result.push(v.id);
}
});
return result;
};
.price {
font-size: 16px;
font-weight: bold
}
}
onShow(() => initCartIndex());
</script>
.goods-count {
margin-right: 25rpx;
}
<style lang="scss" scoped>
.group-item {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
padding: 15rpx;
margin-bottom: 10rpx;
background-color: #fff;
.item {
display: flex;
justify-content: flex-start;
.details {
width: 55%;
display: flex;
flex-direction: column;
justify-content: space-between;
margin-left: 20rpx;
.tag {
margin-bottom: 25%;
}
}
}
.circle {
position: relative;
display: inline-block;
width: 36rpx;
height: 36rpx;
border-radius: 50%;
background-color: #f32329;
margin-right: 20rpx;
.horizontal {
position: absolute;
top: 44%;
left: 50%;
width: 24rpx;
height: 6rpx;
margin-left: -12rpx;
margin-bottom: -3rpx;
border-radius: 4rpx;
background-color: #fff;
}
}
//flex: auto;
.bottom-bar {
height: 50px;
background-color: #FFFFFF;
.number-box {
display: flex;
position: fixed;
bottom: 0;
left: 0;
right: 0;
margin: 0;
.bottom-left {
flex: 2;
flex-direction: column;
justify-content: flex-end;
margin-top: 20%;
}
}
.total-price-box {
display: flex;
margin-left: 50rpx;
line-height: 100rpx;
font-weight: bold;
.goods-price {
color: #dd524d;
.footer {
position: fixed;
bottom: var(--window-bottom);
width: 100%;
height: 100rpx;
background-color: #fff;
padding: 10rpx 40rpx;
display: flex;
flex: auto;
.unit {
font-size: 10px;
}
.price {
font-size: 16px;
}
}
}
justify-content: space-between;
align-items: center;
margin-bottom: 2rpx;
.left {
// height: 100%;
}
.bottom-right {
color: rgb(255, 255, 255);
.right {
display: flex;
flex: 1;
flex-direction: row;
justify-content: center;
align-items: center;
background: linear-gradient(90deg, rgb(255, 138, 24), rgb(254, 96, 53));
}
}
}
</style>
<template>
分类
<button @tap="taps">dianji</button>
<view class="u-wrap">
<!-- 搜索 -->
<view><uni-search-bar placeholder="输入搜索商品" bgColor="#EEEEEE" clearButton="auto" cancelButton="none" @blur="blur" @focus="focus" @confirm="search" /></view>
<view class="u-menu-wrap">
<scroll-view scroll-y scroll-with-animation class="u-tab-view menu-scroll-view" :scroll-top="scrollTop">
<view
v-for="(item, index) in categoryList"
:key="item.id"
class="u-tab-item"
:class="[current == index ? 'u-tab-item-active' : '']"
:data-current="index"
@tap.stop="swichMenu(index, item.id)"
>
<text class="u-line-1">{{ item.name }}</text>
</view>
</scroll-view>
<block v-for="(item, index) in categoryList" :key="index">
<scroll-view scroll-y class="right-box" v-if="current == index">
<view class="page-view">
<view class="class-item">
<view class="item-title">
<text>{{ item.name }}</text>
</view>
<view class="item-container">
<view class="thumb-box" v-for="(current, c) in currentSubCategoryData" :key="current.id" @tap="tapItems(current.id)">
<image class="item-menu-image" :src="current.picUrl" mode=""></image>
<view class="item-menu-name">{{ current.name }}</view>
</view>
</view>
</view>
</view>
</scroll-view>
</block>
</view>
</view>
</template>
<script lang="ts" setup>
import { getCurrentInstance } from 'vue'
import { ref } from 'vue';
import { getCatalogIndex, getCatalogCurrent } from '@/api/category';
const { proxy } = getCurrentInstance()
const scrollTop = ref(0); //tab标题的滚动条位置
const current = ref(0); // 预设当前项的值
const menuHeight = ref(0); // 左边菜单的高度
const menuItemHeight = ref(0); // 左边菜单item的高度
const categoryList = ref(); //右侧tabber数据
const currentSubCategoryData = ref(); //初始tabber数据
let taps = () => {
proxy?.$model.toast('加油')
const tapItems = (id: any) => {
uni.navigateTo({
url: `./items?id=${id}`
})
}
// 点击左边的栏目切换
const swichMenu = async (index: any, id: number) => {
if (index == current) return;
current.value = index;
initCatalogCurrent(id);
// 如果为0,意味着尚未初始化
if (menuHeight.value == 0 || menuItemHeight.value == 0) {
await getElRect('menu-scroll-view', 'menuHeight');
await getElRect('u-tab-item', 'menuItemHeight');
}
// 将菜单菜单活动item垂直居中
scrollTop.value = index * menuItemHeight.value + menuItemHeight.value / 2 - menuHeight.value / 2;
};
// 获取一个目标元素的高度
const getElRect = (elClass?: any, dataVal?: any) => {
new Promise((resolve, reject) => {
const query = uni.createSelectorQuery().in(this);
query
.select('.' + elClass)
.fields({ size: true }, (res: any) => {
// 如果节点尚未生成,res值为null,循环调用执行
if (!res) {
setTimeout(() => {
getElRect(elClass);
}, 10);
return;
}
dataVal = res.height;
})
.exec();
});
};
// tabbar单个分类数据
const initCatalogCurrent = (id: number) => {
getCatalogCurrent({ id }).then((res: any) => {
currentSubCategoryData.value = res.data.data.currentSubCategory;
console.log(res, '单个分类数据');
});
};
const initIndex = () => {
getCatalogIndex().then((res: any) => {
// console.log(res);
// if (res.data.code === 200) {
categoryList.value = res.data.data.categoryList;
currentSubCategoryData.value = res.data.data.currentSubCategory;
console.log(categoryList.value, '分类数据', currentSubCategoryData.value);
// }
});
};
initIndex();
</script>
<style lang="scss" scoped></style>
<style lang="scss" scoped>
.u-wrap {
height: calc(100vh);
/* #ifdef H5 */
height: calc(100vh - var(--window-top));
/* #endif */
display: flex;
flex-direction: column;
}
.u-search-box {
padding: 18rpx 30rpx;
}
.u-menu-wrap {
flex: 1;
display: flex;
overflow: hidden;
}
.u-search-inner {
background-color: rgb(234, 234, 234);
border-radius: 100rpx;
display: flex;
align-items: center;
padding: 10rpx 16rpx;
}
.u-search-text {
font-size: 26rpx;
color: $u-tips-color;
margin-left: 10rpx;
}
.u-tab-view {
width: 200rpx;
height: 100%;
}
.u-tab-item {
height: 110rpx;
background: #f6f6f6;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
font-size: 26rpx;
color: #444;
font-weight: 400;
line-height: 1;
}
.u-tab-item-active {
position: relative;
color: #000;
font-size: 30rpx;
font-weight: 600;
background: #fff;
}
.u-tab-item-active::before {
content: '';
position: absolute;
border-left: 4px solid $u-type-primary;
height: 32rpx;
left: 0;
top: 39rpx;
}
.u-tab-view {
height: 100%;
}
.right-box {
background-color: rgb(250, 250, 250);
}
.page-view {
padding: 16rpx;
}
.class-item {
margin-bottom: 30rpx;
background-color: #fff;
padding: 16rpx;
border-radius: 8rpx;
}
.item-title {
font-size: 26rpx;
color: $u-main-color;
font-weight: bold;
}
.item-menu-name {
font-weight: normal;
font-size: 24rpx;
color: $u-main-color;
}
.item-container {
display: flex;
flex-wrap: wrap;
}
.thumb-box {
width: 33.333333%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
margin-top: 20rpx;
}
.item-menu-image {
width: 120rpx;
height: 120rpx;
}
</style>
<template>
<view class="app-container">
<!-- tabs标签 -->
<u-tabs
name="name"
:list="categoryData.brotherCategory"
v-model="categoryData.current"
@change="tabsChange"
></u-tabs>
<!-- content -->
<view class="content">
<view class="title">
<view
style="width: 100%; text-align: center; font-size: 40rpx; margin-bottom: 20rpx;"
>
{{ categoryData.currentCategory.name }}
</view>
<view style="width: 100%; text-align: center; font-size: 32rpx; color: #999999;">
{{ categoryData.currentCategory.desc }}
</view>
</view>
<view
v-for="(item, index) in categoryData.list"
:key="item.id"
class="item-list"
@tap="tapList(item.id)"
>
<view class="left">
<u-image width="176rpx" height="176rpx" :src="item.picUrl" />
</view>
<view class="details">
<view class="details-top">
<view>{{ item.name }}</view>
<view style="color: #969799;">{{ item.brief }}</view>
</view>
<view class="details-bottom">
<text style="font-size: 32rpx; margin-right: 8rpx;">
{{ item.retailPrice }}
</text>
<text
style="font-size: 24rpx; text-decoration: line-through; color: #969799;"
>
{{ item.counterPrice }}
</text>
</view>
</view>
</view>
<view style="margin: 20rpx;">
<u-loadmore :status="categoryData.status" icon-type="flower" />
</view>
</view>
</view>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue';
import { onLoad, onReachBottom } from '@dcloudio/uni-app';
import { getGoodsCategory, getGoodsList } from '@/api/category';
const categoryId = ref();
const categoryData = reactive({
brotherCategory: [] as any,
currentCategory: {} as any,
list: [] as any,
current: 0,
page: 1,
limit: 10,
total: 0,
status: 'loadmore', //nomore loadmore
});
onLoad((options: any) => {
categoryId.value = options.id;
initGoodsCategory(categoryId.value);
initGoodsList(categoryId.value, categoryData.page, categoryData.limit);
});
// 上拉加载数据
onReachBottom(() => {
// 判断是否还有下一页数据
if (categoryData.page * categoryData.limit >= categoryData.total)
return (categoryData.status = 'nomore');
// 判断是否正在请求其它数据,如果是,则不发起额外的请求
if (categoryData.status === 'loading') return;
categoryData.page += 1;
initGoodsList(categoryId.value, categoryData.page, categoryData.limit);
});
const tapList = (id: any) => {
console.log(id);
uni.navigateTo({ url: `/pages/goods/index?id=${id}` });
};
const tabsChange = (e: any) => {
categoryData.current = e;
const id = categoryData.brotherCategory[e].id;
categoryData.list = [];
categoryData.page = 1;
initGoodsCategory(id);
initGoodsList(id, categoryData.page, categoryData.limit);
};
const initGoodsCategory = (id: number) => {
getGoodsCategory({ id }).then((res: any) => {
categoryData.brotherCategory = res.data.data.brotherCategory;
categoryData.currentCategory = res.data.data.currentCategory;
if (res.data.data.parentCategory.id == categoryId.value) {
categoryId.value = res.data.data.currentCategory.id;
initGoodsCategory(categoryId.value);
initGoodsList(categoryId.value, categoryData.page, categoryData.limit);
}
});
};
const initGoodsList = (categoryId: number, page?: number, limit?: number) => {
categoryData.status = 'loading';
getGoodsList({ categoryId, page, limit }).then((res: any) => {
if (categoryData.total > 10) categoryData.status = 'loadmore';
else categoryData.status = 'nomore';
categoryData.total = res.data.data.total;
categoryData.list = [...categoryData.list, ...res.data.data.list];
});
};
</script>
<style lang="scss" scoped>
page {
background-color: #fff;
}
.app-container {
border-top: 2rpx solid #f4f4f4;
.content {
width: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-webkit-box-align: center;
.title {
width: 100%;
margin: 20rpx 0 80rpx;
}
.item-list {
// border: 1px solid #000;
box-sizing: border-box;
width: 100%;
display: flex;
justify-content: flex-start;
padding: 16rpx 32rpx;
.details {
display: flex;
flex-direction: column;
.details-top {
margin-bottom: 13%;
}
}
}
}
}
</style>
......@@ -32,9 +32,9 @@
</view>
<u-cell-group style="margin-top: 20rpx;">
<u-cell-item v-if="!selectedGoodsItem.specName" icon="" title="规格" value="请选择" :index="0" @click="clickGroup"></u-cell-item>
<u-cell-item v-if="!selectedGoodsItem.specName" icon="" title="规格" value="请选择" :index="0" @tap="clickGroup"></u-cell-item>
<u-cell-item v-else icon="" :title="'已选:' + selectedGoodsItem.specName + '*' + selectedGoodsItem.num" :arrow="false" :index="0" @click="clickGroup"></u-cell-item>
<u-cell-item icon="" title="属性" :index="1" @click="clickGroup"></u-cell-item>
<u-cell-item icon="" title="属性" :index="1" @tap="clickGroup"></u-cell-item>
<u-cell-item icon="" title="运费" value="满88免邮费" :arrow="false" :border-bottom="false"></u-cell-item>
</u-cell-group>
......@@ -57,8 +57,8 @@
</text>
</view>
</view>
<uni-section class="mb-10" title="颜色">
<view class="goods-spec"><uni-data-checkbox mode="tag" v-model="radioValue" :localdata="goodsInfo.spec" @change="changeColor" /></view>
<uni-section v-for="item in detailData?.specificationList" :key="item.id" class="mb-10" :title="item.name">
<view class="goods-spec"><uni-data-checkbox mode="tag" :value="radioValue" :localdata="item.valueList" @change="changeColor" /></view>
</uni-section>
<uni-section class="mb-10" title="数量">
......@@ -85,7 +85,10 @@
<view class="goods-intro">
<uni-segmented-control :current="current" :values="tabButtons" @clickItem="onClickItem" styleType="text" activeColor="#e43d33"></uni-segmented-control>
<view class="content">
<view v-show="current === 0"><u-parse :html="detailData?.info.detail" :show-with-animation="true" lazy-load style="font-size: 0" /></view>
<view v-show="current === 0">
<u-parse v-if="detailData?.info.detail" :html="detailData?.info.detail" :show-with-animation="true" lazy-load style="font-size: 0" />
<u-empty v-else text="暂无数据" mode="data" />
</view>
<view v-show="current === 1">选项卡2的内容</view>
</view>
</view>
......@@ -96,11 +99,14 @@
<u-popup v-model="attrPopup" mode="bottom" height="50%" closeable>
<view class="attr-content">
<view class="title">商品属性</view>
<view v-if="detailData?.attribute.length !== 0">
<view v-for="(item, index) in detailData?.attribute" :key="item.id" class="details">
<text class="left">{{ item.attribute }}</text>
<text class="right">{{ item.value }}</text>
<u-line v-show="detailData?.attribute.length-1 !== index" />
<u-line v-show="detailData?.attribute.length - 1 !== index" />
</view>
</view>
<view v-else><u-empty text="暂无属性" mode="data" /></view>
</view>
</u-popup>
</view>
......@@ -109,43 +115,10 @@
<script lang="ts" setup>
import { ref } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { indexDetails } from '@/api/index';
import { indexDetails, addCart } from '@/api/index';
const attrPopup = ref(false);
const detailData = ref();
onLoad((options: any) => {
console.log(options.id);
indexDetails({ id: options.id }).then((res: any) => {
if (res.data.code === 200) {
}
for (let s in res.data.data?.attribute) {
const value = res.data.data?.attribute[s].value.split('\n')
if(value.length > 1) {
let str: string = ''
value.forEach((item : string) => {
str += ' ' + item
})
res.data.data!.attribute[s].value = str
}
}
detailData.value = res.data.data;
console.log(detailData.value, '商品详情数据');
});
});
const clickGroup = (index: number) => {
switch (index) {
case 0:
popup.value.open('bottom');
resetSelected();
break;
case 1:
attrPopup.value = true;
}
};
const indicatorDots = ref(true);
const popup = ref();
const tabButtons = ref(['商品详情']);
let current = ref(0);
......@@ -230,6 +203,38 @@ const buttonGroup = ref([
}
]);
const detailId = ref()
onLoad((options: any) => {
console.log(options);
detailId.value = options.id
initDetails(options.id)
});
// 点击分组
const clickGroup = (index: number) => {
switch (index) {
case 0:
popup.value.open('bottom');
resetSelected();
break;
case 1:
attrPopup.value = true;
}
};
// 添加checkoutbox属性
const specificationList = () => {
detailData.value?.specificationList.map((item: any, i: number) => {
item.valueList.map((key: any, k: number) => {
if(key.value !== key.id) {
detailData.value!.specificationList[i].valueList[k]['text'] = key.value
detailData.value!.specificationList[i].valueList[k]['value'] = key.id
}
})
})
}
const onClick = (e: any) => {
if (e.index === 0) {
console.log('客服');
......@@ -267,14 +272,16 @@ const buttonClick = (e: any) => {
openPopup();
};
// 打开规格选择
const openPopup = () => {
popup.value.open('bottom');
resetSelected();
};
// 添加购物车
const addToCart = () => {
console.log('添加至购物车', selectedGoodsItem.value);
initDetails(detailId.value)
popup.value.close();
uni.showToast({
title: '已添加至购物车',
......@@ -282,38 +289,65 @@ const addToCart = () => {
});
};
// 立即购买
const buyNow = () => {
console.log('立即购买', selectedGoodsItem.value);
popup.value.close();
};
// 初始产品规格数据
const resetSelected = () => {
selectedGoodsItem.value.id = goodsInfo.value.id;
selectedGoodsItem.value.img = goodsInfo.value.imgList[0].img;
selectedGoodsItem.value.price = goodsInfo.value.price;
specificationList()
selectedGoodsItem.value.id = detailData.value?.id;
selectedGoodsItem.value.img = detailData.value?.productList[0].url;
selectedGoodsItem.value.price = detailData.value?.productList[0].price;
selectedGoodsItem.value.specName = '';
selectedGoodsItem.value.num = 1;
radioValue.value = '';
radioValue.value = detailData.value?.specificationList[0].valueList[0].value;
};
// 修改商品规格
const changeColor = (e: any) => {
console.log(e);
const selected = e.detail.data;
console.log('选择产品规格', selected);
selectedGoodsItem.value.id = selected.id;
selectedGoodsItem.value.img = selected.img;
selectedGoodsItem.value.price = selected.price;
selectedGoodsItem.value.img = selected.picUrl;
selectedGoodsItem.value.price = detailData.value?.productList[0].price;
selectedGoodsItem.value.specName = selected.text;
};
// 购买数量
const changeBuyNum = (value: number) => {
selectedGoodsItem.value.num = value;
};
// 选择选项卡
const onClickItem = (e: any) => {
if (current.value != e.currentIndex) {
current.value = e.currentIndex;
}
};
// 初始化商品详情数据
const initDetails = (id: number) => {
indexDetails({ id }).then((res: any) => {
if (res.data.code === 200) {
}
// 去除数据 换行符
for (let s in res.data.data?.attribute) {
const value = res.data.data?.attribute[s].value.split('\n')
if(value.length > 1) {
let str: string = ''
value.forEach((item: string) => {
str += ' ' + item
})
res.data.data!.attribute[s].value = str
}
}
detailData.value = res.data.data;
console.log(detailData.value, '商品详情数据');
});
}
</script>
<style lang="scss" scoped>
......@@ -516,6 +550,7 @@ const onClickItem = (e: any) => {
border-radius: 30rpx;
.content {
width: 100%;
margin-top: 30rpx;
margin-bottom: calc(100rpx + env(safe-area-inset-bottom));
display: inline-block;
......
......@@ -4,7 +4,7 @@
<!-- 轮播图 -->
<view class="wrap"><u-swiper :list="indexData?.banner" name="url" height="400"></u-swiper></view>
<!-- 宫格布局 -->
<u-grid :col="4" class="grid" @click="clickGrid">
<u-grid :col="4" class="grid" @tap="clickGrid">
<u-grid-item v-for="(item, index) in indexData?.channel" :key="item.id" :index="item.id">
<u-icon :name="item.iconUrl" :size="46"></u-icon>
<view class="grid-text">{{ item.name }}</view>
......@@ -12,9 +12,10 @@
</u-grid>
<view class="goods">
<view style="padding: 20rpx 20rpx;"><u-section title="新品首发" sub-title="查看更多" :show-line="false" /></view>
<uni-row>
<uni-col :span="12" v-for="(item, index) in indexData?.newGoodsList" :key="item.id">
<view class="goods-item" @click="viewGoods(item)">
<view class="goods-item" @tap="viewGoods(item)">
<image class="goods-img" :src="item.picUrl"></image>
<view class="goods-infos">
<uni-row>
......@@ -48,12 +49,11 @@
<script setup lang="ts">
import { ref } from 'vue';
import { homeIndex } from '@/api/index';
// import { GoodsItem } from '@/types/goods';
const indexData = ref();
const clickGrid = (index: any) => {
console.log(index);
uni.navigateTo({ url: '/pages/category/items?id=' + index });
};
const viewGoods = (row: any) => {
......@@ -92,7 +92,6 @@ initIndex();
height: 450rpx;
background-color: #ffffff;
margin: 5rpx;
//border: 1rpx solid #FFFFFF;
border-radius: 25rpx;
overflow: hidden;
.goods-img {
......
<template>
<view class="login-container">
<image src="https://bytelibs-dev.oss-cn-beijing.aliyuncs.com/image/logo/logo.png" mode="scaleToFill" class="title-iamge"></image>
<text class="login-text">欢迎登陆</text>
<view class="login-form">
<input-login :inputData="inputData" @hangleInput="hangleInput" />
<input-login :inputData="inputData1" @hangleInput="hangleInput" />
</view>
<button @tap="clickNextStep" class="getCaptcha">登录</button>
<!-- <image src="https://bytelibs-dev.oss-cn-beijing.aliyuncs.com/image/logo/logo.png" mode="" class="next-step" @click="clickNextStep"></image> -->
<text class="footer-text">定制管理平台</text>
</view>
</template>
<script setup lang="ts">
import { reactive } from 'vue';
import { login } from '@/api/login';
import inputLogin from '@/components/inputLogin.vue';
let inputData = reactive({
inputValue: 'user123' as any,
iconfont: 'icon-a-ziyuan16',
placeholder: '手机号码',
type: 'text',
checkType: 'phone',
check: false,
checkContent: '请输入有效手机号'
});
let inputData1 = reactive({
inputValue: 'user123' as any,
iconfont: 'icon-mima',
placeholder: '密码',
type: 'password',
checkType: 'passWord',
check: false,
checkContent: '请输入密码'
});
let hangleInput = (Value: any, type: string) => {
if (type === 'phone') {
let reg = /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/;
if (!reg.test(Value) || !Value) inputData.check = true;
else inputData.check = false;
} else {
if (!Value) inputData1.check = true;
else inputData1.check = false;
}
};
let clickNextStep = () => {
if (!inputData.inputValue || !inputData.inputValue) {
inputData.check = true;
inputData1.check = true;
return;
} else if (!inputData.check || !inputData1.check) {
initLogin(inputData.inputValue, inputData1.inputValue);
} else {
console.log('检验不通过');
}
};
// user123
let initLogin = async (username: number, password: string) => {
let res: any = await login({ username, password });
if (res.data.errno == 0) {
uni.setStorage({
key: 'token',
data: res.data.data.token,
success: () => {
uni.switchTab({
url: '../profile/index',
success() {
uni.setStorage({
key: 'username',
data: inputData.inputValue,
success() {
uni.showToast({
title: '登陆成功',
icon: 'none',
duration: 1000
});
}
});
}
});
}
});
} else {
uni.showToast({
title: '手机号或密码错误',
icon: 'none',
duration: 2000
});
}
};
</script>
<style lang="scss" scoped>
.login-container {
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
.getCaptcha {
width: 400rpx;
background-color: rgb(253, 243, 208);
color: $u-tips-color;
border: none;
font-size: 30rpx;
margin-top: 20rpx;
&::after {
border: none;
}
}
.title-iamge {
width: 300rpx;
height: 240rpx;
}
.login-text {
margin-top: 10%;
font-weight: 700;
font-size: 40rpx;
color: #1d2b5f;
}
.login-form {
margin-top: 15%;
}
.next-step {
margin-top: 20rpx;
width: 245rpx;
height: 90rpx;
}
.footer-text {
margin-top: 40%;
display: block;
width: 100%;
color: #d79972;
font-size: 30rpx;
text-align: center;
align-self: flex-end;
}
}
</style>
......@@ -6,7 +6,7 @@
<uni-swipe-action-item
v-for="(item, index) in chatList" :key="index"
:right-options="options"
@click="bindClick">
@tap="bindClick">
<!-- 头像显示角标 -->
<uni-list-chat
:title="item.nickname"
......@@ -16,7 +16,7 @@
badge-positon="left"
:badge-text="item.unread"
clickable
@click="openChat(item)">
@tap="openChat(item)">
<!-- 此处可自定义内容 -->
</uni-list-chat>
</uni-swipe-action-item>
......
<template>
<view class="">
产品线
</view>
</template>
<script>
</script>
<style>
</style>
\ No newline at end of file
<template>
</template>
<script>
</script>
<style>
</style>
\ No newline at end of file
<template>
<view class="profile-container">
<view class="profile-info">
<view class="profile-info" @tap="my">
<view class="profile-avatar">
<image src="https://bytelibs-dev.oss-cn-beijing.aliyuncs.com/image/logo/logo.png"/>
</view>
<view class="profile-nickname">
<text>Mr Tsui</text>
<image src="https://bytelibs-dev.oss-cn-beijing.aliyuncs.com/image/logo/logo.png" />
</view>
<view class="profile-nickname"><text>Mr Tsui</text></view>
</view>
<view class="order-center">
<uni-section title="我的订单" type="line" padding>
<template v-slot:right>
<view class="order-more" @click="showAllOrder">全部</view>
<view class="order-more" @tap="showAllOrder">全部</view>
</template>
<uni-grid :column="5" :show-border="false" :square="false" @change="handleOrderTypeChange">
<uni-grid-item v-for="(item ,index) in orderBtnList" :index="index" :key="index">
<uni-grid
:column="5"
:show-border="false"
:square="false"
@change="handleOrderTypeChange"
>
<uni-grid-item
v-for="(item, index) in orderBtnList"
:index="index"
:key="index"
>
<view class="grid-item-box">
<image class="image" :src="item.url" mode="aspectFill" />
<text class="text">{{item.text}}</text>
<text class="text">{{ item.text }}</text>
<view v-if="item.badge" class="grid-dot">
<uni-badge :text="item.badge" :type="item.type" />
</view>
......@@ -30,10 +37,10 @@
<view class="function-expand">
<uni-grid :column="4" :show-border="false" :square="false" @change="change">
<uni-grid-item v-for="(item ,index) in expandBtnList" :index="index" :key="index">
<uni-grid-item v-for="(item, index) in expandBtnList" :index="index" :key="index">
<view class="grid-item-box">
<image class="image" :src="item.url" mode="aspectFill" />
<text class="text">{{item.text}}</text>
<text class="text">{{ item.text }}</text>
<view v-if="item.badge" class="grid-dot">
<uni-badge :text="item.badge" :type="item.type" />
</view>
......@@ -44,87 +51,102 @@
<view class="function-list">
<uni-list>
<!-- <uni-list-item :show-extra-icon="true" showArrow :extra-icon="extraIcon" title="列表左侧带扩展图标"/>-->
<!-- <uni-list-item :show-extra-icon="true" showArrow :extra-icon="extraIcon" title="列表左侧带扩展图标"/>-->
<uni-list-item
title="个人中心"
showArrow
thumb="https://bytelibs-dev.oss-cn-beijing.aliyuncs.com/image/order/address_dizhi.png"
thumb-size="default"/>
thumb-size="default"
/>
<uni-list-item
title="设置"
showArrow
thumb="https://bytelibs-dev.oss-cn-beijing.aliyuncs.com/image/order/address_dizhi.png"
thumb-size="default"/>
thumb-size="default"
/>
<uni-list-item
title="关于"
showArrow
thumb="https://bytelibs-dev.oss-cn-beijing.aliyuncs.com/image/order/address_dizhi.png"
thumb-size="default"/>
thumb-size="default"
/>
</uni-list>
</view>
</view>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import {ref} from "vue";
const my = () => {
uni.navigateTo({
url: '../login/login',
});
};
const orderBtnList = ref([
{
url: 'https://bytelibs-dev.oss-cn-beijing.aliyuncs.com/image/order/payment.png',
text: '待付款',
badge: 1,
type: 'error'
}, {
type: 'error',
},
{
url: 'https://bytelibs-dev.oss-cn-beijing.aliyuncs.com/image/order/daifahuo.png',
text: '待发货',
badge: 1,
type: 'error'
}, {
type: 'error',
},
{
url: 'https://bytelibs-dev.oss-cn-beijing.aliyuncs.com/image/order/daishouhuo.png',
text: '待收货',
badge: 1,
type: 'error'
}, {
type: 'error',
},
{
url: 'https://bytelibs-dev.oss-cn-beijing.aliyuncs.com/image/order/daipingjia.png',
text: '待评价',
badge: 1,
type: 'error'
}, {
type: 'error',
},
{
url: 'https://bytelibs-dev.oss-cn-beijing.aliyuncs.com/image/order/shouhou.png',
text: '售后',
badge: 1,
type: 'error'
}
])
type: 'error',
},
]);
const expandBtnList = ref([
{
url: 'https://bytelibs-dev.oss-cn-beijing.aliyuncs.com/image/order/payment.png',
text: '我的收藏',
badge: 0,
type: 'error'
}, {
type: 'error',
},
{
url: 'https://bytelibs-dev.oss-cn-beijing.aliyuncs.com/image/order/daifahuo.png',
text: '我的足迹',
badge: 0,
type: 'error'
}, {
type: 'error',
},
{
url: 'https://bytelibs-dev.oss-cn-beijing.aliyuncs.com/image/order/daishouhuo.png',
text: '收货地址',
badge: 0,
type: 'error'
}, {
type: 'error',
},
{
url: 'https://bytelibs-dev.oss-cn-beijing.aliyuncs.com/image/order/daipingjia.png',
text: '我的评价',
badge: 0,
type: 'error'
}
])
type: 'error',
},
]);
const handleOrderTypeChange = (e: any) => {
const index = e.detail.index
uni.navigateTo({url: '/pages/order/index?orderType=' + index})
const index = e.detail.index;
uni.navigateTo({ url: '/pages/order/index?orderType=' + index });
// switch (index) {
// case 0:
// console.log('待付款')
......@@ -144,12 +166,11 @@ const handleOrderTypeChange = (e: any) => {
// default:
// break;
// }
}
};
const showAllOrder = () => {
uni.navigateTo({url: '/pages/order/index'})
}
uni.navigateTo({ url: '/pages/order/index' });
};
</script>
<style lang="scss" scoped>
......@@ -157,7 +178,7 @@ const showAllOrder = () => {
.profile-info {
height: 200rpx;
margin-top: 20rpx;
background-color: #FFFFFF;
background-color: #ffffff;
border-radius: 20rpx;
display: flex;
......@@ -184,10 +205,11 @@ const showAllOrder = () => {
}
}
.order-center, .function-expand {
.order-center,
.function-expand {
margin-top: 15rpx;
border-radius: 20rpx;
background-color: #FFFFFF;
background-color: #ffffff;
.order-more {
margin-right: 20rpx;
}
......@@ -203,7 +225,6 @@ const showAllOrder = () => {
justify-content: center;
padding: 10rpx 0;
.grid-item-box-row {
flex: 1;
// position: relative;
/* #ifndef APP-NVUE */
......
<template>
<view style="width: 100%;display:flex;">
<u-checkbox-group @change="checkbox_change" style="width: 100%;display:flex">
<template v-for="item in cartList">
<view style="width: 100%;display:flex;justify-content:space-between;padding: 15rpx;">
<view style="display:flex">
<u-checkbox :name="item.goodsId" v-model="item.checked" shape="circle"></u-checkbox>
<slot name="img" :src="item.img"></slot>
<view style="display:flex;flex-direction: column;justify-content: space-between;margin-left: 20rpx;">
<slot name="title" :title="item.title"></slot>
<slot name="price" :price="item.price"></slot>
</view>
</view>
<view style="display:flex;flex-direction: column;justify-content:flex-end;"><u-number-box v-model="item.num" @change="valChange"></u-number-box></view>
</view>
</template>
</u-checkbox-group>
</view>
</template>
<script>
export default {
emits: ['shopcartmodemits'],
props: {
list: {
type: Array,
default(rawProps) {
return [{ img: '/static/logo.png', title: '标题标题标题1', goodsId: '001', num: 0, price: 0, checked: false }];
}
}
},
data() {
return {
cartList: this.list
};
},
setup(props, ctx) {
const db = e => {
ctx.emit('shopcartmodemits', e);
};
return {
db
};
},
methods: {
checkbox_change(e) {
console.log(this.cartList, '111');
this.dataBack('单选');
},
valChange(e) {
this.dataBack('数量调整');
},
//全选
checkAll() {
for (var i in this.list) {
this.list[i].checked = true;
}
this.dataBack('全选');
},
//取消全选
deCheckAll() {
for (var i in this.list) {
this.list[i].checked = false;
}
this.dataBack('取消全选');
},
//数据回传
dataBack(e) {
this.db({ type: e, list: this.cartList });
}
},
mounted() {
console.log('cartlist', this.cartList);
}
};
</script>
<style lang="scss"></style>
{
"id": "muyu-shopCartMod",
"displayName": "简易购物车插件(仅支持VUE3)",
"version": "v1.0.0",
"description": "一个简易购物车插件,支持自定义插槽,目前仅支持vue3,需要引入(uView Vue3)",
"keywords": [
"购物车",
"VUE3",
"uniapp",
"vk-uview-ui"
],
"dcloudext": {
"category": [
"前端组件",
"通用组件"
]
}
}
\ No newline at end of file
## 1.0.3(2022-09-16)
- 可以使用 uni-scss 控制主题色
## 1.0.2(2022-06-30)
- 优化 在 uni-forms 中的依赖注入方式
## 1.0.1(2022-02-07)
- 修复 multiple 为 true 时,v-model 的值为 null 报错的 bug
## 1.0.0(2021-11-19)
- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-data-checkbox](https://uniapp.dcloud.io/component/uniui/uni-data-checkbox)
## 0.2.5(2021-08-23)
- 修复 在uni-forms中 modelValue 中不存在当前字段,当前字段必填写也不参与校验的问题
## 0.2.4(2021-08-17)
- 修复 单选 list 模式下 ,icon 为 left 时,选中图标不显示的问题
## 0.2.3(2021-08-11)
- 修复 在 uni-forms 中重置表单,错误信息无法清除的问题
## 0.2.2(2021-07-30)
- 优化 在uni-forms组件,与label不对齐的问题
## 0.2.1(2021-07-27)
- 修复 单选默认值为0不能选中的Bug
## 0.2.0(2021-07-13)
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 0.1.11(2021-07-06)
- 优化 删除无用日志
## 0.1.10(2021-07-05)
- 修复 由 0.1.9 引起的非 nvue 端图标不显示的问题
## 0.1.9(2021-07-05)
- 修复 nvue 黑框样式问题
## 0.1.8(2021-06-28)
- 修复 selectedTextColor 属性不生效的Bug
## 0.1.7(2021-06-02)
- 新增 map 属性,可以方便映射text/value属性
## 0.1.6(2021-05-26)
- 修复 不关联服务空间的情况下组件报错的Bug
## 0.1.5(2021-05-12)
- 新增 组件示例地址
## 0.1.4(2021-04-09)
- 修复 nvue 下无法选中的问题
## 0.1.3(2021-03-22)
- 新增 disabled属性
## 0.1.2(2021-02-24)
- 优化 默认颜色显示
## 0.1.1(2021-02-24)
- 新增 支持nvue
## 0.1.0(2021-02-18)
- “暂无数据”显示居中
<template>
<view class="uni-data-checklist" :style="{'margin-top':isTop+'px'}">
<template v-if="!isLocal">
<view class="uni-data-loading">
<uni-load-more v-if="!mixinDatacomErrorMessage" status="loading" iconType="snow" :iconSize="18" :content-text="contentText"></uni-load-more>
<text v-else>{{mixinDatacomErrorMessage}}</text>
</view>
</template>
<template v-else>
<checkbox-group v-if="multiple" class="checklist-group" :class="{'is-list':mode==='list' || wrap}" @change="chagne">
<label class="checklist-box" :class="['is--'+mode,item.selected?'is-checked':'',(disabled || !!item.disabled)?'is-disable':'',index!==0&&mode==='list'?'is-list-border':'']"
:style="item.styleBackgroud" v-for="(item,index) in dataList" :key="index">
<checkbox class="hidden" hidden :disabled="disabled || !!item.disabled" :value="item[map.value]+''" :checked="item.selected" />
<view v-if="(mode !=='tag' && mode !== 'list') || ( mode === 'list' && icon === 'left')" class="checkbox__inner" :style="item.styleIcon">
<view class="checkbox__inner-icon"></view>
</view>
<view class="checklist-content" :class="{'list-content':mode === 'list' && icon ==='left'}">
<text class="checklist-text" :style="item.styleIconText">{{item[map.text]}}</text>
<view v-if="mode === 'list' && icon === 'right'" class="checkobx__list" :style="item.styleBackgroud"></view>
</view>
</label>
</checkbox-group>
<radio-group v-else class="checklist-group" :class="{'is-list':mode==='list','is-wrap':wrap}" @change="chagne">
<!-- -->
<label class="checklist-box" :class="['is--'+mode,item.selected?'is-checked':'',(disabled || !!item.disabled)?'is-disable':'',index!==0&&mode==='list'?'is-list-border':'']"
:style="item.styleBackgroud" v-for="(item,index) in dataList" :key="index">
<radio class="hidden" hidden :disabled="disabled || item.disabled" :value="item[map.value]+''" :checked="item.selected" />
<view v-if="(mode !=='tag' && mode !== 'list') || ( mode === 'list' && icon === 'left')" class="radio__inner"
:style="item.styleBackgroud">
<view class="radio__inner-icon" :style="item.styleIcon"></view>
</view>
<view class="checklist-content" :class="{'list-content':mode === 'list' && icon ==='left'}">
<text class="checklist-text" :style="item.styleIconText">{{item[map.text]}}</text>
<view v-if="mode === 'list' && icon === 'right'" :style="item.styleRightIcon" class="checkobx__list"></view>
</view>
</label>
</radio-group>
</template>
</view>
</template>
<script>
/**
* DataChecklist 数据选择器
* @description 通过数据渲染 checkbox 和 radio
* @tutorial https://ext.dcloud.net.cn/plugin?id=xxx
* @property {String} mode = [default| list | button | tag] 显示模式
* @value default 默认横排模式
* @value list 列表模式
* @value button 按钮模式
* @value tag 标签模式
* @property {Boolean} multiple = [true|false] 是否多选
* @property {Array|String|Number} value 默认值
* @property {Array} localdata 本地数据 ,格式 [{text:'',value:''}]
* @property {Number|String} min 最小选择个数 ,multiple为true时生效
* @property {Number|String} max 最大选择个数 ,multiple为true时生效
* @property {Boolean} wrap 是否换行显示
* @property {String} icon = [left|right] list 列表模式下icon显示位置
* @property {Boolean} selectedColor 选中颜色
* @property {Boolean} emptyText 没有数据时显示的文字 ,本地数据无效
* @property {Boolean} selectedTextColor 选中文本颜色,如不填写则自动显示
* @property {Object} map 字段映射, 默认 map={text:'text',value:'value'}
* @value left 左侧显示
* @value right 右侧显示
* @event {Function} change 选中发生变化触发
*/
export default {
name: 'uniDataChecklist',
mixins: [uniCloud.mixinDatacom || {}],
emits:['input','update:modelValue','change'],
props: {
mode: {
type: String,
default: 'default'
},
multiple: {
type: Boolean,
default: false
},
value: {
type: [Array, String, Number],
default () {
return ''
}
},
// TODO vue3
modelValue: {
type: [Array, String, Number],
default() {
return '';
}
},
localdata: {
type: Array,
default () {
return []
}
},
min: {
type: [Number, String],
default: ''
},
max: {
type: [Number, String],
default: ''
},
wrap: {
type: Boolean,
default: false
},
icon: {
type: String,
default: 'left'
},
selectedColor: {
type: String,
default: ''
},
selectedTextColor: {
type: String,
default: ''
},
emptyText:{
type: String,
default: '暂无数据'
},
disabled:{
type: Boolean,
default: false
},
map:{
type: Object,
default(){
return {
text:'text',
value:'value'
}
}
}
},
watch: {
localdata: {
handler(newVal) {
this.range = newVal
this.dataList = this.getDataList(this.getSelectedValue(newVal))
},
deep: true
},
mixinDatacomResData(newVal) {
this.range = newVal
this.dataList = this.getDataList(this.getSelectedValue(newVal))
},
value(newVal) {
this.dataList = this.getDataList(newVal)
// fix by mehaotian is_reset 在 uni-forms 中定义
// if(!this.is_reset){
// this.is_reset = false
// this.formItem && this.formItem.setValue(newVal)
// }
},
modelValue(newVal) {
this.dataList = this.getDataList(newVal);
// if(!this.is_reset){
// this.is_reset = false
// this.formItem && this.formItem.setValue(newVal)
// }
}
},
data() {
return {
dataList: [],
range: [],
contentText: {
contentdown: '查看更多',
contentrefresh: '加载中',
contentnomore: '没有更多'
},
isLocal:true,
styles: {
selectedColor: '#2979ff',
selectedTextColor: '#666',
},
isTop:0
};
},
computed:{
dataValue(){
if(this.value === '')return this.modelValue
if(this.modelValue === '') return this.value
return this.value
}
},
created() {
// this.form = this.getForm('uniForms')
// this.formItem = this.getForm('uniFormsItem')
// this.formItem && this.formItem.setValue(this.value)
// if (this.formItem) {
// this.isTop = 6
// if (this.formItem.name) {
// // 如果存在name添加默认值,否则formData 中不存在这个字段不校验
// if(!this.is_reset){
// this.is_reset = false
// this.formItem.setValue(this.dataValue)
// }
// this.rename = this.formItem.name
// this.form.inputChildrens.push(this)
// }
// }
if (this.localdata && this.localdata.length !== 0) {
this.isLocal = true
this.range = this.localdata
this.dataList = this.getDataList(this.getSelectedValue(this.range))
} else {
if (this.collection) {
this.isLocal = false
this.loadData()
}
}
},
methods: {
loadData() {
this.mixinDatacomGet().then(res=>{
this.mixinDatacomResData = res.result.data
if(this.mixinDatacomResData.length === 0){
this.isLocal = false
this.mixinDatacomErrorMessage = this.emptyText
}else{
this.isLocal = true
}
}).catch(err=>{
this.mixinDatacomErrorMessage = err.message
})
},
/**
* 获取父元素实例
*/
getForm(name = 'uniForms') {
let parent = this.$parent;
let parentName = parent.$options.name;
while (parentName !== name) {
parent = parent.$parent;
if (!parent) return false
parentName = parent.$options.name;
}
return parent;
},
chagne(e) {
const values = e.detail.value
let detail = {
value: [],
data: []
}
if (this.multiple) {
this.range.forEach(item => {
if (values.includes(item[this.map.value] + '')) {
detail.value.push(item[this.map.value])
detail.data.push(item)
}
})
} else {
const range = this.range.find(item => (item[this.map.value] + '') === values)
if (range) {
detail = {
value: range[this.map.value],
data: range
}
}
}
// this.formItem && this.formItem.setValue(detail.value)
// TODO 兼容 vue2
this.$emit('input', detail.value);
// // TOTO 兼容 vue3
this.$emit('update:modelValue', detail.value);
this.$emit('change', {
detail
})
if (this.multiple) {
// 如果 v-model 没有绑定 ,则走内部逻辑
// if (this.value.length === 0) {
this.dataList = this.getDataList(detail.value, true)
// }
} else {
this.dataList = this.getDataList(detail.value)
}
},
/**
* 获取渲染的新数组
* @param {Object} value 选中内容
*/
getDataList(value) {
// 解除引用关系,破坏原引用关系,避免污染源数据
let dataList = JSON.parse(JSON.stringify(this.range))
let list = []
if (this.multiple) {
if (!Array.isArray(value)) {
value = []
}
}
dataList.forEach((item, index) => {
item.disabled = item.disable || item.disabled || false
if (this.multiple) {
if (value.length > 0) {
let have = value.find(val => val === item[this.map.value])
item.selected = have !== undefined
} else {
item.selected = false
}
} else {
item.selected = value === item[this.map.value]
}
list.push(item)
})
return this.setRange(list)
},
/**
* 处理最大最小值
* @param {Object} list
*/
setRange(list) {
let selectList = list.filter(item => item.selected)
let min = Number(this.min) || 0
let max = Number(this.max) || ''
list.forEach((item, index) => {
if (this.multiple) {
if (selectList.length <= min) {
let have = selectList.find(val => val[this.map.value] === item[this.map.value])
if (have !== undefined) {
item.disabled = true
}
}
if (selectList.length >= max && max !== '') {
let have = selectList.find(val => val[this.map.value] === item[this.map.value])
if (have === undefined) {
item.disabled = true
}
}
}
this.setStyles(item, index)
list[index] = item
})
return list
},
/**
* 设置 class
* @param {Object} item
* @param {Object} index
*/
setStyles(item, index) {
// 设置自定义样式
item.styleBackgroud = this.setStyleBackgroud(item)
item.styleIcon = this.setStyleIcon(item)
item.styleIconText = this.setStyleIconText(item)
item.styleRightIcon = this.setStyleRightIcon(item)
},
/**
* 获取选中值
* @param {Object} range
*/
getSelectedValue(range) {
if (!this.multiple) return this.dataValue
let selectedArr = []
range.forEach((item) => {
if (item.selected) {
selectedArr.push(item[this.map.value])
}
})
return this.dataValue.length > 0 ? this.dataValue : selectedArr
},
/**
* 设置背景样式
*/
setStyleBackgroud(item) {
let styles = {}
let selectedColor = this.selectedColor?this.selectedColor:'#2979ff'
if (this.selectedColor) {
if (this.mode !== 'list') {
styles['border-color'] = item.selected?selectedColor:'#DCDFE6'
}
if (this.mode === 'tag') {
styles['background-color'] = item.selected? selectedColor:'#f5f5f5'
}
}
let classles = ''
for (let i in styles) {
classles += `${i}:${styles[i]};`
}
return classles
},
setStyleIcon(item) {
let styles = {}
let classles = ''
if (this.selectedColor) {
let selectedColor = this.selectedColor?this.selectedColor:'#2979ff'
styles['background-color'] = item.selected?selectedColor:'#fff'
styles['border-color'] = item.selected?selectedColor:'#DCDFE6'
if(!item.selected && item.disabled){
styles['background-color'] = '#F2F6FC'
styles['border-color'] = item.selected?selectedColor:'#DCDFE6'
}
}
for (let i in styles) {
classles += `${i}:${styles[i]};`
}
return classles
},
setStyleIconText(item) {
let styles = {}
let classles = ''
if (this.selectedColor) {
let selectedColor = this.selectedColor?this.selectedColor:'#2979ff'
if (this.mode === 'tag') {
styles.color = item.selected?(this.selectedTextColor?this.selectedTextColor:'#fff'):'#666'
} else {
styles.color = item.selected?(this.selectedTextColor?this.selectedTextColor:selectedColor):'#666'
}
if(!item.selected && item.disabled){
styles.color = '#999'
}
}
for (let i in styles) {
classles += `${i}:${styles[i]};`
}
return classles
},
setStyleRightIcon(item) {
let styles = {}
let classles = ''
if (this.mode === 'list') {
styles['border-color'] = item.selected?this.styles.selectedColor:'#DCDFE6'
}
for (let i in styles) {
classles += `${i}:${styles[i]};`
}
return classles
}
}
}
</script>
<style lang="scss">
$uni-primary: #2979ff !default;
$border-color: #DCDFE6;
$disable:0.4;
@mixin flex {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
}
.uni-data-loading {
@include flex;
flex-direction: row;
justify-content: center;
align-items: center;
height: 36px;
padding-left: 10px;
color: #999;
}
.uni-data-checklist {
position: relative;
z-index: 0;
flex: 1;
// 多选样式
.checklist-group {
@include flex;
flex-direction: row;
flex-wrap: wrap;
&.is-list {
flex-direction: column;
}
.checklist-box {
@include flex;
flex-direction: row;
align-items: center;
position: relative;
margin: 5px 0;
margin-right: 25px;
.hidden {
position: absolute;
opacity: 0;
}
// 文字样式
.checklist-content {
@include flex;
flex: 1;
flex-direction: row;
align-items: center;
justify-content: space-between;
.checklist-text {
font-size: 14px;
color: #666;
margin-left: 5px;
line-height: 14px;
}
.checkobx__list {
border-right-width: 1px;
border-right-color: #007aff;
border-right-style: solid;
border-bottom-width:1px;
border-bottom-color: #007aff;
border-bottom-style: solid;
height: 12px;
width: 6px;
left: -5px;
transform-origin: center;
transform: rotate(45deg);
opacity: 0;
}
}
// 多选样式
.checkbox__inner {
/* #ifndef APP-NVUE */
flex-shrink: 0;
box-sizing: border-box;
/* #endif */
position: relative;
width: 16px;
height: 16px;
border: 1px solid $border-color;
border-radius: 4px;
background-color: #fff;
z-index: 1;
.checkbox__inner-icon {
position: absolute;
/* #ifdef APP-NVUE */
top: 2px;
/* #endif */
/* #ifndef APP-NVUE */
top: 1px;
/* #endif */
left: 5px;
height: 8px;
width: 4px;
border-right-width: 1px;
border-right-color: #fff;
border-right-style: solid;
border-bottom-width:1px ;
border-bottom-color: #fff;
border-bottom-style: solid;
opacity: 0;
transform-origin: center;
transform: rotate(40deg);
}
}
// 单选样式
.radio__inner {
@include flex;
/* #ifndef APP-NVUE */
flex-shrink: 0;
box-sizing: border-box;
/* #endif */
justify-content: center;
align-items: center;
position: relative;
width: 16px;
height: 16px;
border: 1px solid $border-color;
border-radius: 16px;
background-color: #fff;
z-index: 1;
.radio__inner-icon {
width: 8px;
height: 8px;
border-radius: 10px;
opacity: 0;
}
}
// 默认样式
&.is--default {
// 禁用
&.is-disable {
/* #ifdef H5 */
cursor: not-allowed;
/* #endif */
.checkbox__inner {
background-color: #F2F6FC;
border-color: $border-color;
/* #ifdef H5 */
cursor: not-allowed;
/* #endif */
}
.radio__inner {
background-color: #F2F6FC;
border-color: $border-color;
}
.checklist-text {
color: #999;
}
}
// 选中
&.is-checked {
.checkbox__inner {
border-color: $uni-primary;
background-color: $uni-primary;
.checkbox__inner-icon {
opacity: 1;
transform: rotate(45deg);
}
}
.radio__inner {
border-color: $uni-primary;
.radio__inner-icon {
opacity: 1;
background-color: $uni-primary;
}
}
.checklist-text {
color: $uni-primary;
}
// 选中禁用
&.is-disable {
.checkbox__inner {
opacity: $disable;
}
.checklist-text {
opacity: $disable;
}
.radio__inner {
opacity: $disable;
}
}
}
}
// 按钮样式
&.is--button {
margin-right: 10px;
padding: 5px 10px;
border: 1px $border-color solid;
border-radius: 3px;
transition: border-color 0.2s;
// 禁用
&.is-disable {
/* #ifdef H5 */
cursor: not-allowed;
/* #endif */
border: 1px #eee solid;
opacity: $disable;
.checkbox__inner {
background-color: #F2F6FC;
border-color: $border-color;
/* #ifdef H5 */
cursor: not-allowed;
/* #endif */
}
.radio__inner {
background-color: #F2F6FC;
border-color: $border-color;
/* #ifdef H5 */
cursor: not-allowed;
/* #endif */
}
.checklist-text {
color: #999;
}
}
&.is-checked {
border-color: $uni-primary;
.checkbox__inner {
border-color: $uni-primary;
background-color: $uni-primary;
.checkbox__inner-icon {
opacity: 1;
transform: rotate(45deg);
}
}
.radio__inner {
border-color: $uni-primary;
.radio__inner-icon {
opacity: 1;
background-color: $uni-primary;
}
}
.checklist-text {
color: $uni-primary;
}
// 选中禁用
&.is-disable {
opacity: $disable;
}
}
}
// 标签样式
&.is--tag {
margin-right: 10px;
padding: 5px 10px;
border: 1px $border-color solid;
border-radius: 3px;
background-color: #f5f5f5;
.checklist-text {
margin: 0;
color: #666;
}
// 禁用
&.is-disable {
/* #ifdef H5 */
cursor: not-allowed;
/* #endif */
opacity: $disable;
}
&.is-checked {
background-color: $uni-primary;
border-color: $uni-primary;
.checklist-text {
color: #fff;
}
}
}
// 列表样式
&.is--list {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
padding: 10px 15px;
padding-left: 0;
margin: 0;
&.is-list-border {
border-top: 1px #eee solid;
}
// 禁用
&.is-disable {
/* #ifdef H5 */
cursor: not-allowed;
/* #endif */
.checkbox__inner {
background-color: #F2F6FC;
border-color: $border-color;
/* #ifdef H5 */
cursor: not-allowed;
/* #endif */
}
.checklist-text {
color: #999;
}
}
&.is-checked {
.checkbox__inner {
border-color: $uni-primary;
background-color: $uni-primary;
.checkbox__inner-icon {
opacity: 1;
transform: rotate(45deg);
}
}
.radio__inner {
.radio__inner-icon {
opacity: 1;
}
}
.checklist-text {
color: $uni-primary;
}
.checklist-content {
.checkobx__list {
opacity: 1;
border-color: $uni-primary;
}
}
// 选中禁用
&.is-disable {
.checkbox__inner {
opacity: $disable;
}
.checklist-text {
opacity: $disable;
}
}
}
}
}
}
}
</style>
{
"id": "uni-data-checkbox",
"displayName": "uni-data-checkbox 数据选择器",
"version": "1.0.3",
"description": "通过数据驱动的单选框和复选框",
"keywords": [
"uni-ui",
"checkbox",
"单选",
"多选",
"单选多选"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": "^3.1.1"
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
"type": "component-vue"
},
"uni_modules": {
"dependencies": ["uni-load-more","uni-scss"],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}
## DataCheckbox 数据驱动的单选复选框
> **组件名:uni-data-checkbox**
> 代码块: `uDataCheckbox`
本组件是基于uni-app基础组件checkbox的封装。本组件要解决问题包括:
1. 数据绑定型组件:给本组件绑定一个data,会自动渲染一组候选内容。再以往,开发者需要编写不少代码实现类似功能
2. 自动的表单校验:组件绑定了data,且符合[uni-forms](https://ext.dcloud.net.cn/plugin?id=2773)组件的表单校验规范,搭配使用会自动实现表单校验
3. 本组件合并了单选多选
4. 本组件有若干风格选择,如普通的单选多选框、并列button风格、tag风格。开发者可以快速选择需要的风格。但作为一个封装组件,样式代码虽然不用自己写了,却会牺牲一定的样式自定义性
在uniCloud开发中,`DB Schema`中配置了enum枚举等类型后,在web控制台的[自动生成表单](https://uniapp.dcloud.io/uniCloud/schema?id=autocode)功能中,会自动生成``uni-data-checkbox``组件并绑定好data
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-data-checkbox)
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
\ No newline at end of file
## 1.3.3(2022-01-20)
- 新增 showText属性 ,是否显示文本
## 1.3.2(2022-01-19)
- 修复 nvue 平台下不显示文本的bug
## 1.3.1(2022-01-19)
- 修复 微信小程序平台样式选择器报警告的问题
## 1.3.0(2021-11-19)
- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-load-more](https://uniapp.dcloud.io/component/uniui/uni-load-more)
## 1.2.1(2021-08-24)
- 新增 支持国际化
## 1.2.0(2021-07-30)
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.1.8(2021-05-12)
- 新增 组件示例地址
## 1.1.7(2021-03-30)
- 修复 uni-load-more 在首页使用时,h5 平台报 'uni is not defined' 的 bug
## 1.1.6(2021-02-05)
- 调整为uni_modules目录规范
{
"uni-load-more.contentdown": "Pull up to show more",
"uni-load-more.contentrefresh": "loading...",
"uni-load-more.contentnomore": "No more data"
}
import en from './en.json'
import zhHans from './zh-Hans.json'
import zhHant from './zh-Hant.json'
export default {
en,
'zh-Hans': zhHans,
'zh-Hant': zhHant
}
{
"uni-load-more.contentdown": "上拉显示更多",
"uni-load-more.contentrefresh": "正在加载...",
"uni-load-more.contentnomore": "没有更多数据了"
}
{
"uni-load-more.contentdown": "上拉顯示更多",
"uni-load-more.contentrefresh": "正在加載...",
"uni-load-more.contentnomore": "沒有更多數據了"
}
<template>
<view class="uni-load-more" @click="onClick">
<!-- #ifdef APP-NVUE -->
<loading-indicator v-if="!webviewHide && status === 'loading' && showIcon"
:style="{color: color,width:iconSize+'px',height:iconSize+'px'}" :animating="true"
class="uni-load-more__img uni-load-more__img--nvue"></loading-indicator>
<!-- #endif -->
<!-- #ifdef H5 -->
<svg width="24" height="24" viewBox="25 25 50 50"
v-if="!webviewHide && (iconType==='circle' || iconType==='auto' && platform === 'android') && status === 'loading' && showIcon"
:style="{width:iconSize+'px',height:iconSize+'px'}"
class="uni-load-more__img uni-load-more__img--android-H5">
<circle cx="50" cy="50" r="20" fill="none" :style="{color:color}" :stroke-width="3"></circle>
</svg>
<!-- #endif -->
<!-- #ifndef APP-NVUE || H5 -->
<view
v-if="!webviewHide && (iconType==='circle' || iconType==='auto' && platform === 'android') && status === 'loading' && showIcon"
:style="{width:iconSize+'px',height:iconSize+'px'}"
class="uni-load-more__img uni-load-more__img--android-MP">
<view class="uni-load-more__img-icon" :style="{borderTopColor:color,borderTopWidth:iconSize/12}"></view>
<view class="uni-load-more__img-icon" :style="{borderTopColor:color,borderTopWidth:iconSize/12}"></view>
<view class="uni-load-more__img-icon" :style="{borderTopColor:color,borderTopWidth:iconSize/12}"></view>
</view>
<!-- #endif -->
<!-- #ifndef APP-NVUE -->
<view v-else-if="!webviewHide && status === 'loading' && showIcon"
:style="{width:iconSize+'px',height:iconSize+'px'}" class="uni-load-more__img uni-load-more__img--ios-H5">
<image :src="imgBase64" mode="widthFix"></image>
</view>
<!-- #endif -->
<text v-if="showText" class="uni-load-more__text"
:style="{color: color}">{{ status === 'more' ? contentdownText : status === 'loading' ? contentrefreshText : contentnomoreText }}</text>
</view>
</template>
<script>
let platform
setTimeout(() => {
platform = uni.getSystemInfoSync().platform
}, 16)
import {
initVueI18n
} from '@dcloudio/uni-i18n'
import messages from './i18n/index.js'
const {
t
} = initVueI18n(messages)
/**
* LoadMore 加载更多
* @description 用于列表中,做滚动加载使用,展示 loading 的各种状态
* @tutorial https://ext.dcloud.net.cn/plugin?id=29
* @property {String} status = [more|loading|noMore] loading 的状态
* @value more loading前
* @value loading loading中
* @value noMore 没有更多了
* @property {Number} iconSize 指定图标大小
* @property {Boolean} iconSize = [true|false] 是否显示 loading 图标
* @property {String} iconType = [snow|circle|auto] 指定图标样式
* @value snow ios雪花加载样式
* @value circle 安卓唤醒加载样式
* @value auto 根据平台自动选择加载样式
* @property {String} color 图标和文字颜色
* @property {Object} contentText 各状态文字说明,值为:{contentdown: "上拉显示更多",contentrefresh: "正在加载...",contentnomore: "没有更多数据了"}
* @event {Function} clickLoadMore 点击加载更多时触发
*/
export default {
name: 'UniLoadMore',
emits: ['clickLoadMore'],
props: {
status: {
// 上拉的状态:more-loading前;loading-loading中;noMore-没有更多了
type: String,
default: 'more'
},
showIcon: {
type: Boolean,
default: true
},
iconType: {
type: String,
default: 'auto'
},
iconSize: {
type: Number,
default: 24
},
color: {
type: String,
default: '#777777'
},
contentText: {
type: Object,
default () {
return {
contentdown: '',
contentrefresh: '',
contentnomore: ''
}
}
},
showText: {
type: Boolean,
default: true
}
},
data() {
return {
webviewHide: false,
platform: platform,
imgBase64: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QzlBMzU3OTlEOUM0MTFFOUI0NTZDNERBQURBQzI4RkUiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QzlBMzU3OUFEOUM0MTFFOUI0NTZDNERBQURBQzI4RkUiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpDOUEzNTc5N0Q5QzQxMUU5QjQ1NkM0REFBREFDMjhGRSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpDOUEzNTc5OEQ5QzQxMUU5QjQ1NkM0REFBREFDMjhGRSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pt+ALSwAAA6CSURBVHja1FsLkFZV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'
}
},
computed: {
iconSnowWidth() {
return (Math.floor(this.iconSize / 24) || 1) * 2
},
contentdownText() {
return this.contentText.contentdown || t("uni-load-more.contentdown")
},
contentrefreshText() {
return this.contentText.contentrefresh || t("uni-load-more.contentrefresh")
},
contentnomoreText() {
return this.contentText.contentnomore || t("uni-load-more.contentnomore")
}
},
mounted() {
// #ifdef APP-PLUS
var pages = getCurrentPages();
var page = pages[pages.length - 1];
var currentWebview = page.$getAppWebview();
currentWebview.addEventListener('hide', () => {
this.webviewHide = true
})
currentWebview.addEventListener('show', () => {
this.webviewHide = false
})
// #endif
},
methods: {
onClick() {
this.$emit('clickLoadMore', {
detail: {
status: this.status,
}
})
}
}
}
</script>
<style lang="scss" >
.uni-load-more {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
height: 40px;
align-items: center;
justify-content: center;
}
.uni-load-more__text {
font-size: 14px;
margin-left: 8px;
}
.uni-load-more__img {
width: 24px;
height: 24px;
// margin-right: 8px;
}
.uni-load-more__img--nvue {
color: #666666;
}
.uni-load-more__img--android,
.uni-load-more__img--ios {
width: 24px;
height: 24px;
transform: rotate(0deg);
}
/* #ifndef APP-NVUE */
.uni-load-more__img--android {
animation: loading-ios 1s 0s linear infinite;
}
@keyframes loading-android {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.uni-load-more__img--ios-H5 {
position: relative;
animation: loading-ios-H5 1s 0s step-end infinite;
}
.uni-load-more__img--ios-H5 image {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
}
@keyframes loading-ios-H5 {
0% {
transform: rotate(0deg);
}
8% {
transform: rotate(30deg);
}
16% {
transform: rotate(60deg);
}
24% {
transform: rotate(90deg);
}
32% {
transform: rotate(120deg);
}
40% {
transform: rotate(150deg);
}
48% {
transform: rotate(180deg);
}
56% {
transform: rotate(210deg);
}
64% {
transform: rotate(240deg);
}
73% {
transform: rotate(270deg);
}
82% {
transform: rotate(300deg);
}
91% {
transform: rotate(330deg);
}
100% {
transform: rotate(360deg);
}
}
/* #endif */
/* #ifdef H5 */
.uni-load-more__img--android-H5 {
animation: loading-android-H5-rotate 2s linear infinite;
transform-origin: center center;
}
.uni-load-more__img--android-H5 circle {
display: inline-block;
animation: loading-android-H5-dash 1.5s ease-in-out infinite;
stroke: currentColor;
stroke-linecap: round;
}
@keyframes loading-android-H5-rotate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
@keyframes loading-android-H5-dash {
0% {
stroke-dasharray: 1, 200;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -40;
}
100% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -120;
}
}
/* #endif */
/* #ifndef APP-NVUE || H5 */
.uni-load-more__img--android-MP {
position: relative;
width: 24px;
height: 24px;
transform: rotate(0deg);
animation: loading-ios 1s 0s ease infinite;
}
.uni-load-more__img--android-MP .uni-load-more__img-icon {
position: absolute;
box-sizing: border-box;
width: 100%;
height: 100%;
border-radius: 50%;
border: solid 2px transparent;
border-top: solid 2px #777777;
transform-origin: center;
}
.uni-load-more__img--android-MP .uni-load-more__img-icon:nth-child(1) {
animation: loading-android-MP-1 1s 0s linear infinite;
}
.uni-load-more__img--android-MP .uni-load-more__img-icon:nth-child(2) {
animation: loading-android-MP-2 1s 0s linear infinite;
}
.uni-load-more__img--android-MP .uni-load-more__img-icon:nth-child(3) {
animation: loading-android-MP-3 1s 0s linear infinite;
}
@keyframes loading-android {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
@keyframes loading-android-MP-1 {
0% {
transform: rotate(0deg);
}
50% {
transform: rotate(90deg);
}
100% {
transform: rotate(360deg);
}
}
@keyframes loading-android-MP-2 {
0% {
transform: rotate(0deg);
}
50% {
transform: rotate(180deg);
}
100% {
transform: rotate(360deg);
}
}
@keyframes loading-android-MP-3 {
0% {
transform: rotate(0deg);
}
50% {
transform: rotate(270deg);
}
100% {
transform: rotate(360deg);
}
}
/* #endif */
</style>
{
"id": "uni-load-more",
"displayName": "uni-load-more 加载更多",
"version": "1.3.3",
"description": "LoadMore 组件,常用在列表里面,做滚动加载使用。",
"keywords": [
"uni-ui",
"uniui",
"加载更多",
"load-more"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
},
"uni_modules": {
"dependencies": ["uni-scss"],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}
\ No newline at end of file
### LoadMore 加载更多
> **组件名:uni-load-more**
> 代码块: `uLoadMore`
用于列表中,做滚动加载使用,展示 loading 的各种状态。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-load-more)
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
## 1.0.3(2022-01-21)
- 优化 组件示例
## 1.0.2(2021-11-22)
- 修复 / 符号在 vue 不同版本兼容问题引起的报错问题
## 1.0.1(2021-11-22)
- 修复 vue3中scss语法兼容问题
## 1.0.0(2021-11-18)
- init
@import './styles/index.scss';
{
"id": "uni-scss",
"displayName": "uni-scss 辅助样式",
"version": "1.0.3",
"description": "uni-sass是uni-ui提供的一套全局样式 ,通过一些简单的类名和sass变量,实现简单的页面布局操作,比如颜色、边距、圆角等。",
"keywords": [
"uni-scss",
"uni-ui",
"辅助样式"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": "^3.1.0"
},
"dcloudext": {
"category": [
"JS SDK",
"通用 SDK"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "u"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "n",
"联盟": "n"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}
`uni-sass``uni-ui`提供的一套全局样式 ,通过一些简单的类名和`sass`变量,实现简单的页面布局操作,比如颜色、边距、圆角等。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-sass)
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
\ No newline at end of file
@import './setting/_variables.scss';
@import './setting/_border.scss';
@import './setting/_color.scss';
@import './setting/_space.scss';
@import './setting/_radius.scss';
@import './setting/_text.scss';
@import './setting/_styles.scss';
.uni-border {
border: 1px $uni-border-1 solid;
}
\ No newline at end of file
// TODO 暂时不需要 class ,需要用户使用变量实现 ,如果使用类名其实并不推荐
// @mixin get-styles($k,$c) {
// @if $k == size or $k == weight{
// font-#{$k}:#{$c}
// }@else{
// #{$k}:#{$c}
// }
// }
$uni-ui-color:(
// 主色
primary: $uni-primary,
primary-disable: $uni-primary-disable,
primary-light: $uni-primary-light,
// 辅助色
success: $uni-success,
success-disable: $uni-success-disable,
success-light: $uni-success-light,
warning: $uni-warning,
warning-disable: $uni-warning-disable,
warning-light: $uni-warning-light,
error: $uni-error,
error-disable: $uni-error-disable,
error-light: $uni-error-light,
info: $uni-info,
info-disable: $uni-info-disable,
info-light: $uni-info-light,
// 中性色
main-color: $uni-main-color,
base-color: $uni-base-color,
secondary-color: $uni-secondary-color,
extra-color: $uni-extra-color,
// 背景色
bg-color: $uni-bg-color,
// 边框颜色
border-1: $uni-border-1,
border-2: $uni-border-2,
border-3: $uni-border-3,
border-4: $uni-border-4,
// 黑色
black:$uni-black,
// 白色
white:$uni-white,
// 透明
transparent:$uni-transparent
) !default;
@each $key, $child in $uni-ui-color {
.uni-#{"" + $key} {
color: $child;
}
.uni-#{"" + $key}-bg {
background-color: $child;
}
}
.uni-shadow-sm {
box-shadow: $uni-shadow-sm;
}
.uni-shadow-base {
box-shadow: $uni-shadow-base;
}
.uni-shadow-lg {
box-shadow: $uni-shadow-lg;
}
.uni-mask {
background-color:$uni-mask;
}
@mixin radius($r,$d:null ,$important: false){
$radius-value:map-get($uni-radius, $r) if($important, !important, null);
// Key exists within the $uni-radius variable
@if (map-has-key($uni-radius, $r) and $d){
@if $d == t {
border-top-left-radius:$radius-value;
border-top-right-radius:$radius-value;
}@else if $d == r {
border-top-right-radius:$radius-value;
border-bottom-right-radius:$radius-value;
}@else if $d == b {
border-bottom-left-radius:$radius-value;
border-bottom-right-radius:$radius-value;
}@else if $d == l {
border-top-left-radius:$radius-value;
border-bottom-left-radius:$radius-value;
}@else if $d == tl {
border-top-left-radius:$radius-value;
}@else if $d == tr {
border-top-right-radius:$radius-value;
}@else if $d == br {
border-bottom-right-radius:$radius-value;
}@else if $d == bl {
border-bottom-left-radius:$radius-value;
}
}@else{
border-radius:$radius-value;
}
}
@each $key, $child in $uni-radius {
@if($key){
.uni-radius-#{"" + $key} {
@include radius($key)
}
}@else{
.uni-radius {
@include radius($key)
}
}
}
@each $direction in t, r, b, l,tl, tr, br, bl {
@each $key, $child in $uni-radius {
@if($key){
.uni-radius-#{"" + $direction}-#{"" + $key} {
@include radius($key,$direction,false)
}
}@else{
.uni-radius-#{$direction} {
@include radius($key,$direction,false)
}
}
}
}
@mixin fn($space,$direction,$size,$n) {
@if $n {
#{$space}-#{$direction}: #{$size*$uni-space-root}px
} @else {
#{$space}-#{$direction}: #{-$size*$uni-space-root}px
}
}
@mixin get-styles($direction,$i,$space,$n){
@if $direction == t {
@include fn($space, top,$i,$n);
}
@if $direction == r {
@include fn($space, right,$i,$n);
}
@if $direction == b {
@include fn($space, bottom,$i,$n);
}
@if $direction == l {
@include fn($space, left,$i,$n);
}
@if $direction == x {
@include fn($space, left,$i,$n);
@include fn($space, right,$i,$n);
}
@if $direction == y {
@include fn($space, top,$i,$n);
@include fn($space, bottom,$i,$n);
}
@if $direction == a {
@if $n {
#{$space}:#{$i*$uni-space-root}px;
} @else {
#{$space}:#{-$i*$uni-space-root}px;
}
}
}
@each $orientation in m,p {
$space: margin;
@if $orientation == m {
$space: margin;
} @else {
$space: padding;
}
@for $i from 0 through 16 {
@each $direction in t, r, b, l, x, y, a {
.uni-#{$orientation}#{$direction}-#{$i} {
@include get-styles($direction,$i,$space,true);
}
.uni-#{$orientation}#{$direction}-n#{$i} {
@include get-styles($direction,$i,$space,false);
}
}
}
}
\ No newline at end of file
/* #ifndef APP-NVUE */
$-color-white:#fff;
$-color-black:#000;
@mixin base-style($color) {
color: #fff;
background-color: $color;
border-color: mix($-color-black, $color, 8%);
&:not([hover-class]):active {
background: mix($-color-black, $color, 10%);
border-color: mix($-color-black, $color, 20%);
color: $-color-white;
outline: none;
}
}
@mixin is-color($color) {
@include base-style($color);
&[loading] {
@include base-style($color);
&::before {
margin-right:5px;
}
}
&[disabled] {
&,
&[loading],
&:not([hover-class]):active {
color: $-color-white;
border-color: mix(darken($color,10%), $-color-white);
background-color: mix($color, $-color-white);
}
}
}
@mixin base-plain-style($color) {
color:$color;
background-color: mix($-color-white, $color, 90%);
border-color: mix($-color-white, $color, 70%);
&:not([hover-class]):active {
background: mix($-color-white, $color, 80%);
color: $color;
outline: none;
border-color: mix($-color-white, $color, 50%);
}
}
@mixin is-plain($color){
&[plain] {
@include base-plain-style($color);
&[loading] {
@include base-plain-style($color);
&::before {
margin-right:5px;
}
}
&[disabled] {
&,
&:active {
color: mix($-color-white, $color, 40%);
background-color: mix($-color-white, $color, 90%);
border-color: mix($-color-white, $color, 80%);
}
}
}
}
.uni-btn {
margin: 5px;
color: #393939;
border:1px solid #ccc;
font-size: 16px;
font-weight: 200;
background-color: #F9F9F9;
// TODO 暂时处理边框隐藏一边的问题
overflow: visible;
&::after{
border: none;
}
&:not([type]),&[type=default] {
color: #999;
&[loading] {
background: none;
&::before {
margin-right:5px;
}
}
&[disabled]{
color: mix($-color-white, #999, 60%);
&,
&[loading],
&:active {
color: mix($-color-white, #999, 60%);
background-color: mix($-color-white,$-color-black , 98%);
border-color: mix($-color-white, #999, 85%);
}
}
&[plain] {
color: #999;
background: none;
border-color: $uni-border-1;
&:not([hover-class]):active {
background: none;
color: mix($-color-white, $-color-black, 80%);
border-color: mix($-color-white, $-color-black, 90%);
outline: none;
}
&[disabled]{
&,
&[loading],
&:active {
background: none;
color: mix($-color-white, #999, 60%);
border-color: mix($-color-white, #999, 85%);
}
}
}
}
&:not([hover-class]):active {
color: mix($-color-white, $-color-black, 50%);
}
&[size=mini] {
font-size: 16px;
font-weight: 200;
border-radius: 8px;
}
&.uni-btn-small {
font-size: 14px;
}
&.uni-btn-mini {
font-size: 12px;
}
&.uni-btn-radius {
border-radius: 999px;
}
&[type=primary] {
@include is-color($uni-primary);
@include is-plain($uni-primary)
}
&[type=success] {
@include is-color($uni-success);
@include is-plain($uni-success)
}
&[type=error] {
@include is-color($uni-error);
@include is-plain($uni-error)
}
&[type=warning] {
@include is-color($uni-warning);
@include is-plain($uni-warning)
}
&[type=info] {
@include is-color($uni-info);
@include is-plain($uni-info)
}
}
/* #endif */
@mixin get-styles($k,$c) {
@if $k == size or $k == weight{
font-#{$k}:#{$c}
}@else{
#{$k}:#{$c}
}
}
@each $key, $child in $uni-headings {
/* #ifndef APP-NVUE */
.uni-#{$key} {
@each $k, $c in $child {
@include get-styles($k,$c)
}
}
/* #endif */
/* #ifdef APP-NVUE */
.container .uni-#{$key} {
@each $k, $c in $child {
@include get-styles($k,$c)
}
}
/* #endif */
}
// @use "sass:math";
@import '../tools/functions.scss';
// 间距基础倍数
$uni-space-root: 2 !default;
// 边框半径默认值
$uni-radius-root:5px !default;
$uni-radius: () !default;
// 边框半径断点
$uni-radius: map-deep-merge(
(
0: 0,
// TODO 当前版本暂时不支持 sm 属性
// 'sm': math.div($uni-radius-root, 2),
null: $uni-radius-root,
'lg': $uni-radius-root * 2,
'xl': $uni-radius-root * 6,
'pill': 9999px,
'circle': 50%
),
$uni-radius
);
// 字体家族
$body-font-family: 'Roboto', sans-serif !default;
// 文本
$heading-font-family: $body-font-family !default;
$uni-headings: () !default;
$letterSpacing: -0.01562em;
$uni-headings: map-deep-merge(
(
'h1': (
size: 32px,
weight: 300,
line-height: 50px,
// letter-spacing:-0.01562em
),
'h2': (
size: 28px,
weight: 300,
line-height: 40px,
// letter-spacing: -0.00833em
),
'h3': (
size: 24px,
weight: 400,
line-height: 32px,
// letter-spacing: normal
),
'h4': (
size: 20px,
weight: 400,
line-height: 30px,
// letter-spacing: 0.00735em
),
'h5': (
size: 16px,
weight: 400,
line-height: 24px,
// letter-spacing: normal
),
'h6': (
size: 14px,
weight: 500,
line-height: 18px,
// letter-spacing: 0.0125em
),
'subtitle': (
size: 12px,
weight: 400,
line-height: 20px,
// letter-spacing: 0.00937em
),
'body': (
font-size: 14px,
font-weight: 400,
line-height: 22px,
// letter-spacing: 0.03125em
),
'caption': (
'size': 12px,
'weight': 400,
'line-height': 20px,
// 'letter-spacing': 0.03333em,
// 'text-transform': false
)
),
$uni-headings
);
// 主色
$uni-primary: #2979ff !default;
$uni-primary-disable:lighten($uni-primary,20%) !default;
$uni-primary-light: lighten($uni-primary,25%) !default;
// 辅助色
// 除了主色外的场景色,需要在不同的场景中使用(例如危险色表示危险的操作)。
$uni-success: #18bc37 !default;
$uni-success-disable:lighten($uni-success,20%) !default;
$uni-success-light: lighten($uni-success,25%) !default;
$uni-warning: #f3a73f !default;
$uni-warning-disable:lighten($uni-warning,20%) !default;
$uni-warning-light: lighten($uni-warning,25%) !default;
$uni-error: #e43d33 !default;
$uni-error-disable:lighten($uni-error,20%) !default;
$uni-error-light: lighten($uni-error,25%) !default;
$uni-info: #8f939c !default;
$uni-info-disable:lighten($uni-info,20%) !default;
$uni-info-light: lighten($uni-info,25%) !default;
// 中性色
// 中性色用于文本、背景和边框颜色。通过运用不同的中性色,来表现层次结构。
$uni-main-color: #3a3a3a !default; // 主要文字
$uni-base-color: #6a6a6a !default; // 常规文字
$uni-secondary-color: #909399 !default; // 次要文字
$uni-extra-color: #c7c7c7 !default; // 辅助说明
// 边框颜色
$uni-border-1: #F0F0F0 !default;
$uni-border-2: #EDEDED !default;
$uni-border-3: #DCDCDC !default;
$uni-border-4: #B9B9B9 !default;
// 常规色
$uni-black: #000000 !default;
$uni-white: #ffffff !default;
$uni-transparent: rgba($color: #000000, $alpha: 0) !default;
// 背景色
$uni-bg-color: #f7f7f7 !default;
/* 水平间距 */
$uni-spacing-sm: 8px !default;
$uni-spacing-base: 15px !default;
$uni-spacing-lg: 30px !default;
// 阴影
$uni-shadow-sm:0 0 5px rgba($color: #d8d8d8, $alpha: 0.5) !default;
$uni-shadow-base:0 1px 8px 1px rgba($color: #a5a5a5, $alpha: 0.2) !default;
$uni-shadow-lg:0px 1px 10px 2px rgba($color: #a5a4a4, $alpha: 0.5) !default;
// 蒙版
$uni-mask: rgba($color: #000000, $alpha: 0.4) !default;
// 合并 map
@function map-deep-merge($parent-map, $child-map){
$result: $parent-map;
@each $key, $child in $child-map {
$parent-has-key: map-has-key($result, $key);
$parent-value: map-get($result, $key);
$parent-type: type-of($parent-value);
$child-type: type-of($child);
$parent-is-map: $parent-type == map;
$child-is-map: $child-type == map;
@if (not $parent-has-key) or ($parent-type != $child-type) or (not ($parent-is-map and $child-is-map)){
$result: map-merge($result, ( $key: $child ));
}@else {
$result: map-merge($result, ( $key: map-deep-merge($parent-value, $child) ));
}
}
@return $result;
};
// 间距基础倍数
$uni-space-root: 2;
// 边框半径默认值
$uni-radius-root:5px;
// 主色
$uni-primary: #2979ff;
// 辅助色
$uni-success: #4cd964;
// 警告色
$uni-warning: #f0ad4e;
// 错误色
$uni-error: #dd524d;
// 描述色
$uni-info: #909399;
// 中性色
$uni-main-color: #303133;
$uni-base-color: #606266;
$uni-secondary-color: #909399;
$uni-extra-color: #C0C4CC;
// 背景色
$uni-bg-color: #f5f5f5;
// 边框颜色
$uni-border-1: #DCDFE6;
$uni-border-2: #E4E7ED;
$uni-border-3: #EBEEF5;
$uni-border-4: #F2F6FC;
// 常规色
$uni-black: #000000;
$uni-white: #ffffff;
$uni-transparent: rgba($color: #000000, $alpha: 0);
@import './styles/setting/_variables.scss';
// 间距基础倍数
$uni-space-root: 2;
// 边框半径默认值
$uni-radius-root:5px;
// 主色
$uni-primary: #2979ff;
$uni-primary-disable:mix(#fff,$uni-primary,50%);
$uni-primary-light: mix(#fff,$uni-primary,80%);
// 辅助色
// 除了主色外的场景色,需要在不同的场景中使用(例如危险色表示危险的操作)。
$uni-success: #18bc37;
$uni-success-disable:mix(#fff,$uni-success,50%);
$uni-success-light: mix(#fff,$uni-success,80%);
$uni-warning: #f3a73f;
$uni-warning-disable:mix(#fff,$uni-warning,50%);
$uni-warning-light: mix(#fff,$uni-warning,80%);
$uni-error: #e43d33;
$uni-error-disable:mix(#fff,$uni-error,50%);
$uni-error-light: mix(#fff,$uni-error,80%);
$uni-info: #8f939c;
$uni-info-disable:mix(#fff,$uni-info,50%);
$uni-info-light: mix(#fff,$uni-info,80%);
// 中性色
// 中性色用于文本、背景和边框颜色。通过运用不同的中性色,来表现层次结构。
$uni-main-color: #3a3a3a; // 主要文字
$uni-base-color: #6a6a6a; // 常规文字
$uni-secondary-color: #909399; // 次要文字
$uni-extra-color: #c7c7c7; // 辅助说明
// 边框颜色
$uni-border-1: #F0F0F0;
$uni-border-2: #EDEDED;
$uni-border-3: #DCDCDC;
$uni-border-4: #B9B9B9;
// 常规色
$uni-black: #000000;
$uni-white: #ffffff;
$uni-transparent: rgba($color: #000000, $alpha: 0);
// 背景色
$uni-bg-color: #f7f7f7;
/* 水平间距 */
$uni-spacing-sm: 8px;
$uni-spacing-base: 15px;
$uni-spacing-lg: 30px;
// 阴影
$uni-shadow-sm:0 0 5px rgba($color: #d8d8d8, $alpha: 0.5);
$uni-shadow-base:0 1px 8px 1px rgba($color: #a5a5a5, $alpha: 0.2);
$uni-shadow-lg:0px 1px 10px 2px rgba($color: #a5a4a4, $alpha: 0.5);
// 蒙版
$uni-mask: rgba($color: #000000, $alpha: 0.4);
export const TokenKey: string = 'X-Litemall-Admin-Token'
export const TokenKey: string = 'X-Litemall-Admin-Token';
// 获取指定缓存
export const getCache= (key: string) => {
export const getCache = (key: string) => {
uni.getStorage({
key: key,
success: (res: any) => {
return res.data
return res.data;
}
})
}
});
};
// 获取缓存信息
export const getAllCache= () => {
export const getAllCache = () => {
uni.getStorageInfo({
success: (res: any) => {
return res
return res;
}
})
}
});
};
// 修改指定缓存
export const setCache = (key: string, data: any) => {
uni.setStorage({
key: key,
data
})
}
});
};
// 移除制定缓存
export const renoveCache = (key: any) => {
uni.removeStorage({
key
})
}
});
};
// 清除本地缓存
export const clearCache = () => {
uni.clearStorage()
}
\ No newline at end of file
uni.clearStorage();
};
export const toLogin = () => {
uni.getStorage({
key: 'token',
fail:(e: any) => {
if (e.errMsg == 'getStorage:fail data not found') {
uni.navigateTo({
url: '../login/login',
success(res: any) {
uni.showToast({
title: '请先登录',
icon: 'error'
});
}
});
}
}
});
};
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论