[商城整个模块,及个人中心相应的模块调整]

This commit is contained in:
2021-10-27 14:18:46 +08:00
parent e6181694d2
commit 2c1f11afd7
77 changed files with 14646 additions and 46 deletions

View File

@@ -0,0 +1,93 @@
## 1.2.82021-08-17
1、修复搜索导航栏按钮组位置问题
## 1.2.72021-08-13
1、h5端自动同步标签标题如微信标题<br>
2、组件内新增h5AutoTitle配置后可以h5端自动获取页面标题详情看描述文件
## 1.2.62021-08-13
更新说明文档
## 1.2.52021-08-13
修复按钮组位置偏差问题
## 1.2.42021-07-21
1、btn的icon添加text可以带文字<br>
2、修复样式btn右边间距、输入框字体大小改为inherit等
## 1.2.32021-07-20
1、开启了model滚动监听<br>
2、按钮组添加了badge设置角标
## 1.2.22021-05-25
1、新增设置样式事件setStyle()可通过ref来调用
2、修改config内style传参格式改为string类型兼容小程序
3、新增组件内注释
4、其它小优化
## 1.2.12021-03-16
处理了手机从竖屏变横屏后显示错乱问题
## 1.2.02021-03-05
处理了右按钮样式小程序兼容错误
## 1.1.92021-03-01
处理nvue兼容性引入scss失败、css错误
## 1.1.82021-02-25
1、兼容nvue
2、添加背景图
## 1.1.72021-02-24
1、兼容uni_modules官方新推出的插件管理兼容nv写法需要在pages.json添加代码"easycom": {"nv": "@/uni_modules/pyh-nv/components/pyh-nv/pyh-nv.vue"}
2、nvRoute函数更名为nv
## 1.1.62021-02-01
1、修复model定位问题
## 1.1.52021-02-01
1、全类型支持设置右方按钮组
2、添加h5 document.title等于config的标题
3、添加属性model可在页面内独立使用常用于不满足右方按钮小程序不显示的兼容方案使用2个nv
4、优化代码结构
## 1.1.42020-11-18
1、修复微信公众号中input的disabled点击跳转失效问题
2、修复右上角纯图片按钮变形问题
## 1.1.32020-09-27
修复config空值有时会报错的bug
## 1.1.22020-09-14
添加通用导航栏渐变色背景功能渐变色背景会导致transparent背景色渐变失效
## 1.1.12020-09-01
修复icon原生组件在小程序内高度铺满导致的错误问题
## 1.1.02020-08-27
1、使用icon代替图片图标,完全独立组件
2、添加回到顶部的功能
## 1.0.92020-08-18
''' 1、单logo模式支持全样式设置可实现全背景图等
2、优化了路由跳转判断及多端跳转
3、组件内利用了scss的特性优化了主色的修改
4、示例项目内添加了全局变量globalData以及全路由封装函数nvRoute组件也做了兼容处理可快速设置配置如需路由做特殊处理比如history模式等可使用封装的nvRoute统一处理 '''
## 1.0.82020-08-17
1、修改搜索框动态赋值方式更加方便直接修改search.value需要初始化value旧的赋值方式已废弃。重要 2、注释样式上版本组件内样式没有注释uni.scss的部分
## 1.0.72020-08-13
1、修改标题字体的size和weight,等同于uniapp的h5样式 2、补充组件主色覆盖样式的注释可去除注释快速修改也可使用uni.scss快速修改主色
## 1.0.62020-07-29
1、补充文档对于搜索框赋值的说明添加动态赋值功能
## 1.0.52020-07-20
补充单组件文件缺少的文件iconfont.wxss(后续版本已移除该文件)
## 1.0.42020-07-08
1、修复fixed定位辅助容器高度问题
2、补充示例项目属性项
## 1.0.32020-07-08
1、添加config.position属性并且默认为'fixed' 2、添加config.fixedAssist属性———固定定位辅助导航栏高度与导航栏一致可设置背景色 3、原home返回键背景取消如需要需使用componentBgColor 4、状态栏字体颜色与导航栏字体颜色一致状态栏字体只支持#000000或#ffffff 5、config.color 改为导航栏和状态栏字体色,也用于渐变完成时字体色(状态栏字体只支持#000000或#ffffff 6、transparent.initColor代替之前的状态栏字体颜色设置该值为导航栏与状态栏初始色状态栏字体只支持#000000或#ffffff 7、修改默认字体色为'#000000'
## 1.0.22020-07-07
修改示例配置,更友好上手
## 1.0.12020-07-07
上传初版,更新说明文档
## 1.0.02020-07-07
上传初版

Binary file not shown.

View File

