vue3 ts uniapp基本组件封装、通用组件库myCompont、瀑布流组件、城市选择组件、自定义导航栏、自定义底部菜单组件等

gitee地址
uniapp插件地址

本人封装了一个vue3 ts的uniapp通用组件,欢迎大家使用有任何问题可以去Q交流也可以去gitee上提,共同学习,完全免费

myCompont 组件说明

组件目录

复制代码
m-button 按钮
m-checkbox 多选组件
m-city-selector 城市选择
m-code 验证码
m-countdown 定时获取验证码
m-downlist 搜索框
m-form 表单组件
m-form-item 表单项组件
m-icon icon组件
m-images 图片组件
m-list 数据列表
m-loading 加载中
m-login 快捷登录
m-navbar 自定义导航
m-number-box 数字输入框
m-picker 选择弹出
m-popup 弹出框
m-rating 评分
m-skeleton 骨架
m-swiper 轮播图 m-swiper-item
m-tabbar 自定义底部菜单
m-toast 消息提示
m-uploadimg 图片上传组件
m-video 视频显示组件
m-waterfall 瀑布流组件

组件使用

m-button

按钮组件

复制代码
showText: {
	type: Boolean, // 是否显示按钮文字 
	default: true
},
type:{
	type: String,
	default: "text"},
fontSize: {
	type: String,
	default: "24rpx"
},
openType: {
	type: String, //调用小程序原生使用
	default: ""
},
btnStyle: {
	type: Object, //按钮样式
	default: () => ({})
},
color: {
	type: String, //文字颜色
	default: "#fff"
},
text: {
	type: String, //文本内容
	default: '确定'
},
click: {
	type: Function, //点击事件
	default: null
}


<m-button openType="share" @click="share" type="botton" :title="``" :btnStyle="style1">
    <view class="flex flex-column align-center" style="margin-top: 6rpx;" @click="share">
        <view class="flex align-center justify-center">
            <text class="iconfont icon-share"></text>
        </view>
            <view class="foaim">
                分享
            </view>
    </view>
</m-button>

m-checkbox

复选按钮

复制代码
 * @param activeColor 选中的背景颜色
   * @param inactiveColor 未选中的背景颜色
   * @param iconColor 图标颜色
   * @param direction 选择框和文本的布局方向
   * @param size 选择框的大小
   * @param gap 选择框和文本的间距
   * @param activeValue 选中的值
   * @param inactiveValue 未选中的值
   
   
   modelValue: any
shape?: 'circle' | 'square' | 'round'
direction?: 'left' | 'right' | 'top' | 'bottom'
size?: number
/** 选中的背景颜色 */
activeColor?: string
/** 未选中的时候颜色 border颜色 */
inactiveColor?: string
/** 图标颜色*/
iconColor?: string
gap?: number
/**自定义选中值*/
activeValue?: any // ✅ 自定义选中值
/** 自定义未选中值*/
inactiveValue?: any // ✅ 自定义未选中值

<m-checkbox
  :size="20"
  shape="circle"
  direction="left"
  :activeColor="'#4199FF'"
  :inactiveColor="'#666666'"
  :iconColor="'#fff'"
  @onchange="onchange($event, index)"
  v-model="item.checked"
>
</m-checkbox>

m-city-selector

城市选择 城市选择插件,城市数据在city.ts中,可以自行更新,选择城市后给父组件返回选中城市数据。支持城市搜索

复制代码
详情 https://ext.dcloud.net.cn/plugin?id=24847

m-code

输入验证码

复制代码
 /**
 * 双向绑定的值
 */
modelValue?: string | number
/**
 * 验证码长度
 * @default 4
 */
length?: number
/**
 * 输入框边框颜色(选中时)
 * @default '#9666FF'
 */
borderColor?: string
/**
 * 文字颜色
 * @default '#333'
 */
textColor?: string
/**
 * 文字大小,单位 rpx
 * @default 36
 */
textSize?: number | string
/**
 * 每个格子的宽高,单位 rpx
 * @default 90
 */
size?: number | string

m-countdown

获取手机验证码倒计时

复制代码
duration


<m-countdown ref="countdownRef" 
  :duration="60"
  @click="getCode"
  @start="onStart"
  @end="onEnd"></m-countdown>
  
  onStart 开始
  getCode 点击 获取验证码
  onEnd 结束

m-downlist

