fix(code): 修正代码错误及不严谨的地方
This commit is contained in:
@@ -1,638 +0,0 @@
|
||||
<template>
|
||||
<view class="order-container" :class="{ 'safe-area': isIphoneX }">
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<view class="payment-navbar" :style="{ 'padding-top': menuButtonBounding.top + 'px', height: menuButtonBounding.height + 'px' }">
|
||||
<view class="nav-wrap">
|
||||
<text class="iconfont icon-back_light" @click="back"></text>
|
||||
<view class="navbar-title">确认订单</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="payment-navbar-block" :style="{ height: menuButtonBounding.bottom + 'px' }"></view>
|
||||
<!-- #endif -->
|
||||
|
||||
<scroll-view scroll-y="true" class="order-scroll-container">
|
||||
<view class="payment-navbar-block"></view>
|
||||
<template v-if="paymentData">
|
||||
<template v-if="paymentData.is_virtual">
|
||||
<!-- 虚拟商品联系方式 -->
|
||||
<view class="mobile-wrap">
|
||||
<view class="tips color-base-text">
|
||||
<text class="iconfont icongantanhao"></text>
|
||||
购买虚拟类商品需填写手机号,方便商家与您联系
|
||||
</view>
|
||||
<view class="form-group">
|
||||
<text class="icon">
|
||||
<image :src="$util.img('public/uniapp/order/icon-mobile.png')" mode="widthFix"></image>
|
||||
</text>
|
||||
<text class="text">手机号码</text>
|
||||
<input type="number" maxlength="11" placeholder="请输入您的手机号码" placeholder-class="color-tip placeholder" class="input" v-model="orderCreateData.member_address.mobile" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<!-- 配送方式 -->
|
||||
<view class="delivery-mode" v-if="goodsData.delivery.express_type.length > 1">
|
||||
<view class="action">
|
||||
<view :class="{ active: item.name == orderCreateData.delivery.delivery_type }" v-for="(item, index) in goodsData.delivery.express_type" :key="index" @click="selectDeliveryType(item)">
|
||||
{{ item.title }}
|
||||
<!-- 外圆角 -->
|
||||
<view class="out-radio"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="address-box" :class="{ 'not-delivery-type': goodsData.delivery.express_type.length <= 1 }" v-if="orderCreateData.delivery.delivery_type == 'express'">
|
||||
<view class="info-wrap" v-if="memberAddress" @click="selectAddress">
|
||||
<view class="content">
|
||||
<text class="name">{{ memberAddress.name ? memberAddress.name : '' }}</text>
|
||||
<text class="mobile">{{ memberAddress.mobile ? memberAddress.mobile : '' }}</text>
|
||||
<view class="desc-wrap">
|
||||
{{ memberAddress.full_address ? memberAddress.full_address : '' }}
|
||||
{{ memberAddress.address ? memberAddress.address : '' }}
|
||||
</view>
|
||||
</view>
|
||||
<text class="cell-more iconfont icon-right"></text>
|
||||
</view>
|
||||
<view class="empty-wrap" v-else @click="selectAddress">
|
||||
<view class="info">请设置收货地址</view>
|
||||
<view class="cell-more">
|
||||
<view class="iconfont icon-right"></view>
|
||||
</view>
|
||||
</view>
|
||||
<image class="address-line" :src="$util.img('public/uniapp/order/address-line.png')"></image>
|
||||
</view>
|
||||
|
||||
<view class="address-box" :class="{ 'not-delivery-type': goodsData.delivery.express_type.length <= 1 }" v-if="orderCreateData.delivery.delivery_type == 'local'">
|
||||
<view v-if="localMemberAddress">
|
||||
<block v-if="storeList && Object.keys(storeList).length > 1">
|
||||
<view class="local-delivery-store" v-if="storeInfo" @click="openPopup('deliveryPopup')">
|
||||
<view class="info">
|
||||
由
|
||||
<text class="store-name">{{ storeInfo.store_name }}</text>
|
||||
提供配送
|
||||
</view>
|
||||
<view class="cell-more">
|
||||
<text>点击切换</text>
|
||||
<text class="iconfont icon-right"></text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="local-delivery-store">
|
||||
<view class="info">
|
||||
<text class="store-name">您的附近没有可配送的门店,请选择其他配送方式</text>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<view class="info-wrap local" @click="selectAddress">
|
||||
<view class="content">
|
||||
<text class="name">{{ localMemberAddress.name ? localMemberAddress.name : '' }}
|
||||
</text>
|
||||
<text class="mobile">{{ localMemberAddress.mobile ? localMemberAddress.mobile : '' }}
|
||||
</text>
|
||||
<view class="desc-wrap">
|
||||
{{ localMemberAddress.full_address ? localMemberAddress.full_address : '' }}
|
||||
{{ localMemberAddress.address ? localMemberAddress.address : '' }}
|
||||
</view>
|
||||
</view>
|
||||
<text class="cell-more iconfont icon-right"></text>
|
||||
</view>
|
||||
<view class="local-box" v-if="calculateGoodsData.config.local && calculateGoodsData.delivery.local.info.time_is_open == 1">
|
||||
<view class="pick-block" @click="localtime('')">
|
||||
<view class="title font-size-base">送达时间</view>
|
||||
<view class="time-picker">
|
||||
<text :class="{ 'color-tip': !deliveryTime }">{{ deliveryTime ? deliveryTime : '请选择送达时间' }}</text>
|
||||
<text class="iconfont icon-right cell-more"></text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="empty-wrap" v-else @click="selectAddress">
|
||||
<view class="info">请设置收货地址</view>
|
||||
<view class="cell-more">
|
||||
<view class="iconfont icon-right"></view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<image class="address-line" :src="$util.img('public/uniapp/order/address-line.png')"></image>
|
||||
</view>
|
||||
|
||||
<!-- 门店信息 -->
|
||||
<view class="store-box" :class="{ 'not-delivery-type': goodsData.delivery.express_type.length <= 1 }" v-if="orderCreateData.delivery.delivery_type == 'store'">
|
||||
<block v-if="storeInfo">
|
||||
<view @click="openPopup('deliveryPopup')" class="store-info">
|
||||
<view class="store-address-info">
|
||||
<view class="info-wrap">
|
||||
<view class="title">
|
||||
<text>{{ storeInfo.store_name }}</text>
|
||||
</view>
|
||||
<view class="store-detail">
|
||||
<view v-if="storeInfo.open_date">营业时间:{{ storeInfo.open_date }}</view>
|
||||
<view class="address">{{ storeInfo.full_address }} {{ storeInfo.address }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="cell-more iconfont icon-right" v-if="storeList && Object.keys(storeList).length > 1"></view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="mobile-wrap store-mobile" v-if="orderCreateData.member_address">
|
||||
<view class="form-group">
|
||||
<text class="text">姓名</text>
|
||||
<input type="text" placeholder-class="color-tip placeholder" class="input" disabled v-model="orderCreateData.member_address.name" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="mobile-wrap store-mobile" v-if="orderCreateData.member_address">
|
||||
<view class="form-group">
|
||||
<text class="text">预留手机</text>
|
||||
<input type="number" maxlength="11" placeholder="请输入您的手机号码" placeholder-class="color-tip placeholder" class="input" v-model="orderCreateData.member_address.mobile" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="store-time" @click="storetime('')">
|
||||
<view class="left">提货时间</view>
|
||||
<view class="right">
|
||||
{{ deliveryTime }}
|
||||
<text class="iconfont icon-right"></text>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<view v-else class="empty">当前无自提门店,请选择其它配送方式</view>
|
||||
<image class="address-line" :src="$util.img('public/uniapp/order/address-line.png')"></image>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<!-- 店铺 -->
|
||||
<view class="site-wrap order-goods" v-if="calculateGoodsData">
|
||||
<view class="site-header">
|
||||
<view class="iconfont icon-dianpu"></view>
|
||||
<text class="site-name">门店</text>
|
||||
</view>
|
||||
<view class="site-body">
|
||||
<!-- 商品 -->
|
||||
<view class="goods-item" v-for="(goodsItem, goodsIndex) in calculateGoodsData.goods_list" :key="goodsIndex">
|
||||
<view class="goods-wrap">
|
||||
<view class="goods-img" @click="$util.redirectTo('/pages/goods/detail', { goods_id: goodsItem.goods_id })">
|
||||
<image :src="$util.img(goodsItem.sku_image, { size: 'mid' })" @error="imageError(goodsIndex)" mode="aspectFill"/>
|
||||
</view>
|
||||
<view class="goods-info">
|
||||
<view class="top-wrap">
|
||||
<view @click="$util.redirectTo('/pages/goods/detail', { goods_id: goodsItem.goods_id })" class="goods-name">{{ goodsItem.sku_name }}</view>
|
||||
<view class="sku" v-if="goodsItem.sku_spec_format">
|
||||
<view class="goods-spec">
|
||||
<block v-for="(x, i) in goodsItem.sku_spec_format" :key="i">
|
||||
<view>{{ x.spec_value_name }}</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
<block v-if="goodsItem.is_virtual == 0">
|
||||
<view class="error-tips" v-if="orderCreateData.delivery &&
|
||||
orderCreateData.delivery.delivery_type &&
|
||||
goodsItem.support_trade_type &&
|
||||
goodsItem.support_trade_type.indexOf(orderCreateData.delivery.delivery_type) == -1
|
||||
">
|
||||
<text class="iconfont icon-gantanhao"></text>
|
||||
<text>该商品不支持{{ orderCreateData.delivery.delivery_type_name }}</text>
|
||||
</view>
|
||||
</block>
|
||||
<view class="error-tips" v-if="goodsItem.error && goodsItem.error.message">
|
||||
<text class="iconfont icon-gantanhao"></text>
|
||||
<text>{{ goodsItem.error.message }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="goods-sub-section">
|
||||
<view class="color-base-text">
|
||||
<text class="unit price-style small">{{ $lang('common.currencySymbol') }}</text>
|
||||
<text class="goods-price price-style large">{{ parseFloat(goodsItem.price).toFixed(2).split('.')[0] }}</text>
|
||||
<text class="unit price-style small">.{{ parseFloat(goodsItem.price).toFixed(2).split('.')[1] }}</text>
|
||||
</view>
|
||||
<view>
|
||||
<text class="font-size-tag">x</text>
|
||||
<text class="font-size-base">{{ goodsItem.num }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="member-goods-card order-cell" v-if="calculateGoodsData.goods_list[goodsIndex].member_card_list" @click="selectMemberGoodsCard(goodsIndex)">
|
||||
<text class="tit">次卡抵扣</text>
|
||||
<view class="box text-overflow">
|
||||
<block v-if="calculateGoodsData.goods_list[goodsIndex].card_promotion_money">
|
||||
<text class="text">次卡抵扣{{ calculateGoodsData.goods_list[goodsIndex].card_use_num }}张/{{ calculateGoodsData.goods_list[goodsIndex].card_use_num }}次</text>
|
||||
<text class="price-font">-¥{{ calculateGoodsData.goods_list[goodsIndex].card_promotion_money | moneyFormat }}</text>
|
||||
</block>
|
||||
<text class="color-tip" v-else>请选择次卡</text>
|
||||
</view>
|
||||
<text class="iconfont icon-right"></text>
|
||||
</view>
|
||||
<view class="goods-form" v-if="goodsData.goods_list[goodsIndex].goods_form" @click="editForm(goodsIndex)">
|
||||
<ns-form :data="goodsData.goods_list[goodsIndex].goods_form.json_data" ref="goodsForm" :custom-attr="{ sku_id: goodsItem.sku_id, form_id: goodsData.goods_list[goodsIndex].goods_form.id }"/>
|
||||
<text class="cell-more iconfont icon-right"></text>
|
||||
<view class="shade"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="site-wrap buyer-message">
|
||||
<view class="order-cell">
|
||||
<text class="tit">买家留言</text>
|
||||
<view class="box text-overflow " @click="openPopup('buyerMessagePopup')">
|
||||
<text v-if="orderCreateData.buyer_message">{{ orderCreateData.buyer_message }}</text>
|
||||
<text class="color-sub" v-else>无留言</text>
|
||||
</view>
|
||||
<text class="iconfont icon-right"></text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="paymentData.system_form" class="system-form-wrap">
|
||||
<view class="order-cell">
|
||||
<text class="tit">{{ paymentData.system_form.form_name }}</text>
|
||||
</view>
|
||||
<ns-form :data="paymentData.system_form.json_data" ref="form"/>
|
||||
</view>
|
||||
|
||||
<view class="site-wrap" v-if="calculateGoodsData || promotionInfo || (calculateGoodsData && calculateGoodsData.max_usable_point > 0) || goodsData.invoice">
|
||||
<view class="site-footer">
|
||||
<view class="order-cell coupon" v-if="modules.indexOf('coupon') != -1">
|
||||
<text class="tit">优惠券</text>
|
||||
<view class="box text-overflow" @click="openPopup('couponPopup')">
|
||||
<template v-if="orderCreateData.coupon && orderCreateData.coupon.coupon_id">
|
||||
<text>已使用优惠券,优惠</text>
|
||||
<text class="unit price-font">{{ $lang('common.currencySymbol') }}</text>
|
||||
<text class="money price-font">{{ (calculateData && calculateData.coupon_money ? calculateData.coupon_money : 0) | moneyFormat }}</text>
|
||||
</template>
|
||||
<text v-else>不使用优惠券</text>
|
||||
</view>
|
||||
<text class="iconfont icon-right"></text>
|
||||
</view>
|
||||
<view class="order-cell" v-if="promotionInfo">
|
||||
<text class="tit">活动优惠</text>
|
||||
<view class="box text-overflow" @click="openPopup('promotionPopup')">
|
||||
<text>{{ promotionInfo.title }}</text>
|
||||
</view>
|
||||
<text class="iconfont icon-right"></text>
|
||||
</view>
|
||||
<view class="order-cell point" v-if="calculateGoodsData && calculateGoodsData.max_usable_point > 0">
|
||||
<text class="tit">
|
||||
<text>使用{{ parseInt(calculateGoodsData.max_usable_point) }}积分可抵扣</text>
|
||||
<text class="unit price-font">{{ $lang('common.currencySymbol') }}</text>
|
||||
<text class="money price-font">{{ calculateData.point_money | moneyFormat }}</text>
|
||||
</text>
|
||||
<view class="box"></view>
|
||||
<ns-switch class="balance-switch" @change="usePoint" :checked="orderCreateData.is_point == 1"/>
|
||||
</view>
|
||||
<view class="order-cell order-invoice-cell" v-if="goodsData.invoice.invoice_status == 1">
|
||||
<text class="tit">发票</text>
|
||||
<view class="box text-overflow" @click="openPopup('invoicePopup')">
|
||||
<text v-if="orderCreateData.is_invoice == 1">{{ orderCreateData.invoice_type == 1 ? '纸质' : '电子' }}发票({{ orderCreateData.invoice_content }})</text>
|
||||
<text v-else>无需发票</text>
|
||||
</view>
|
||||
<text class="iconfont icon-right"></text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="site-wrap box member-card-wrap" v-if="paymentData.recommend_member_card && Object.keys(paymentData.recommend_member_card).length > 0">
|
||||
<view class="head" @click="selectMemberCard">
|
||||
<text class="iconfont icon-huiyuan"></text>
|
||||
<view class="info">
|
||||
开通{{ paymentData.recommend_member_card.level_name }}
|
||||
<text>本单预计可省</text>
|
||||
<text class="price-color">{{ paymentData.recommend_member_card.discount_money | moneyFormat }}</text>
|
||||
<text>元</text>
|
||||
</view>
|
||||
<text class="iconfont" :class="orderCreateData.is_open_card == 1 ? 'icon-yuan_checked color-base-text' : 'icon-yuan_checkbox'"></text>
|
||||
</view>
|
||||
<view class="body" v-if="orderCreateData.is_open_card">
|
||||
<view class="item" :class="{ 'active color-base-border': item.key == orderCreateData.member_card_unit }" v-for="(item, index) in cardChargeType" :key="index" @click="selectMembercardUnit(item.key)">
|
||||
<view class="title">{{ item.title }}</view>
|
||||
<view class="price price-font">{{ $lang('common.currencySymbol') }}{{ parseFloat(item.value) }}/{{ item.unit }}</view>
|
||||
<text class="iconfont icon-icon color-base-text price-font identify" v-if="item.key == orderCreateData.member_card_unit"></text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 订单金额 -->
|
||||
<template v-if="calculateData">
|
||||
<view class="order-money">
|
||||
<view class="order-cell">
|
||||
<text class="tit">商品金额</text>
|
||||
<view class="box">
|
||||
<text class="unit color-title price-font">{{ $lang('common.currencySymbol') }}</text>
|
||||
<text class="money color-title price-font">{{ calculateData.goods_money | moneyFormat }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="order-cell" v-if="calculateData.is_virtual == 0 && calculateData.delivery_money > 0">
|
||||
<text class="tit">运费</text>
|
||||
<view class="box color-base-text">
|
||||
<text class="operator">+</text>
|
||||
<text class="unit price-font">{{ $lang('common.currencySymbol') }}</text>
|
||||
<text class="money price-font">{{ calculateData.delivery_money | moneyFormat }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="order-cell" v-if="orderCreateData.is_invoice && calculateData.invoice_money > 0">
|
||||
<text class="tit">
|
||||
<text>税费</text>
|
||||
<text class="color-base-text font-bold price-font">({{ goodsData.invoice.invoice_rate }}%)</text>
|
||||
</text>
|
||||
<view class="box color-base-text">
|
||||
<text class="operator">+</text>
|
||||
<text class="unit price-font">{{ $lang('common.currencySymbol') }}</text>
|
||||
<text class="money price-font">{{ calculateData.invoice_money | moneyFormat }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="order-cell" v-if="orderCreateData.is_invoice && calculateData.invoice_delivery_money > 0">
|
||||
<text class="tit">发票邮寄费</text>
|
||||
<view class="box color-base-text">
|
||||
<text class="operator">+</text>
|
||||
<text class="unit price-font">{{ $lang('common.currencySymbol') }}</text>
|
||||
<text class="money price-font">{{ calculateData.invoice_delivery_money | moneyFormat }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="order-cell" v-if="calculateData.promotion_money > 0">
|
||||
<text class="tit">优惠</text>
|
||||
<view class="box color-base-text">
|
||||
<text class="operator">-</text>
|
||||
<text class="unit price-font">{{ $lang('common.currencySymbol') }}</text>
|
||||
<text class="money price-font">{{ calculateData.promotion_money | moneyFormat }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="order-cell" v-if="calculateData.coupon_money">
|
||||
<text class="tit">优惠券</text>
|
||||
<view class="box color-base-text">
|
||||
<text class="operator">-</text>
|
||||
<text class="unit price-font">{{ $lang('common.currencySymbol') }}</text>
|
||||
<text class="money price-font">{{ calculateData.coupon_money | moneyFormat }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="order-cell" v-if="calculateData.point_money > 0">
|
||||
<text class="tit">积分抵扣</text>
|
||||
<view class="box color-base-text">
|
||||
<text class="operator">-</text>
|
||||
<text class="unit price-font">{{ $lang('common.currencySymbol') }}</text>
|
||||
<text class="money price-font">{{ calculateData.point_money | moneyFormat }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="order-cell" v-if="calculateData.member_card_money > 0">
|
||||
<text class="tit">会员卡</text>
|
||||
<view class="box color-base-text">
|
||||
<text class="operator">+</text>
|
||||
<text class="unit price-font">{{ $lang('common.currencySymbol') }}</text>
|
||||
<text class="money price-font">{{ calculateData.member_card_money | moneyFormat }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="transactionAgreement.title && transactionAgreement.content" class="agreement">购买前请先阅读<text @click="$refs.agreementPopup.open()">《{{ transactionAgreement.title }}》</text>,下单即代表同意该协议</view>
|
||||
|
||||
<view class="order-submit bottom-safe-area">
|
||||
<view class="order-settlement-info">
|
||||
<text class="font-size-base color-tip margin-right">共{{ calculateData.goods_num }}件</text>
|
||||
<text class="font-size-base">合计:</text>
|
||||
<text class=" unit price-font">{{ $lang('common.currencySymbol') }}</text>
|
||||
<text class=" money price-font">{{ parseFloat(calculateData.pay_money).toFixed(2).split('.')[0] }}</text>
|
||||
<text class=" unit price-font">.{{ parseFloat(calculateData.pay_money).toFixed(2).split('.')[1] }}</text>
|
||||
</view>
|
||||
<view class="submit-btn">
|
||||
<button type="primary" class="mini" size="mini" @click="create()" v-if="!surplusStartMoney()">提交订单</button>
|
||||
<button v-else class="no-submit mini" size="mini">差{{ surplusStartMoney() | moneyFormat }}起送</button>
|
||||
</view>
|
||||
</view>
|
||||
<view class="order-submit-block"></view>
|
||||
|
||||
<payment ref="choosePaymentPopup" @close="payClose" v-if="calculateData"></payment>
|
||||
</template>
|
||||
|
||||
|
||||
<!-- 活动优惠弹窗 -->
|
||||
<uni-popup ref="promotionPopup" type="bottom" v-if="promotionInfo">
|
||||
<view class="promotion-popup popup">
|
||||
<view class="popup-header">
|
||||
<text class="tit">活动优惠</text>
|
||||
<text class="iconfont icon-close" @click="closePopup('promotionPopup')"></text>
|
||||
</view>
|
||||
<scroll-view scroll-y="true" class="popup-body" :class="{ 'safe-area': isIphoneX }">
|
||||
<view class="order-cell" style="align-items: baseline;">
|
||||
<view class="tit">
|
||||
<text class="promotion-mark ns-gradient-promotionpages-payment">{{ promotionInfo.title }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="promotion-content">
|
||||
<view class="tit tit-content" style="white-space: pre-line;" v-html="promotionInfo.content"></view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="popup-footer" :class="{ 'bottom-safe-area': isIphoneX }">
|
||||
<view class="confirm-btn color-base-bg" @click="closePopup('promotionPopup')">确定</view>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
|
||||
<!-- 门店列表弹窗 -->
|
||||
<uni-popup ref="deliveryPopup" type="bottom">
|
||||
<view class="delivery-popup popup">
|
||||
<view class="popup-header">
|
||||
<text class="tit">已为您甄选出附近所有相关门店</text>
|
||||
<text class="iconfont icon-close" @click="closePopup('deliveryPopup')"></text>
|
||||
</view>
|
||||
<view class="popup-body store-popup" :class="{ 'safe-area': isIphoneX }">
|
||||
|
||||
<mescroll-uni @getData="getStore" ref="mescroll" top="50px">
|
||||
<block slot="list">
|
||||
<view class="delivery-content">
|
||||
<block v-if="storeData">
|
||||
<view class="item-wrap" v-for="(item, index) in storeData" :key="index" @click="selectPickupPoint(item)">
|
||||
<view class="detail">
|
||||
<view class="name" :class="item.store_id == orderCreateData.delivery.store_id ? 'color-base-text' : ''">
|
||||
<text>{{ item.store_name }}</text>
|
||||
<text v-if="item.distance">({{ item.distance }}km)</text>
|
||||
</view>
|
||||
<view class="info">
|
||||
<view :class="item.store_id == orderCreateData.delivery.store_id ? 'color-base-text' : ''" class="font-size-goods-tag">营业时间:{{ item.open_date }}</view>
|
||||
<view :class="item.store_id == orderCreateData.delivery.store_id ? 'color-base-text' : ''" class="font-size-goods-tag">地址:{{ item.full_address }}{{ item.address }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="icon" v-if="item.store_id == orderCreateData.delivery.store_id">
|
||||
<text class="iconfont icon-yuan_checked color-base-text"></text>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<view v-else class="empty-wrap">
|
||||
<ns-empty text="所选择收货地址附近没有可以自提的门店" :isIndex="false"></ns-empty>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</block>
|
||||
</mescroll-uni>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
|
||||
<!-- 留言弹窗 -->
|
||||
<uni-popup ref="buyerMessagePopup" type="bottom">
|
||||
<view style="height: auto;" class="buyermessag-popup popup" @touchmove.prevent.stop>
|
||||
<view class="popup-header">
|
||||
<text class="tit">买家留言</text>
|
||||
<text class="iconfont icon-close" @click="closePopup('buyerMessagePopup')"></text>
|
||||
</view>
|
||||
<scroll-view scroll-y="true" class="popup-body" :class="{ 'safe-area': isIphoneX }">
|
||||
<view>
|
||||
<view class="buyermessag-cell">
|
||||
<view class="buyermessag-form-group">
|
||||
<textarea type="text" maxlength="100" placeholder="留言前建议先与商家协调一致" placeholder-class="color-tip" v-model="orderCreateData.buyer_message"/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="popup-footer" @click="saveBuyerMessage" :class="{ 'bottom-safe-area': isIphoneX }">
|
||||
<view class="confirm-btn color-base-bg">确定</view>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
|
||||
<!-- 优惠券弹窗 -->
|
||||
<uni-popup ref="couponPopup" type="bottom" v-if="calculateGoodsData" :mask-click="false">
|
||||
<view class="coupon-popup popup" @touchmove.prevent.stop>
|
||||
<view class="popup-header">
|
||||
<text class="tit">优惠券</text>
|
||||
<text class="iconfont icon-close" @click="closePopup('couponPopup')"></text>
|
||||
</view>
|
||||
|
||||
<scroll-view scroll-y="true" class="popup-body" :class="{ 'safe-area': isIphoneX }">
|
||||
<view v-if="coupon_list.length > 0">
|
||||
<view class="coupon-item" v-for="(couponItem, couponIndex) in coupon_list" :key="couponIndex" @click="selectCoupon(couponItem)">
|
||||
<view class="coupon-info" :style="{ backgroundColor: 'var(--main-color-shallow)' }">
|
||||
<view class="info-wrap">
|
||||
<image class="coupon-line" mode="heightFix" :src="$util.img('public/uniapp/coupon/coupon_line.png')"/>
|
||||
<view class="coupon-money">
|
||||
<template v-if="couponItem.type == 'divideticket'">
|
||||
<text class="unit">{{ $lang('common.currencySymbol') }}</text>
|
||||
<text class="money">{{ parseFloat(couponItem.money) }}</text>
|
||||
</template>
|
||||
<template v-else-if="couponItem.type == 'reward'">
|
||||
<text class="unit">{{ $lang('common.currencySymbol') }}</text>
|
||||
<text class="money">{{ parseFloat(couponItem.money) }}</text>
|
||||
</template>
|
||||
<template v-else-if="couponItem.type == 'discount'">
|
||||
<text class="money">{{ parseFloat(couponItem.discount) }}</text>
|
||||
<text class="unit">折</text>
|
||||
</template>
|
||||
<view class="at-least">
|
||||
<template v-if="couponItem.at_least > 0">
|
||||
满{{ couponItem.at_least }}可用
|
||||
</template>
|
||||
<template v-else>
|
||||
无门槛
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="desc-wrap">
|
||||
<view class="coupon-name">{{ couponItem.coupon_name }}</view>
|
||||
<view v-if="couponItem.type == 'discount' && couponItem.discount_limit > 0" class="limit">最多可抵¥{{ couponItem.discount_limit }}</view>
|
||||
<view class="time font-size-goods-tag">有效期:{{ couponItem.end_time ? $util.timeStampTurnTime(couponItem.end_time) : '长期有效' }}</view>
|
||||
</view>
|
||||
<view class="iconfont" :class="orderCreateData.coupon.coupon_id == couponItem.coupon_id ? 'icon-yuan_checked color-base-text' : 'icon-yuan_checkbox'"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="coupon-empty">暂无可用的优惠券</view>
|
||||
</scroll-view>
|
||||
|
||||
<view class="popup-footer" :class="{ 'bottom-safe-area': isIphoneX }">
|
||||
<view class="confirm-btn color-base-bg" @click="useCpopon">确定</view>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
|
||||
<!-- 交易协议 -->
|
||||
<view @touchmove.prevent>
|
||||
<uni-popup ref="agreementPopup" type="center" :maskClick="false">
|
||||
<view class="agreement-conten-box">
|
||||
<view class="close">
|
||||
<text class="iconfont icon-close" @click="$refs.agreementPopup.close()"></text>
|
||||
</view>
|
||||
<view class="title">{{ transactionAgreement.title }}</view>
|
||||
<view class="con">
|
||||
<scroll-view scroll-y="true" class="con">
|
||||
<rich-text :nodes="transactionAgreement.content"></rich-text>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</view>
|
||||
|
||||
<!-- 表单修改弹窗 -->
|
||||
<uni-popup ref="editFormPopup" type="bottom">
|
||||
<view style="height: auto;" class="form-popup popup" @touchmove.prevent.stop>
|
||||
<view class="popup-header">
|
||||
<text class="tit">买家信息</text>
|
||||
<text class="iconfont icon-close" @click="$refs.editFormPopup.close()"></text>
|
||||
</view>
|
||||
<scroll-view scroll-y="true" class="popup-body" :class="{ 'safe-area': isIphoneX }">
|
||||
<ns-form v-if="tempFormData" :data="tempFormData.json_data" ref="tempForm"></ns-form>
|
||||
</scroll-view>
|
||||
<view class="popup-footer" @click="saveForm" :class="{ 'bottom-safe-area': isIphoneX }">
|
||||
<view class="confirm-btn color-base-bg">确定</view>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
|
||||
<uni-popup ref="memberGoodsCardPopup" type="bottom">
|
||||
<view class="member-card-popup popup" @touchmove.prevent.stop>
|
||||
<view class="popup-header">
|
||||
<text class="tit">选择次卡</text>
|
||||
<text class="iconfont icon-close" @click="$refs.memberGoodsCardPopup.close()"></text>
|
||||
</view>
|
||||
<scroll-view scroll-y="true" class="popup-body" :class="{ 'safe-area': isIphoneX }">
|
||||
<view v-for="(item, index) in selectGoodsCard.cardList" class="card-item" @click="selectGoodsCard.click(item.item_id)">
|
||||
<view class="content">
|
||||
<view class="title">{{ item.goods_name }}</view>
|
||||
<view class="info">
|
||||
<text v-if="item.card_type == 'timecard'">不限次数</text>
|
||||
<text v-if="item.card_type == 'oncecard'">剩余{{ item.num - item.use_num }}次</text>
|
||||
<text v-if="item.card_type == 'commoncard'">剩余{{ item.total_num - item.total_use_num }}次</text>
|
||||
<text>|</text>
|
||||
<text>{{ item.end_time ? $util.timeStampTurnTime(item.end_time) : '长期有效' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="iconfont" :class="selectGoodsCard.itemId == item.item_id ? 'icon-yuan_checked color-base-text' : 'icon-yuan_checkbox'"></view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="popup-footer" @click="saveMemberGoodsCard" :class="{ 'bottom-safe-area': isIphoneX }">
|
||||
<view class="confirm-btn color-base-bg">确定</view>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</template>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 门店自提时间 -->
|
||||
<ns-select-time @selectTime="selectPickupTime" ref="timePopup"></ns-select-time>
|
||||
|
||||
<ns-login ref="login"></ns-login>
|
||||
<loading-cover ref="loadingCover"></loading-cover>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import payment from './payment.js';
|
||||
|
||||
export default {
|
||||
name: 'common-payment',
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
props: {
|
||||
api: Object,
|
||||
createDataKey: String
|
||||
},
|
||||
mixins: [payment]
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '@/common/css/order_parment.scss';
|
||||
|
||||
.order-cell .promotion-content {
|
||||
flex: 1;
|
||||
}
|
||||
</style>
|
||||
@@ -603,7 +603,7 @@
|
||||
<text class="iconfont icon-close" @click="$refs.memberGoodsCardPopup.close()"></text>
|
||||
</view>
|
||||
<scroll-view scroll-y="true" class="popup-body" :class="{ 'safe-area': isIphoneX }">
|
||||
<view v-for="(item, index) in selectGoodsCard.cardList" class="card-item" @click="selectGoodsCard.click(item.item_id)">
|
||||
<view v-for="(item, index) in selectGoodsCard.cardList" :key="item.item_id || index" class="card-item" @click="selectGoodsCard.click(item.item_id)">
|
||||
<view class="content">
|
||||
<view class="title">{{ item.goods_name }}</view>
|
||||
<view class="info">
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
:interval="swiperConfig.interval || 3000"
|
||||
:duration="swiperConfig.duration || 500"
|
||||
:display-multiple-items="swiperConfig.displayMultipleItems || 3">
|
||||
<swiper-item v-for="(item, index) in list" :key="index" @click="toDetail(item)">
|
||||
<swiper-item v-for="(item, index) in list" :key="item.article_id || index" @click="toDetail(item)">
|
||||
<view class="swiper-item-content">
|
||||
<view :class="['item', value.ornament.type]" :style="itemCss">
|
||||
<view class="article-img">
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style lang="scss" scoped>
|
||||
|
||||
.fui-audio {
|
||||
width: 100%;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
<!-- 商品列表 -->
|
||||
<template v-if="value.template == 'row1-of1'">
|
||||
<view class="item" v-for="(item, index) in list" :key="index" @click="toDetail(item)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="item" v-for="(item, index) in list" :key="item.bargain_id || index" @click="toDetail(item)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }" :src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix" @error="imageError(index)"/>
|
||||
</view>
|
||||
@@ -67,7 +67,7 @@
|
||||
|
||||
<template v-if="value.template == 'horizontal-slide'">
|
||||
<scroll-view v-if="value.slideMode == 'scroll'" class="scroll" :scroll-x="true" :show-scrollbar="false">
|
||||
<view class="item" v-for="(item, index) in list" :key="index" @click="toDetail(item)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="item" v-for="(item, index) in list" :key="item.bargain_id || index" @click="toDetail(item)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }" :src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix" @error="imageError(index)" :lazy-load="true"/>
|
||||
<image class="bg" v-if="value.saleStyle.control && value.template == 'horizontal-slide' && value.style != 'style-2'" :src="$util.img('public/uniapp/bargain/bg.png')" mode="widthFix"/>
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
<block v-if="categoryTree.length">
|
||||
<scroll-view scroll-y="true" class="tree-wrap">
|
||||
<view class="category-item-wrap">
|
||||
<view class="category-item" v-for="(item, index) in categoryTree" :key="index" :class="[
|
||||
<view class="category-item" v-for="(item, index) in categoryTree" :key="item.category_id || index" :class="[
|
||||
{ select: select == index },
|
||||
{ 'border-bottom': value.template == 4 && select + 1 === index },
|
||||
{ 'border-top': value.template == 4 && select - 1 === index }
|
||||
@@ -84,7 +84,7 @@
|
||||
@scroll="listenScroll" @touchstart="touchStart" :refresher-enabled="true"
|
||||
refresher-default-style="none" :refresher-triggered="triggered" @refresherrefresh="onRefresh"
|
||||
@refresherrestore="onRestore">
|
||||
<view class="child-category" v-for="(item, index) in categoryTree" :key="index" :id="'category-' + index">
|
||||
<view class="child-category" v-for="(item, index) in categoryTree" :key="item.category_id || index" :id="'category-' + index">
|
||||
<diy-category-item :category="item" :value="value" ref="categoryItem" :index="index"
|
||||
:select="select" :oneCategorySelect="oneCategorySelect" :isList="isList" @tologin="toLogin"
|
||||
@selectsku="selectSku($event, index)" @addCart="addCartPoint"
|
||||
@@ -95,7 +95,7 @@
|
||||
|
||||
<view class="content-wrap"
|
||||
v-if="(value.template == 2 || value.template == 3 || value.template == 4) && loadType == 'part'">
|
||||
<view class="child-category-wrap" v-for="(item, index) in categoryTree" :key="index"
|
||||
<view class="child-category-wrap" v-for="(item, index) in categoryTree" :key="item.category_id || index"
|
||||
:id="'category-' + index" :style="{ display: select == index ? 'block' : 'none' }">
|
||||
<diy-category-item :category="item" :value="value" ref="categoryItem" :index="index"
|
||||
:last="index == categoryTree.length - 1 ? true : false" :select="select"
|
||||
|
||||
@@ -20,4 +20,4 @@ export default {
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
<style lang="scss"></style>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<swiper class="coupon-style-one" circular>
|
||||
<swiper-item v-for="(numItem, numIndex) in Math.ceil(computedCouponList.length / 3)" :key="numIndex" class="coupon-item-box">
|
||||
|
||||
<view v-for="(item, index) in computedCouponList" class="coupon-item"
|
||||
<view v-for="(item, index) in computedCouponList" class="coupon-item" :key="item.coupon_id || index"
|
||||
v-if="index >= [numIndex * 3] && index < [(numIndex + 1) * 3]" :style="{
|
||||
color: value.moneyColor,
|
||||
backgroundImage: 'url(' + $util.img('public/uniapp/coupon/style1-bg.png') + ')',
|
||||
@@ -43,7 +43,7 @@
|
||||
<template v-if="value.style == '2'">
|
||||
<swiper class="coupon-style-two" circular>
|
||||
<swiper-item v-for="(numItem, numIndex) in Math.ceil(computedCouponList.length / 3)" :key="numIndex" class="coupon-item-box">
|
||||
<view class="coupon-item" v-for="(item, index) in computedCouponList" :key="index"
|
||||
<view class="coupon-item" v-for="(item, index) in computedCouponList" :key="item.coupon_id || index"
|
||||
v-if="index >= [numIndex * 3] && index < [(numIndex + 1) * 3]" :style="{
|
||||
color: value.moneyColor,
|
||||
backgroundImage: 'url(' + $util.img('public/uniapp/coupon/coupon_bg1.png') + ')',
|
||||
@@ -76,7 +76,7 @@
|
||||
<template v-if="value.style == '3'">
|
||||
<swiper class="coupon-style-three" circular>
|
||||
<swiper-item v-for="(numItem, numIndex) in Math.ceil(computedCouponList.length / 3)" :key="numIndex" class="coupon-item-box">
|
||||
<view class="coupon-item" v-for="(item, index) in computedCouponList" :key="index"
|
||||
<view class="coupon-item" v-for="(item, index) in computedCouponList" :key="item.coupon_id || index"
|
||||
v-if="index >= [numIndex * 3] && index < [(numIndex + 1) * 3]" :style="{
|
||||
color: value.moneyColor,
|
||||
backgroundImage: 'url(' + $util.img('public/uniapp/coupon/coupon_shu.png') + ')',
|
||||
@@ -110,7 +110,7 @@
|
||||
<template v-if="value.style == '4'">
|
||||
<swiper class="coupon-style-four" circular>
|
||||
<swiper-item v-for="(numItem, numIndex) in Math.ceil(computedCouponList.length / 3)" :key="numIndex" class="coupon-item-box">
|
||||
<view class="coupon-item" v-for="(item, index) in computedCouponList" :key="index"
|
||||
<view class="coupon-item" v-for="(item, index) in computedCouponList" :key="item.coupon_id || index"
|
||||
v-if="index >= [numIndex * 3] && index < [(numIndex + 1) * 3]" :style="{
|
||||
color: value.moneyColor,
|
||||
backgroundImage: 'url(' + $util.img('public/uniapp/coupon/style4_bg.png') + ')',
|
||||
@@ -143,7 +143,7 @@
|
||||
<view class="coupon-style-five">
|
||||
<view class="coupon-all">
|
||||
<view class="coupon-box">
|
||||
<view class="coupon-list" v-for="(item, index) in computedCouponList" :key="index" @click="couponAction(item, index)">
|
||||
<view class="coupon-list" v-for="(item, index) in computedCouponList" :key="item.coupon_id || index" @click="couponAction(item, index)">
|
||||
<image :src="$util.img('public/uniapp/coupon/style5_bg.png')"></image>
|
||||
<view class="coupon">
|
||||
<view class="coupon-info">
|
||||
@@ -176,7 +176,7 @@
|
||||
<template v-if="value.style == '6'">
|
||||
<swiper class="coupon-style-six" circular>
|
||||
<swiper-item class="style-six-wrap" v-for="(numItem, numIndex) in Math.ceil(computedCouponList.length / 3)" :key="numIndex">
|
||||
<view class="coupon" v-for="(item, index) in computedCouponList" :key="index"
|
||||
<view class="coupon" v-for="(item, index) in computedCouponList" :key="item.coupon_id || index"
|
||||
v-if="index >= [numIndex * 3] && index < [(numIndex + 1) * 3]" :style="{
|
||||
color: value.moneyColor,
|
||||
backgroundImage: 'url(' + $util.img('public/uniapp/coupon/style6-bg-1.png') + ')',
|
||||
@@ -230,7 +230,7 @@
|
||||
<template v-if="value.style == '7'">
|
||||
<scroll-view class="coupon-style-seven" scroll-x="true">
|
||||
<view class="wrap">
|
||||
<view class="coupon-list" v-for="(item, index) in computedCouponList" :key="index" @click="couponAction(item, index)">
|
||||
<view class="coupon-list" v-for="(item, index) in computedCouponList" :key="item.coupon_id || index" @click="couponAction(item, index)">
|
||||
<image :src="$util.img('public/uniapp/coupon/style7_bg.png')"></image>
|
||||
<view class="coupon">
|
||||
<view class="coupon-info">
|
||||
@@ -1067,7 +1067,7 @@
|
||||
background: transparent;
|
||||
}
|
||||
</style>
|
||||
<style scoped>
|
||||
<style lang="scss" scoped>
|
||||
.coupon-all>>>.uni-scroll-view::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<view data-component-name="diy-fenxiao-goods-list" class="diy-fenxiao" v-if="list.length" :class="['goods-list', value.template, value.style]" :style="goodsListWarpCss">
|
||||
<view class="goods-item" v-for="(item, index) in list" :key="index" @click="toDetail(item)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="goods-item" v-for="(item, index) in list" :key="item.goods_id || index" @click="toDetail(item)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="goods-img" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }" :src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix" @error="imgError(index)"/>
|
||||
</view>
|
||||
|
||||
@@ -26,4 +26,4 @@
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
<style lang="scss"></style>
|
||||
@@ -5,7 +5,7 @@
|
||||
<view class="title-wrap" v-show="value.title" :style="{ color: value.textColor, fontWeight: value.fontWeight ? 'bold' : '' }">{{ value.title }}
|
||||
</view>
|
||||
<view class="ul-wrap">
|
||||
<view class="li-item" v-for="(item, index) in list" :key="index">
|
||||
<view class="li-item" v-for="(item, index) in list" :key="item.brand_id || index">
|
||||
<image class="brand-pic" :src="$util.img(item.image_url)" mode="aspectFit" @click="handlerClick(item)" @tap="handlerClick(item)" @error="imgError(index)" :style="itemCss"/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
:key="index"
|
||||
v-if="index >= [(numItem) * (value.pageCount * value.rowCount)] && index < [(numItem+1) * (value.pageCount * value.rowCount)]"
|
||||
:style="{ width: 100 / value.rowCount + '%' }" @click="redirectTo(item.link)">
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef H5 -->
|
||||
<view class="graphic-nav-item" :class="[value.mode]" v-for="(item, index) in value.list"
|
||||
:key="index"
|
||||
v-if="index >= [(numItem - 1) * (value.pageCount * value.rowCount)] && index < [numItem * (value.pageCount * value.rowCount)]"
|
||||
:style="{ width: 100 / value.rowCount + '%' }" @click="redirectTo(item.link)">
|
||||
<!-- #endif -->
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef H5 -->
|
||||
<view class="graphic-nav-item" :class="[value.mode]" v-for="(item, index) in value.list"
|
||||
:key="index"
|
||||
v-if="index >= [(numItem - 1) * (value.pageCount * value.rowCount)] && index < [numItem * (value.pageCount * value.rowCount)]"
|
||||
:style="{ width: 100 / value.rowCount + '%' }" @click="redirectTo(item.link)">
|
||||
<!-- #endif -->
|
||||
<view class="graphic-img" v-if="value.mode != 'text'"
|
||||
:style="{ fontSize: value.imageSize * 2 + 'rpx', width: value.imageSize * 2 + 'rpx', height: value.imageSize * 2 + 'rpx' }">
|
||||
<image v-if="item.iconType == 'img'"
|
||||
@@ -37,7 +37,12 @@
|
||||
:style="{ fontSize: value.font.size * 2 + 'rpx', fontWeight: value.font.weight, color: value.font.color }">
|
||||
{{ item.title }}
|
||||
</text>
|
||||
</view>
|
||||
<!-- #ifdef H5 -->
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef MP -->
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
|
||||
@@ -159,7 +164,7 @@
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
<style lang="scss">
|
||||
/* 固定显示 */
|
||||
.graphic-nav.fixed-layout>>>.uni-scroll-view-content {
|
||||
display: flex;
|
||||
|
||||
@@ -37,4 +37,4 @@ export default {
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
<style lang="scss"></style>
|
||||
|
||||
@@ -22,4 +22,4 @@ export default {
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
<style lang="scss"></style>
|
||||
|
||||
@@ -242,7 +242,7 @@
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style scoped>
|
||||
<style lang="scss" scoped>
|
||||
.coupon-all>>>.uni-scroll-view::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -1457,7 +1457,7 @@
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style scoped>
|
||||
<style lang="scss" scoped>
|
||||
.member-complete-info-popup /deep/ .uni-popup__wrapper.bottom,
|
||||
.member-complete-info-popup /deep/ .uni-popup__wrapper.bottom .uni-popup__wrapper-box {
|
||||
border-top-left-radius: 30rpx !important;
|
||||
|
||||
@@ -179,7 +179,7 @@
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
<style lang="scss">
|
||||
/* 单行滑动 */
|
||||
.merch-nav.singleSlide>>>.uni-scroll-view-content {
|
||||
display: flex;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
</view>
|
||||
|
||||
<scroll-view class="diy-notes-box" scroll-x="true" show-scrollbar="true">
|
||||
<view class="notes-box-item" v-for="(item, i) in dataList" :key="i" @click="handlerClick(item)" @tap="handlerClick(item)"
|
||||
<view class="notes-box-item" v-for="(item, i) in dataList" :key="item.note_id || i" @click="handlerClick(item)" @tap="handlerClick(item)"
|
||||
:style="notesItemStyle">
|
||||
<view class="notes-item" v-if="item.status == 1">
|
||||
<view class="notes-item-con">
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
<style lang="scss">
|
||||
.quick-nav >>> .uni-scroll-view-content {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
<view class="content-wrap">
|
||||
<template v-if="value.template == 'row1-of1'">
|
||||
<view class="item" v-for="(item, index) in dataList" :key="index" @click="toDetail(item.id)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="item" v-for="(item, index) in dataList" :key="item.goods_id || index" @click="toDetail(item.id)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }" :src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix" @error="imageError(index)"/>
|
||||
</view>
|
||||
@@ -82,7 +82,7 @@
|
||||
</template>
|
||||
|
||||
<template v-if="value.template == 'row1-of2'">
|
||||
<view class="item" v-for="(item, index) in dataList" :key="index" @click="toDetail(item.id)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="item" v-for="(item, index) in dataList" :key="item.goods_id || index" @click="toDetail(item.id)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }" :src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix" @error="imageError(index)"/>
|
||||
</view>
|
||||
@@ -119,7 +119,7 @@
|
||||
|
||||
<template v-if="value.template == 'horizontal-slide'">
|
||||
<scroll-view v-if="value.slideMode == 'scroll'" class="scroll" :scroll-x="true" :show-scrollbar="false">
|
||||
<view class="item" v-for="(item, index) in dataList" :key="index" @click="toDetail(item.id)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="item" v-for="(item, index) in dataList" :key="item.goods_id || index" @click="toDetail(item.id)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }" :src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix" @error="imageError(index)"/>
|
||||
</view>
|
||||
@@ -147,7 +147,7 @@
|
||||
</scroll-view>
|
||||
<swiper v-if="value.slideMode == 'slide'" :autoplay="false" class="swiper" :style="{ height: swiperHeight }">
|
||||
<swiper-item v-for="(pageItem, pageIndex) in page" :key="pageIndex" :class="['swiper-item', dataList[pageIndex] && [dataList[pageIndex].length / 3].length >= 1 && 'flex-between']">
|
||||
<view class="item" v-for="(item, dataIndex) in dataList[pageIndex]" :key="dataIndex" @click="toDetail(item.id)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="item" v-for="(item, dataIndex) in dataList[pageIndex]" :key="item.goods_id || dataIndex" @click="toDetail(item.id)" :class="[value.ornament.type]" :style="goodsItemCss">
|
||||
<view class="img-wrap" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }">
|
||||
<image :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }" :src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix" @error="imageError(dataIndex, pageIndex)"/>
|
||||
</view>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<view class="diy-store-label">
|
||||
<block v-if="businessConfig.store_business == 'store'">
|
||||
<scroll-view scroll-x="true" :class="[value.contentStyle, { between: list.length == 3 }]" :style="storeLabelWrapCss" :enable-flex="true">
|
||||
<view v-for="(item, index) in storeLabel" :class="['item']">
|
||||
<view v-for="(item, index) in storeLabel" :key="item.label_id || index" :class="['item']">
|
||||
<diy-icon v-if="value.icon" class="icon-box" :icon="value.icon" :value="value.style ? value.style : 'null'"></diy-icon>
|
||||
<text class="label-name" :style="{ color: value.textColor, fontSize: value.fontSize * 2 + 'rpx', fontWeight: value.fontWeight }">{{ item }}</text>
|
||||
</view>
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style lang="scss" scoped>
|
||||
video {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -452,4 +452,4 @@
|
||||
<style lang="scss">
|
||||
@import '@/common/css/goods_detail.scss';
|
||||
</style>
|
||||
<style scoped></style>
|
||||
<style lang="scss" scoped></style>
|
||||
@@ -1,52 +1,52 @@
|
||||
<!-- 下拉刷新区域 -->
|
||||
<template>
|
||||
<view v-if="mOption.use" class="mescroll-downwarp">
|
||||
<view class="downwarp-content">
|
||||
<view class="downwarp-progress" :class="{ 'mescroll-rotate': isDownLoading }" :style="{ transform: downRotate }"></view>
|
||||
<view class="downwarp-tip">{{ downText }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
option: Object, // down的配置项
|
||||
type: Number, // 下拉状态(inOffset:1, outOffset:2, showLoading:3, endDownScroll:4)
|
||||
rate: Number // 下拉比率 (inOffset: rate<1; outOffset: rate>=1)
|
||||
},
|
||||
computed: {
|
||||
// 支付宝小程序需写成计算属性,prop定义default仍报错
|
||||
mOption() {
|
||||
return this.option || {};
|
||||
},
|
||||
// 是否在加载中
|
||||
isDownLoading() {
|
||||
return this.type === 3;
|
||||
},
|
||||
// 旋转的角度
|
||||
downRotate() {
|
||||
return 'rotate(' + 360 * this.rate + 'deg)';
|
||||
},
|
||||
// 文本提示
|
||||
downText() {
|
||||
switch (this.type) {
|
||||
case 1:
|
||||
return this.mOption.textInOffset;
|
||||
case 2:
|
||||
return this.mOption.textOutOffset;
|
||||
case 3:
|
||||
return this.mOption.textLoading;
|
||||
case 4:
|
||||
return this.mOption.textLoading;
|
||||
default:
|
||||
return this.mOption.textInOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@import './mescroll-down.css';
|
||||
</style>
|
||||
<!-- 下拉刷新区域 -->
|
||||
<template>
|
||||
<view v-if="mOption.use" class="mescroll-downwarp">
|
||||
<view class="downwarp-content">
|
||||
<view class="downwarp-progress" :class="{ 'mescroll-rotate': isDownLoading }" :style="{ transform: downRotate }"></view>
|
||||
<view class="downwarp-tip">{{ downText }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
option: Object, // down的配置项
|
||||
type: Number, // 下拉状态(inOffset:1, outOffset:2, showLoading:3, endDownScroll:4)
|
||||
rate: Number // 下拉比率 (inOffset: rate<1; outOffset: rate>=1)
|
||||
},
|
||||
computed: {
|
||||
// 支付宝小程序需写成计算属性,prop定义default仍报错
|
||||
mOption() {
|
||||
return this.option || {};
|
||||
},
|
||||
// 是否在加载中
|
||||
isDownLoading() {
|
||||
return this.type === 3;
|
||||
},
|
||||
// 旋转的角度
|
||||
downRotate() {
|
||||
return 'rotate(' + 360 * this.rate + 'deg)';
|
||||
},
|
||||
// 文本提示
|
||||
downText() {
|
||||
switch (this.type) {
|
||||
case 1:
|
||||
return this.mOption.textInOffset;
|
||||
case 2:
|
||||
return this.mOption.textOutOffset;
|
||||
case 3:
|
||||
return this.mOption.textLoading;
|
||||
case 4:
|
||||
return this.mOption.textLoading;
|
||||
default:
|
||||
return this.mOption.textInOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import './mescroll-down.css';
|
||||
</style>
|
||||
|
||||
@@ -1,90 +1,90 @@
|
||||
<!--空布局
|
||||
|
||||
可作为独立的组件, 不使用mescroll的页面也能单独引入, 以便APP全局统一管理:
|
||||
import MescrollEmpty from '@/components/mescroll-uni/components/mescroll-empty.vue';
|
||||
<mescroll-empty v-if="isShowEmpty" :option="optEmpty" @emptyclick="emptyClick"></mescroll-empty>
|
||||
|
||||
-->
|
||||
<template>
|
||||
<view class="mescroll-empty" :class="{ 'empty-fixed': option.fixed }" :style="{ 'z-index': option.zIndex, top: option.top }">
|
||||
<image v-if="icon" class="empty-icon" :src="icon" mode="widthFix" />
|
||||
<view v-if="tip" class="empty-tip">{{ tip }}</view>
|
||||
<view v-if="option.btnText" class="empty-btn" @click="emptyClick">{{ option.btnText }}</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 引入全局配置
|
||||
import GlobalOption from './../mescroll-uni-option.js';
|
||||
export default {
|
||||
props: {
|
||||
// empty的配置项: 默认为GlobalOption.up.empty
|
||||
option: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
},
|
||||
// 使用computed获取配置,用于支持option的动态配置
|
||||
computed: {
|
||||
// 图标
|
||||
icon() {
|
||||
return this.option.icon == null ? GlobalOption.up.empty.icon : this.option.icon; // 此处不使用短路求值, 用于支持传空串不显示图标
|
||||
},
|
||||
// 文本提示
|
||||
tip() {
|
||||
return this.option.tip == null ? GlobalOption.up.empty.tip : this.option.tip; // 此处不使用短路求值, 用于支持传空串不显示文本提示
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 点击按钮
|
||||
emptyClick() {
|
||||
this.$emit('emptyclick');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* 无任何数据的空布局 */
|
||||
.mescroll-empty {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
padding: 100rpx 50rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.mescroll-empty.empty-fixed {
|
||||
z-index: 99;
|
||||
position: absolute; /*transform会使fixed失效,最终会降级为absolute */
|
||||
top: 100rpx;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.mescroll-empty .empty-icon {
|
||||
width: 280rpx;
|
||||
height: 280rpx;
|
||||
}
|
||||
|
||||
.mescroll-empty .empty-tip {
|
||||
margin-top: 20rpx;
|
||||
font-size: $font-size-tag;
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.mescroll-empty .empty-btn {
|
||||
display: inline-block;
|
||||
margin-top: 40rpx;
|
||||
min-width: 200rpx;
|
||||
padding: 18rpx;
|
||||
font-size: $font-size-base;
|
||||
border: 1rpx solid #e04b28;
|
||||
border-radius: 60rpx;
|
||||
color: #e04b28;
|
||||
}
|
||||
|
||||
.mescroll-empty .empty-btn:active {
|
||||
opacity: 0.75;
|
||||
}
|
||||
</style>
|
||||
<!--空布局
|
||||
|
||||
可作为独立的组件, 不使用mescroll的页面也能单独引入, 以便APP全局统一管理:
|
||||
import MescrollEmpty from '@/components/mescroll-uni/components/mescroll-empty.vue';
|
||||
<mescroll-empty v-if="isShowEmpty" :option="optEmpty" @emptyclick="emptyClick"></mescroll-empty>
|
||||
|
||||
-->
|
||||
<template>
|
||||
<view class="mescroll-empty" :class="{ 'empty-fixed': option.fixed }" :style="{ 'z-index': option.zIndex, top: option.top }">
|
||||
<image v-if="icon" class="empty-icon" :src="icon" mode="widthFix" />
|
||||
<view v-if="tip" class="empty-tip">{{ tip }}</view>
|
||||
<view v-if="option.btnText" class="empty-btn" @click="emptyClick">{{ option.btnText }}</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 引入全局配置
|
||||
import GlobalOption from './../mescroll-uni-option.js';
|
||||
export default {
|
||||
props: {
|
||||
// empty的配置项: 默认为GlobalOption.up.empty
|
||||
option: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
},
|
||||
// 使用computed获取配置,用于支持option的动态配置
|
||||
computed: {
|
||||
// 图标
|
||||
icon() {
|
||||
return this.option.icon == null ? GlobalOption.up.empty.icon : this.option.icon; // 此处不使用短路求值, 用于支持传空串不显示图标
|
||||
},
|
||||
// 文本提示
|
||||
tip() {
|
||||
return this.option.tip == null ? GlobalOption.up.empty.tip : this.option.tip; // 此处不使用短路求值, 用于支持传空串不显示文本提示
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 点击按钮
|
||||
emptyClick() {
|
||||
this.$emit('emptyclick');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
/* 无任何数据的空布局 */
|
||||
.mescroll-empty {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
padding: 100rpx 50rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.mescroll-empty.empty-fixed {
|
||||
z-index: 99;
|
||||
position: absolute; /*transform会使fixed失效,最终会降级为absolute */
|
||||
top: 100rpx;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.mescroll-empty .empty-icon {
|
||||
width: 280rpx;
|
||||
height: 280rpx;
|
||||
}
|
||||
|
||||
.mescroll-empty .empty-tip {
|
||||
margin-top: 20rpx;
|
||||
font-size: $font-size-tag;
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.mescroll-empty .empty-btn {
|
||||
display: inline-block;
|
||||
margin-top: 40rpx;
|
||||
min-width: 200rpx;
|
||||
padding: 18rpx;
|
||||
font-size: $font-size-base;
|
||||
border: 1rpx solid #e04b28;
|
||||
border-radius: 60rpx;
|
||||
color: #e04b28;
|
||||
}
|
||||
|
||||
.mescroll-empty .empty-btn:active {
|
||||
opacity: 0.75;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,81 +1,81 @@
|
||||
<!-- 回到顶部的按钮 -->
|
||||
<template>
|
||||
<image
|
||||
v-if="mOption.src"
|
||||
class="mescroll-totop"
|
||||
:class="[value ? 'mescroll-totop-in' : 'mescroll-totop-out', { 'mescroll-safe-bottom': mOption.safearea }]"
|
||||
:style="{ 'z-index': mOption.zIndex, left: left, right: right, bottom: addUnit(mOption.bottom), width: addUnit(mOption.width), 'border-radius': addUnit(mOption.radius) }"
|
||||
:src="mOption.src"
|
||||
mode="widthFix"
|
||||
@click="toTopClick"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
// up.toTop的配置项
|
||||
option: Object,
|
||||
// 是否显示
|
||||
value: false
|
||||
},
|
||||
computed: {
|
||||
// 支付宝小程序需写成计算属性,prop定义default仍报错
|
||||
mOption() {
|
||||
return this.option || {};
|
||||
},
|
||||
// 优先显示左边
|
||||
left() {
|
||||
return this.mOption.left ? this.addUnit(this.mOption.left) : 'auto';
|
||||
},
|
||||
// 右边距离 (优先显示左边)
|
||||
right() {
|
||||
return this.mOption.left ? 'auto' : this.addUnit(this.mOption.right);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
addUnit(num) {
|
||||
if (!num) return 0;
|
||||
if (typeof num === 'number') return num + 'rpx';
|
||||
return num;
|
||||
},
|
||||
toTopClick() {
|
||||
this.$emit('input', false); // 使v-model生效
|
||||
this.$emit('click'); // 派发点击事件
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* 回到顶部的按钮 */
|
||||
.mescroll-totop {
|
||||
z-index: 99;
|
||||
position: fixed !important; /* 加上important避免编译到H5,在多mescroll中定位失效 */
|
||||
right: 46rpx !important;
|
||||
bottom: 272rpx !important;
|
||||
width: 72rpx;
|
||||
height: auto;
|
||||
border-radius: 50%;
|
||||
opacity: 0;
|
||||
transition: opacity 0.5s; /* 过渡 */
|
||||
margin-bottom: var(--window-bottom); /* css变量 */
|
||||
}
|
||||
|
||||
/* 适配 iPhoneX */
|
||||
.mescroll-safe-bottom {
|
||||
margin-bottom: calc(var(--window-bottom) + constant(safe-area-inset-bottom)); /* window-bottom + 适配 iPhoneX */
|
||||
margin-bottom: calc(var(--window-bottom) + env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
/* 显示 -- 淡入 */
|
||||
.mescroll-totop-in {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* 隐藏 -- 淡出且不接收事件*/
|
||||
.mescroll-totop-out {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
<!-- 回到顶部的按钮 -->
|
||||
<template>
|
||||
<image
|
||||
v-if="mOption.src"
|
||||
class="mescroll-totop"
|
||||
:class="[value ? 'mescroll-totop-in' : 'mescroll-totop-out', { 'mescroll-safe-bottom': mOption.safearea }]"
|
||||
:style="{ 'z-index': mOption.zIndex, left: left, right: right, bottom: addUnit(mOption.bottom), width: addUnit(mOption.width), 'border-radius': addUnit(mOption.radius) }"
|
||||
:src="mOption.src"
|
||||
mode="widthFix"
|
||||
@click="toTopClick"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
// up.toTop的配置项
|
||||
option: Object,
|
||||
// 是否显示
|
||||
value: false
|
||||
},
|
||||
computed: {
|
||||
// 支付宝小程序需写成计算属性,prop定义default仍报错
|
||||
mOption() {
|
||||
return this.option || {};
|
||||
},
|
||||
// 优先显示左边
|
||||
left() {
|
||||
return this.mOption.left ? this.addUnit(this.mOption.left) : 'auto';
|
||||
},
|
||||
// 右边距离 (优先显示左边)
|
||||
right() {
|
||||
return this.mOption.left ? 'auto' : this.addUnit(this.mOption.right);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
addUnit(num) {
|
||||
if (!num) return 0;
|
||||
if (typeof num === 'number') return num + 'rpx';
|
||||
return num;
|
||||
},
|
||||
toTopClick() {
|
||||
this.$emit('input', false); // 使v-model生效
|
||||
this.$emit('click'); // 派发点击事件
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
/* 回到顶部的按钮 */
|
||||
.mescroll-totop {
|
||||
z-index: 99;
|
||||
position: fixed !important; /* 加上important避免编译到H5,在多mescroll中定位失效 */
|
||||
right: 46rpx !important;
|
||||
bottom: 272rpx !important;
|
||||
width: 72rpx;
|
||||
height: auto;
|
||||
border-radius: 50%;
|
||||
opacity: 0;
|
||||
transition: opacity 0.5s; /* 过渡 */
|
||||
margin-bottom: var(--window-bottom); /* css变量 */
|
||||
}
|
||||
|
||||
/* 适配 iPhoneX */
|
||||
.mescroll-safe-bottom {
|
||||
margin-bottom: calc(var(--window-bottom) + constant(safe-area-inset-bottom)); /* window-bottom + 适配 iPhoneX */
|
||||
margin-bottom: calc(var(--window-bottom) + env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
/* 显示 -- 淡入 */
|
||||
.mescroll-totop-in {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* 隐藏 -- 淡出且不接收事件*/
|
||||
.mescroll-totop-out {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,39 +1,39 @@
|
||||
<!-- 上拉加载区域 -->
|
||||
<template>
|
||||
<view class="mescroll-upwarp">
|
||||
<!-- 加载中 (此处不能用v-if,否则android小程序快速上拉可能会不断触发上拉回调) -->
|
||||
<view v-show="isUpLoading">
|
||||
<view class="upwarp-progress mescroll-rotate"></view>
|
||||
<view class="upwarp-tip">{{ mOption.textLoading }}</view>
|
||||
</view>
|
||||
<!-- 无数据 -->
|
||||
<view v-if="isUpNoMore" class="upwarp-nodata">{{ mOption.textNoMore }}</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
option: Object, // up的配置项
|
||||
type: Number // 上拉加载的状态:0(loading前),1(loading中),2(没有更多了)
|
||||
},
|
||||
computed: {
|
||||
// 支付宝小程序需写成计算属性,prop定义default仍报错
|
||||
mOption() {
|
||||
return this.option || {};
|
||||
},
|
||||
// 加载中
|
||||
isUpLoading() {
|
||||
return this.type === 1;
|
||||
},
|
||||
// 没有更多了
|
||||
isUpNoMore() {
|
||||
return this.type === 2;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@import './mescroll-up.css';
|
||||
</style>
|
||||
<!-- 上拉加载区域 -->
|
||||
<template>
|
||||
<view class="mescroll-upwarp">
|
||||
<!-- 加载中 (此处不能用v-if,否则android小程序快速上拉可能会不断触发上拉回调) -->
|
||||
<view v-show="isUpLoading">
|
||||
<view class="upwarp-progress mescroll-rotate"></view>
|
||||
<view class="upwarp-tip">{{ mOption.textLoading }}</view>
|
||||
</view>
|
||||
<!-- 无数据 -->
|
||||
<view v-if="isUpNoMore" class="upwarp-nodata">{{ mOption.textNoMore }}</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
option: Object, // up的配置项
|
||||
type: Number // 上拉加载的状态:0(loading前),1(loading中),2(没有更多了)
|
||||
},
|
||||
computed: {
|
||||
// 支付宝小程序需写成计算属性,prop定义default仍报错
|
||||
mOption() {
|
||||
return this.option || {};
|
||||
},
|
||||
// 加载中
|
||||
isUpLoading() {
|
||||
return this.type === 1;
|
||||
},
|
||||
// 没有更多了
|
||||
isUpNoMore() {
|
||||
return this.type === 2;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import './mescroll-up.css';
|
||||
</style>
|
||||
|
||||
@@ -1,298 +1,298 @@
|
||||
<template>
|
||||
<view
|
||||
class="mescroll-body"
|
||||
:style="{ minHeight: minHeight, 'padding-top': padTop, 'padding-bottom': padBottom, 'padding-bottom': padBottomConstant, 'padding-bottom': padBottomEnv }"
|
||||
@touchstart="touchstartEvent"
|
||||
@touchmove="touchmoveEvent"
|
||||
@touchend="touchendEvent"
|
||||
@touchcancel="touchendEvent"
|
||||
>
|
||||
<view class="mescroll-body-content mescroll-touch" :style="{ transform: translateY, transition: transition }">
|
||||
<!-- 下拉加载区域 (支付宝小程序子组件传参给子子组件仍报单项数据流的异常,暂时不通过mescroll-down组件实现)-->
|
||||
<!-- <mescroll-down :option="mescroll.optDown" :type="downLoadType" :rate="downRate"></mescroll-down> -->
|
||||
<view v-if="mescroll.optDown.use" class="mescroll-downwarp">
|
||||
<view class="downwarp-content">
|
||||
<view class="downwarp-progress" :class="{ 'mescroll-rotate': isDownLoading }" :style="{ transform: downRotate }"></view>
|
||||
<view class="downwarp-tip">{{ downText }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 列表内容 -->
|
||||
<slot></slot>
|
||||
|
||||
<!-- 空布局 -->
|
||||
<!-- <mescroll-empty v-if="isShowEmpty" :option="mescroll.optUp.empty" @emptyclick="emptyClick"></mescroll-empty> -->
|
||||
|
||||
<!-- 上拉加载区域 (下拉刷新时不显示, 支付宝小程序子组件传参给子子组件仍报单项数据流的异常,暂时不通过mescroll-up组件实现)-->
|
||||
<!-- <mescroll-up v-if="mescroll.optUp.use && !isDownLoading" :option="mescroll.optUp" :type="upLoadType"></mescroll-up> -->
|
||||
<view v-if="mescroll.optUp.use && !isDownLoading" class="mescroll-upwarp">
|
||||
<!-- 加载中 (此处不能用v-if,否则android小程序快速上拉可能会不断触发上拉回调) -->
|
||||
<view v-show="upLoadType === 1">
|
||||
<view class="upwarp-progress mescroll-rotate"></view>
|
||||
<view class="upwarp-tip">{{ mescroll.optUp.textLoading }}</view>
|
||||
</view>
|
||||
<!-- 无数据 -->
|
||||
<view v-if="upLoadType === 2" class="upwarp-nodata">{{ mescroll.optUp.textNoMore }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 回到顶部按钮 (fixed元素需写在transform外面,防止降级为absolute)-->
|
||||
<mescroll-top v-model="isShowToTop" :option="mescroll.optUp.toTop" @click="toTopClick" v-if="showTop"></mescroll-top>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 引入mescroll-uni.js,处理核心逻辑
|
||||
import MeScroll from './mescroll-uni.js';
|
||||
// 引入全局配置
|
||||
import GlobalOption from './mescroll-uni-option.js';
|
||||
// 引入空布局组件
|
||||
import MescrollEmpty from './components/mescroll-empty.vue';
|
||||
// 引入回到顶部组件
|
||||
import MescrollTop from './components/mescroll-top.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MescrollEmpty,
|
||||
MescrollTop
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
mescroll: { optDown: {}, optUp: {} }, // mescroll实例
|
||||
downHight: 0, //下拉刷新: 容器高度
|
||||
downRate: 0, // 下拉比率(inOffset: rate<1; outOffset: rate>=1)
|
||||
downLoadType: 4, // 下拉刷新状态 (inOffset:1, outOffset:2, showLoading:3, endDownScroll:4)
|
||||
upLoadType: 0, // 上拉加载状态:0(loading前),1(loading中),2(没有更多了)
|
||||
isShowEmpty: false, // 是否显示空布局
|
||||
isShowToTop: false, // 是否显示回到顶部按钮
|
||||
windowHeight: 0, // 可使用窗口的高度
|
||||
statusBarHeight: 0 // 状态栏高度
|
||||
};
|
||||
},
|
||||
props: {
|
||||
down: Object, // 下拉刷新的参数配置
|
||||
up: Object, // 上拉加载的参数配置
|
||||
top: [String, Number], // 下拉布局往下的偏移量 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx, 百分比则相对于windowHeight)
|
||||
topbar: Boolean, // top的偏移量是否加上状态栏高度, 默认false (使用场景:取消原生导航栏时,配置此项可自动加上状态栏高度的偏移量)
|
||||
bottom: [String, Number], // 上拉布局往上的偏移量 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx, 百分比则相对于windowHeight)
|
||||
safearea: Boolean, // bottom的偏移量是否加上底部安全区的距离, 默认false (需要适配iPhoneX时使用)
|
||||
height: [String, Number], // 指定mescroll最小高度,默认windowHeight,使列表不满屏仍可下拉
|
||||
showTop: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// mescroll最小高度,默认windowHeight,使列表不满屏仍可下拉
|
||||
minHeight() {
|
||||
return this.toPx(this.height || '100%') + 'px';
|
||||
},
|
||||
// 下拉布局往下偏移的距离 (px)
|
||||
numTop() {
|
||||
return this.toPx(this.top) + (this.topbar ? this.statusBarHeight : 0);
|
||||
},
|
||||
padTop() {
|
||||
return this.numTop + 'px';
|
||||
},
|
||||
// 上拉布局往上偏移 (px)
|
||||
numBottom() {
|
||||
return this.toPx(this.bottom);
|
||||
},
|
||||
padBottom() {
|
||||
return this.numBottom + 'px';
|
||||
},
|
||||
padBottomConstant() {
|
||||
return this.safearea ? 'calc(' + this.padBottom + ' + constant(safe-area-inset-bottom))' : this.padBottom;
|
||||
},
|
||||
padBottomEnv() {
|
||||
return this.safearea ? 'calc(' + this.padBottom + ' + env(safe-area-inset-bottom))' : this.padBottom;
|
||||
},
|
||||
// 是否为重置下拉的状态
|
||||
isDownReset() {
|
||||
return this.downLoadType === 3 || this.downLoadType === 4;
|
||||
},
|
||||
// 过渡
|
||||
transition() {
|
||||
return this.isDownReset ? 'transform 300ms' : '';
|
||||
},
|
||||
translateY() {
|
||||
return this.downHight > 0 ? 'translateY(' + this.downHight + 'px)' : ''; // transform会使fixed失效,需注意把fixed元素写在mescroll之外
|
||||
},
|
||||
// 是否在加载中
|
||||
isDownLoading() {
|
||||
return this.downLoadType === 3;
|
||||
},
|
||||
// 旋转的角度
|
||||
downRotate() {
|
||||
return 'rotate(' + 360 * this.downRate + 'deg)';
|
||||
},
|
||||
// 文本提示
|
||||
downText() {
|
||||
switch (this.downLoadType) {
|
||||
case 1:
|
||||
return this.mescroll.optDown.textInOffset;
|
||||
case 2:
|
||||
return this.mescroll.optDown.textOutOffset;
|
||||
case 3:
|
||||
return this.mescroll.optDown.textLoading;
|
||||
case 4:
|
||||
return this.mescroll.optDown.textLoading;
|
||||
default:
|
||||
return this.mescroll.optDown.textInOffset;
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
//number,rpx,upx,px,% --> px的数值
|
||||
toPx(num) {
|
||||
if (typeof num === 'string') {
|
||||
if (num.indexOf('px') !== -1) {
|
||||
if (num.indexOf('rpx') !== -1) {
|
||||
// "10rpx"
|
||||
num = num.replace('rpx', '');
|
||||
} else if (num.indexOf('upx') !== -1) {
|
||||
// "10upx"
|
||||
num = num.replace('upx', '');
|
||||
} else {
|
||||
// "10px"
|
||||
return Number(num.replace('px', ''));
|
||||
}
|
||||
} else if (num.indexOf('%') !== -1) {
|
||||
// 传百分比,则相对于windowHeight,传"10%"则等于windowHeight的10%
|
||||
let rate = Number(num.replace('%', '')) / 100;
|
||||
return this.windowHeight * rate;
|
||||
}
|
||||
}
|
||||
return num ? uni.upx2px(Number(num)) : 0;
|
||||
},
|
||||
//注册列表touchstart事件,用于下拉刷新
|
||||
touchstartEvent(e) {
|
||||
this.mescroll.touchstartEvent(e);
|
||||
},
|
||||
//注册列表touchmove事件,用于下拉刷新
|
||||
touchmoveEvent(e) {
|
||||
this.mescroll.touchmoveEvent(e);
|
||||
},
|
||||
//注册列表touchend事件,用于下拉刷新
|
||||
touchendEvent(e) {
|
||||
this.mescroll.touchendEvent(e);
|
||||
},
|
||||
// 点击空布局的按钮回调
|
||||
emptyClick() {
|
||||
this.$emit('emptyclick', this.mescroll);
|
||||
},
|
||||
// 点击回到顶部的按钮回调
|
||||
toTopClick() {
|
||||
this.mescroll.scrollTo(0, this.mescroll.optUp.toTop.duration); // 执行回到顶部
|
||||
this.$emit('topclick', this.mescroll); // 派发点击回到顶部按钮的回调
|
||||
}
|
||||
},
|
||||
// 使用created初始化mescroll对象; 如果用mounted部分css样式编译到H5会失效
|
||||
created() {
|
||||
let vm = this;
|
||||
|
||||
let diyOption = {
|
||||
// 下拉刷新的配置
|
||||
down: {
|
||||
inOffset(mescroll) {
|
||||
vm.downLoadType = 1; // 下拉的距离进入offset范围内那一刻的回调 (自定义mescroll组件时,此行不可删)
|
||||
},
|
||||
outOffset(mescroll) {
|
||||
vm.downLoadType = 2; // 下拉的距离大于offset那一刻的回调 (自定义mescroll组件时,此行不可删)
|
||||
},
|
||||
onMoving(mescroll, rate, downHight) {
|
||||
// 下拉过程中的回调,滑动过程一直在执行;
|
||||
vm.downHight = downHight; // 设置下拉区域的高度 (自定义mescroll组件时,此行不可删)
|
||||
vm.downRate = rate; //下拉比率 (inOffset: rate<1; outOffset: rate>=1)
|
||||
},
|
||||
showLoading(mescroll, downHight) {
|
||||
vm.downLoadType = 3; // 显示下拉刷新进度的回调 (自定义mescroll组件时,此行不可删)
|
||||
vm.downHight = downHight; // 设置下拉区域的高度 (自定义mescroll组件时,此行不可删)
|
||||
},
|
||||
endDownScroll(mescroll) {
|
||||
vm.downLoadType = 4; // 结束下拉 (自定义mescroll组件时,此行不可删)
|
||||
vm.downHight = 0; // 设置下拉区域的高度 (自定义mescroll组件时,此行不可删)
|
||||
},
|
||||
// 派发下拉刷新的回调
|
||||
callback: function(mescroll) {
|
||||
vm.$emit('down', mescroll);
|
||||
}
|
||||
},
|
||||
// 上拉加载的配置
|
||||
up: {
|
||||
// 显示加载中的回调
|
||||
showLoading() {
|
||||
vm.upLoadType = 1;
|
||||
},
|
||||
// 显示无更多数据的回调
|
||||
showNoMore() {
|
||||
vm.upLoadType = 2;
|
||||
},
|
||||
// 隐藏上拉加载的回调
|
||||
hideUpScroll() {
|
||||
vm.upLoadType = 0;
|
||||
},
|
||||
// 空布局
|
||||
empty: {
|
||||
onShow(isShow) {
|
||||
// 显示隐藏的回调
|
||||
vm.isShowEmpty = isShow;
|
||||
}
|
||||
},
|
||||
// 回到顶部
|
||||
toTop: {
|
||||
onShow(isShow) {
|
||||
// 显示隐藏的回调
|
||||
vm.isShowToTop = isShow;
|
||||
}
|
||||
},
|
||||
// 派发上拉加载的回调
|
||||
callback: function(mescroll) {
|
||||
vm.$emit('up', mescroll);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
MeScroll.extend(diyOption, GlobalOption); // 混入全局的配置
|
||||
let myOption = JSON.parse(
|
||||
JSON.stringify({
|
||||
down: vm.down,
|
||||
up: vm.up
|
||||
})
|
||||
); // 深拷贝,避免对props的影响
|
||||
MeScroll.extend(myOption, diyOption); // 混入具体界面的配置
|
||||
|
||||
// 初始化MeScroll对象
|
||||
vm.mescroll = new MeScroll(myOption, true); // 传入true,标记body为滚动区域
|
||||
// init回调mescroll对象
|
||||
vm.$emit('init', vm.mescroll);
|
||||
|
||||
// 设置高度
|
||||
const sys = uni.getSystemInfoSync();
|
||||
if (sys.windowHeight) vm.windowHeight = sys.windowHeight;
|
||||
if (sys.statusBarHeight) vm.statusBarHeight = sys.statusBarHeight;
|
||||
// 使down的bottomOffset生效
|
||||
vm.mescroll.setBodyHeight(sys.windowHeight);
|
||||
|
||||
// 因为使用的是page的scroll,这里需自定义scrollTo
|
||||
vm.mescroll.resetScrollTo((y, t) => {
|
||||
uni.pageScrollTo({
|
||||
scrollTop: y,
|
||||
duration: t
|
||||
});
|
||||
});
|
||||
|
||||
// 具体的界面如果不配置up.toTop.safearea,则取本vue的safearea值
|
||||
if (vm.up && vm.up.toTop && vm.up.toTop.safearea != null) {
|
||||
} else {
|
||||
vm.mescroll.optUp.toTop.safearea = vm.safearea;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@import './mescroll-body.css';
|
||||
@import './components/mescroll-down.css';
|
||||
@import './components/mescroll-up.css';
|
||||
</style>
|
||||
<template>
|
||||
<view
|
||||
class="mescroll-body"
|
||||
:style="{ minHeight: minHeight, 'padding-top': padTop, 'padding-bottom': padBottom, 'padding-bottom': padBottomConstant, 'padding-bottom': padBottomEnv }"
|
||||
@touchstart="touchstartEvent"
|
||||
@touchmove="touchmoveEvent"
|
||||
@touchend="touchendEvent"
|
||||
@touchcancel="touchendEvent"
|
||||
>
|
||||
<view class="mescroll-body-content mescroll-touch" :style="{ transform: translateY, transition: transition }">
|
||||
<!-- 下拉加载区域 (支付宝小程序子组件传参给子子组件仍报单项数据流的异常,暂时不通过mescroll-down组件实现)-->
|
||||
<!-- <mescroll-down :option="mescroll.optDown" :type="downLoadType" :rate="downRate"></mescroll-down> -->
|
||||
<view v-if="mescroll.optDown.use" class="mescroll-downwarp">
|
||||
<view class="downwarp-content">
|
||||
<view class="downwarp-progress" :class="{ 'mescroll-rotate': isDownLoading }" :style="{ transform: downRotate }"></view>
|
||||
<view class="downwarp-tip">{{ downText }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 列表内容 -->
|
||||
<slot></slot>
|
||||
|
||||
<!-- 空布局 -->
|
||||
<!-- <mescroll-empty v-if="isShowEmpty" :option="mescroll.optUp.empty" @emptyclick="emptyClick"></mescroll-empty> -->
|
||||
|
||||
<!-- 上拉加载区域 (下拉刷新时不显示, 支付宝小程序子组件传参给子子组件仍报单项数据流的异常,暂时不通过mescroll-up组件实现)-->
|
||||
<!-- <mescroll-up v-if="mescroll.optUp.use && !isDownLoading" :option="mescroll.optUp" :type="upLoadType"></mescroll-up> -->
|
||||
<view v-if="mescroll.optUp.use && !isDownLoading" class="mescroll-upwarp">
|
||||
<!-- 加载中 (此处不能用v-if,否则android小程序快速上拉可能会不断触发上拉回调) -->
|
||||
<view v-show="upLoadType === 1">
|
||||
<view class="upwarp-progress mescroll-rotate"></view>
|
||||
<view class="upwarp-tip">{{ mescroll.optUp.textLoading }}</view>
|
||||
</view>
|
||||
<!-- 无数据 -->
|
||||
<view v-if="upLoadType === 2" class="upwarp-nodata">{{ mescroll.optUp.textNoMore }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 回到顶部按钮 (fixed元素需写在transform外面,防止降级为absolute)-->
|
||||
<mescroll-top v-model="isShowToTop" :option="mescroll.optUp.toTop" @click="toTopClick" v-if="showTop"></mescroll-top>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 引入mescroll-uni.js,处理核心逻辑
|
||||
import MeScroll from './mescroll-uni.js';
|
||||
// 引入全局配置
|
||||
import GlobalOption from './mescroll-uni-option.js';
|
||||
// 引入空布局组件
|
||||
import MescrollEmpty from './components/mescroll-empty.vue';
|
||||
// 引入回到顶部组件
|
||||
import MescrollTop from './components/mescroll-top.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MescrollEmpty,
|
||||
MescrollTop
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
mescroll: { optDown: {}, optUp: {} }, // mescroll实例
|
||||
downHight: 0, //下拉刷新: 容器高度
|
||||
downRate: 0, // 下拉比率(inOffset: rate<1; outOffset: rate>=1)
|
||||
downLoadType: 4, // 下拉刷新状态 (inOffset:1, outOffset:2, showLoading:3, endDownScroll:4)
|
||||
upLoadType: 0, // 上拉加载状态:0(loading前),1(loading中),2(没有更多了)
|
||||
isShowEmpty: false, // 是否显示空布局
|
||||
isShowToTop: false, // 是否显示回到顶部按钮
|
||||
windowHeight: 0, // 可使用窗口的高度
|
||||
statusBarHeight: 0 // 状态栏高度
|
||||
};
|
||||
},
|
||||
props: {
|
||||
down: Object, // 下拉刷新的参数配置
|
||||
up: Object, // 上拉加载的参数配置
|
||||
top: [String, Number], // 下拉布局往下的偏移量 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx, 百分比则相对于windowHeight)
|
||||
topbar: Boolean, // top的偏移量是否加上状态栏高度, 默认false (使用场景:取消原生导航栏时,配置此项可自动加上状态栏高度的偏移量)
|
||||
bottom: [String, Number], // 上拉布局往上的偏移量 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx, 百分比则相对于windowHeight)
|
||||
safearea: Boolean, // bottom的偏移量是否加上底部安全区的距离, 默认false (需要适配iPhoneX时使用)
|
||||
height: [String, Number], // 指定mescroll最小高度,默认windowHeight,使列表不满屏仍可下拉
|
||||
showTop: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// mescroll最小高度,默认windowHeight,使列表不满屏仍可下拉
|
||||
minHeight() {
|
||||
return this.toPx(this.height || '100%') + 'px';
|
||||
},
|
||||
// 下拉布局往下偏移的距离 (px)
|
||||
numTop() {
|
||||
return this.toPx(this.top) + (this.topbar ? this.statusBarHeight : 0);
|
||||
},
|
||||
padTop() {
|
||||
return this.numTop + 'px';
|
||||
},
|
||||
// 上拉布局往上偏移 (px)
|
||||
numBottom() {
|
||||
return this.toPx(this.bottom);
|
||||
},
|
||||
padBottom() {
|
||||
return this.numBottom + 'px';
|
||||
},
|
||||
padBottomConstant() {
|
||||
return this.safearea ? 'calc(' + this.padBottom + ' + constant(safe-area-inset-bottom))' : this.padBottom;
|
||||
},
|
||||
padBottomEnv() {
|
||||
return this.safearea ? 'calc(' + this.padBottom + ' + env(safe-area-inset-bottom))' : this.padBottom;
|
||||
},
|
||||
// 是否为重置下拉的状态
|
||||
isDownReset() {
|
||||
return this.downLoadType === 3 || this.downLoadType === 4;
|
||||
},
|
||||
// 过渡
|
||||
transition() {
|
||||
return this.isDownReset ? 'transform 300ms' : '';
|
||||
},
|
||||
translateY() {
|
||||
return this.downHight > 0 ? 'translateY(' + this.downHight + 'px)' : ''; // transform会使fixed失效,需注意把fixed元素写在mescroll之外
|
||||
},
|
||||
// 是否在加载中
|
||||
isDownLoading() {
|
||||
return this.downLoadType === 3;
|
||||
},
|
||||
// 旋转的角度
|
||||
downRotate() {
|
||||
return 'rotate(' + 360 * this.downRate + 'deg)';
|
||||
},
|
||||
// 文本提示
|
||||
downText() {
|
||||
switch (this.downLoadType) {
|
||||
case 1:
|
||||
return this.mescroll.optDown.textInOffset;
|
||||
case 2:
|
||||
return this.mescroll.optDown.textOutOffset;
|
||||
case 3:
|
||||
return this.mescroll.optDown.textLoading;
|
||||
case 4:
|
||||
return this.mescroll.optDown.textLoading;
|
||||
default:
|
||||
return this.mescroll.optDown.textInOffset;
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
//number,rpx,upx,px,% --> px的数值
|
||||
toPx(num) {
|
||||
if (typeof num === 'string') {
|
||||
if (num.indexOf('px') !== -1) {
|
||||
if (num.indexOf('rpx') !== -1) {
|
||||
// "10rpx"
|
||||
num = num.replace('rpx', '');
|
||||
} else if (num.indexOf('upx') !== -1) {
|
||||
// "10upx"
|
||||
num = num.replace('upx', '');
|
||||
} else {
|
||||
// "10px"
|
||||
return Number(num.replace('px', ''));
|
||||
}
|
||||
} else if (num.indexOf('%') !== -1) {
|
||||
// 传百分比,则相对于windowHeight,传"10%"则等于windowHeight的10%
|
||||
let rate = Number(num.replace('%', '')) / 100;
|
||||
return this.windowHeight * rate;
|
||||
}
|
||||
}
|
||||
return num ? uni.upx2px(Number(num)) : 0;
|
||||
},
|
||||
//注册列表touchstart事件,用于下拉刷新
|
||||
touchstartEvent(e) {
|
||||
this.mescroll.touchstartEvent(e);
|
||||
},
|
||||
//注册列表touchmove事件,用于下拉刷新
|
||||
touchmoveEvent(e) {
|
||||
this.mescroll.touchmoveEvent(e);
|
||||
},
|
||||
//注册列表touchend事件,用于下拉刷新
|
||||
touchendEvent(e) {
|
||||
this.mescroll.touchendEvent(e);
|
||||
},
|
||||
// 点击空布局的按钮回调
|
||||
emptyClick() {
|
||||
this.$emit('emptyclick', this.mescroll);
|
||||
},
|
||||
// 点击回到顶部的按钮回调
|
||||
toTopClick() {
|
||||
this.mescroll.scrollTo(0, this.mescroll.optUp.toTop.duration); // 执行回到顶部
|
||||
this.$emit('topclick', this.mescroll); // 派发点击回到顶部按钮的回调
|
||||
}
|
||||
},
|
||||
// 使用created初始化mescroll对象; 如果用mounted部分css样式编译到H5会失效
|
||||
created() {
|
||||
let vm = this;
|
||||
|
||||
let diyOption = {
|
||||
// 下拉刷新的配置
|
||||
down: {
|
||||
inOffset(mescroll) {
|
||||
vm.downLoadType = 1; // 下拉的距离进入offset范围内那一刻的回调 (自定义mescroll组件时,此行不可删)
|
||||
},
|
||||
outOffset(mescroll) {
|
||||
vm.downLoadType = 2; // 下拉的距离大于offset那一刻的回调 (自定义mescroll组件时,此行不可删)
|
||||
},
|
||||
onMoving(mescroll, rate, downHight) {
|
||||
// 下拉过程中的回调,滑动过程一直在执行;
|
||||
vm.downHight = downHight; // 设置下拉区域的高度 (自定义mescroll组件时,此行不可删)
|
||||
vm.downRate = rate; //下拉比率 (inOffset: rate<1; outOffset: rate>=1)
|
||||
},
|
||||
showLoading(mescroll, downHight) {
|
||||
vm.downLoadType = 3; // 显示下拉刷新进度的回调 (自定义mescroll组件时,此行不可删)
|
||||
vm.downHight = downHight; // 设置下拉区域的高度 (自定义mescroll组件时,此行不可删)
|
||||
},
|
||||
endDownScroll(mescroll) {
|
||||
vm.downLoadType = 4; // 结束下拉 (自定义mescroll组件时,此行不可删)
|
||||
vm.downHight = 0; // 设置下拉区域的高度 (自定义mescroll组件时,此行不可删)
|
||||
},
|
||||
// 派发下拉刷新的回调
|
||||
callback: function(mescroll) {
|
||||
vm.$emit('down', mescroll);
|
||||
}
|
||||
},
|
||||
// 上拉加载的配置
|
||||
up: {
|
||||
// 显示加载中的回调
|
||||
showLoading() {
|
||||
vm.upLoadType = 1;
|
||||
},
|
||||
// 显示无更多数据的回调
|
||||
showNoMore() {
|
||||
vm.upLoadType = 2;
|
||||
},
|
||||
// 隐藏上拉加载的回调
|
||||
hideUpScroll() {
|
||||
vm.upLoadType = 0;
|
||||
},
|
||||
// 空布局
|
||||
empty: {
|
||||
onShow(isShow) {
|
||||
// 显示隐藏的回调
|
||||
vm.isShowEmpty = isShow;
|
||||
}
|
||||
},
|
||||
// 回到顶部
|
||||
toTop: {
|
||||
onShow(isShow) {
|
||||
// 显示隐藏的回调
|
||||
vm.isShowToTop = isShow;
|
||||
}
|
||||
},
|
||||
// 派发上拉加载的回调
|
||||
callback: function(mescroll) {
|
||||
vm.$emit('up', mescroll);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
MeScroll.extend(diyOption, GlobalOption); // 混入全局的配置
|
||||
let myOption = JSON.parse(
|
||||
JSON.stringify({
|
||||
down: vm.down,
|
||||
up: vm.up
|
||||
})
|
||||
); // 深拷贝,避免对props的影响
|
||||
MeScroll.extend(myOption, diyOption); // 混入具体界面的配置
|
||||
|
||||
// 初始化MeScroll对象
|
||||
vm.mescroll = new MeScroll(myOption, true); // 传入true,标记body为滚动区域
|
||||
// init回调mescroll对象
|
||||
vm.$emit('init', vm.mescroll);
|
||||
|
||||
// 设置高度
|
||||
const sys = uni.getSystemInfoSync();
|
||||
if (sys.windowHeight) vm.windowHeight = sys.windowHeight;
|
||||
if (sys.statusBarHeight) vm.statusBarHeight = sys.statusBarHeight;
|
||||
// 使down的bottomOffset生效
|
||||
vm.mescroll.setBodyHeight(sys.windowHeight);
|
||||
|
||||
// 因为使用的是page的scroll,这里需自定义scrollTo
|
||||
vm.mescroll.resetScrollTo((y, t) => {
|
||||
uni.pageScrollTo({
|
||||
scrollTop: y,
|
||||
duration: t
|
||||
});
|
||||
});
|
||||
|
||||
// 具体的界面如果不配置up.toTop.safearea,则取本vue的safearea值
|
||||
if (vm.up && vm.up.toTop && vm.up.toTop.safearea != null) {
|
||||
} else {
|
||||
vm.mescroll.optUp.toTop.safearea = vm.safearea;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import './mescroll-body.css';
|
||||
@import './components/mescroll-down.css';
|
||||
@import './components/mescroll-up.css';
|
||||
</style>
|
||||
|
||||
@@ -1,429 +1,429 @@
|
||||
<template>
|
||||
<view class="mescroll-uni-warp">
|
||||
<scroll-view :id="viewId" class="mescroll-uni" :class="{ 'mescroll-uni-fixed': isFixed }" :style="{
|
||||
height: scrollHeight,
|
||||
'padding-top': padTop,
|
||||
'padding-bottom': padBottom,
|
||||
'padding-bottom': padBottomConstant,
|
||||
'padding-bottom': padBottomEnv,
|
||||
top: fixedTop,
|
||||
bottom: fixedBottom,
|
||||
bottom: fixedBottomConstant,
|
||||
bottom: fixedBottomEnv,
|
||||
background: background,
|
||||
'padding-left': paddingBoth,
|
||||
'padding-right': paddingBoth
|
||||
}" :scroll-top="scrollTop" :scroll-with-animation="scrollAnim" @scroll="scroll" @touchstart="touchstartEvent"
|
||||
@touchmove="touchmoveEvent" @touchend="touchendEvent" @touchcancel="touchendEvent" :scroll-y="isDownReset"
|
||||
:enable-back-to-top="true">
|
||||
<view class="mescroll-uni-content" :style="{ transform: translateY, transition: transition }">
|
||||
<!-- 下拉加载区域 (支付宝小程序子组件传参给子子组件仍报单项数据流的异常,暂时不通过mescroll-down组件实现)-->
|
||||
<!-- <mescroll-down :option="mescroll.optDown" :type="downLoadType" :rate="downRate"></mescroll-down> -->
|
||||
<view v-if="mescroll.optDown.use" class="mescroll-downwarp">
|
||||
<view class="downwarp-content">
|
||||
<!-- <view class="downwarp-progress" :class="{'mescroll-rotate': isDownLoading}" :style="{'transform': downRotate}"></view> -->
|
||||
<view class="downwarp-tip">{{ downText }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 列表内容 -->
|
||||
<slot></slot>
|
||||
|
||||
<!-- 空布局 -->
|
||||
<!-- <mescroll-empty v-if="isShowEmpty" :option="mescroll.optUp.empty" @emptyclick="emptyClick"></mescroll-empty> -->
|
||||
|
||||
<!-- 上拉加载区域 (下拉刷新时不显示, 支付宝小程序子组件传参给子子组件仍报单项数据流的异常,暂时不通过mescroll-up组件实现)-->
|
||||
<!-- <mescroll-up v-if="mescroll.optUp.use && !isDownLoading" :option="mescroll.optUp" :type="upLoadType"></mescroll-up> -->
|
||||
<view v-if="mescroll.optUp.use && !isDownLoading" class="mescroll-upwarp">
|
||||
<!-- 加载中 (此处不能用v-if,否则android小程序快速上拉可能会不断触发上拉回调) -->
|
||||
<view v-show="upLoadType === 1">
|
||||
<!-- <view class="upwarp-progress mescroll-rotate"></view>
|
||||
<view class="upwarp-tip">{{ mescroll.optUp.textLoading }}</view> -->
|
||||
<ns-loading></ns-loading>
|
||||
</view>
|
||||
<!-- 无数据 -->
|
||||
<view v-if="upLoadType === 2" class="upwarp-nodata">{{ mescroll.optUp.textNoMore }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 回到顶部按钮 (fixed元素,需写在scroll-view外面,防止滚动的时候抖动)-->
|
||||
<mescroll-top v-if="showTop" v-model="isShowToTop" :option="mescroll.optUp.toTop" @click="toTopClick"></mescroll-top>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 引入mescroll-uni.js,处理核心逻辑
|
||||
import MeScroll from './mescroll-uni.js';
|
||||
// 引入全局配置
|
||||
import GlobalOption from './mescroll-uni-option.js';
|
||||
// 引入空布局组件
|
||||
import MescrollEmpty from './components/mescroll-empty.vue';
|
||||
// 引入回到顶部组件
|
||||
import MescrollTop from './components/mescroll-top.vue';
|
||||
|
||||
import nsLoading from '@/components/ns-loading/ns-loading.vue';
|
||||
|
||||
export default {
|
||||
name: 'mescroll-uni',
|
||||
components: {
|
||||
MescrollEmpty,
|
||||
MescrollTop
|
||||
},
|
||||
props: {
|
||||
down: Object, // 下拉刷新的参数配置
|
||||
up: Object, // 上拉加载的参数配置
|
||||
top: [String, Number], // 下拉布局往下的偏移量 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx, 百分比则相对于windowHeight)
|
||||
topbar: Boolean, // top的偏移量是否加上状态栏高度, 默认false (使用场景:取消原生导航栏时,配置此项可自动加上状态栏高度的偏移量)
|
||||
bottom: [String, Number], // 上拉布局往上的偏移量 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx, 百分比则相对于windowHeight)
|
||||
safearea: Boolean, // bottom的偏移量是否加上底部安全区的距离, 默认false (需要适配iPhoneX时使用)
|
||||
fixed: {
|
||||
// 是否通过fixed固定mescroll的高度, 默认true
|
||||
type: Boolean,
|
||||
default () {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
height: [String,
|
||||
Number
|
||||
], // 指定mescroll的高度, 此项有值,则不使用fixed. (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx, 百分比则相对于windowHeight)
|
||||
showTop: {
|
||||
//是否需要展示返回顶部按钮
|
||||
type: Boolean,
|
||||
default () {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
background: String,
|
||||
paddingBoth: {
|
||||
type: [String, Number],
|
||||
default () {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
mescroll: {
|
||||
optDown: {},
|
||||
optUp: {}
|
||||
}, // mescroll实例
|
||||
viewId: 'id_' +
|
||||
Math.random()
|
||||
.toString(36)
|
||||
.substr(2), // 随机生成mescroll的id(不能数字开头,否则找不到元素)
|
||||
downHight: 0, //下拉刷新: 容器高度
|
||||
downRate: 0, // 下拉比率(inOffset: rate<1; outOffset: rate>=1)
|
||||
downLoadType: 4, // 下拉刷新状态 (inOffset:1, outOffset:2, showLoading:3, endDownScroll:4)
|
||||
upLoadType: 0, // 上拉加载状态:0(loading前),1(loading中),2(没有更多了)
|
||||
isShowEmpty: false, // 是否显示空布局
|
||||
isShowToTop: false, // 是否显示回到顶部按钮
|
||||
scrollTop: 0, // 滚动条的位置
|
||||
scrollAnim: false, // 是否开启滚动动画
|
||||
windowTop: 0, // 可使用窗口的顶部位置
|
||||
windowBottom: 0, // 可使用窗口的底部位置
|
||||
windowHeight: 0, // 可使用窗口的高度
|
||||
statusBarHeight: 0 // 状态栏高度
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
// 是否使用fixed定位 (当height有值,则不使用)
|
||||
isFixed() {
|
||||
return !this.height && this.fixed;
|
||||
},
|
||||
// mescroll的高度
|
||||
scrollHeight() {
|
||||
if (this.isFixed) {
|
||||
return 'auto';
|
||||
} else if (this.height) {
|
||||
return this.toPx(this.height) + 'px';
|
||||
} else {
|
||||
return '100%';
|
||||
}
|
||||
},
|
||||
// 下拉布局往下偏移的距离 (px)
|
||||
numTop() {
|
||||
// #ifdef H5
|
||||
return this.toPx(this.top) + (this.topbar ? this.statusBarHeight : 0);
|
||||
// #endif
|
||||
|
||||
// #ifdef MP
|
||||
return this.toPx(this.top) + (this.topbar ? 44 + this.statusBarHeight : 0);
|
||||
// #endif
|
||||
},
|
||||
fixedTop() {
|
||||
return this.isFixed ? this.numTop + this.windowTop + 'px' : 0;
|
||||
},
|
||||
padTop() {
|
||||
return !this.isFixed ? this.numTop + 'px' : 0;
|
||||
},
|
||||
// 上拉布局往上偏移 (px)
|
||||
numBottom() {
|
||||
return this.toPx(this.bottom);
|
||||
},
|
||||
fixedBottom() {
|
||||
return this.isFixed ? this.numBottom + this.windowBottom + 'px' : 0;
|
||||
},
|
||||
fixedBottomConstant() {
|
||||
return this.safearea ? 'calc(' + this.fixedBottom + ' + constant(safe-area-inset-bottom))' : this
|
||||
.fixedBottom;
|
||||
},
|
||||
fixedBottomEnv() {
|
||||
return this.safearea ? 'calc(' + this.fixedBottom + ' + env(safe-area-inset-bottom))' : this.fixedBottom;
|
||||
},
|
||||
padBottom() {
|
||||
return !this.isFixed ? this.numBottom + 'px' : 0;
|
||||
},
|
||||
padBottomConstant() {
|
||||
return this.safearea ? 'calc(' + this.padBottom + ' + constant(safe-area-inset-bottom))' : this.padBottom;
|
||||
},
|
||||
padBottomEnv() {
|
||||
return this.safearea ? 'calc(' + this.padBottom + ' + env(safe-area-inset-bottom))' : this.padBottom;
|
||||
},
|
||||
// 是否为重置下拉的状态
|
||||
isDownReset() {
|
||||
return this.downLoadType === 3 || this.downLoadType === 4;
|
||||
},
|
||||
// 过渡
|
||||
transition() {
|
||||
return this.isDownReset ? 'transform 300ms' : '';
|
||||
},
|
||||
translateY() {
|
||||
return this.downHight > 0 ? 'translateY(' + this.downHight + 'px)' :
|
||||
''; // transform会使fixed失效,需注意把fixed元素写在mescroll之外
|
||||
},
|
||||
// 是否在加载中
|
||||
isDownLoading() {
|
||||
return this.downLoadType === 3;
|
||||
},
|
||||
// 旋转的角度
|
||||
downRotate() {
|
||||
return 'rotate(' + 360 * this.downRate + 'deg)';
|
||||
},
|
||||
// 文本提示
|
||||
downText() {
|
||||
switch (this.downLoadType) {
|
||||
case 1:
|
||||
return this.mescroll.optDown.textInOffset;
|
||||
case 2:
|
||||
return this.mescroll.optDown.textOutOffset;
|
||||
case 3:
|
||||
return this.mescroll.optDown.textLoading;
|
||||
case 4:
|
||||
return this.mescroll.optDown.textLoading;
|
||||
default:
|
||||
return this.mescroll.optDown.textInOffset;
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
//number,rpx,upx,px,% --> px的数值
|
||||
toPx(num) {
|
||||
if (typeof num === 'string') {
|
||||
if (num.indexOf('px') !== -1) {
|
||||
if (num.indexOf('rpx') !== -1) {
|
||||
// "10rpx"
|
||||
num = num.replace('rpx', '');
|
||||
} else if (num.indexOf('upx') !== -1) {
|
||||
// "10upx"
|
||||
num = num.replace('upx', '');
|
||||
} else {
|
||||
// "10px"
|
||||
return Number(num.replace('px', ''));
|
||||
}
|
||||
} else if (num.indexOf('%') !== -1) {
|
||||
// 传百分比,则相对于windowHeight,传"10%"则等于windowHeight的10%
|
||||
let rate = Number(num.replace('%', '')) / 100;
|
||||
return this.windowHeight * rate;
|
||||
}
|
||||
}
|
||||
return num ? uni.upx2px(Number(num)) : 0;
|
||||
},
|
||||
//注册列表滚动事件,用于下拉刷新和上拉加载
|
||||
scroll(e) {
|
||||
this.mescroll.scroll(e.detail, () => {
|
||||
this.$emit('scroll', this
|
||||
.mescroll); // 此时可直接通过 this.mescroll.scrollTop获取滚动条位置; this.mescroll.isScrollUp获取是否向上滑动
|
||||
});
|
||||
},
|
||||
//注册列表touchstart事件,用于下拉刷新
|
||||
touchstartEvent(e) {
|
||||
this.mescroll.touchstartEvent(e);
|
||||
},
|
||||
//注册列表touchmove事件,用于下拉刷新
|
||||
touchmoveEvent(e) {
|
||||
this.mescroll.touchmoveEvent(e);
|
||||
},
|
||||
//注册列表touchend事件,用于下拉刷新
|
||||
touchendEvent(e) {
|
||||
this.mescroll.touchendEvent(e);
|
||||
},
|
||||
// 点击空布局的按钮回调
|
||||
emptyClick() {
|
||||
this.$emit('emptyclick', this.mescroll);
|
||||
},
|
||||
// 点击回到顶部的按钮回调
|
||||
toTopClick() {
|
||||
this.mescroll.scrollTo(0, this.mescroll.optUp.toTop.duration); // 执行回到顶部
|
||||
this.$emit('topclick', this.mescroll); // 派发点击回到顶部按钮的回调
|
||||
},
|
||||
// 更新滚动区域的高度 (使内容不满屏和到底,都可继续翻页)
|
||||
setClientHeight() {
|
||||
if (this.mescroll.getClientHeight(true) === 0 && !this.isExec) {
|
||||
this.isExec = true; // 避免多次获取
|
||||
this.$nextTick(() => {
|
||||
// 确保dom已渲染
|
||||
try {
|
||||
let view = uni
|
||||
.createSelectorQuery()
|
||||
.in(this)
|
||||
.select('#' + this.viewId);
|
||||
view.boundingClientRect(data => {
|
||||
this.isExec = false;
|
||||
if (data) {
|
||||
this.mescroll.setClientHeight(data.height);
|
||||
} else if (this.clientNum != 3) {
|
||||
// 极少部分情况,可能dom还未渲染完毕,递归获取,最多重试3次
|
||||
this.clientNum = this.clientNum == null ? 1 : this.clientNum + 1;
|
||||
setTimeout(() => {
|
||||
this.setClientHeight();
|
||||
}, this.clientNum * 100);
|
||||
}
|
||||
}).exec();
|
||||
} catch (e) {}
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
// 使用created初始化mescroll对象; 如果用mounted部分css样式编译到H5会失效
|
||||
created() {
|
||||
let vm = this;
|
||||
|
||||
let diyOption = {
|
||||
// 下拉刷新的配置
|
||||
down: {
|
||||
inOffset(mescroll) {
|
||||
vm.downLoadType = 1; // 下拉的距离进入offset范围内那一刻的回调 (自定义mescroll组件时,此行不可删)
|
||||
},
|
||||
outOffset(mescroll) {
|
||||
vm.downLoadType = 2; // 下拉的距离大于offset那一刻的回调 (自定义mescroll组件时,此行不可删)
|
||||
},
|
||||
onMoving(mescroll, rate, downHight) {
|
||||
// 下拉过程中的回调,滑动过程一直在执行;
|
||||
vm.downHight = downHight; // 设置下拉区域的高度 (自定义mescroll组件时,此行不可删)
|
||||
vm.downRate = rate; //下拉比率 (inOffset: rate<1; outOffset: rate>=1)
|
||||
},
|
||||
showLoading(mescroll, downHight) {
|
||||
vm.downLoadType = 3; // 显示下拉刷新进度的回调 (自定义mescroll组件时,此行不可删)
|
||||
vm.downHight = downHight; // 设置下拉区域的高度 (自定义mescroll组件时,此行不可删)
|
||||
},
|
||||
endDownScroll(mescroll) {
|
||||
vm.downLoadType = 4; // 结束下拉 (自定义mescroll组件时,此行不可删)
|
||||
vm.downHight = 0; // 设置下拉区域的高度 (自定义mescroll组件时,此行不可删)
|
||||
},
|
||||
// 派发下拉刷新的回调
|
||||
callback: function(mescroll) {
|
||||
vm.$emit('down', mescroll);
|
||||
}
|
||||
},
|
||||
// 上拉加载的配置
|
||||
up: {
|
||||
// 显示加载中的回调
|
||||
showLoading() {
|
||||
vm.upLoadType = 1;
|
||||
},
|
||||
// 显示无更多数据的回调
|
||||
showNoMore() {
|
||||
vm.upLoadType = 2;
|
||||
},
|
||||
// 隐藏上拉加载的回调
|
||||
hideUpScroll() {
|
||||
vm.upLoadType = 0;
|
||||
},
|
||||
// 空布局
|
||||
empty: {
|
||||
onShow(isShow) {
|
||||
// 显示隐藏的回调
|
||||
vm.isShowEmpty = isShow;
|
||||
}
|
||||
},
|
||||
// 回到顶部
|
||||
toTop: {
|
||||
onShow(isShow) {
|
||||
// 显示隐藏的回调
|
||||
vm.isShowToTop = isShow;
|
||||
}
|
||||
},
|
||||
// 派发上拉加载的回调
|
||||
callback: function(mescroll) {
|
||||
vm.$emit('up', mescroll);
|
||||
// 更新容器的高度 (多mescroll的情况)
|
||||
vm.setClientHeight();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
MeScroll.extend(diyOption, GlobalOption); // 混入全局的配置
|
||||
let myOption = JSON.parse(
|
||||
JSON.stringify({
|
||||
down: vm.down,
|
||||
up: vm.up
|
||||
})
|
||||
); // 深拷贝,避免对props的影响
|
||||
MeScroll.extend(myOption, diyOption); // 混入具体界面的配置
|
||||
|
||||
// 初始化MeScroll对象
|
||||
vm.mescroll = new MeScroll(myOption);
|
||||
vm.mescroll.viewId = vm.viewId; // 附带id
|
||||
// init回调mescroll对象
|
||||
vm.$emit('init', vm.mescroll);
|
||||
|
||||
// 设置高度
|
||||
const sys = uni.getSystemInfoSync();
|
||||
if (sys.windowTop) vm.windowTop = sys.windowTop;
|
||||
if (sys.windowBottom) vm.windowBottom = sys.windowBottom;
|
||||
if (sys.windowHeight) vm.windowHeight = sys.windowHeight;
|
||||
if (sys.statusBarHeight) vm.statusBarHeight = sys.statusBarHeight;
|
||||
// 使down的bottomOffset生效
|
||||
vm.mescroll.setBodyHeight(sys.windowHeight);
|
||||
|
||||
// 因为使用的是scrollview,这里需自定义scrollTo
|
||||
vm.mescroll.resetScrollTo((y, t) => {
|
||||
let curY = vm.mescroll.getScrollTop();
|
||||
vm.scrollAnim = t !== 0; // t为0,则不使用动画过渡
|
||||
if (t === 0 || t === 300) {
|
||||
// 当t使用默认配置的300时,则使用系统自带的动画过渡
|
||||
vm.scrollTop = curY;
|
||||
vm.$nextTick(function() {
|
||||
vm.scrollTop = y;
|
||||
});
|
||||
} else {
|
||||
vm.mescroll.getStep(
|
||||
curY,
|
||||
y,
|
||||
step => {
|
||||
// 此写法可支持配置t
|
||||
vm.scrollTop = step;
|
||||
},
|
||||
t
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// 具体的界面如果不配置up.toTop.safearea,则取本vue的safearea值
|
||||
if (vm.up && vm.up.toTop && vm.up.toTop.safearea != null) {} else {
|
||||
vm.mescroll.optUp.toTop.safearea = vm.safearea;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// 设置容器的高度
|
||||
this.setClientHeight();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@import './mescroll-uni.css';
|
||||
@import './components/mescroll-down.css';
|
||||
@import './components/mescroll-up.css';
|
||||
<template>
|
||||
<view class="mescroll-uni-warp">
|
||||
<scroll-view :id="viewId" class="mescroll-uni" :class="{ 'mescroll-uni-fixed': isFixed }" :style="{
|
||||
height: scrollHeight,
|
||||
'padding-top': padTop,
|
||||
'padding-bottom': padBottom,
|
||||
'padding-bottom': padBottomConstant,
|
||||
'padding-bottom': padBottomEnv,
|
||||
top: fixedTop,
|
||||
bottom: fixedBottom,
|
||||
bottom: fixedBottomConstant,
|
||||
bottom: fixedBottomEnv,
|
||||
background: background,
|
||||
'padding-left': paddingBoth,
|
||||
'padding-right': paddingBoth
|
||||
}" :scroll-top="scrollTop" :scroll-with-animation="scrollAnim" @scroll="scroll" @touchstart="touchstartEvent"
|
||||
@touchmove="touchmoveEvent" @touchend="touchendEvent" @touchcancel="touchendEvent" :scroll-y="isDownReset"
|
||||
:enable-back-to-top="true">
|
||||
<view class="mescroll-uni-content" :style="{ transform: translateY, transition: transition }">
|
||||
<!-- 下拉加载区域 (支付宝小程序子组件传参给子子组件仍报单项数据流的异常,暂时不通过mescroll-down组件实现)-->
|
||||
<!-- <mescroll-down :option="mescroll.optDown" :type="downLoadType" :rate="downRate"></mescroll-down> -->
|
||||
<view v-if="mescroll.optDown.use" class="mescroll-downwarp">
|
||||
<view class="downwarp-content">
|
||||
<!-- <view class="downwarp-progress" :class="{'mescroll-rotate': isDownLoading}" :style="{'transform': downRotate}"></view> -->
|
||||
<view class="downwarp-tip">{{ downText }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 列表内容 -->
|
||||
<slot></slot>
|
||||
|
||||
<!-- 空布局 -->
|
||||
<!-- <mescroll-empty v-if="isShowEmpty" :option="mescroll.optUp.empty" @emptyclick="emptyClick"></mescroll-empty> -->
|
||||
|
||||
<!-- 上拉加载区域 (下拉刷新时不显示, 支付宝小程序子组件传参给子子组件仍报单项数据流的异常,暂时不通过mescroll-up组件实现)-->
|
||||
<!-- <mescroll-up v-if="mescroll.optUp.use && !isDownLoading" :option="mescroll.optUp" :type="upLoadType"></mescroll-up> -->
|
||||
<view v-if="mescroll.optUp.use && !isDownLoading" class="mescroll-upwarp">
|
||||
<!-- 加载中 (此处不能用v-if,否则android小程序快速上拉可能会不断触发上拉回调) -->
|
||||
<view v-show="upLoadType === 1">
|
||||
<!-- <view class="upwarp-progress mescroll-rotate"></view>
|
||||
<view class="upwarp-tip">{{ mescroll.optUp.textLoading }}</view> -->
|
||||
<ns-loading></ns-loading>
|
||||
</view>
|
||||
<!-- 无数据 -->
|
||||
<view v-if="upLoadType === 2" class="upwarp-nodata">{{ mescroll.optUp.textNoMore }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 回到顶部按钮 (fixed元素,需写在scroll-view外面,防止滚动的时候抖动)-->
|
||||
<mescroll-top v-if="showTop" v-model="isShowToTop" :option="mescroll.optUp.toTop" @click="toTopClick"></mescroll-top>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 引入mescroll-uni.js,处理核心逻辑
|
||||
import MeScroll from './mescroll-uni.js';
|
||||
// 引入全局配置
|
||||
import GlobalOption from './mescroll-uni-option.js';
|
||||
// 引入空布局组件
|
||||
import MescrollEmpty from './components/mescroll-empty.vue';
|
||||
// 引入回到顶部组件
|
||||
import MescrollTop from './components/mescroll-top.vue';
|
||||
|
||||
import nsLoading from '@/components/ns-loading/ns-loading.vue';
|
||||
|
||||
export default {
|
||||
name: 'mescroll-uni',
|
||||
components: {
|
||||
MescrollEmpty,
|
||||
MescrollTop
|
||||
},
|
||||
props: {
|
||||
down: Object, // 下拉刷新的参数配置
|
||||
up: Object, // 上拉加载的参数配置
|
||||
top: [String, Number], // 下拉布局往下的偏移量 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx, 百分比则相对于windowHeight)
|
||||
topbar: Boolean, // top的偏移量是否加上状态栏高度, 默认false (使用场景:取消原生导航栏时,配置此项可自动加上状态栏高度的偏移量)
|
||||
bottom: [String, Number], // 上拉布局往上的偏移量 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx, 百分比则相对于windowHeight)
|
||||
safearea: Boolean, // bottom的偏移量是否加上底部安全区的距离, 默认false (需要适配iPhoneX时使用)
|
||||
fixed: {
|
||||
// 是否通过fixed固定mescroll的高度, 默认true
|
||||
type: Boolean,
|
||||
default () {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
height: [String,
|
||||
Number
|
||||
], // 指定mescroll的高度, 此项有值,则不使用fixed. (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx, 百分比则相对于windowHeight)
|
||||
showTop: {
|
||||
//是否需要展示返回顶部按钮
|
||||
type: Boolean,
|
||||
default () {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
background: String,
|
||||
paddingBoth: {
|
||||
type: [String, Number],
|
||||
default () {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
mescroll: {
|
||||
optDown: {},
|
||||
optUp: {}
|
||||
}, // mescroll实例
|
||||
viewId: 'id_' +
|
||||
Math.random()
|
||||
.toString(36)
|
||||
.substr(2), // 随机生成mescroll的id(不能数字开头,否则找不到元素)
|
||||
downHight: 0, //下拉刷新: 容器高度
|
||||
downRate: 0, // 下拉比率(inOffset: rate<1; outOffset: rate>=1)
|
||||
downLoadType: 4, // 下拉刷新状态 (inOffset:1, outOffset:2, showLoading:3, endDownScroll:4)
|
||||
upLoadType: 0, // 上拉加载状态:0(loading前),1(loading中),2(没有更多了)
|
||||
isShowEmpty: false, // 是否显示空布局
|
||||
isShowToTop: false, // 是否显示回到顶部按钮
|
||||
scrollTop: 0, // 滚动条的位置
|
||||
scrollAnim: false, // 是否开启滚动动画
|
||||
windowTop: 0, // 可使用窗口的顶部位置
|
||||
windowBottom: 0, // 可使用窗口的底部位置
|
||||
windowHeight: 0, // 可使用窗口的高度
|
||||
statusBarHeight: 0 // 状态栏高度
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
// 是否使用fixed定位 (当height有值,则不使用)
|
||||
isFixed() {
|
||||
return !this.height && this.fixed;
|
||||
},
|
||||
// mescroll的高度
|
||||
scrollHeight() {
|
||||
if (this.isFixed) {
|
||||
return 'auto';
|
||||
} else if (this.height) {
|
||||
return this.toPx(this.height) + 'px';
|
||||
} else {
|
||||
return '100%';
|
||||
}
|
||||
},
|
||||
// 下拉布局往下偏移的距离 (px)
|
||||
numTop() {
|
||||
// #ifdef H5
|
||||
return this.toPx(this.top) + (this.topbar ? this.statusBarHeight : 0);
|
||||
// #endif
|
||||
|
||||
// #ifdef MP
|
||||
return this.toPx(this.top) + (this.topbar ? 44 + this.statusBarHeight : 0);
|
||||
// #endif
|
||||
},
|
||||
fixedTop() {
|
||||
return this.isFixed ? this.numTop + this.windowTop + 'px' : 0;
|
||||
},
|
||||
padTop() {
|
||||
return !this.isFixed ? this.numTop + 'px' : 0;
|
||||
},
|
||||
// 上拉布局往上偏移 (px)
|
||||
numBottom() {
|
||||
return this.toPx(this.bottom);
|
||||
},
|
||||
fixedBottom() {
|
||||
return this.isFixed ? this.numBottom + this.windowBottom + 'px' : 0;
|
||||
},
|
||||
fixedBottomConstant() {
|
||||
return this.safearea ? 'calc(' + this.fixedBottom + ' + constant(safe-area-inset-bottom))' : this
|
||||
.fixedBottom;
|
||||
},
|
||||
fixedBottomEnv() {
|
||||
return this.safearea ? 'calc(' + this.fixedBottom + ' + env(safe-area-inset-bottom))' : this.fixedBottom;
|
||||
},
|
||||
padBottom() {
|
||||
return !this.isFixed ? this.numBottom + 'px' : 0;
|
||||
},
|
||||
padBottomConstant() {
|
||||
return this.safearea ? 'calc(' + this.padBottom + ' + constant(safe-area-inset-bottom))' : this.padBottom;
|
||||
},
|
||||
padBottomEnv() {
|
||||
return this.safearea ? 'calc(' + this.padBottom + ' + env(safe-area-inset-bottom))' : this.padBottom;
|
||||
},
|
||||
// 是否为重置下拉的状态
|
||||
isDownReset() {
|
||||
return this.downLoadType === 3 || this.downLoadType === 4;
|
||||
},
|
||||
// 过渡
|
||||
transition() {
|
||||
return this.isDownReset ? 'transform 300ms' : '';
|
||||
},
|
||||
translateY() {
|
||||
return this.downHight > 0 ? 'translateY(' + this.downHight + 'px)' :
|
||||
''; // transform会使fixed失效,需注意把fixed元素写在mescroll之外
|
||||
},
|
||||
// 是否在加载中
|
||||
isDownLoading() {
|
||||
return this.downLoadType === 3;
|
||||
},
|
||||
// 旋转的角度
|
||||
downRotate() {
|
||||
return 'rotate(' + 360 * this.downRate + 'deg)';
|
||||
},
|
||||
// 文本提示
|
||||
downText() {
|
||||
switch (this.downLoadType) {
|
||||
case 1:
|
||||
return this.mescroll.optDown.textInOffset;
|
||||
case 2:
|
||||
return this.mescroll.optDown.textOutOffset;
|
||||
case 3:
|
||||
return this.mescroll.optDown.textLoading;
|
||||
case 4:
|
||||
return this.mescroll.optDown.textLoading;
|
||||
default:
|
||||
return this.mescroll.optDown.textInOffset;
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
//number,rpx,upx,px,% --> px的数值
|
||||
toPx(num) {
|
||||
if (typeof num === 'string') {
|
||||
if (num.indexOf('px') !== -1) {
|
||||
if (num.indexOf('rpx') !== -1) {
|
||||
// "10rpx"
|
||||
num = num.replace('rpx', '');
|
||||
} else if (num.indexOf('upx') !== -1) {
|
||||
// "10upx"
|
||||
num = num.replace('upx', '');
|
||||
} else {
|
||||
// "10px"
|
||||
return Number(num.replace('px', ''));
|
||||
}
|
||||
} else if (num.indexOf('%') !== -1) {
|
||||
// 传百分比,则相对于windowHeight,传"10%"则等于windowHeight的10%
|
||||
let rate = Number(num.replace('%', '')) / 100;
|
||||
return this.windowHeight * rate;
|
||||
}
|
||||
}
|
||||
return num ? uni.upx2px(Number(num)) : 0;
|
||||
},
|
||||
//注册列表滚动事件,用于下拉刷新和上拉加载
|
||||
scroll(e) {
|
||||
this.mescroll.scroll(e.detail, () => {
|
||||
this.$emit('scroll', this
|
||||
.mescroll); // 此时可直接通过 this.mescroll.scrollTop获取滚动条位置; this.mescroll.isScrollUp获取是否向上滑动
|
||||
});
|
||||
},
|
||||
//注册列表touchstart事件,用于下拉刷新
|
||||
touchstartEvent(e) {
|
||||
this.mescroll.touchstartEvent(e);
|
||||
},
|
||||
//注册列表touchmove事件,用于下拉刷新
|
||||
touchmoveEvent(e) {
|
||||
this.mescroll.touchmoveEvent(e);
|
||||
},
|
||||
//注册列表touchend事件,用于下拉刷新
|
||||
touchendEvent(e) {
|
||||
this.mescroll.touchendEvent(e);
|
||||
},
|
||||
// 点击空布局的按钮回调
|
||||
emptyClick() {
|
||||
this.$emit('emptyclick', this.mescroll);
|
||||
},
|
||||
// 点击回到顶部的按钮回调
|
||||
toTopClick() {
|
||||
this.mescroll.scrollTo(0, this.mescroll.optUp.toTop.duration); // 执行回到顶部
|
||||
this.$emit('topclick', this.mescroll); // 派发点击回到顶部按钮的回调
|
||||
},
|
||||
// 更新滚动区域的高度 (使内容不满屏和到底,都可继续翻页)
|
||||
setClientHeight() {
|
||||
if (this.mescroll.getClientHeight(true) === 0 && !this.isExec) {
|
||||
this.isExec = true; // 避免多次获取
|
||||
this.$nextTick(() => {
|
||||
// 确保dom已渲染
|
||||
try {
|
||||
let view = uni
|
||||
.createSelectorQuery()
|
||||
.in(this)
|
||||
.select('#' + this.viewId);
|
||||
view.boundingClientRect(data => {
|
||||
this.isExec = false;
|
||||
if (data) {
|
||||
this.mescroll.setClientHeight(data.height);
|
||||
} else if (this.clientNum != 3) {
|
||||
// 极少部分情况,可能dom还未渲染完毕,递归获取,最多重试3次
|
||||
this.clientNum = this.clientNum == null ? 1 : this.clientNum + 1;
|
||||
setTimeout(() => {
|
||||
this.setClientHeight();
|
||||
}, this.clientNum * 100);
|
||||
}
|
||||
}).exec();
|
||||
} catch (e) {}
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
// 使用created初始化mescroll对象; 如果用mounted部分css样式编译到H5会失效
|
||||
created() {
|
||||
let vm = this;
|
||||
|
||||
let diyOption = {
|
||||
// 下拉刷新的配置
|
||||
down: {
|
||||
inOffset(mescroll) {
|
||||
vm.downLoadType = 1; // 下拉的距离进入offset范围内那一刻的回调 (自定义mescroll组件时,此行不可删)
|
||||
},
|
||||
outOffset(mescroll) {
|
||||
vm.downLoadType = 2; // 下拉的距离大于offset那一刻的回调 (自定义mescroll组件时,此行不可删)
|
||||
},
|
||||
onMoving(mescroll, rate, downHight) {
|
||||
// 下拉过程中的回调,滑动过程一直在执行;
|
||||
vm.downHight = downHight; // 设置下拉区域的高度 (自定义mescroll组件时,此行不可删)
|
||||
vm.downRate = rate; //下拉比率 (inOffset: rate<1; outOffset: rate>=1)
|
||||
},
|
||||
showLoading(mescroll, downHight) {
|
||||
vm.downLoadType = 3; // 显示下拉刷新进度的回调 (自定义mescroll组件时,此行不可删)
|
||||
vm.downHight = downHight; // 设置下拉区域的高度 (自定义mescroll组件时,此行不可删)
|
||||
},
|
||||
endDownScroll(mescroll) {
|
||||
vm.downLoadType = 4; // 结束下拉 (自定义mescroll组件时,此行不可删)
|
||||
vm.downHight = 0; // 设置下拉区域的高度 (自定义mescroll组件时,此行不可删)
|
||||
},
|
||||
// 派发下拉刷新的回调
|
||||
callback: function(mescroll) {
|
||||
vm.$emit('down', mescroll);
|
||||
}
|
||||
},
|
||||
// 上拉加载的配置
|
||||
up: {
|
||||
// 显示加载中的回调
|
||||
showLoading() {
|
||||
vm.upLoadType = 1;
|
||||
},
|
||||
// 显示无更多数据的回调
|
||||
showNoMore() {
|
||||
vm.upLoadType = 2;
|
||||
},
|
||||
// 隐藏上拉加载的回调
|
||||
hideUpScroll() {
|
||||
vm.upLoadType = 0;
|
||||
},
|
||||
// 空布局
|
||||
empty: {
|
||||
onShow(isShow) {
|
||||
// 显示隐藏的回调
|
||||
vm.isShowEmpty = isShow;
|
||||
}
|
||||
},
|
||||
// 回到顶部
|
||||
toTop: {
|
||||
onShow(isShow) {
|
||||
// 显示隐藏的回调
|
||||
vm.isShowToTop = isShow;
|
||||
}
|
||||
},
|
||||
// 派发上拉加载的回调
|
||||
callback: function(mescroll) {
|
||||
vm.$emit('up', mescroll);
|
||||
// 更新容器的高度 (多mescroll的情况)
|
||||
vm.setClientHeight();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
MeScroll.extend(diyOption, GlobalOption); // 混入全局的配置
|
||||
let myOption = JSON.parse(
|
||||
JSON.stringify({
|
||||
down: vm.down,
|
||||
up: vm.up
|
||||
})
|
||||
); // 深拷贝,避免对props的影响
|
||||
MeScroll.extend(myOption, diyOption); // 混入具体界面的配置
|
||||
|
||||
// 初始化MeScroll对象
|
||||
vm.mescroll = new MeScroll(myOption);
|
||||
vm.mescroll.viewId = vm.viewId; // 附带id
|
||||
// init回调mescroll对象
|
||||
vm.$emit('init', vm.mescroll);
|
||||
|
||||
// 设置高度
|
||||
const sys = uni.getSystemInfoSync();
|
||||
if (sys.windowTop) vm.windowTop = sys.windowTop;
|
||||
if (sys.windowBottom) vm.windowBottom = sys.windowBottom;
|
||||
if (sys.windowHeight) vm.windowHeight = sys.windowHeight;
|
||||
if (sys.statusBarHeight) vm.statusBarHeight = sys.statusBarHeight;
|
||||
// 使down的bottomOffset生效
|
||||
vm.mescroll.setBodyHeight(sys.windowHeight);
|
||||
|
||||
// 因为使用的是scrollview,这里需自定义scrollTo
|
||||
vm.mescroll.resetScrollTo((y, t) => {
|
||||
let curY = vm.mescroll.getScrollTop();
|
||||
vm.scrollAnim = t !== 0; // t为0,则不使用动画过渡
|
||||
if (t === 0 || t === 300) {
|
||||
// 当t使用默认配置的300时,则使用系统自带的动画过渡
|
||||
vm.scrollTop = curY;
|
||||
vm.$nextTick(function() {
|
||||
vm.scrollTop = y;
|
||||
});
|
||||
} else {
|
||||
vm.mescroll.getStep(
|
||||
curY,
|
||||
y,
|
||||
step => {
|
||||
// 此写法可支持配置t
|
||||
vm.scrollTop = step;
|
||||
},
|
||||
t
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// 具体的界面如果不配置up.toTop.safearea,则取本vue的safearea值
|
||||
if (vm.up && vm.up.toTop && vm.up.toTop.safearea != null) {} else {
|
||||
vm.mescroll.optUp.toTop.safearea = vm.safearea;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// 设置容器的高度
|
||||
this.setClientHeight();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import './mescroll-uni.css';
|
||||
@import './components/mescroll-down.css';
|
||||
@import './components/mescroll-up.css';
|
||||
</style>
|
||||
@@ -164,7 +164,7 @@
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
<style lang="scss" scoped>
|
||||
.register-box /deep/ .uni-scroll-view {
|
||||
background: unset !important;
|
||||
}
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
<template>
|
||||
<view class="ns-goods-action bottom-safe-area" :class="{ 'bottom-safe-area': safeArea }"><slot></slot></view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ns-goods-action',
|
||||
props: {
|
||||
safeArea: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.ns-goods-action {
|
||||
position: fixed;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #fff;
|
||||
z-index: 9;
|
||||
}
|
||||
.ns-goods-action.bottom-safe-area {
|
||||
padding-bottom: 0;
|
||||
padding-bottom: constant(safe-area-inset-bottom);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<view class="ns-goods-action bottom-safe-area" :class="{ 'bottom-safe-area': safeArea }"><slot></slot></view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ns-goods-action',
|
||||
props: {
|
||||
safeArea: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.ns-goods-action {
|
||||
position: fixed;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #fff;
|
||||
z-index: 9;
|
||||
}
|
||||
.ns-goods-action.bottom-safe-area {
|
||||
padding-bottom: 0;
|
||||
padding-bottom: constant(safe-area-inset-bottom);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -768,7 +768,7 @@
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style scoped>
|
||||
<style lang="scss" scoped>
|
||||
/deep/ .reward-popup .uni-popup__wrapper-box {
|
||||
background: none !important;
|
||||
max-width: unset !important;
|
||||
|
||||
@@ -171,7 +171,7 @@
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style lang="scss" scoped>
|
||||
/deep/ .newgift-content uni-image {
|
||||
width: 113rpx !important;
|
||||
height: 24rpx !important;
|
||||
|
||||
@@ -1,69 +1,69 @@
|
||||
<template>
|
||||
<view>
|
||||
<view class="weui-switch" :class="{ 'weui-switch-on': checked, 'color-base-border': checked }" @click="change()">
|
||||
<view class="bgview" :class="{ 'color-base-bg': checked }"></view>
|
||||
<view class="spotview"></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'nsSwitch',
|
||||
props: {
|
||||
checked: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
change() {
|
||||
this.$emit('change');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.weui-switch {
|
||||
display: block;
|
||||
position: relative;
|
||||
width: 94rpx;
|
||||
height: 45rpx;
|
||||
outline: 0;
|
||||
border-radius: 30rpx;
|
||||
border: 2rpx solid;
|
||||
border-color: #dfdfdf;
|
||||
transition: background-color 0.1s, border 0.1s;
|
||||
}
|
||||
|
||||
.weui-switch .bgview {
|
||||
content: ' ';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 94rpx;
|
||||
height: 45rpx;
|
||||
border-radius: 30rpx;
|
||||
transition: transform 0.35s cubic-bezier(0.45, 1, 0.4, 1);
|
||||
}
|
||||
.weui-switch .spotview {
|
||||
content: ' ';
|
||||
position: absolute;
|
||||
top: 2rpx;
|
||||
left: 4rpx;
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
border-radius: 50%;
|
||||
background-color: #ffffff;
|
||||
box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.4);
|
||||
transition: transform 0.35s cubic-bezier(0.4, 0.4, 0.25, 1.35);
|
||||
}
|
||||
.weui-switch-on {
|
||||
border-color: #6f6f6f;
|
||||
}
|
||||
.weui-switch-on .bgview {
|
||||
border-color: #1aad19;
|
||||
}
|
||||
.weui-switch-on .spotview {
|
||||
transform: translateX(48rpx);
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<view>
|
||||
<view class="weui-switch" :class="{ 'weui-switch-on': checked, 'color-base-border': checked }" @click="change()">
|
||||
<view class="bgview" :class="{ 'color-base-bg': checked }"></view>
|
||||
<view class="spotview"></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'nsSwitch',
|
||||
props: {
|
||||
checked: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
change() {
|
||||
this.$emit('change');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.weui-switch {
|
||||
display: block;
|
||||
position: relative;
|
||||
width: 94rpx;
|
||||
height: 45rpx;
|
||||
outline: 0;
|
||||
border-radius: 30rpx;
|
||||
border: 2rpx solid;
|
||||
border-color: #dfdfdf;
|
||||
transition: background-color 0.1s, border 0.1s;
|
||||
}
|
||||
|
||||
.weui-switch .bgview {
|
||||
content: ' ';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 94rpx;
|
||||
height: 45rpx;
|
||||
border-radius: 30rpx;
|
||||
transition: transform 0.35s cubic-bezier(0.45, 1, 0.4, 1);
|
||||
}
|
||||
.weui-switch .spotview {
|
||||
content: ' ';
|
||||
position: absolute;
|
||||
top: 2rpx;
|
||||
left: 4rpx;
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
border-radius: 50%;
|
||||
background-color: #ffffff;
|
||||
box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.4);
|
||||
transition: transform 0.35s cubic-bezier(0.4, 0.4, 0.25, 1.35);
|
||||
}
|
||||
.weui-switch-on {
|
||||
border-color: #6f6f6f;
|
||||
}
|
||||
.weui-switch-on .bgview {
|
||||
border-color: #1aad19;
|
||||
}
|
||||
.weui-switch-on .spotview {
|
||||
transform: translateX(48rpx);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -150,7 +150,7 @@
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
<style lang="scss" scoped>
|
||||
.register-box /deep/ .uni-scroll-view {
|
||||
background: unset !important;
|
||||
}
|
||||
|
||||
@@ -1,58 +1,58 @@
|
||||
<!-- 回到顶部的按钮 -->
|
||||
<template>
|
||||
<image
|
||||
class="mescroll-totop"
|
||||
:class="[value ? 'mescroll-totop-in' : 'mescroll-totop-out']"
|
||||
:src="$util.img('public/uniapp/common/mescroll-totop.png')"
|
||||
mode="widthFix"
|
||||
@click="toTopClick"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
value: true
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
toTopClick() {
|
||||
this.$emit('toTop'); // 派发点击事件
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* 回到顶部的按钮 */
|
||||
.mescroll-totop {
|
||||
z-index: 99;
|
||||
position: fixed !important; /* 加上important避免编译到H5,在多mescroll中定位失效 */
|
||||
right: 46rpx !important;
|
||||
bottom: 272rpx !important;
|
||||
width: 72rpx;
|
||||
height: 72rpx;
|
||||
border-radius: 50%;
|
||||
opacity: 0;
|
||||
transition: opacity 0.5s; /* 过渡 */
|
||||
margin-bottom: var(--window-bottom); /* css变量 */
|
||||
}
|
||||
|
||||
/* 适配 iPhoneX */
|
||||
.mescroll-safe-bottom {
|
||||
margin-bottom: calc(var(--window-bottom) + constant(safe-area-inset-bottom)); /* window-bottom + 适配 iPhoneX */
|
||||
margin-bottom: calc(var(--window-bottom) + env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
/* 显示 -- 淡入 */
|
||||
.mescroll-totop-in {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* 隐藏 -- 淡出且不接收事件*/
|
||||
.mescroll-totop-out {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
<!-- 回到顶部的按钮 -->
|
||||
<template>
|
||||
<image
|
||||
class="mescroll-totop"
|
||||
:class="[value ? 'mescroll-totop-in' : 'mescroll-totop-out']"
|
||||
:src="$util.img('public/uniapp/common/mescroll-totop.png')"
|
||||
mode="widthFix"
|
||||
@click="toTopClick"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
value: true
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
toTopClick() {
|
||||
this.$emit('toTop'); // 派发点击事件
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
/* 回到顶部的按钮 */
|
||||
.mescroll-totop {
|
||||
z-index: 99;
|
||||
position: fixed !important; /* 加上important避免编译到H5,在多mescroll中定位失效 */
|
||||
right: 46rpx !important;
|
||||
bottom: 272rpx !important;
|
||||
width: 72rpx;
|
||||
height: 72rpx;
|
||||
border-radius: 50%;
|
||||
opacity: 0;
|
||||
transition: opacity 0.5s; /* 过渡 */
|
||||
margin-bottom: var(--window-bottom); /* css变量 */
|
||||
}
|
||||
|
||||
/* 适配 iPhoneX */
|
||||
.mescroll-safe-bottom {
|
||||
margin-bottom: calc(var(--window-bottom) + constant(safe-area-inset-bottom)); /* window-bottom + 适配 iPhoneX */
|
||||
margin-bottom: calc(var(--window-bottom) + env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
/* 显示 -- 淡入 */
|
||||
.mescroll-totop-in {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* 隐藏 -- 淡出且不接收事件*/
|
||||
.mescroll-totop-out {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,105 +1,105 @@
|
||||
<template>
|
||||
<text
|
||||
v-if="text"
|
||||
:class="inverted ? 'uni-badge-' + type + ' uni-badge--' + size + ' uni-badge-inverted' : 'uni-badge-' + type + ' uni-badge--' + size"
|
||||
class="uni-badge"
|
||||
@click="onClick()"
|
||||
>
|
||||
{{ text }}
|
||||
</text>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'UniBadge',
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: 'default'
|
||||
},
|
||||
inverted: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
text: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
size: {
|
||||
// small.normal
|
||||
type: String,
|
||||
default: 'normal'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onClick() {
|
||||
this.$emit('click');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.uni-badge {
|
||||
font-family: 'Helvetica Neue', Helvetica, sans-serif;
|
||||
box-sizing: border-box;
|
||||
font-size: 24rpx;
|
||||
line-height: 1;
|
||||
display: inline-block;
|
||||
padding: 6rpx 12rpx;
|
||||
color: #333;
|
||||
border-radius: 200rpx;
|
||||
background-color: #e5e5e5;
|
||||
}
|
||||
|
||||
.uni-badge.uni-badge-inverted {
|
||||
padding: 0 10rpx 0 0;
|
||||
color: #999;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.uni-badge-primary {
|
||||
color: #fff;
|
||||
background-color: #007aff;
|
||||
}
|
||||
|
||||
.uni-badge-primary.uni-badge-inverted {
|
||||
color: #007aff;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.uni-badge-success {
|
||||
color: #fff;
|
||||
background-color: #4cd964;
|
||||
}
|
||||
|
||||
.uni-badge-success.uni-badge-inverted {
|
||||
color: #4cd964;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.uni-badge-warning {
|
||||
color: #fff;
|
||||
background-color: #f0ad4e;
|
||||
}
|
||||
|
||||
.uni-badge-warning.uni-badge-inverted {
|
||||
color: #f0ad4e;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.uni-badge-error {
|
||||
color: #fff;
|
||||
background-color: #dd524d;
|
||||
}
|
||||
|
||||
.uni-badge-error.uni-badge-inverted {
|
||||
color: #dd524d;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.uni-badge--small {
|
||||
transform: scale(0.8);
|
||||
transform-origin: center center;
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<text
|
||||
v-if="text"
|
||||
:class="inverted ? 'uni-badge-' + type + ' uni-badge--' + size + ' uni-badge-inverted' : 'uni-badge-' + type + ' uni-badge--' + size"
|
||||
class="uni-badge"
|
||||
@click="onClick()"
|
||||
>
|
||||
{{ text }}
|
||||
</text>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'UniBadge',
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: 'default'
|
||||
},
|
||||
inverted: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
text: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
size: {
|
||||
// small.normal
|
||||
type: String,
|
||||
default: 'normal'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onClick() {
|
||||
this.$emit('click');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.uni-badge {
|
||||
font-family: 'Helvetica Neue', Helvetica, sans-serif;
|
||||
box-sizing: border-box;
|
||||
font-size: 24rpx;
|
||||
line-height: 1;
|
||||
display: inline-block;
|
||||
padding: 6rpx 12rpx;
|
||||
color: #333;
|
||||
border-radius: 200rpx;
|
||||
background-color: #e5e5e5;
|
||||
}
|
||||
|
||||
.uni-badge.uni-badge-inverted {
|
||||
padding: 0 10rpx 0 0;
|
||||
color: #999;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.uni-badge-primary {
|
||||
color: #fff;
|
||||
background-color: #007aff;
|
||||
}
|
||||
|
||||
.uni-badge-primary.uni-badge-inverted {
|
||||
color: #007aff;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.uni-badge-success {
|
||||
color: #fff;
|
||||
background-color: #4cd964;
|
||||
}
|
||||
|
||||
.uni-badge-success.uni-badge-inverted {
|
||||
color: #4cd964;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.uni-badge-warning {
|
||||
color: #fff;
|
||||
background-color: #f0ad4e;
|
||||
}
|
||||
|
||||
.uni-badge-warning.uni-badge-inverted {
|
||||
color: #f0ad4e;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.uni-badge-error {
|
||||
color: #fff;
|
||||
background-color: #dd524d;
|
||||
}
|
||||
|
||||
.uni-badge-error.uni-badge-inverted {
|
||||
color: #dd524d;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.uni-badge--small {
|
||||
transform: scale(0.8);
|
||||
transform-origin: center center;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,146 +1,146 @@
|
||||
<template>
|
||||
<view v-if="visibleSync" :class="{ 'uni-drawer--visible': showDrawer, 'uni-drawer--right': rightMode }" class="uni-drawer" @touchmove.stop.prevent="moveHandle">
|
||||
<view class="uni-drawer__mask" @tap="close" ></view>
|
||||
<view class="uni-drawer__content" :class="{ 'safe-area': isIphoneX }"><slot /></view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'UniDrawer',
|
||||
props: {
|
||||
/**
|
||||
* 显示状态
|
||||
*/
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
/**
|
||||
* 显示模式(左、右),只在初始化生效
|
||||
*/
|
||||
mode: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
/**
|
||||
* 蒙层显示状态
|
||||
*/
|
||||
mask: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
visibleSync: false,
|
||||
showDrawer: false,
|
||||
rightMode: false,
|
||||
closeTimer: null,
|
||||
watchTimer: null,
|
||||
isIphoneX: false
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
visible(val) {
|
||||
clearTimeout(this.watchTimer);
|
||||
setTimeout(() => {
|
||||
this.showDrawer = val;
|
||||
}, 100);
|
||||
if (this.visibleSync) {
|
||||
clearTimeout(this.closeTimer);
|
||||
}
|
||||
if (val) {
|
||||
this.visibleSync = val;
|
||||
} else {
|
||||
this.watchTimer = setTimeout(() => {
|
||||
this.visibleSync = val;
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.isIphoneX = this.$util.uniappIsIPhoneX();
|
||||
this.visibleSync = this.visible;
|
||||
setTimeout(() => {
|
||||
this.showDrawer = this.visible;
|
||||
}, 100);
|
||||
this.rightMode = this.mode === 'right';
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
this.showDrawer = false;
|
||||
this.closeTimer = setTimeout(() => {
|
||||
this.visibleSync = false;
|
||||
this.$emit('close');
|
||||
}, 200);
|
||||
},
|
||||
moveHandle() {}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
.uni-drawer {
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
z-index: 999;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.uni-drawer.uni-drawer--right .uni-drawer__content {
|
||||
left: auto;
|
||||
right: 0;
|
||||
transform: translatex(100%);
|
||||
}
|
||||
|
||||
.uni-drawer.uni-drawer--visible {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.uni-drawer.uni-drawer--visible .uni-drawer__content {
|
||||
transform: translatex(0);
|
||||
}
|
||||
|
||||
.uni-drawer.uni-drawer--visible .uni-drawer__mask {
|
||||
display: block;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.uni-drawer__mask {
|
||||
display: block;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
|
||||
.uni-drawer__content {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 61.8%;
|
||||
height: 100%;
|
||||
background: #fff;
|
||||
transition: all 0.3s ease-out;
|
||||
transform: translatex(-100%);
|
||||
}
|
||||
|
||||
.safe-area {
|
||||
padding-bottom: 68rpx;
|
||||
padding-top: 44rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<view v-if="visibleSync" :class="{ 'uni-drawer--visible': showDrawer, 'uni-drawer--right': rightMode }" class="uni-drawer" @touchmove.stop.prevent="moveHandle">
|
||||
<view class="uni-drawer__mask" @tap="close" ></view>
|
||||
<view class="uni-drawer__content" :class="{ 'safe-area': isIphoneX }"><slot /></view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'UniDrawer',
|
||||
props: {
|
||||
/**
|
||||
* 显示状态
|
||||
*/
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
/**
|
||||
* 显示模式(左、右),只在初始化生效
|
||||
*/
|
||||
mode: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
/**
|
||||
* 蒙层显示状态
|
||||
*/
|
||||
mask: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
visibleSync: false,
|
||||
showDrawer: false,
|
||||
rightMode: false,
|
||||
closeTimer: null,
|
||||
watchTimer: null,
|
||||
isIphoneX: false
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
visible(val) {
|
||||
clearTimeout(this.watchTimer);
|
||||
setTimeout(() => {
|
||||
this.showDrawer = val;
|
||||
}, 100);
|
||||
if (this.visibleSync) {
|
||||
clearTimeout(this.closeTimer);
|
||||
}
|
||||
if (val) {
|
||||
this.visibleSync = val;
|
||||
} else {
|
||||
this.watchTimer = setTimeout(() => {
|
||||
this.visibleSync = val;
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.isIphoneX = this.$util.uniappIsIPhoneX();
|
||||
this.visibleSync = this.visible;
|
||||
setTimeout(() => {
|
||||
this.showDrawer = this.visible;
|
||||
}, 100);
|
||||
this.rightMode = this.mode === 'right';
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
this.showDrawer = false;
|
||||
this.closeTimer = setTimeout(() => {
|
||||
this.visibleSync = false;
|
||||
this.$emit('close');
|
||||
}, 200);
|
||||
},
|
||||
moveHandle() {}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
.uni-drawer {
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
z-index: 999;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.uni-drawer.uni-drawer--right .uni-drawer__content {
|
||||
left: auto;
|
||||
right: 0;
|
||||
transform: translatex(100%);
|
||||
}
|
||||
|
||||
.uni-drawer.uni-drawer--visible {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.uni-drawer.uni-drawer--visible .uni-drawer__content {
|
||||
transform: translatex(0);
|
||||
}
|
||||
|
||||
.uni-drawer.uni-drawer--visible .uni-drawer__mask {
|
||||
display: block;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.uni-drawer__mask {
|
||||
display: block;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
|
||||
.uni-drawer__content {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 61.8%;
|
||||
height: 100%;
|
||||
background: #fff;
|
||||
transition: all 0.3s ease-out;
|
||||
transform: translatex(-100%);
|
||||
}
|
||||
|
||||
.safe-area {
|
||||
padding-bottom: 68rpx;
|
||||
padding-top: 44rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,223 +1,223 @@
|
||||
<template>
|
||||
<view v-if="width" :style="{ width: width }" class="uni-grid-item">
|
||||
<view
|
||||
:class="{ border: showBorder, 'uni-grid-item__box-square': square, 'border-top': showBorder && index < column, 'uni-highlight': highlight }"
|
||||
:style="{ 'border-color': borderColor }"
|
||||
class="uni-grid-item__box"
|
||||
@click="_onClick"
|
||||
>
|
||||
<view v-if="marker === 'dot'" :style="{ left: top * 2 + 'rpx', top: left * 2 + 'rpx' }" class="uni-grid-item__box-dot" />
|
||||
<view v-if="marker === 'badge'" :style="{ left: top * 2 + 'rpx', top: left * 2 + 'rpx' }" class="uni-grid-item__box-badge">
|
||||
<uni-badge :text="text" :type="type" :size="size" :inverted="inverted" />
|
||||
</view>
|
||||
<view v-if="marker === 'image'" :style="{ left: top * 2 + 'rpx', top: left * 2 + 'rpx' }" class="uni-grid-item__box-image">
|
||||
<image :style="{ width: imgWidth * 2 + 'rpx' }" :src="src" class="box-image" mode="widthFix" />
|
||||
</view>
|
||||
<view class="uni-grid-item__box-item"><slot /></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import uniBadge from '@/components/uni-badge/uni-badge.vue';
|
||||
export default {
|
||||
name: 'UniGridItem',
|
||||
components: {
|
||||
uniBadge
|
||||
},
|
||||
props: {
|
||||
// 类型:可选值,dot:圆点;badge:角标;image:图片
|
||||
marker: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 水平方向
|
||||
hor: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
// 垂直方向
|
||||
ver: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
// badge 下颜色类型,可选值:default(灰色)、primary(蓝色)、success(绿色)、warning(黄色)、error(红色)
|
||||
type: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// badge 下显示内容,汉字最多为1个
|
||||
text: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// badge 下 Badge 大小
|
||||
size: {
|
||||
type: String,
|
||||
default: 'normal'
|
||||
},
|
||||
// badge 下 是否无需背景颜色
|
||||
inverted: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// image 下图片路径
|
||||
src: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// image 下图片宽度 ,最大 为 100 。 默认为 30
|
||||
imgWidth: {
|
||||
type: Number,
|
||||
default: 30
|
||||
}
|
||||
},
|
||||
inject: ['grid'],
|
||||
data() {
|
||||
return {
|
||||
column: 0,
|
||||
showBorder: true,
|
||||
square: true,
|
||||
highlight: true,
|
||||
left: 0,
|
||||
top: 0,
|
||||
index: 0,
|
||||
openNum: 2,
|
||||
width: 0,
|
||||
borderColor: '#e5e5e5'
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.column = this.grid.column;
|
||||
this.showBorder = this.grid.showBorder;
|
||||
this.square = this.grid.square;
|
||||
this.highlight = this.grid.highlight;
|
||||
this.top = this.hor === 0 ? this.grid.hor : this.hor;
|
||||
this.left = this.ver === 0 ? this.grid.ver : this.ver;
|
||||
this.borderColor = this.grid.borderColor;
|
||||
this.index = this.grid.index++;
|
||||
},
|
||||
// #ifdef H5
|
||||
mounted() {
|
||||
this.grid._getSize(width => {
|
||||
this.width = width;
|
||||
});
|
||||
},
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
onReady() {
|
||||
this.grid._getSize(width => {
|
||||
this.width = width;
|
||||
});
|
||||
},
|
||||
// #endif
|
||||
methods: {
|
||||
_onClick() {
|
||||
this.grid.change({
|
||||
detail: {
|
||||
index: this.index
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.uni-grid-item {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.uni-grid-item__box {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.uni-grid-item__box-item {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: 32rpx;
|
||||
color: #666;
|
||||
padding: 20rpx 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.uni-grid-item__box-item .image {
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
}
|
||||
|
||||
.uni-grid-item__box-item .text {
|
||||
font-size: 26rpx;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
.uni-grid-item__box.uni-grid-item__box-square {
|
||||
height: 0;
|
||||
padding-top: 100%;
|
||||
}
|
||||
|
||||
.uni-grid-item__box.uni-grid-item__box-square .uni-grid-item__box-item {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.uni-grid-item__box.border {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
border-bottom: 2rpx #e5e5e5 solid;
|
||||
border-right: 2rpx #e5e5e5 solid;
|
||||
}
|
||||
|
||||
.uni-grid-item__box.border-top {
|
||||
border-top: 2rpx #e5e5e5 solid;
|
||||
}
|
||||
|
||||
.uni-grid-item__box.uni-highlight:active {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.uni-grid-item__box-badge,
|
||||
.uni-grid-item__box-dot,
|
||||
.uni-grid-item__box-image {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.uni-grid-item__box-dot {
|
||||
width: 20rpx;
|
||||
height: 20rpx;
|
||||
background: #ff5a5f;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.uni-grid-item__box-badge {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.uni-grid-item__box-image {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.uni-grid-item__box-image .box-image {
|
||||
width: 90rpx;
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<view v-if="width" :style="{ width: width }" class="uni-grid-item">
|
||||
<view
|
||||
:class="{ border: showBorder, 'uni-grid-item__box-square': square, 'border-top': showBorder && index < column, 'uni-highlight': highlight }"
|
||||
:style="{ 'border-color': borderColor }"
|
||||
class="uni-grid-item__box"
|
||||
@click="_onClick"
|
||||
>
|
||||
<view v-if="marker === 'dot'" :style="{ left: top * 2 + 'rpx', top: left * 2 + 'rpx' }" class="uni-grid-item__box-dot" />
|
||||
<view v-if="marker === 'badge'" :style="{ left: top * 2 + 'rpx', top: left * 2 + 'rpx' }" class="uni-grid-item__box-badge">
|
||||
<uni-badge :text="text" :type="type" :size="size" :inverted="inverted" />
|
||||
</view>
|
||||
<view v-if="marker === 'image'" :style="{ left: top * 2 + 'rpx', top: left * 2 + 'rpx' }" class="uni-grid-item__box-image">
|
||||
<image :style="{ width: imgWidth * 2 + 'rpx' }" :src="src" class="box-image" mode="widthFix" />
|
||||
</view>
|
||||
<view class="uni-grid-item__box-item"><slot /></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import uniBadge from '@/components/uni-badge/uni-badge.vue';
|
||||
export default {
|
||||
name: 'UniGridItem',
|
||||
components: {
|
||||
uniBadge
|
||||
},
|
||||
props: {
|
||||
// 类型:可选值,dot:圆点;badge:角标;image:图片
|
||||
marker: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 水平方向
|
||||
hor: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
// 垂直方向
|
||||
ver: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
// badge 下颜色类型,可选值:default(灰色)、primary(蓝色)、success(绿色)、warning(黄色)、error(红色)
|
||||
type: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// badge 下显示内容,汉字最多为1个
|
||||
text: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// badge 下 Badge 大小
|
||||
size: {
|
||||
type: String,
|
||||
default: 'normal'
|
||||
},
|
||||
// badge 下 是否无需背景颜色
|
||||
inverted: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// image 下图片路径
|
||||
src: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// image 下图片宽度 ,最大 为 100 。 默认为 30
|
||||
imgWidth: {
|
||||
type: Number,
|
||||
default: 30
|
||||
}
|
||||
},
|
||||
inject: ['grid'],
|
||||
data() {
|
||||
return {
|
||||
column: 0,
|
||||
showBorder: true,
|
||||
square: true,
|
||||
highlight: true,
|
||||
left: 0,
|
||||
top: 0,
|
||||
index: 0,
|
||||
openNum: 2,
|
||||
width: 0,
|
||||
borderColor: '#e5e5e5'
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.column = this.grid.column;
|
||||
this.showBorder = this.grid.showBorder;
|
||||
this.square = this.grid.square;
|
||||
this.highlight = this.grid.highlight;
|
||||
this.top = this.hor === 0 ? this.grid.hor : this.hor;
|
||||
this.left = this.ver === 0 ? this.grid.ver : this.ver;
|
||||
this.borderColor = this.grid.borderColor;
|
||||
this.index = this.grid.index++;
|
||||
},
|
||||
// #ifdef H5
|
||||
mounted() {
|
||||
this.grid._getSize(width => {
|
||||
this.width = width;
|
||||
});
|
||||
},
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
onReady() {
|
||||
this.grid._getSize(width => {
|
||||
this.width = width;
|
||||
});
|
||||
},
|
||||
// #endif
|
||||
methods: {
|
||||
_onClick() {
|
||||
this.grid.change({
|
||||
detail: {
|
||||
index: this.index
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.uni-grid-item {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.uni-grid-item__box {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.uni-grid-item__box-item {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: 32rpx;
|
||||
color: #666;
|
||||
padding: 20rpx 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.uni-grid-item__box-item .image {
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
}
|
||||
|
||||
.uni-grid-item__box-item .text {
|
||||
font-size: 26rpx;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
.uni-grid-item__box.uni-grid-item__box-square {
|
||||
height: 0;
|
||||
padding-top: 100%;
|
||||
}
|
||||
|
||||
.uni-grid-item__box.uni-grid-item__box-square .uni-grid-item__box-item {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.uni-grid-item__box.border {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
border-bottom: 2rpx #e5e5e5 solid;
|
||||
border-right: 2rpx #e5e5e5 solid;
|
||||
}
|
||||
|
||||
.uni-grid-item__box.border-top {
|
||||
border-top: 2rpx #e5e5e5 solid;
|
||||
}
|
||||
|
||||
.uni-grid-item__box.uni-highlight:active {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.uni-grid-item__box-badge,
|
||||
.uni-grid-item__box-dot,
|
||||
.uni-grid-item__box-image {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.uni-grid-item__box-dot {
|
||||
width: 20rpx;
|
||||
height: 20rpx;
|
||||
background: #ff5a5f;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.uni-grid-item__box-badge {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.uni-grid-item__box-image {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.uni-grid-item__box-image .box-image {
|
||||
width: 90rpx;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -84,7 +84,7 @@ export default {
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
<style lang="scss">
|
||||
|
||||
.uni-grid {
|
||||
display: flex;
|
||||
|
||||
@@ -1,221 +1,221 @@
|
||||
<template>
|
||||
<view v-if="showPopup" class="uni-popup">
|
||||
<view :class="[ani, animation ? 'ani' : '', !custom ? 'uni-custom' : '']" class="uni-popup__mask" @click="close(true)" ></view>
|
||||
<view :class="[type, ani, animation ? 'ani' : '', !custom ? 'uni-custom' : '']" class="uni-popup__wrapper goodslist-uni-popup safe-area" @click="close(true)" v-if="isIphoneX">
|
||||
<view class="uni-popup__wrapper-box goodslist-uni-popup-box" @click.stop="clear"><slot /></view>
|
||||
</view>
|
||||
<view :class="[type, ani, animation ? 'ani' : '', !custom ? 'uni-custom' : '']" class="uni-popup__wrapper goodslist-uni-popup" @click="close(true)" v-else>
|
||||
<view class="uni-popup__wrapper-box goodslist-uni-popup-box" @click.stop="clear"><slot /></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'UniPopup',
|
||||
props: {
|
||||
// 开启动画
|
||||
animation: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 弹出层类型,可选值,top: 顶部弹出层;bottom:底部弹出层;center:全屏弹出层
|
||||
type: {
|
||||
type: String,
|
||||
default: 'center'
|
||||
},
|
||||
// 是否开启自定义
|
||||
custom: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// maskClick
|
||||
maskClick: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
ani: '',
|
||||
showPopup: false,
|
||||
callback: null,
|
||||
isIphoneX: false
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
show(newValue) {
|
||||
if (newValue) {
|
||||
this.open();
|
||||
} else {
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.isIphoneX = this.$util.uniappIsIPhoneX();
|
||||
},
|
||||
methods: {
|
||||
clear() {},
|
||||
open(callback) {
|
||||
if (callback) this.callback = callback;
|
||||
|
||||
this.$emit('change', {
|
||||
show: true
|
||||
});
|
||||
this.showPopup = true;
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.ani = 'uni-' + this.type;
|
||||
}, 30);
|
||||
});
|
||||
},
|
||||
close(type, callback) {
|
||||
if (!this.maskClick && type) return;
|
||||
this.$emit('change', {
|
||||
show: false
|
||||
});
|
||||
this.ani = '';
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.showPopup = false;
|
||||
}, 300);
|
||||
});
|
||||
|
||||
if (callback) callback();
|
||||
|
||||
if (this.callback) this.callback.call(this);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
|
||||
.uni-popup {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 999;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.uni-popup__mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 998;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.uni-popup__mask.ani {
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.uni-popup__mask.uni-bottom,
|
||||
.uni-popup__mask.uni-center,
|
||||
.uni-popup__mask.uni-right,
|
||||
.uni-popup__mask.uni-left,
|
||||
.uni-popup__mask.uni-top {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper {
|
||||
position: absolute;
|
||||
z-index: 999;
|
||||
box-sizing: border-box;
|
||||
//background: #ffffff;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.ani {
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.top {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.bottom {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: translateY(100%);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.right {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: translateX(100%);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.left {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.center {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
transform: scale(1.2);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper-box {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
|
||||
//background: #fff;
|
||||
}
|
||||
.uni-popup__wrapper.uni-custom.center .uni-popup__wrapper-box {
|
||||
position: relative;
|
||||
max-width: 80%;
|
||||
max-height: 80%;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.uni-custom.bottom .uni-popup__wrapper-box,
|
||||
.uni-popup__wrapper.uni-custom.top .uni-popup__wrapper-box {
|
||||
width: 100%;
|
||||
max-height: 500px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.uni-bottom,
|
||||
.uni-popup__wrapper.uni-top {
|
||||
transform: translateY(0);
|
||||
}
|
||||
.uni-popup__wrapper.uni-left,
|
||||
.uni-popup__wrapper.uni-right {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.uni-center {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* isIphoneX系列手机底部安全距离 */
|
||||
.bottom.safe-area {
|
||||
padding-bottom: constant(safe-area-inset-bottom);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<view v-if="showPopup" class="uni-popup">
|
||||
<view :class="[ani, animation ? 'ani' : '', !custom ? 'uni-custom' : '']" class="uni-popup__mask" @click="close(true)" ></view>
|
||||
<view :class="[type, ani, animation ? 'ani' : '', !custom ? 'uni-custom' : '']" class="uni-popup__wrapper goodslist-uni-popup safe-area" @click="close(true)" v-if="isIphoneX">
|
||||
<view class="uni-popup__wrapper-box goodslist-uni-popup-box" @click.stop="clear"><slot /></view>
|
||||
</view>
|
||||
<view :class="[type, ani, animation ? 'ani' : '', !custom ? 'uni-custom' : '']" class="uni-popup__wrapper goodslist-uni-popup" @click="close(true)" v-else>
|
||||
<view class="uni-popup__wrapper-box goodslist-uni-popup-box" @click.stop="clear"><slot /></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'UniPopup',
|
||||
props: {
|
||||
// 开启动画
|
||||
animation: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 弹出层类型,可选值,top: 顶部弹出层;bottom:底部弹出层;center:全屏弹出层
|
||||
type: {
|
||||
type: String,
|
||||
default: 'center'
|
||||
},
|
||||
// 是否开启自定义
|
||||
custom: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// maskClick
|
||||
maskClick: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
ani: '',
|
||||
showPopup: false,
|
||||
callback: null,
|
||||
isIphoneX: false
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
show(newValue) {
|
||||
if (newValue) {
|
||||
this.open();
|
||||
} else {
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.isIphoneX = this.$util.uniappIsIPhoneX();
|
||||
},
|
||||
methods: {
|
||||
clear() {},
|
||||
open(callback) {
|
||||
if (callback) this.callback = callback;
|
||||
|
||||
this.$emit('change', {
|
||||
show: true
|
||||
});
|
||||
this.showPopup = true;
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.ani = 'uni-' + this.type;
|
||||
}, 30);
|
||||
});
|
||||
},
|
||||
close(type, callback) {
|
||||
if (!this.maskClick && type) return;
|
||||
this.$emit('change', {
|
||||
show: false
|
||||
});
|
||||
this.ani = '';
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.showPopup = false;
|
||||
}, 300);
|
||||
});
|
||||
|
||||
if (callback) callback();
|
||||
|
||||
if (this.callback) this.callback.call(this);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
|
||||
.uni-popup {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 999;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.uni-popup__mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 998;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.uni-popup__mask.ani {
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.uni-popup__mask.uni-bottom,
|
||||
.uni-popup__mask.uni-center,
|
||||
.uni-popup__mask.uni-right,
|
||||
.uni-popup__mask.uni-left,
|
||||
.uni-popup__mask.uni-top {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper {
|
||||
position: absolute;
|
||||
z-index: 999;
|
||||
box-sizing: border-box;
|
||||
//background: #ffffff;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.ani {
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.top {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.bottom {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: translateY(100%);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.right {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: translateX(100%);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.left {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.center {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
transform: scale(1.2);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper-box {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
|
||||
//background: #fff;
|
||||
}
|
||||
.uni-popup__wrapper.uni-custom.center .uni-popup__wrapper-box {
|
||||
position: relative;
|
||||
max-width: 80%;
|
||||
max-height: 80%;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.uni-custom.bottom .uni-popup__wrapper-box,
|
||||
.uni-popup__wrapper.uni-custom.top .uni-popup__wrapper-box {
|
||||
width: 100%;
|
||||
max-height: 500px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.uni-bottom,
|
||||
.uni-popup__wrapper.uni-top {
|
||||
transform: translateY(0);
|
||||
}
|
||||
.uni-popup__wrapper.uni-left,
|
||||
.uni-popup__wrapper.uni-right {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.uni-center {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* isIphoneX系列手机底部安全距离 */
|
||||
.bottom.safe-area {
|
||||
padding-bottom: constant(safe-area-inset-bottom);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,222 +1,222 @@
|
||||
<template>
|
||||
<view v-if="showPopup" class="uni-popup">
|
||||
<view :class="[ani, animation ? 'ani' : '', !custom ? 'uni-custom' : '']" class="uni-popup__mask" @click="close(true)" ></view>
|
||||
<view :class="[type, ani, animation ? 'ani' : '', !custom ? 'uni-custom' : '']" class="uni-popup__wrapper safe-area" @click="close(true)" v-if="isIphoneX">
|
||||
<view class="uni-popup__wrapper-box" @click.stop="clear"><slot /></view>
|
||||
</view>
|
||||
<view :class="[type, ani, animation ? 'ani' : '', !custom ? 'uni-custom' : '']" class="uni-popup__wrapper" @click="close(true)" v-else>
|
||||
<view class="uni-popup__wrapper-box" @click.stop="clear"><slot /></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'UniPopup',
|
||||
props: {
|
||||
// 开启动画
|
||||
animation: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 弹出层类型,可选值,top: 顶部弹出层;bottom:底部弹出层;center:全屏弹出层
|
||||
type: {
|
||||
type: String,
|
||||
default: 'center'
|
||||
},
|
||||
// 是否开启自定义
|
||||
custom: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// maskClick
|
||||
maskClick: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
ani: '',
|
||||
showPopup: false,
|
||||
callback: null,
|
||||
isIphoneX: false
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
show(newValue) {
|
||||
if (newValue) {
|
||||
this.open();
|
||||
} else {
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.isIphoneX = this.$util.uniappIsIPhoneX();
|
||||
},
|
||||
methods: {
|
||||
clear() {},
|
||||
open(callback) {
|
||||
if (callback) this.callback = callback;
|
||||
|
||||
this.$emit('change', {
|
||||
show: true
|
||||
});
|
||||
this.showPopup = true;
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.ani = 'uni-' + this.type;
|
||||
}, 30);
|
||||
});
|
||||
},
|
||||
close(type, callback) {
|
||||
|
||||
if (!this.maskClick && type) return;
|
||||
this.$emit('change', {
|
||||
show: false
|
||||
});
|
||||
this.ani = '';
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.showPopup = false;
|
||||
}, 300);
|
||||
});
|
||||
|
||||
if (callback) callback();
|
||||
|
||||
if (this.callback) this.callback.call(this);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
|
||||
.uni-popup {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 999;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.uni-popup__mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 998;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.uni-popup__mask.ani {
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.uni-popup__mask.uni-bottom,
|
||||
.uni-popup__mask.uni-center,
|
||||
.uni-popup__mask.uni-right,
|
||||
.uni-popup__mask.uni-left,
|
||||
.uni-popup__mask.uni-top {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper {
|
||||
position: absolute;
|
||||
z-index: 999;
|
||||
box-sizing: border-box;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.ani {
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.top {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.bottom {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: translateY(100%);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.right {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: translateX(100%);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.left {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.center {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
transform: scale(1.2);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper-box {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
|
||||
background: #fff;
|
||||
}
|
||||
.uni-popup__wrapper.uni-custom.center .uni-popup__wrapper-box {
|
||||
position: relative;
|
||||
max-width: 80%;
|
||||
max-height: 80%;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.uni-custom.bottom .uni-popup__wrapper-box,
|
||||
.uni-popup__wrapper.uni-custom.top .uni-popup__wrapper-box {
|
||||
width: 100%;
|
||||
max-height: 500px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.uni-bottom,
|
||||
.uni-popup__wrapper.uni-top {
|
||||
transform: translateY(0);
|
||||
}
|
||||
.uni-popup__wrapper.uni-left,
|
||||
.uni-popup__wrapper.uni-right {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.uni-center {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* isIphoneX系列手机底部安全距离 */
|
||||
.bottom.safe-area {
|
||||
padding-bottom: constant(safe-area-inset-bottom);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<view v-if="showPopup" class="uni-popup">
|
||||
<view :class="[ani, animation ? 'ani' : '', !custom ? 'uni-custom' : '']" class="uni-popup__mask" @click="close(true)" ></view>
|
||||
<view :class="[type, ani, animation ? 'ani' : '', !custom ? 'uni-custom' : '']" class="uni-popup__wrapper safe-area" @click="close(true)" v-if="isIphoneX">
|
||||
<view class="uni-popup__wrapper-box" @click.stop="clear"><slot /></view>
|
||||
</view>
|
||||
<view :class="[type, ani, animation ? 'ani' : '', !custom ? 'uni-custom' : '']" class="uni-popup__wrapper" @click="close(true)" v-else>
|
||||
<view class="uni-popup__wrapper-box" @click.stop="clear"><slot /></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'UniPopup',
|
||||
props: {
|
||||
// 开启动画
|
||||
animation: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 弹出层类型,可选值,top: 顶部弹出层;bottom:底部弹出层;center:全屏弹出层
|
||||
type: {
|
||||
type: String,
|
||||
default: 'center'
|
||||
},
|
||||
// 是否开启自定义
|
||||
custom: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// maskClick
|
||||
maskClick: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
ani: '',
|
||||
showPopup: false,
|
||||
callback: null,
|
||||
isIphoneX: false
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
show(newValue) {
|
||||
if (newValue) {
|
||||
this.open();
|
||||
} else {
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.isIphoneX = this.$util.uniappIsIPhoneX();
|
||||
},
|
||||
methods: {
|
||||
clear() {},
|
||||
open(callback) {
|
||||
if (callback) this.callback = callback;
|
||||
|
||||
this.$emit('change', {
|
||||
show: true
|
||||
});
|
||||
this.showPopup = true;
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.ani = 'uni-' + this.type;
|
||||
}, 30);
|
||||
});
|
||||
},
|
||||
close(type, callback) {
|
||||
|
||||
if (!this.maskClick && type) return;
|
||||
this.$emit('change', {
|
||||
show: false
|
||||
});
|
||||
this.ani = '';
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.showPopup = false;
|
||||
}, 300);
|
||||
});
|
||||
|
||||
if (callback) callback();
|
||||
|
||||
if (this.callback) this.callback.call(this);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
|
||||
.uni-popup {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 999;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.uni-popup__mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 998;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.uni-popup__mask.ani {
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.uni-popup__mask.uni-bottom,
|
||||
.uni-popup__mask.uni-center,
|
||||
.uni-popup__mask.uni-right,
|
||||
.uni-popup__mask.uni-left,
|
||||
.uni-popup__mask.uni-top {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper {
|
||||
position: absolute;
|
||||
z-index: 999;
|
||||
box-sizing: border-box;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.ani {
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.top {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.bottom {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: translateY(100%);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.right {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: translateX(100%);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.left {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.center {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
transform: scale(1.2);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper-box {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
|
||||
background: #fff;
|
||||
}
|
||||
.uni-popup__wrapper.uni-custom.center .uni-popup__wrapper-box {
|
||||
position: relative;
|
||||
max-width: 80%;
|
||||
max-height: 80%;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.uni-custom.bottom .uni-popup__wrapper-box,
|
||||
.uni-popup__wrapper.uni-custom.top .uni-popup__wrapper-box {
|
||||
width: 100%;
|
||||
max-height: 500px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.uni-bottom,
|
||||
.uni-popup__wrapper.uni-top {
|
||||
transform: translateY(0);
|
||||
}
|
||||
.uni-popup__wrapper.uni-left,
|
||||
.uni-popup__wrapper.uni-right {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.uni-popup__wrapper.uni-center {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* isIphoneX系列手机底部安全距离 */
|
||||
.bottom.safe-area {
|
||||
padding-bottom: constant(safe-area-inset-bottom);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
<style lang="scss">
|
||||
.uni-popup {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
|
||||
@@ -67,7 +67,7 @@ export default {
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
<style lang="scss">
|
||||
|
||||
.uni-tag {
|
||||
box-sizing: border-box;
|
||||
|
||||
@@ -210,7 +210,7 @@ export default {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style lang="scss" scoped>
|
||||
.uv-count-num {
|
||||
display: inline-flex;
|
||||
text-align: center;
|
||||
|
||||
Reference in New Issue
Block a user