@@ -0,0 +1,515 @@
<template name="nv">
<view class="pyh-nv-box" :style="style">
<view class='nvHeight' :style="[{'height':navigatorHeight+'px'},{'background':(config.fixedAssist&&config.fixedAssist.bgColor)||''}]" v-if="isFixed&&!(config.fixedAssist&&config.fixedAssist.hide)"></view>
<image :src="config.bgImage" :style="[{'position':config.model?'fixed':'absolute'},{'top':(config.model?(navigatorTop+'px'):0)},{'width':windowWidth+'px','height':navigatorHeight+'px'}]" v-if="config.bgImage" class="bgImage"></image>
<view :class="['nvBox',{'noModel':!config.model}]" :style="[{'width':windowWidth+'px'},{'color':getTxtColor},{'background':getBgColor},{'opacity':config.transparent&&config.transparent.type=='content'?transparent.opacity:1},{'position':isFixed?'fixed':'relative'},{'top':(isFixed&&config.model?(navigatorTop+'px'):0)}]">
<view class='nvHeight' :style="[{'height':navigatorHeight+'px'}]"></view>
<view class='nvFixed' :style="[{'width':windowWidth+'px'}]">
<!-- 单logo -->
<view :class="['nvContent','nvLogoBox',{'androidwx':androidwx}]" v-if="config.type=='logo'">
<image :src="config.logo.src?config.logo.src:'/static/logo.png'" class="nvLogo" :style="config.logo.style" :mode="config.logo.style|getImgMode" @tap.stop="nvLogoTap"></image>
<view v-if="config.btn&&config.btn.length>0" class="nvBtnGroup">
<block v-for="(b,n) in config.btn" :key="n">
<view class="nvBtn" v-if="b.icon" @tap.stop="nvBtnTap" :data-index="n" :data-type="b.type" :style="b.style||''">
<image :src="b.icon" mode="widthFix" class="nvBtnImg"></image>
<text class="nvBtnIconTxt" v-if="b.text">{{b.text}}</text>
<view class="nvBadge" v-if="b.badge&&b.badge.text" :style="b.badge.style||''">{{b.badge.text}}</view>
</view>
<view class="nvBtn" v-else-if="b.text" @tap.stop="nvBtnTap" :data-index="n" :data-type="b.type" :style="b.style||{color:getTxtColor}">
<text>{{b.text}}</text>
<view class="nvBadge" v-if="b.badge&&b.badge.text" :style="b.badge.style||''">{{b.badge.text}}</view>
</view>
</block>
</view>
</view>
<!-- 含搜索 -->
<view :class="['nvContent','nvSearchBox',{'nvHadBack':!config.hideback}]" v-else-if="config.type=='search'">
<image :src="config.logo.src?config.logo.src:'/static/logo.png'" class="nvLogo nvSearchLogo" :style="config.logo.style" :mode="config.logo.style|getImgMode" @tap.stop="nvLogoTap" v-if="config.logo&&!config.address"></image>
<view class="nvAddress" :style="[{'background':(config.address.bgColor||config.componentBgColor||'')},{'color':(config.address.color||'')}]" v-if="config.address" @tap.stop="nvAddressTap">
<text class="iconfont nvAddressIcon" :style="{'color':(config.address.color||'')}">&#xe613;</text>
<view class="nvAddressTextBox">
<text class="nvAddressText">{{config.address[config.address.fields||'province']||'广东省'}}</text>
</view>
</view>
<view class="nvSForm" >
<view class="nvSBox" :style="[{'background':(config.search.bgColor||config.componentBgColor||'')},{'border':config.search.border||''}]" @tap.stop="searchTap" data-isInput="true">
<icon type="search" size="18" class="searchIcon"></icon>
<input class="nvInput" type="text" :value="inputValue" :focus="config.search.focus" :placeholder="config.search.placeholder" :disabled="!config.search.input" @input="inputChange" @confirm="formSubmit" :confirm-type="config.search.confirmType||'search'" placeholder-class="searchPlac" :placeholder-style="config.search.placeholderStyle||''"/>
<icon type="clear" size="15" class="nvSClose" @tap.stop="inputClear" v-if="inputValue"></icon>
</view>
<text class='nvSBtn' @tap.stop="formSubmit" v-if="config.search.btn&&config.search.input" :style="config.search.btn.style||''">{{config.search.btn.text||'搜索'}}</text>
</view>
<view v-if="config.btn&&config.btn.length>0" class="nvBtnGroup nvBtnGroup-static">
<block v-for="(b,n) in config.btn" :key="n">
<view class="nvBtn" v-if="b.icon" @tap.stop="nvBtnTap" :data-index="n" :data-type="b.type" :style="b.style||''">
<image :src="b.icon" mode="widthFix" class="nvBtnImg"></image>
<text class="nvBtnIconTxt" v-if="b.text">{{b.text}}</text>
<view class="nvBadge" v-if="b.badge&&b.badge.text" :style="b.badge.style||''">{{b.badge.text}}</view>
</view>
<view class="nvBtn" v-else-if="b.text" @tap.stop="nvBtnTap" :data-index="n" :data-type="b.type" :style="b.style||{color:getTxtColor}">
<text>{{b.text}}</text>
<view class="nvBadge" v-if="b.badge&&b.badge.text" :style="b.badge.style||''">{{b.badge.text}}</view>
</view>
</block>
</view>
</view>
<!-- 默认导航栏 -->
<view class="nvContent nvDefault" v-else>
<view v-if="config.tabArr&&config.tabArr.length>0" :class="['nvTitle','nvTabBox',{'androidwx':androidwx}]">
<view :class="['nvTab',{'nvTabHide':t.hide}]" @tap.stop="nvTabTap" :data-index="i" v-for="(t,i) in config.tabArr" :key="i">
<text :class="[t.active?'nTTxt-ac':'nTTxt']" :style="{'color':(t.active?mainColor:getTxtColor)}">{{t.title}}</text>
<view :class="[t.active?'nTLine-ac':'nTLine']"></view>
</view>
</view>
<view v-else :class="['nvTitle',{'androidwx':androidwx},{'hideback':config.hideback}]">
<text :style="{'color': getTxtColor}">{{config.title||title}}</text>
</view>
<view v-if="config.btn&&config.btn.length>0" class="nvBtnGroup">
<block v-for="(b,n) in config.btn" :key="n">
<view class="nvBtn" v-if="b.icon" @tap.stop="nvBtnTap" :data-index="n" :data-type="b.type" :style="b.style||''">
<image :src="b.icon" mode="widthFix" class="nvBtnImg"></image>
<text class="nvBtnIconTxt" v-if="b.text">{{b.text}}</text>
<view class="nvBadge" v-if="b.badge&&b.badge.text" :style="b.badge.style||''">{{b.badge.text}}</view>
</view>
<view class="nvBtn" v-else-if="b.text" @tap.stop="nvBtnTap" :data-index="n" :data-type="b.type" :style="b.style||{color:getTxtColor}">
<text>{{b.text}}</text>
<view class="nvBadge" v-if="b.badge&&b.badge.text" :style="b.badge.style||''">{{b.badge.text}}</view>
</view>
</block>
</view>
</view>
<!-- 返回键 -->
<text :class="['iconfont','nvback',{'nvhome':isSharePage&&!config.closeCheckback}]" @tap.stop="backTap" :style="{'background':(isSharePage&&!config.closeCheckback?(config.componentBgColor||''):''),'color':getTxtColor,'border-radius':'26rpx','font-size': isSharePage&&!config.closeCheckback?'36rpx':'54rpx'}" v-if="!config.hideback">{{isSharePage&&!config.closeCheckback?'&#xe605;':'&#xe743;'}}</text>
</view>
</view>
<text class="iconfont nvToTop" :style="(config.toTop&&config.toTop.style)||''" v-if="config.toTop&&showToTop" @tap.stop="toTopTap">&#xe64d;</text>
</view>
</template>
<script>
var platform;
//#ifdef H5
platform="h5"
//#endif
//#ifdef APP-PLUS
platform="app"
//#endif
//#ifdef MP
platform="mp"
//#endif
export default {
name:"nv",
props:{
config:{
type:Object,
default(){
return {}
}
},
},
data() {
return {
title:getApp().globalData.NAME||"pyh-nv",
h5AutoTitle:true,
platform:platform||'h5',
mainColor:getApp().globalData.mainColor||"#fff",
currentPages:getCurrentPages().length||1,
home:getApp().globalData.HOME||"/pages/index/index",
inputValue:'',
showToTop:false,
transparent:{
initColor:"#ffffff",
finishColor:"#000000",
color:"#ffffff",
opacity:0
},
windowWidth:uni.getSystemInfoSync().windowWidth,
style:""
};
},
watch:{
"config.search.value":function(value){
//监听输入框值得改变
var e = {detail:{value:value}};
this.inputValue = e.detail.value;
if(this.config.type=="search"&&this.config.search.input)this.$emit("nvInput",e);
}
},
filters:{
getImgMode(style){
//获取图片mode类型
if(style&&style.indexOf("height")>-1){
return 'aspectFill';
}else{
return 'widthFix';
}
}
},
computed:{
statusHeight(){
//状态栏高度
var statusBarHeight = this.config.model?0:uni.getSystemInfoSync().statusBarHeight;
return statusBarHeight+'px';
},
navigatorHeight(){
//导航栏高度
var statusBarHeight = this.config.model?0:uni.getSystemInfoSync().statusBarHeight;
var windowWidth = this.lockWindowWidth&&this.windowWidth>750?375:this.windowWidth;
return parseInt(88*windowWidth/750)+statusBarHeight;
},
navigatorTop(){
//model类型下的顶部高度
var windowWidth = this.lockWindowWidth&&this.windowWidth>750?375:this.windowWidth;
if(this.config.model){
return parseInt(88*windowWidth/750)+uni.getSystemInfoSync().statusBarHeight;
}else{
return 0;
}
},
//安全区域高度
safeArea(){return this.config.safeArea||uni.getSystemInfoSync().safeArea.height;},
//固定定位判断
isFixed(){return this.config.transparent||this.config.position=='fixed'||this.config.position=='absolute'||!this.config.position;},
//判断分享页
isSharePage(){return this.currentPages==1;},
//安卓微信
androidwx(){
if(this.config.checkAndroidwx&&this.platform=="mp"&&uni.getSystemInfoSync().platform.indexOf("ios")==-1){
return true;
}else{
return false;
}
},
//获取字体色
getTxtColor(){
return ((this.config.transparent&&this.config.transparent.initColor)?this.transparent.color:'')||this.config.color||'';
},
//获取/转换背景色
getBgColor(){
var that = this;
if(this.config.bgImage){
return "transparent";
}else if(this.config.bgColor&&this.config.bgColor.indexOf("gradient")>-1){
return this.config.bgColor;
}else{
return (this.config.bgColor||this.config.transparent)?'rgba('+getRgbString()+','+(this.config.transparent&&this.config.transparent.type!='content'?this.transparent.opacity:1)+')':'#fff';
}
function getRgbString(){
var bgColor = that.config.bgColor||"#ffffff",returnString=""
if(bgColor.indexOf(",")>-1){
returnString = bgColor.split('(')[1].replace(')','').split(',').slice(0,3).join(",")
}else{
if(bgColor.length==4)bgColor = bgColor+bgColor.charAt(bgColor.length-1)+bgColor.charAt(bgColor.length-1)+bgColor.charAt(bgColor.length-1)
var string = bgColor.replace("#",'');
returnString = parseInt(string.substring(0,2), 16)+','+parseInt(string.substring(2,4), 16)+','+parseInt(string.substring(4,6), 16)
}
return returnString
}
}
},
created() {
// #ifdef APP-NVUE
var domModule = weex.requireModule("dom");
domModule.addRule('fontFace', {
'fontFamily': 'iconfont',
'src': "url('http://at.alicdn.com/t/font_1687851_vdpjdiddv6.ttf')"
})
// #endif
if(this.config.search&&this.config.search.value)this.inputValue=this.config.search.value;
if(this.config.transparent&&this.config.transparent.initColor){
var initColor = this.config.transparent.initColor,finishColor = this.config.color||"#000000";
if(initColor.indexOf("#")>-1&&initColor.length==4){
initColor = initColor+initColor.charAt(initColor.length-1)+initColor.charAt(initColor.length-1)+initColor.charAt(initColor.length-1);
}
if(finishColor.indexOf("#")>-1&&finishColor.length==4){
finishColor = finishColor+finishColor.charAt(finishColor.length-1)+finishColor.charAt(finishColor.length-1)+finishColor.charAt(finishColor.length-1);
}
if(!((initColor=="#000000"||initColor=="#ffffff")&&(finishColor=="#000000"||finishColor=="#ffffff"))){
console.log("状态栏颜色只支持,#000000或#ffffff");
}
this.transparent.initColor = initColor;
this.transparent.color = initColor;
this.transparent.finishColor = finishColor;
}
this.deviceOrientation=uni.getSystemInfoSync().windowWidth>750?"landscape":"portrait";
if(this.deviceOrientation=="portrait")this.lockWindowWidth=true;
uni.onWindowResize((res)=>{
if(this.deviceOrientation!=res.deviceOrientation){
this.deviceOrientation = res.deviceOrientation;
this.windowWidth = res.size.windowWidth;
}
})
},
mounted() {
if(this.config.color){
var obj = {frontColor:this.config.color,backgroundColor:this.config.bgColor||"#ffffff"};
uni.setNavigationBarColor(obj);
}
if(this.config.transparent&&this.config.transparent.initColor){
var obj = {frontColor:this.transparent.initColor,backgroundColor:this.config.bgColor||"#ffffff"};
uni.setNavigationBarColor(obj);
}
if(platform=="h5"&&!this.config.model){
this.config.title&&uni.setNavigationBarTitle({title:this.config.title})
if(document.title&&this.h5AutoTitle)this.title=document.title
document.setTitle = function(t) {document.title = t;var i = document.createElement('iframe');/*i.src = '//m.baidu.com/favicon.ico';*/i.style.display = 'none';i.onload = function() {setTimeout(function(){i.remove();}, 9)};document.body.appendChild(i);}
setTimeout(()=>{document.setTitle(this.config.title||this.title);}, 1);
}
},
onUnload() {uni.offWindowResize();},
methods:{
setStyle(object){
//设置导航栏样式
var style = "";
for(var i in object){style += (i+":"+object[i]+";")}
this.style=style;
},
nvLogoTap(e){
//logo点击
var url = this.config.logo.url;
this.$emit("nvLogoTap");
url&&uni.reLaunch({url:url});
},
nvAddressTap(e){
//地址图标点击
this.$emit("nvAddressTap");
},
searchTap(e){
//搜索按钮点击
if(this.config.search.url||this.config.search.linkType){
this.linkTo({currentTarget:{dataset:{url:this.config.search.url,type:this.config.search.linkType||''}}});
}else{
this.$emit("searchTap");
}
},
inputChange(e){
//输入框输入
this.inputValue = e.detail.value;
if(this.config.type=="search"&&this.config.search.input)this.$emit("nvInput",e)
},
inputClear(e){
//输入框清除
this.inputValue="";
if(this.config.type=="search"&&this.config.search.input)this.$emit("nvInput",e);
},
formSubmit(e){
//输入框提交
var e = {detail:{value:this.inputValue}};
this.$emit("nvFormSubmit",e)
},
nvBtnTap(e){
//右按键点击
var e = {type:e.currentTarget.dataset.type,index:parseInt(e.currentTarget.dataset.index)};
this.$emit("nvBtnTap",e);
},
nvTabTap(e){
//中间tab按键点击
var e = {index:parseInt(e.currentTarget.dataset.index)};
this.$emit("nvTabTap",e);
},
toTopTap(e){
//回到顶部
this.showToTop=false
uni.pageScrollTo({scrollTop:0,duration:this.config.toTop.duration||(this.config.toTop.duration===0?0:300)});
this.$emit("nvToTop");
},
pageScroll(e={scrollTop:0}){
//页面滚动
if(!this.config.transparent)return;
var anchor = this.navigatorHeight;
if(this.config.transparent.anchor)anchor=this.config.transparent.anchor;
var op = parseFloat(parseFloat(e.scrollTop/anchor).toFixed(1));
if(e.scrollTop<=anchor){
this.transparent.opacity = op;
if(this.config.transparent.initColor){
if(op>=.5){
this.transparent.color=this.transparent.finishColor;
uni.setNavigationBarColor({frontColor:this.transparent.finishColor,backgroundColor:this.config.bgColor||"#ffffff"});
}else{
this.transparent.color=this.transparent.initColor;
uni.setNavigationBarColor({frontColor:this.transparent.initColor,backgroundColor:this.config.bgColor||"#ffffff"});
}
}
}else{
this.transparent.opacity = 1;
}
if(this.config.toTop){
if(this.showToTop&&e.scrollTop<this.safeArea){
this.showToTop=false;
}
if(!this.showToTop&&e.scrollTop>=this.safeArea){
this.showToTop=true;
}
}
},
backTap(){
//返回键点击
if(this.config.backpress){
this.$emit("backTap");
}else{
this.linkTo({currentTarget:{dataset:{type:'navigateBack'}}});
}
},
linkTo(e) {
//跳转
var url=e.currentTarget.dataset.url,
type=e.currentTarget.dataset.type,
isInput=e.currentTarget.dataset.isInput;
if(isInput&&this.config.type=="search"&&this.config.search&&this.config.search.input){
return;
}
if(this.$nv){
this.$nv(url,type);
}else{
if(!url&&!type)return;
if(url=="/"||url==".")return;
if(typeof(url)=="object"){
uni.navigateTo(url);
return
}
if(typeof(url)=="number"){
if(this.currentPages==1){
uni.reLaunch({url:this.home})
}else{
uni.navigateBack({delta:Math.abs(url||1)})
}
return;
}
if(type){
if (type.indexOf("ab")>-1) {
uni.switchTab({ url: url });
} else if (type=='-1'||type.indexOf("redirect")>-1||type.indexOf("rep")>-1) {
uni.redirectTo({ url: url });
} else if (type.indexOf("aunch")>-1) {
uni.reLaunch({ url: url });
} else if (type.indexOf("ack")>-1) {
if(this.currentPages==1){
uni.reLaunch({url:this.home});
}else{
uni.navigateBack();
}
}else{
uni.navigateTo({url:url});
}
}else{
if(url.indexOf("/")==0||url.indexOf(".")==0){
uni.navigateTo({url:url});
}else{
if(url.indexOf("?")>0){url+="&platform="+platform;}else{url+="?platform="+platform;};
if(platform=="h5"){
top.location.href=url;
}else if(platform=="app"){
plus.runtime.openUrl(url);
}else{
uni.navigateTo({url:"/pages/other/webview/webview?src="+url.replace("?","&")});
}
}
}
}
}
}
}
</script>
<style lang="scss" scoped>
@font-face {
font-family: iconfont;
src: url('./iconfont.ttf')
}
.iconfont {
font-family: iconfont;
font-size: 30rpx;
font-style: normal;
}
//主色可以设置uni.scss的$mainColor
//或
//uni.scss未定义或定义为null,修改下方$mainColor的默认值
$mainColor: #aa55ff !default;
.pyh-nv-box{position: relative;}
.bgImage{position: absolute;left: 0;top: 0;}
.nvBox{background-color: #fff;z-index: 991;color: #000000;}
.noModel{z-index: 992;}
.nvHeight{height: 88rpx;}
.nvFixed{position: absolute;bottom: 0;height: 88rpx;left: 0;z-index: 992;padding: 0 20rpx;}
.nvContent{flex: 1;height: 88rpx;align-items: center;}
.nvInput{font-size: inherit;flex: 1;}
.searchIcon{
width: 18px;
margin-right: 20rpx;
/* #ifdef MP */
height: 18px;
/* #endif */
}
.nvTitle{position: absolute;top: 0;left: 0;right: 0;text-align: center;height: 88rpx;line-height: 88rpx;align-items: center;justify-content: center;padding: 0 80rpx;font-size: 32rpx;font-weight: bold;overflow: hidden;text-overflow: ellipsis;}
.androidwx{text-align: left;padding-left: 80rpx;justify-content: flex-start!important;}
.nvback{font-size: 54rpx;position: absolute;left: 6rpx;padding-left: 8rpx;bottom: 18rpx;flex-direction: row;align-items: center;z-index: 992;width: 52rpx;height: 52rpx;}
.nvhome{border-radius: 26rpx;font-size: 36rpx;padding: 0;left: 20rpx;text-align: center;justify-content: center;}
.nvHadBack{padding-left: 60rpx;}
//logo
.nvLogoBox{align-items: center;justify-content: center;position: absolute;left: 0;padding-right: 0rpx!important;left: 0;right: 0;}
.nvLogo{width: 60rpx;}
//含搜索框
.nvSearchLogo{margin-right: 20rpx;}
.nvAddress{background-color: #f8f8f8;border-radius: 44rpx;justify-content: center;align-items: center;padding: 0 16rpx 0 10rpx;font-size: 28rpx;line-height: 30rpx;margin-right: 20rpx;color: #000000;height: 60rpx;width: 144rpx;}
.nvAddressIcon{width: 30rpx;margin-right: 4rpx;font-size: 34rpx;}
.nvAddressTextBox{width: 84rpx;overflow: hidden;}
.nvAddressText{flex: 1;font-size: 28rpx;line-height: 30rpx;overflow: hidden;text-overflow: ellipsis;}
.searchPlac{color: #bbb;}
.nvSForm{flex: 1;justify-content: space-between;align-items: center;}
.nvSBox{flex: 1;border-radius: 44rpx;background-color: #f8f8f8;height: 60rpx;line-height: 60rpx;padding: 0 20rpx;align-items: center;}
.nvSBtn{color: #fff;border-radius: 44rpx;height: 60rpx;line-height: 60rpx;width: 120rpx;padding: 0;text-align: center;font-size: 28rpx;margin-left: 20rpx;background-color: $mainColor;}
.nvSClose{
/* #ifdef MP */
height: 15px;
/* #endif */
}
//右边按钮组
.nvBtnGroup{position: absolute;right: 20rpx;top: 0;height: 88rpx;align-items: center;justify-content: center;z-index: 993;font-size: 28rpx;color: #000000;}
.nvBtn{display: flex;align-items: center;justify-content: center;flex-direction: column;text-align: center;}
.nvBtn:first-child{margin-left: 0;}
.nvBtn,.nvBtnImg{padding: 0;margin-left: 20rpx;background: transparent;border: 0;color: #000000;z-index: 3;font-size: 28rpx;position: relative;}
.nvBtnImg{width: 48rpx;margin-left: 0;}
.nvBtnGroup-static{position: relative;padding-left: 20rpx;right: 0;}
.nvBtn .nvBadge{width: 26rpx;height: 26rpx;position: absolute;top: -8rpx;right: -8rpx;display: flex;align-items: center;justify-content: center;border-radius: 50%;overflow: hidden;background-color: red;color: #fff;font-size: 16rpx;z-index: 4;}
//tab栏
.nvTabBox{position: absolute!important;}
.nvTab{flex-direction: column!important;align-items: center;justify-content: flex-end;margin: 0 10rpx;position: relative;}
.nTTxt,.nTTxt-ac{padding: 0 10rpx;line-height: 88rpx;}
.nTLine,.nTLine-ac{height: 4rpx;border-radius: 2rpx;background: transparent;position: absolute;bottom: 0;left: 0;right: 0;}
.nTTxt-ac{color: $mainColor;}
.nTLine-ac{background: $mainColor;}
.nvTabHide{width:0;height:0;margin:0;overflow:hidden;}
//回到顶部
.nvToTop{position: fixed;bottom: 200rpx;right: 40rpx;z-index: 992;background: #fff;border-radius: 50%;width: 80rpx;height: 80rpx;text-align: center;line-height: 80rpx;font-size: 46rpx;box-shadow: 2rpx 2rpx 2rpx 2rpx #ddd;}
//小程序胶囊留位
/* #ifdef MP-WEIXIN */
.noModel .nvContent{padding-right: 200rpx;}
.noModel .nvSBtn,.noModel .nvBtnGroup{display: none;}
/* #endif */
/* #ifdef APP-NVUE */
.nvContent,.nvback,.nvLogoBox,.nvSearchBox,.nvAddress,.nvSForm,.nvSBox,.nvBtnGroup,.nvTabBox,.nvTab{flex-direction: row;}
.nvTitle,.nvAddress,.nvAddressText{lines: 1;}
.pyh-nv-box,.nvBox,.nvHeight,.nvFixed,.nvTitle,.nvLogoBox,.nvSearchBox,.nTLine,.nTLine-ac{flex: 1;}
.nvTab{flex-direction: column!important;align-items: center;justify-content: flex-end;line-height: 80rpx;margin: 0 10rpx;}
/* #endif */
/* #ifndef APP-NVUE */
.nvContent,.nvback,.nvLogoBox,.nvSearchBox,.nvAddress,.nvSForm,.nvSBox,.nvBtnGroup,.nvTabBox,.nvTab{display: flex;flex-direction: row;}
.nvTitle,.nvAddressText{white-space: nowrap;}
.nvBox,.nvBox *,.nvContent,.nvTitle,.nvFixed{box-sizing: border-box;}
.nvLogo,.nvAddressIcon,.nvBtnImg{height: auto;}
.pyh-nv-box,.nvBox,.nvHeight,.nvFixed,.nvTitle,.nvLogoBox,.nvSearchBox,.nTLine,.nTLine-ac{width: 100%;}
/* #endif */
</style>

View File

@@ -0,0 +1,79 @@
{
"id": "pyh-nv",
"name": "pyh-nv 全自定义、全兼容、全功能、多类型、可渐变导航栏",
"version": "1.2.8",
"description": "所有属性都可自定义兼容各端包括nvue所有类型导航栏都可渐变还可设置状态栏字体色1.1.6版本后续非uni_modules版本不再更新",
"keywords": [
"导航栏",
"自定义",
"渐变",
"状态栏",
"多端兼容"
],
"displayName": "pyh-nv 全自定义、全兼容、全功能、多类型、可渐变导航栏",
"repository": "https://github.com/Ulovely/pyh-nv",
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": ""
},
"uni_modules": {
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "u",
"IE": "u",
"Edge": "u",
"Firefox": "u",
"Safari": "u"
},
"小程序": {
"微信": "y",
"阿里": "u",
"百度": "u",
"字节跳动": "u",
"QQ": "u"
},
"快应用": {
"华为": "u",
"联盟": "u"
}
}
}
},
"engines": {
"HBuilderX": "^3.1.0"
}
}

View File

@@ -0,0 +1,131 @@
### pyh-nv 全自定义、全兼容、全功能、多类型、可渐变导航栏
pyh-nv 导航栏组件,组件名:``nv``,代码块: nv。
**使用方式:**
uni_modules:
[uni_modules使用方法](https://uniapp.dcloud.io/uni_modules?id=%e4%bd%bf%e7%94%a8-uni_modules-%e6%8f%92%e4%bb%b6)
uni_modules在template内的名称为pyh-nv,兼容nv写法需要在pages.json添加代码
"easycom": {"nv": "@/uni_modules/pyh-nv/components/pyh-nv/pyh-nv.vue"}
非uni_modules:
复制uni_modules->pyh-nv->components->pyh-nv文件到根目录的components下
在 ``main.js`` 中引用组件
```javascript
import nv from "@/components/pyh-nv/pyh-nv.vue";
Vue.component("nv",nv)
```
在 ``template`` 中使用组件
```html
<nv></nv>
<nv :config="{'hideback':true}"></nv>
<nv :config="config"></nv>
```
在 ``script`` 中 config 说明
所有配置都为选填,无需要可以不配置,不复杂!!!</br>
所有配置都为选填,无需要可以不配置,不复杂!!!</br>
所有配置都为选填,无需要可以不配置,不复杂!!!</br>
**config 属性说明:**
|属性名 |类型 |默认值 |说明 |
|--- |---- |--- |--- |
|title |String |'pyh-nv' |标题,默认值为getApp().globalData.NAME或组件内title写死的字符串h5端能自动同步标签标题比如微信标题标题可以使用config配置修改|
|position |String |'fixed' |定位方式,fixed和absoult都是固定定位其它值为静态导航栏随页面滚动 |
|hideback |Boolean|false |是否隐藏导航栏返回功能 |
|model |Boolean|false |是否页面内独立使用模型如果是固定定位top为导航栏高度 |
|bgImage |String |'' |导航栏背景图,如果使用则bgColor无效|
|bgColor |String |'#ffffff' |导航栏背景色,如果使用渐变色transparent渐变属性失效|
|color |String |'#000000' |导航栏和状态栏字体色,也用于渐变完成时字体色(状态栏字体只支持#000000或#ffffff|
|componentBgColor |String |'#f8f8f8' |导航栏组件背景色(可被覆盖),如果有设置,回到首页的返回键有背景色|
|type |String |'default' |导航栏类型(默认为通用),还有logo和search |
|safeArea |Number |安全高度 |暂时只用于控制滚动显示,比如回到顶部 |
|toTop |Object | |是否使用回到顶部,有该属性就是使用,详细见下方toTop说明} |
|logo |Object | |导航栏logo的配置,仅type为logo或search时有效,详细见下方logo说明 |
|search |Object | |导航栏含搜索框的配置,仅type为search时有效,详细见下方search说明 |
|transparent |Object | |导航栏渐变配置,详细见下方transparent说明 |
|fixedAssist |Object | |固定/绝对定位时辅助容器,{hide:false,bgColor:''} |
|address |Object | |搜索导航栏左地址配置,{province:'广东省'} |
|btn |Array |[] |导航栏右方按钮组,{text:'点击1',style:''},{icon:'',text:'',badge:{text:'1',style:''}}|
|tabArr |Array |[] |导航栏中间tab切换,{title:'',active:true,hide:false} |
**pyh-nv.vue 内配置说明:**
|title |String |'pyh-nv' |标题默认值,getApp().globalData.NAME或自定义字符串 |
|h5AutoTitle |Boolean|false |为true时而且config没传入title,h5端自动获取pages.json的navigationBarTitleText|
**config 内 toTop 配置说明:**
|属性名 |类型 |默认值 |说明 |
|--- |---- |--- |--- |
|duration |Number |300 |回到顶部的滚动动画时间ms |
|style |String |'' |样式配置 |
**config 内 logo 配置说明:**
|属性名 |类型 |默认值 |说明 |
|--- |---- |--- |--- |
|src |String |'/static/logo.png' |logo路径 |
|url |String |'' |如果传值,点击logo会reLaunch到该url |
|style |String |'' |样式配置 |
**config 内 search 配置说明:**
|属性名 |类型 |默认值 |说明 |
|--- |---- |--- |--- |
|value |String |'' |input的初始值如需动态赋值必须初始化 |
|bgColor |String |'#f8f8f8' |组件背景色,覆盖 componentBgColor |
|input |Boolean|false |输入框提示语样式 |
|url |String |'' |input为false时生效,点击navigateTo到url |
|focus |Boolean|false |是否自动聚焦 |
|border |String |'' |输入框边框样式 |
|placeholder |String |'搜索' |输入框提示语 |
|placeholderStyle |String |'' |输入框提示语样式 |
|btn |Object | |input为true时生效,搜索框提交按钮,{text:'搜索',style:''} |
|confirmType |String |'search' |同官方input的confirm-type,设置回车键文字 |
**config 内 transparent 配置说明:**
|属性名 |类型 |默认值 |说明 |
|--- |---- |--- |--- |
|type |String |'background' |渐变类型,content为全透明渐变 |
|anchor |Number |当前导航栏高度 |最终渐变位置 |
|initColor |String |'#ffffff' |导航栏与状态栏初始色,(状态栏字体只支持#000000或#ffffff |
**组件pyh-nv 事件说明(详情请参考示例项目)**
|属名 |说明 |
|--- |---- |
|nvLogoTap |点击logo,仅logo存在时生效 |
|nvAddressTap |点击地址,仅地址存在时生效 |
|nvInput |输入框input事件,仅search.input为true时生效 |
|nvFormSubmit |输入框确认事件,仅search.input为true时生效 |
|nvBtnTap |右方按钮组点击事件,仅右方按钮存在时生效 |
|nvTabTap |中间tab组点击事件,仅中间tab按钮存在时生效 |
**ref 事件说明(详情请参考示例项目)**
|事件名 |参数类型 |参数默认值 |说明 |
|--- |---- |---- |---
|setStyle |Object |{} |直接设置导航栏样式 |
|pageScroll |Object |{scrollTop:0} |传递页面滚动信息 |
**感谢:**
> 有更多优化建议和需求,请联系作者 panyh 。谢谢!

View File

@@ -0,0 +1,8 @@
## 1.1.02021-07-30
- 组件兼容 vue3如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.0.72021-05-12
- 新增 组件示例地址
## 1.0.62021-02-05
- 调整为uni_modules目录规范
- 优化 按钮背景色调整
- 优化 兼容pc端

View File

@@ -0,0 +1,448 @@
<template>
<view class="uni-cursor-point">
<view v-if="popMenu && (leftBottom||rightBottom||leftTop||rightTop) && content.length > 0" :class="{
'uni-fab--leftBottom': leftBottom,
'uni-fab--rightBottom': rightBottom,
'uni-fab--leftTop': leftTop,
'uni-fab--rightTop': rightTop
}"
class="uni-fab">
<view :class="{
'uni-fab__content--left': horizontal === 'left',
'uni-fab__content--right': horizontal === 'right',
'uni-fab__content--flexDirection': direction === 'vertical',
'uni-fab__content--flexDirectionStart': flexDirectionStart,
'uni-fab__content--flexDirectionEnd': flexDirectionEnd,
'uni-fab__content--other-platform': !isAndroidNvue
}"
:style="{ width: boxWidth, height: boxHeight, backgroundColor: styles.backgroundColor }" class="uni-fab__content"
elevation="5">
<view v-if="flexDirectionStart || horizontalLeft" class="uni-fab__item uni-fab__item--first" />
<view v-for="(item, index) in content" :key="index" :class="{ 'uni-fab__item--active': isShow }" class="uni-fab__item"
@click="_onItemClick(index, item)">
<image :src="item.active ? item.selectedIconPath : item.iconPath" class="uni-fab__item-image" mode="widthFix" />
<text class="uni-fab__item-text" :style="{ color: item.active ? styles.selectedColor : styles.color }">{{ item.text }}</text>
</view>
<view v-if="flexDirectionEnd || horizontalRight" class="uni-fab__item uni-fab__item--first" />
</view>
</view>
<view :class="{
'uni-fab__circle--leftBottom': leftBottom,
'uni-fab__circle--rightBottom': rightBottom,
'uni-fab__circle--leftTop': leftTop,
'uni-fab__circle--rightTop': rightTop,
'uni-fab__content--other-platform': !isAndroidNvue
}"
class="uni-fab__circle uni-fab__plus" :style="{ 'background-color': styles.buttonColor }" @click="_onClick">
<view class="fab-circle-v" :class="{'uni-fab__plus--active': isShow && content.length > 0}"></view>
<view class="fab-circle-h" :class="{'uni-fab__plus--active': isShow && content.length > 0}"></view>
</view>
</view>
</template>
<script>
let platform = 'other'
// #ifdef APP-NVUE
platform = uni.getSystemInfoSync().platform
// #endif
/**
* Fab 悬浮按钮
* @description 点击可展开一个图形按钮菜单
* @tutorial https://ext.dcloud.net.cn/plugin?id=144
* @property {Object} pattern 可选样式配置项
* @property {Object} horizontal = [left | right] 水平对齐方式
* @value left 左对齐
* @value right 右对齐
* @property {Object} vertical = [bottom | top] 垂直对齐方式
* @value bottom 下对齐
* @value top 上对齐
* @property {Object} direction = [horizontal | vertical] 展开菜单显示方式
* @value horizontal 水平显示
* @value vertical 垂直显示
* @property {Array} content 展开菜单内容配置项
* @property {Boolean} popMenu 是否使用弹出菜单
* @event {Function} trigger 展开菜单点击事件,返回点击信息
* @event {Function} fabClick 悬浮按钮点击事件
*/
export default {
name: 'UniFab',
emits:['fabClick','trigger'],
props: {
pattern: {
type: Object,
default () {
return {}
}
},
horizontal: {
type: String,
default: 'left'
},
vertical: {
type: String,
default: 'bottom'
},
direction: {
type: String,
default: 'horizontal'
},
content: {
type: Array,
default () {
return []
}
},
show: {
type: Boolean,
default: false
},
popMenu: {
type: Boolean,
default: true
}
},
data() {
return {
fabShow: false,
isShow: false,
isAndroidNvue: platform === 'android',
styles: {
color: '#3c3e49',
selectedColor: '#007AFF',
backgroundColor: '#fff',
buttonColor: '#007AFF'
}
}
},
computed: {
contentWidth(e) {
return (this.content.length + 1) * 55 + 10 + 'px'
},
contentWidthMin() {
return 55 + 'px'
},
// 动态计算宽度
boxWidth() {
return this.getPosition(3, 'horizontal')
},
// 动态计算高度
boxHeight() {
return this.getPosition(3, 'vertical')
},
// 计算左下位置
leftBottom() {
return this.getPosition(0, 'left', 'bottom')
},
// 计算右下位置
rightBottom() {
return this.getPosition(0, 'right', 'bottom')
},
// 计算左上位置
leftTop() {
return this.getPosition(0, 'left', 'top')
},
rightTop() {
return this.getPosition(0, 'right', 'top')
},
flexDirectionStart() {
return this.getPosition(1, 'vertical', 'top')
},
flexDirectionEnd() {
return this.getPosition(1, 'vertical', 'bottom')
},
horizontalLeft() {
return this.getPosition(2, 'horizontal', 'left')
},
horizontalRight() {
return this.getPosition(2, 'horizontal', 'right')
}
},
watch: {
pattern(newValue, oldValue) {
//console.log(JSON.stringify(newValue))
this.styles = Object.assign({}, this.styles, newValue)
}
},
created() {
this.isShow = this.show
if (this.top === 0) {
this.fabShow = true
}
// 初始化样式
this.styles = Object.assign({}, this.styles, this.pattern)
},
methods: {
_onClick() {
this.$emit('fabClick')
if (!this.popMenu) {
return
}
this.isShow = !this.isShow
},
open() {
this.isShow = true
},
close() {
this.isShow = false
},
/**
* 按钮点击事件
*/
_onItemClick(index, item) {
this.$emit('trigger', {
index,
item
})
},
/**
* 获取 位置信息
*/
getPosition(types, paramA, paramB) {
if (types === 0) {
return this.horizontal === paramA && this.vertical === paramB
} else if (types === 1) {
return this.direction === paramA && this.vertical === paramB
} else if (types === 2) {
return this.direction === paramA && this.horizontal === paramB
} else {
return this.isShow && this.direction === paramA ? this.contentWidth : this.contentWidthMin
}
}
}
}
</script>
<style lang="scss" scoped>
.uni-fab {
position: fixed;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
align-items: center;
z-index: 10;
}
.uni-cursor-point {
/* #ifdef H5 */
cursor: pointer;
/* #endif */
}
.uni-fab--active {
opacity: 1;
}
.uni-fab--leftBottom {
left: 5px;
bottom: 20px;
/* #ifdef H5 */
left: calc(5px + var(--window-left));
bottom: calc(20px + var(--window-bottom));
/* #endif */
padding: 10px;
}
.uni-fab--leftTop {
left: 5px;
top: 30px;
/* #ifdef H5 */
left: calc(5px + var(--window-left));
top: calc(30px + var(--window-top));
/* #endif */
padding: 10px;
}
.uni-fab--rightBottom {
right: 5px;
bottom: 20px;
/* #ifdef H5 */
right: calc(5px + var(--window-right));
bottom: calc(20px + var(--window-bottom));
/* #endif */
padding: 10px;
}
.uni-fab--rightTop {
right: 5px;
top: 30px;
/* #ifdef H5 */
right: calc(5px + var(--window-right));
top: calc(30px + var(--window-top));
/* #endif */
padding: 10px;
}
.uni-fab__circle {
position: fixed;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
align-items: center;
width: 55px;
height: 55px;
background-color: #3c3e49;
border-radius: 55px;
z-index: 11;
}
.uni-fab__circle--leftBottom {
left: 15px;
bottom: 30px;
/* #ifdef H5 */
left: calc(15px + var(--window-left));
bottom: calc(30px + var(--window-bottom));
/* #endif */
}
.uni-fab__circle--leftTop {
left: 15px;
top: 40px;
/* #ifdef H5 */
left: calc(15px + var(--window-left));
top: calc(40px + var(--window-top));
/* #endif */
}
.uni-fab__circle--rightBottom {
right: 15px;
bottom: 30px;
/* #ifdef H5 */
right: calc(15px + var(--window-right));
bottom: calc(30px + var(--window-bottom));
/* #endif */
}
.uni-fab__circle--rightTop {
right: 15px;
top: 40px;
/* #ifdef H5 */
right: calc(15px + var(--window-right));
top: calc(40px + var(--window-top));
/* #endif */
}
.uni-fab__circle--left {
left: 0;
}
.uni-fab__circle--right {
right: 0;
}
.uni-fab__circle--top {
top: 0;
}
.uni-fab__circle--bottom {
bottom: 0;
}
.uni-fab__plus {
font-weight: bold;
}
.fab-circle-v {
position: absolute;
width: 3px;
height: 31px;
left: 26px;
top: 12px;
background-color: white;
transform: rotate(0deg);
transition: transform 0.3s;
}
.fab-circle-h {
position: absolute;
width: 31px;
height: 3px;
left: 12px;
top: 26px;
background-color: white;
transform: rotate(0deg);
transition: transform 0.3s;
}
.uni-fab__plus--active {
transform: rotate(135deg);
}
.uni-fab__content {
/* #ifndef APP-NVUE */
box-sizing: border-box;
display: flex;
/* #endif */
flex-direction: row;
border-radius: 55px;
overflow: hidden;
transition-property: width, height;
transition-duration: 0.2s;
width: 55px;
border-color: #DDDDDD;
border-width: 1rpx;
border-style: solid;
}
.uni-fab__content--other-platform {
border-width: 0px;
box-shadow: 0 0 5px 2px rgba(0, 0, 0, 0.2);
}
.uni-fab__content--left {
justify-content: flex-start;
}
.uni-fab__content--right {
justify-content: flex-end;
}
.uni-fab__content--flexDirection {
flex-direction: column;
justify-content: flex-end;
}
.uni-fab__content--flexDirectionStart {
flex-direction: column;
justify-content: flex-start;
}
.uni-fab__content--flexDirectionEnd {
flex-direction: column;
justify-content: flex-end;
}
.uni-fab__item {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: center;
align-items: center;
width: 55px;
height: 55px;
opacity: 0;
transition: opacity 0.2s;
}
.uni-fab__item--active {
opacity: 1;
}
.uni-fab__item-image {
width: 25px;
height: 25px;
margin-bottom: 3px;
}
.uni-fab__item-text {
color: #FFFFFF;
font-size: 12px;
}
.uni-fab__item--first {
width: 55px;
}
</style>

View File

@@ -0,0 +1,383 @@
<template>
<view>
<view :class="{
leftBottom: leftBottom,
rightBottom: rightBottom,
leftTop: leftTop,
rightTop: rightTop
}" v-if="leftBottom||rightBottom||leftTop||rightTop" class="fab-box fab">
<view :class="{
left: horizontal === 'left' && direction === 'horizontal',
top: vertical === 'top' && direction === 'vertical',
bottom: vertical === 'bottom' && direction === 'vertical',
right: horizontal === 'right' && direction === 'horizontal'
}" :style="{ 'background-color': styles.buttonColor }" class="fab-circle" @click="_onClick">
<view class="fab-circle-box" :class="{ active: isShow }">
<view class="fab-circle-v"></view>
<view class="fab-circle-h"></view>
</view>
</view>
<view :class="{
left: horizontal === 'left',
right: horizontal === 'right',
flexDirection: direction === 'vertical',
flexDirectionStart: flexDirectionStart,
flexDirectionEnd: flexDirectionEnd
}" :style="{ width: boxWidth, height: boxHeight, background: styles.backgroundColor }" class="fab-content">
<view v-if="flexDirectionStart || horizontalLeft" class="fab-item first" />
<view v-for="(item, index) in content" :key="index" :class="{ active: isShow }" :style="{
color: item.active ? styles.selectedColor : styles.color
}" class="fab-item" @click="_onItemClick(index, item)">
<image :src="item.active ? item.selectedIconPath : item.iconPath" class="content-image" mode="widthFix" />
<text class="text">{{ item.text }}</text>
</view>
<view v-if="flexDirectionEnd || horizontalRight" class="fab-item first" />
</view>
</view>
</view>
</template>
<script>
import uniIcons from "../uni-icons/uni-icons.vue";
export default {
name: 'UniFab',
components:{
uniIcons
},
props: {
pattern: {
type: Object,
default () {
return {}
}
},
horizontal: {
type: String,
default: 'left'
},
vertical: {
type: String,
default: 'bottom'
},
direction: {
type: String,
default: 'horizontal'
},
content: {
type: Array,
default () {
return []
}
},
show: {
type: Boolean,
default: false
}
},
data() {
return {
fabShow: false,
flug: true,
isShow: false,
styles: {
color: '#3c3e49',
selectedColor: '#007AFF',
backgroundColor: '#fff',
buttonColor: '#3c3e49'
}
}
},
computed: {
contentWidth(e) {
return uni.upx2px((this.content.length + 1) * 110 + 20) + 'px'
},
contentWidthMin() {
return uni.upx2px(110) + 'px'
},
// 动态计算宽度
boxWidth() {
return this.getPosition(3, 'horizontal')
},
// 动态计算高度
boxHeight() {
return this.getPosition(3, 'vertical')
},
// 计算左下位置
leftBottom() {
return this.getPosition(0, 'left', 'bottom')
},
// 计算右下位置
rightBottom() {
return this.getPosition(0, 'right', 'bottom')
},
// 计算左上位置
leftTop() {
return this.getPosition(0, 'left', 'top')
},
rightTop() {
return this.getPosition(0, 'right', 'top')
},
flexDirectionStart() {
return this.getPosition(1, 'vertical', 'top')
},
flexDirectionEnd() {
return this.getPosition(1, 'vertical', 'bottom')
},
horizontalLeft() {
return this.getPosition(2, 'horizontal', 'left')
},
horizontalRight() {
return this.getPosition(2, 'horizontal', 'right')
}
},
watch: {
pattern(newValue, oldValue) {
//console.log(JSON.stringify(newValue))
this.styles = Object.assign({}, this.styles, newValue)
}
},
created() {
this.isShow = this.show
if (this.top === 0) {
this.fabShow = true
}
// 初始化样式
this.styles = Object.assign({}, this.styles, this.pattern)
},
methods: {
_onClick() {
this.isShow = !this.isShow
},
open() {
this.isShow = true
},
close() {
this.isShow = false
},
/**
* 按钮点击事件
*/
_onItemClick(index, item) {
this.$emit('trigger', {
index,
item
})
},
/**
* 获取 位置信息
*/
getPosition(types, paramA, paramB) {
if (types === 0) {
return this.horizontal === paramA && this.vertical === paramB
} else if (types === 1) {
return this.direction === paramA && this.vertical === paramB
} else if (types === 2) {
return this.direction === paramA && this.horizontal === paramB
} else {
return this.isShow && this.direction === paramA ? this.contentWidth : this.contentWidthMin
}
}
}
}
</script>
<style lang="scss" scoped>
.uni-icon {
font-family: uniicons;
font-size: 30px;
font-weight: normal;
font-style: normal;
line-height: 1;
display: inline-block;
text-decoration: none;
-webkit-font-smoothing: antialiased;
}
.fab-box {
position: fixed;
display: flex;
justify-content: center;
align-items: center;
z-index: 2;
}
.fab-box.top {
width: 60rpx;
height: 60rpx;
right: 30rpx;
bottom: 60rpx;
border: 1px #5989b9 solid;
background: #6699cc;
border-radius: 10rpx;
color: #fff;
transition: all 0.3;
opacity: 0;
}
.fab-box.active {
opacity: 1;
}
.fab-box.fab {
z-index: 10;
}
.fab-box.fab.leftBottom {
left: 30rpx;
bottom: 60rpx;
}
.fab-box.fab.leftTop {
left: 30rpx;
top: 80rpx;
/* #ifdef H5 */
top: calc(80rpx + var(--window-top));
/* #endif */
}
.fab-box.fab.rightBottom {
right: 30rpx;
bottom: 60rpx;
}
.fab-box.fab.rightTop {
right: 30rpx;
top: 80rpx;
/* #ifdef H5 */
top: calc(80rpx + var(--window-top));
/* #endif */
}
.fab-circle {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
width: 110rpx;
height: 110rpx;
background: #3c3e49;
/* background: #5989b9; */
border-radius: 50%;
box-shadow: 0 0 5px 2px rgba(0, 0, 0, 0.2);
z-index: 11;
}
.fab-circle-box {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
transition: all 0.3s;
}
.fab-circle-v {
position: absolute;
width: 8rpx;
height: 60rpx;
left: 50%;
top: 50%;
margin: -30rpx 0 0 -4rpx;
background-color: white;
}
.fab-circle-h {
position: absolute;
width: 60rpx;
height: 8rpx;
left: 50%;
top: 50%;
margin: -4rpx 0 0 -30rpx;
background-color: white;
}
.fab-circle.left {
left: 0;
}
.fab-circle.right {
right: 0;
}
.fab-circle.top {
top: 0;
}
.fab-circle.bottom {
bottom: 0;
}
.fab-circle .uni-icon-plusempty {
color: #ffffff;
font-size: 80rpx;
transition: all 0.3s;
font-weight: bold;
}
.fab-circle-box.active {
transform: rotate(135deg);
font-size: 80rpx;
}
.fab-content {
background: #6699cc;
box-sizing: border-box;
display: flex;
border-radius: 100rpx;
overflow: hidden;
box-shadow: 0 0 5px 2px rgba(0, 0, 0, 0.1);
transition: all 0.2s;
width: 110rpx;
}
.fab-content.left {
justify-content: flex-start;
}
.fab-content.right {
justify-content: flex-end;
}
.fab-content.flexDirection {
flex-direction: column;
justify-content: flex-end;
}
.fab-content.flexDirectionStart {
flex-direction: column;
justify-content: flex-start;
}
.fab-content.flexDirectionEnd {
flex-direction: column;
justify-content: flex-end;
}
.fab-content .fab-item {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 110rpx;
height: 110rpx;
font-size: 24rpx;
color: #fff;
opacity: 0;
transition: opacity 0.2s;
}
.fab-content .fab-item.active {
opacity: 1;
}
.fab-content .fab-item .content-image {
width: 50rpx;
height: 50rpx;
margin-bottom: 5rpx;
}
.fab-content .fab-item.first {
width: 110rpx;
}
</style>