复制代码
items: Record<string, any>[] 数据类型
selectedId?: string | number | null 选择中的
valueKey?: string  数据的KEY
labelKey?: string lbae key字段
multiple?: boolean 是否多选

<m-downlist style="width: 100%" v-model:selectedId="formData.merchant_category_id" @search="searchStore"
			:items="adminStoreClassData" valueKey="merchant_category_id"
labelKey="category_name"></m-downlist>

m-form

表单组件

复制代码
<m-form ref="formRef" :rules="rules" :labelStyle="labelStyle" :model="formData">
	<view class="detail">
		<view class="itms">
			<m-form-item label="收货人" prop="real_name">
				<input v-model="formData.real_name" placeholder="收货人"></input>
			</m-form-item>
		</view>
		<view class="itms">
			<m-form-item label="联系手机" prop="phone">
				<input v-model="formData.phone" placeholder="联系手机"></input>
			</m-form-item>
		</view>
		<view class="itms">
			<m-form-item label="所在地区" prop="province">
				<view class="flex justify-space w" @click="selectAddress">
					<!-- <input disabled v-model="formData.real_name" placeholder-style="color:#C8C8C8;" placeholder="请输入店铺名称" /> -->
					<view style="width:400rpx;">
						<view v-if="!formData.province">
							请选择地区
						</view>
						<view v-else>
							<text>
								{{formData.province}}
							</text>
							<text>
								{{formData.city}}
							</text>
							<text>
								{{formData.district}}
							</text>
						</view>
					</view>
					<m-images :url='mapicon' width="28rpx" height="34rpx"></m-images>
				</view>
				<view>

				</view>
			</m-form-item>
		</view>
		<view class="itms">
			<m-form-item label="详细地址" prop="address_name">
				<input v-model="formData.address_name" placeholder="请输入详细地址"></input>
			</m-form-item>
		</view>


	</view>
	<!-- 设为默认地址 -->
	<view class="flex align-center"
		style="margin-top:20rpx;gap:6rpx;background:#fff;height: 122rpx;padding-left:68rpx">
		<m-checkbox :size="14" direction="left" :activeColor="'#4199FF'" :inactiveColor="'#666666'"
			:iconColor="'#fff'" :gap="0" :activeValue="1" :inactiveValue="0" shape="circle"
			v-model="formData.is_default" />
		<text style="color:#4199FF;">设为默认地址</text>
	</view>
</m-form>

表单验证
// 表单验证
const rules = ref({
	real_name: [
		{ required: true, message: '请输入收货人', trigger: 'blur' },
	],
	phone: [
		{ required: true, message: '请输入手机号码', trigger: 'blur' },
		{
			pattern: /^1[3-9]\d{9}$/,
			message: '手机号格式不正确',
			trigger: 'blur'
		}
	],
	province: [
		{ required: true, message: '请选择地区', trigger: 'blur' },
	],
	address_name: [
		{ required: true, message: '请输入详细地址', trigger: 'blur' },
	]


})
获取验证结果
const valid = await formRef.value.validate()

if (!valid.valid) {
  return toastRef.value.show('请将数据填写完整')
}

m-icon

icon组件

复制代码
<m-icon
  :size="midButton && item.midButton ? midButtonSize : iconSize"
  :name="elIconPath(index)"
  img-mode="scaleToFill"
  :color="elColor(index)"
  :custom-prefix="item.customIcon ? 'custom-icon' : 'uicon'"
/>

m-images

图片显示组件

复制代码
// 图片链接
url: {
  type: String,
  required: true
},
// 图片裁剪、缩放模式
mode: {
  type: String as PropType<ModeType>,
  default: 'scaleToFill'
},
// 宽度
width: {
  type: [String, Number],
  default: '100%'
},
// 高度
height: {
  type: [String, Number],
  default: '100%'
},
// loading图片大小
loadingSize: {
  type: [String, Number],
  default: '60rpx'
},
// 圆角 角度
rounded:{
	  type: [Number,String],
	  default: 0
},
// 是否开启点击后查看大图
showLarge:{
	  type:Boolean,
	  default:false
},
// 查看大图的数组
currImage:{
	  type: Array,
	  default: ()=>[]
}

     <m-images :url="serachUrl" width="40rpx" height="40rpx" />

m-list

m-loading

加载状态

复制代码
  status?: LoadStatus    /**'loading' | 'nodata' | 'getall' | 'loaded' 加载中 暂无数据 加载更多 加载完成 */
 <m-loading v-if="loading!='loaded'"  :status="loading"></m-loading>

m-login

其他登录方式

复制代码
<view>
	<m-login></m-login>

自定义导航栏

复制代码
backColor: { type: String, default: '#000019' }, // 返回图标颜色
background: { type: String, default: '' }, // 导航栏背景色
isFixed: { type: Boolean, default: true }, // 是否固定顶部
borderBottom: { type: Boolean, default: true }, // 是否显示底部边框
isBack: { type: [Boolean, String], default: true }, // 是否显示返回按钮
height: { type: [String, Number], default: '' }, // 导航栏高度(非小程序平台)
backText: { type: String, default: '' }, // 返回按钮文字
backTextStyle: { type: Object, default: () => ({ color: '#606266' }) }, // 返回文字样式
title: { type: String, default: '' }, // 标题文本
titleWidth: { type: [String, Number], default: '250' }, // 标题宽度
titleColor: { type: String, default: '#606266' }, // 标题颜色
immersive: { type: Boolean, default: false }, // 是否沉浸式
titleBold: { type: Boolean, default: false }, // 标题是否加粗
titleSize: { type: [String, Number], default: 32 }, // 标题字号
customBack: { type: Function, default: null } // 自定义返回事件



  <m-navbar :title="title" :isBack="true" :background="backgroundNav">
  <view class="ssetflex justify-space" style="width: 94%">
    <JointSearch
      ref="joinREf"
      v-model="searchKeyword"
      @clear="clear"
      labelKey="keyword"
      :showType="false"
      :background="`#F9F9F9`"
      @confirm="confirmInput"
    />
  </view>
</m-navbar>

m-number-box

数字输入框

复制代码
 modelValue: { type: [Number, String], default: 1 },
min: { type: [Number, String], default: 1 },
max: { type: [Number, String], default: 100 },
step: { type: [Number, String], default: 1 },
disabled: { type: Boolean, default: false },
showMinus: { type: Boolean, default: true },
showPlus: { type: Boolean, default: true },


 <m-number-box style="height: 100%;" :showMinus="false" :showPlus="false" :max="spectData?spectData.stock:`1`" v-model="inputValue"></m-number-box>

m-picker

下拉选择数据

复制代码
 modelValue: boolean
columns: PickerItem[]
defaultValue?: (string | number)[]
labelKey?: string 
valueKey?: string

 <m-picker v-model="qyShowSelect" :columns="configPay.bankAccountType" 
 @change="qyPickerChange" labelKey="name" 
  valueKey="type"></m-picker>

m-popup

弹出层

复制代码
	// 显示隐藏
	/** 显示隐藏*/
modelValue: { type: Boolean, default: false },
showmark: { type: Boolean, default: true },
bacground: { type: String, default: '#fff' },
title: { type: String, default: '' },
fontSize: { type: Number, default: 26 },
fontWeight: { type: Boolean, default: true },
showClose: { type: Boolean, default: false },
lineHeight: { type: Number, default: 30 },
zIndex: { type: Number, default: 11 },
closeIndex: { type: Number, default: 0 },
showTitle:{ type: Boolean, default: true },
 /** 圆角: 可以传字符串统一四个角,也可以传对象分别控制 */
  borderRadius: {
    type: [String, Object] as PropType<RadiusType>,
    default: '20rpx'
  },
type: {
  type: String as PropType<Direction>,
  default: 'bottom',
},


 <m-popup :zIndex="22" v-model="showSelectSpec" :showClose="true">
   <SelectSpec :productDetail="productData" @changeSku="changeSku"></SelectSpec>
</m-popup>

m-rating

评分

复制代码
modelValue: { type: Number, default: 0 }, // 当前评分(可小数)
max: { type: Number, default: 5 },        // 总星数
color: { type: String, default: "#FF7300" }, // 实心颜色
emptyColor: { type: String, default: "#e1e1e1" }, // 空心颜色

<m-rating v-model="item.service_score" color="#FFF05D" :max="5" />

m-skeleton

复制代码
 <m-skeleton v-if="loading" :rows="5" width="300rpx" height="400rpx"></m-skeleton>

m-swiper

轮播图

复制代码
* 轮播图组件
 * 支持视频和图片轮播
 * 轮播切换时视频暂停,视频播放时轮播暂停,视频结束后轮播恢复