View File

@@ -0,0 +1,83 @@
{
"id": "uni-fab",
"displayName": "uni-fab 悬浮按钮",
"version": "1.1.0",
"description": "悬浮按钮 fab button ,点击可展开一个图标按钮菜单。",
"keywords": [
"uni-ui",
"uniui",
"按钮",
"悬浮按钮",
"fab"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
}
}
}
}
}

View File

@@ -0,0 +1,91 @@
## Fab 悬浮按钮
> **组件名uni-fab**
> 代码块: `uFab`
点击可展开一个图形按钮菜单
### 安装方式
本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`
如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
> **注意事项**
> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。
> - 不建议动态修改属性,可能会耗损部分性能。
> - 展开菜单暂不支持字体图标,使用图片路径时建议使用绝对路径,相对路径可能会有问题。
> - 选中状态要通过自己控制,如果不希望有选中状态,不处理 `active` 即可。
> - 展开菜单建议最多显示四个,如果过多对于小屏手机可能会超出屏幕。
### 基本用法
`template` 中使用组件
```html
<template>
<view>
<uni-fab
:pattern="pattern"
:content="content"
:horizontal="horizontal"
:vertical="vertical"
:direction="direction"
@trigger="trigger"
></uni-fab>
</view>
</template>
```
## API
### Fab Props
| 属性名 | 类型 | 默认值 | 说明 |
| :-: | :-: | :-: | :-: |
| pattern | Object | - | 可选样式配置项 |
| horizontal| String | 'left' | 水平对齐方式。`left`:左对齐,`right`:右对齐 |
| vertical | String | 'bottom' | 垂直对齐方式。`bottom`:下对齐,`top`:上对齐 |
| direction | String | 'horizontal' | 展开菜单显示方式。`horizontal`:水平显示,`vertical`:垂直显示 |
| popMenu | Boolean | true | 是否使用弹出菜单 |
| content | Array | - | 展开菜单内容配置项 |
**pattern配置项**
| 参数 | 类型 | 默认值 | 说明 |
| :-: | :-: | :-: | :-: |
| color | String | #3c3e49 | 文字默认颜色 |
| selectedColor | String | #007AFF | 文字选中时的颜色 |
| backgroundColor | String | #ffffff | 背景色 |
| buttonColor | String | #3c3e49 | 按钮背景色 |
**content配置项**
| 参数 | 类型 | 说明 |
| :-: | :-: | :-: | :-: |
| iconPath | String | 图片路径 |
| selectedIconPath | String | 选中后图片路径|
| text | String | 文字 |
| active | Boolean | 是否选中当前 |
### Fab Events
| 参数 | 类型 | 说明 |
| :-: | :-: | :-: |
| @trigger | Function | 展开菜单点击事件,返回点击信息|
| @fabClick | Function | 悬浮按钮点击事件 |
## 组件示例
点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/fab/fab](https://hellouniapp.dcloud.net.cn/pages/extUI/fab/fab)

View File

@@ -0,0 +1,10 @@
## 1.2.12021-08-24
- 新增 支持国际化
## 1.2.02021-07-30
- 组件兼容 vue3如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.1.82021-05-12
- 新增 组件示例地址
## 1.1.72021-03-30
- 修复 uni-load-more 在首页使用时h5 平台报 'uni is not defined' 的 bug
## 1.1.62021-02-05
- 调整为uni_modules目录规范

View File

@@ -0,0 +1,5 @@
{
"uni-load-more.contentdown": "Pull up to show more",
"uni-load-more.contentrefresh": "loading...",
"uni-load-more.contentnomore": "No more data"
}

View File

@@ -0,0 +1,8 @@
import en from './en.json'
import zhHans from './zh-Hans.json'
import zhHant from './zh-Hant.json'
export default {
en,
'zh-Hans': zhHans,
'zh-Hant': zhHant
}

View File

@@ -0,0 +1,5 @@
{
"uni-load-more.contentdown": "上拉显示更多",
"uni-load-more.contentrefresh": "正在加载...",
"uni-load-more.contentnomore": "没有更多数据了"
}

View File

@@ -0,0 +1,5 @@
{
"uni-load-more.contentdown": "上拉顯示更多",
"uni-load-more.contentrefresh": "正在加載...",
"uni-load-more.contentnomore": "沒有更多數據了"
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,86 @@
{
"id": "uni-load-more",
"displayName": "uni-load-more 加载更多",
"version": "1.2.1",
"description": "LoadMore 组件,常用在列表里面,做滚动加载使用。",
"keywords": [
"uni-ui",
"uniui",
"加载更多",
"load-more"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "u"
}
}
}
}
}

View File

@@ -0,0 +1,70 @@
### LoadMore 加载更多
> **组件名uni-load-more**
> 代码块: `uLoadMore`
用于列表中,做滚动加载使用,展示 loading 的各种状态。
### 安装方式
本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`
如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
### 使用方式
在 ``template`` 中使用组件
```html
<uni-load-more :status="more"></uni-load-more>
```
## API
### LoadMore Props
|属性名 |类型 | 可选值 |默认值 |说明 |
|:-: |:-: |:-: |:-: |:-: |
|iconSize |Number |- |24 |指定图标大小 |
|status |String |more/loading/noMore |more |loading 的状态 |
|showIcon |Boolean|- |true |是否显示 loading 图标 |
|iconType |String |snow/circle/auto |auto |指定图标样式|
|color |String |- |#777777 |图标和文字颜色 |
|contentText|Object|- |{contentdown: "上拉显示更多",contentrefresh: "正在加载...",contentnomore: "没有更多数据了"}|各状态文字说明 |
#### Status Options
|参数名称 |说明 |
|:-: |:-: |
|more |loading前 |
|loading|loading前中 |
|more |没有更多数据 |
#### IconType Options
|参数名称 |说明 |
|:-: |:-: |
|snow |ios雪花加载样式 |
|circle |安卓环形加载样式 |
|auto |根据平台自动选择加载样式 |
> **说明**
> `iconType`为`snow`时,在`APP-NVUE`平台不可设置大小,在非`APP-NVUE`平台不可设置颜色
### 事件说明
|事件名 |说明 |返回值 |
|:-: |:-: |:-: |
|clickLoadMore |点击加载更多时触发 |e.detail={status:'loading'}|
## 组件示例
点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/load-more/load-more](https://hellouniapp.dcloud.net.cn/pages/extUI/load-more/load-more)

View File

@@ -0,0 +1,20 @@
## 1.2.22021-09-10
- 优化 默认值修改为 0 颗星
## 1.2.12021-07-30
- 优化 vue3下事件警告的问题
## 1.2.02021-07-13
- 组件兼容 vue3如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.1.22021-05-12
- 新增 组件示例地址
## 1.1.12021-04-21
- 修复 布局变化后 uni-rate 星星计算不准确的 bug
- 优化 添加依赖 uni-icons, 导入 uni-rate 自动下载依赖
## 1.1.02021-04-16
- 修复 uni-rate 属性 margin 值为 string 组件失效的 bug
## 1.0.92021-02-05
- 优化 组件引用关系通过uni_modules引用组件
## 1.0.82021-02-05
- 调整为uni_modules目录规范
- 支持 pc 端

View File

@@ -0,0 +1,393 @@
<template>
<view>
<view
ref="uni-rate"
class="uni-rate"
>
<view
class="uni-rate__icon"
:class="{'uni-cursor-not-allowed': disabled}"
:style="{ 'margin-right': marginNumber + 'px' }"
v-for="(star, index) in stars"
:key="index"
@touchstart.stop="touchstart"
@touchmove.stop="touchmove"
@mousedown.stop="mousedown"
@mousemove.stop="mousemove"
@mouseleave="mouseleave"
>
<uni-icons
:color="color"
:size="size"
:type="isFill ? 'star-filled' : 'star'"
/>
<!-- #ifdef APP-NVUE -->
<view
:style="{ width: star.activeWitch.replace('%','')*size/100+'px'}"
class="uni-rate__icon-on"
>
<uni-icons
style="text-align: left;"
:color="disabled?'#ccc':activeColor"
:size="size"
type="star-filled"
/>
</view>
<!-- #endif -->
<!-- #ifndef APP-NVUE -->
<view
:style="{ width: star.activeWitch}"
class="uni-rate__icon-on"
>
<uni-icons
:color="disabled?disabledColor:activeColor"
:size="size"
type="star-filled"
/>
</view>
<!-- #endif -->
</view>
</view>
</view>
</template>
<script>
// #ifdef APP-NVUE
const dom = uni.requireNativePlugin('dom');
// #endif
/**
* Rate 评分
* @description 评分组件
* @tutorial https://ext.dcloud.net.cn/plugin?id=33
* @property {Boolean} isFill = [true|false] 星星的类型,是否为实心类型, 默认为实心
* @property {String} color 未选中状态的星星颜色,默认为 "#ececec"
* @property {String} activeColor 选中状态的星星颜色,默认为 "#ffca3e"
* @property {String} disabledColor 禁用状态的星星颜色,默认为 "#c0c0c0"
* @property {Number} size 星星的大小
* @property {Number} value/v-model 当前评分
* @property {Number} max 最大评分评分数量,目前一分一颗星
* @property {Number} margin 星星的间距,单位 px
* @property {Boolean} disabled = [true|false] 是否为禁用状态,默认为 false
* @property {Boolean} readonly = [true|false] 是否为只读状态,默认为 false
* @property {Boolean} allowHalf = [true|false] 是否实现半星,默认为 false
* @property {Boolean} touchable = [true|false] 是否支持滑动手势,默认为 true
* @event {Function} change uniRate 的 value 改变时触发事件e={value:Number}
*/
export default {
name: "UniRate",
props: {
isFill: {
// 星星的类型,是否镂空
type: [Boolean, String],
default: true
},
color: {
// 星星未选中的颜色
type: String,
default: "#ececec"
},
activeColor: {
// 星星选中状态颜色
type: String,
default: "#ffca3e"
},
disabledColor: {
// 星星禁用状态颜色
type: String,
default: "#c0c0c0"
},
size: {
// 星星的大小
type: [Number, String],
default: 24
},
value: {
// 当前评分
type: [Number, String],
default: 0
},
modelValue: {
// 当前评分
type: [Number, String],
default: 0
},
max: {
// 最大评分
type: [Number, String],
default: 5
},
margin: {
// 星星的间距
type: [Number, String],
default: 0
},
disabled: {
// 是否可点击
type: [Boolean, String],
default: false
},
readonly: {
// 是否只读
type: [Boolean, String],
default: false
},
allowHalf: {
// 是否显示半星
type: [Boolean, String],
default: false
},
touchable: {
// 是否支持滑动手势
type: [Boolean, String],
default: true
}
},
data() {
return {
valueSync: "",
userMouseFristMove: true,
userRated: false,
userLastRate: 1
};
},
watch: {
value(newVal) {
this.valueSync = Number(newVal);
},
modelValue(newVal) {
this.valueSync = Number(newVal);
},
},
computed: {
stars() {
const value = this.valueSync ? this.valueSync : 0;
const starList = [];
const floorValue = Math.floor(value);
const ceilValue = Math.ceil(value);
for (let i = 0; i < this.max; i++) {
if (floorValue > i) {
starList.push({
activeWitch: "100%"
});
} else if (ceilValue - 1 === i) {
starList.push({
activeWitch: (value - floorValue) * 100 + "%"
});
} else {
starList.push({
activeWitch: "0"
});
}
}
return starList;
},
marginNumber() {
return Number(this.margin)
}
},
created() {
this.valueSync = Number(this.value||this.modelValue);
this._rateBoxLeft = 0
this._oldValue = null
},
mounted() {
setTimeout(() => {
this._getSize()
}, 100)
// #ifdef H5
this.PC = this.IsPC()
// #endif
},
methods: {
touchstart(e) {
// #ifdef H5
if( this.IsPC() ) return
// #endif
if (this.readonly || this.disabled) return
const {
clientX,
screenX
} = e.changedTouches[0]
// TODO 做一下兼容,只有 Nvue 下才有 screenX其他平台式 clientX
this._getRateCount(clientX || screenX)
},
touchmove(e) {
// #ifdef H5
if( this.IsPC() ) return
// #endif
if (this.readonly || this.disabled || !this.touchable) return
const {
clientX,
screenX
} = e.changedTouches[0]
this._getRateCount(clientX || screenX)
},
/**
* 兼容 PC @tian
*/
mousedown(e) {
// #ifdef H5
if( !this.IsPC() ) return
if (this.readonly || this.disabled) return
const {
clientX,
} = e
this.userLastRate = this.valueSync
this._getRateCount(clientX)
this.userRated = true
// #endif
},
mousemove(e) {
// #ifdef H5
if( !this.IsPC() ) return
if( this.userRated ) return
if( this.userMouseFristMove ) {
console.log('---mousemove----', this.valueSync);
this.userLastRate = this.valueSync
this.userMouseFristMove = false
}
if (this.readonly || this.disabled || !this.touchable) return
const {
clientX,
} = e
this._getRateCount(clientX)
// #endif
},
mouseleave(e) {
// #ifdef H5
if( !this.IsPC() ) return
if (this.readonly || this.disabled || !this.touchable) return
if( this.userRated ) {
this.userRated = false
return
}
this.valueSync = this.userLastRate
// #endif
},
// #ifdef H5
IsPC() {
var userAgentInfo = navigator.userAgent;
var Agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"];
var flag = true;
for (let v = 0; v < Agents.length - 1; v++) {
if (userAgentInfo.indexOf(Agents[v]) > 0) {
flag = false;
break;
}
}
return flag;
},
// #endif
/**
* 获取星星个数
*/
_getRateCount(clientX) {
this._getSize()
const size = Number(this.size)
if(size === NaN){
return new Error('size 属性只能设置为数字')
}
const rateMoveRange = clientX - this._rateBoxLeft
let index = parseInt(rateMoveRange / (size + this.marginNumber))
index = index < 0 ? 0 : index;
index = index > this.max ? this.max : index;
const range = parseInt(rateMoveRange - (size + this.marginNumber) * index);
let value = 0;
if (this._oldValue === index && !this.PC) return;
this._oldValue = index;
if (this.allowHalf) {
if (range > (size / 2)) {
value = index + 1
} else {
value = index + 0.5
}
} else {
value = index + 1
}
value = Math.max(0.5, Math.min(value, this.max))
this.valueSync = value
this._onChange()
},
/**
* 触发动态修改
*/
_onChange() {
this.$emit("input", this.valueSync);
this.$emit("update:modelValue", this.valueSync);
this.$emit("change", {
value: this.valueSync
});
},
/**
* 获取星星距离屏幕左侧距离
*/
_getSize() {
// #ifndef APP-NVUE
uni.createSelectorQuery()
.in(this)
.select('.uni-rate')
.boundingClientRect()
.exec(ret => {
if (ret) {
this._rateBoxLeft = ret[0].left
}
})
// #endif
// #ifdef APP-NVUE
dom.getComponentRect(this.$refs['uni-rate'], (ret) => {
const size = ret.size
if (size) {
this._rateBoxLeft = size.left
}
})
// #endif
}
}
};
</script>
<style
lang="scss"
scoped
>
.uni-rate {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
line-height: 1;
font-size: 0;
flex-direction: row;
/* #ifdef H5 */
cursor: pointer;
/* #endif */
}
.uni-rate__icon {
position: relative;
line-height: 1;
font-size: 0;
}
.uni-rate__icon-on {
overflow: hidden;
position: absolute;
top: 0;
left: 0;
line-height: 1;
text-align: left;
}
.uni-cursor-not-allowed {
/* #ifdef H5 */
cursor: not-allowed !important;
/* #endif */
}
</style>

View File

@@ -0,0 +1,87 @@
{
"id": "uni-rate",
"displayName": "uni-rate 评分",
"version": "1.2.2",
"description": "Rate 评分组件,可自定义评分星星图标的大小、间隔、评分数。",
"keywords": [
"uni-ui",
"uniui",
"评分"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
},
"uni_modules": {
"dependencies": [
"uni-icons"
],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "u"
}
}
}
}
}