<m-swiper :url="swiperData" width="750rpx" height="600rpx" ></m-swiper>

m-tabbar

自定义底部导航

复制代码
// 非凸起按钮未激活的图标,可以是uView内置图标名或自定义扩展图标库的图标
    // 或者png图标的【绝对路径】,建议尺寸为80px * 80px
    // 如果是中间凸起的按钮,只能使用图片,且建议为120px * 120px的png图片
    iconPath: "home",
    // 激活(选中)的图标,同上
    selectedIconPath: "home-fill",
    // 显示的提示文字
    text: "首页",
    // 红色角标显示的数字,如果需要移除角标,配置此参数为0即可
    count: 2,
    // 如果配置此值为true,那么角标将会以红点的形式显示
    isDot: true,
    // 如果使用自定义扩展的图标库字体,需配置此值为true
    // 自定义字体图标库教程:https://www.uviewui.com/guide/customIcon.html
    customIcon: false,
    // 如果是凸起按钮项,需配置此值为true
    midButton: false,
    // 点击某一个item时,跳转的路径,此路径必须是pagees.json中tabBar字段中定义的路径
    pagePath: "", // 1.5.6新增,路径需要以"/"开头
	
	定义 tabbar 场景,我们不建议在一个页面内通过几个组件,用v-if切换去模拟各个页面,而应该使用 uni-app 自带的 tabbar 系统,同时隐藏原生的 tabbar, 再引入自定导航栏,这样可以保证原有性能,同时又能自定义 tabbar,思路如下:
	
	在 pages.json 中正常定义 tabbar 逻辑和字段,只需配置tabBar字段list中的pagePath(需以"/"开头)属性即可
	在各个 tabbar 页面引入u-tabbar组件,组件会默认自动通过uni.hideTabBar()隐藏系统 tabbar
	通过vuex引用同一份 tabbar 组件的list参数,这样可以做到修改某一个页面的u-tabbar数据,其他页面的u-tabbar也能同步更新
	组件内部会自动处理各种跳转的逻辑,同时需要注意以下两点:
	要在list参数中配置pagePath路径,此路径为pages.json中定义的 tabbar 字段的路径
	此种方式,无需通过v-model绑定活动项,内部会自动进行判断和跳转
	
	代码
	let list = [
	  {
	    // 非凸起按钮未激活的图标,可以是uView内置图标名或自定义扩展图标库的图标
	    // 或者png图标的【绝对路径】,建议尺寸为80px * 80px
	    // 如果是中间凸起的按钮,只能使用图片,且建议为120px * 120px的png图片
	    iconPath: "home",
	    // 激活(选中)的图标,同上
	    selectedIconPath: "home-fill",
	    // 显示的提示文字
	    text: "首页",
	    // 红色角标显示的数字,如果需要移除角标,配置此参数为0即可
	    count: 2,
	    // 如果配置此值为true,那么角标将会以红点的形式显示
	    isDot: true,
	    // 如果使用自定义扩展的图标库字体,需配置此值为true
	    // 自定义字体图标库教程:https://www.uviewui.com/guide/customIcon.html
	    customIcon: false,
	    // 如果是凸起按钮项,需配置此值为true
	    midButton: false,
	    // 点击某一个item时,跳转的路径,此路径必须是pagees.json中tabBar字段中定义的路径
	    pagePath: "", // 1.5.6新增,路径需要以"/"开头
	  },
	];
	
	# 代码
	
	 <view>
	    <view class="u-page">
	      <!-- 所有内容的容器 -->
	    </view>
	    <!-- 与包裹页面所有内容的元素u-page同级,且在它的下方 -->
	    <u-tabbar v-model="current" :list="list" :mid-button="true"></u-tabbar>
	  </view>
	</template>
	
	<script>
	  export default {
	    data() {
	      return {
	        list: [
	          {
	            iconPath: "home",
	            selectedIconPath: "home-fill",
	            text: "首页",
	            count: 2,
	            isDot: true,
	            customIcon: false,
	          },
	          {
	            iconPath: "photo",
	            selectedIconPath: "photo-fill",
	            text: "放映厅",
	            customIcon: false,
	          },
	          {
	            iconPath: "https://cdn.uviewui.com/uview/common/min_button.png",
	            selectedIconPath: "https://cdn.uviewui.com/uview/common/min_button_select.png",
	            text: "发布",
	            midButton: true,
	            customIcon: false,
	          },
	          {
	            iconPath: "play-right",
	            selectedIconPath: "play-right-fill",
	            text: "直播",
	            customIcon: false,
	          },
	          {
	            iconPath: "account",
	            selectedIconPath: "account-fill",
	            text: "我的",
	            count: 23,
	            isDot: false,
	            customIcon: false,
	          },
	        ],
	        current: 0,
	      };
	    },
	  };

m-toast

消息提示

复制代码
      <m-toast ref="toastREf"></m-toast>
	  
	  const toastREf = ref<InstanceType<typeof MToast> | null>(null);
	    toastREf.value?.show("删除成功");

m-uploadimg

图片上传组件

复制代码
<m-uploadimg v-model="formData.licenceUrl" :defaultImage="businessUrl" :imgWidth="552"
  @defaultClick="defaultClickbase(1)" :imgHeight="396">
  <template #default="{ index, src }">
    <view @click.stop="upYbFile(1)" v-if="!formData.licenceUrl" class="addImgUp">
      点击上传
    </view>
  </template>
</m-uploadimg>

// 默认显示的营业执照
const businessUrl = ref(
  staticUrl + "/tx_user_sever_img/createStore/zhizhoa.png"
);
const defaultClickbase = (num:number) => {
 upYbFile(num)
};

m-watrfall

瀑布流组件

复制代码
 * @param value  瀑布流数据
 * @param addTime 插入数据的时间间隔
 * @param keyIdData / id值,用于清除某一条数据时,根据此idKey名称找到并移除

<m-waterfall :value="product" ref="commproduct">
	<!-- 左边数据 -->
	<template v-slot:left="{leftList}">
		<view @click="goodsDetail(item)" class="prodecutitem" v-for="(item,index) in leftList" :key="item.goodsId" >
			<view style="width: 100%;">
				<m-imgage  mode="widthFix" :url="statusUrl+item.showImage"></m-imgage>
			</view>
			<view class="textDertail">
				<view class="title">{{item.name}}</view>
				<!-- <view class="desc">{{item.title}}</view> -->
				<view class="descList">
					<text class="tej" v-for="(citem,cindex) in item.labelName.split(',')" :key="citem">{{citem}}</text>
					<!-- <text class="tej">特价</text>
					<text class="te24">24H发货</text> -->
				</view>
				<view class="numb1">
					<text class="fh">¥</text><text class="pay">{{item[leveKey]}}</text>/元
				</view>
				<view class="numb2">
					原价¥{{item.originalPrice}}/元
				</view>
			</view>
		</view>
	</template>
	<!-- 右边数据 -->
	<template v-slot:right="{rightList}">
		<view class="prodecutitem" v-for="(item,index) in rightList" :key="item.goodsId" @click="goodsDetail(item)">
			<view>
				<m-imgage  :url="statusUrl+item.showImage" mode="widthFix"></m-imgage>
			</view>
			<view class="textDertail">
				<view class="title">{{item.name}}</view>
				<!-- <view class="desc">{{item.title}}</view> -->
				<view class="descList" v-if="item.labelName">
					<text class="tej" v-for="(citem,cindex) in item.labelName.split(',')" :key="citem">{{citem}}</text>
					<!-- <text class="te24">24H发货</text> -->
				</view>
				<view class="numb1">
					<text class="fh">¥</text><text class="pay">{{item[leveKey]}}</text>/元
				</view>
				<view class="numb2">
					原价¥{{item.originalPrice}}/元
				</view>
			</view>
		</view>
	</template>
</m-waterfall>
相关推荐
不爱说话郭德纲4 小时前
告别漫长的HbuilderX云打包排队!uni-app x 安卓本地打包保姆级教程(附白屏、包体积过大排坑指南)
android·前端·uni-app
jonjia5 小时前
模块、脚本与声明文件
typescript
jonjia5 小时前
配置 TypeScript
typescript
jonjia5 小时前
TypeScript 工具函数开发
typescript
jonjia5 小时前
注解与断言
typescript
jonjia5 小时前
IDE 超能力
typescript
jonjia5 小时前
对象类型
typescript
jonjia5 小时前
快速搭建 TypeScript 开发环境
typescript
jonjia5 小时前
TypeScript 的奇怪之处
typescript
jonjia5 小时前
类型派生
typescript