View File

@@ -0,0 +1,107 @@
## Rate 评分
> **组件名uni-rate**
> 代码块: `uRate`
> 关联组件:`uni-icons`
评分组件,多用于购买商品后,对商品进行评价等场景
> **注意事项**
> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的使用说明,可以帮你避免一些错误。
> - 暂时不支持零星选择
> - 当前版本暂不支持修改图标,后续版本会继续优化
> - 绑定值推荐使用 `v-model` 的方式
> - 如需设置一个星星表示多分显示5个星星最高分10分。这种情况请在 change 事件监听中自行处理,获取到的值乘以你的基数就可以,默认组件是一星一分
### 安装方式
本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`
如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
## 基本用法
```html
<!-- 基本用法 -->
<!-- 需要在 script 中绑定 value 变量 -->
<uni-rate v-model="value" @change="onChange"/>
<!-- 不支持滑动手势选择评分 -->
<uni-rate :touchable="false" :value="5"/>
<!-- 设置尺寸大小 -->
<uni-rate :size="18" :value="5"/>
<!-- 设置评分数 -->
<uni-rate :max="10" :value="5" />
<!-- 设置星星间隔 -->
<uni-rate :value="4" :margin="20" />
<!-- 设置颜色 -->
<uni-rate :value="3" color="#bbb" active-color="red" />
<!-- 选择半星 -->
<uni-rate allow-half :value="3.5" />
<!-- 只读状态 -->
<uni-rate :readonly="true" :value="2" />
<!-- 禁用状态 -->
<uni-rate :disabled="true" disabledColor="#ccc" :value="3" />
<!-- 未选中的星星为镂空状态 -->
<uni-rate :value="3" :is-fill="false" />
```
```javascript
export default {
components: {},
data() {
return {
value: 2
}
},
methods: {
onChange(e) {
console.log('rate发生改变:' + JSON.stringify(e))
}
}
}
```
## API
### Rate Props
属性名 | 类型 | 默认值 | 说明
:-: | :-: | :-: | :-:
value/v-model | Number | 0 | 当前评分
color | String | #ececec | 未选中状态的星星颜色
activeColor | String | #ffca3e | 选中状态的星星颜色
disabledColor | String | #c0c0c0 | 禁用状态的星星颜色
size | Number | 24 | 星星的大小
max | Number | 5 | 最大评分评分数量,目前一分一颗星
margin | Number | 0 | 星星的间距,单位 px
isFill | Boolean | true | 星星的类型,是否为实心类型
disabled | Boolean | false | 是否为禁用状态 (之前版本为已读状态,现更正为禁用状态)
readonly | Boolean | false | 是否为只读状态
allowHalf | Boolean | false | 是否展示半星
touchable | Boolean | true | 是否支持滑动手势
### Rate Events
事件称名 | 说明 | 返回参数
:-: | :-: | :-:
@change | 改变 value 的值返回 | e = { value:number }
## 组件示例
点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/rate/rate](https://hellouniapp.dcloud.net.cn/pages/extUI/rate/rate)