This commit is contained in:
hupeng
2023-10-11 11:27:47 +08:00
commit d0b337c596
659 changed files with 67106 additions and 0 deletions

View File

@ -0,0 +1,15 @@
export default {
props: {
// 宫格的name
name: {
type: [String, Number, null],
default: null
},
// 背景颜色
bgColor: {
type: String,
default: 'transparent'
},
...uni.$uv?.props?.gridItem
}
}

View File

@ -0,0 +1,218 @@
<template>
<!-- #ifndef APP-NVUE -->
<view
class="uv-grid-item"
hover-class="uv-grid-item--hover-class"
:hover-stay-time="200"
@tap="clickHandler"
:class="classes"
:style="[itemStyle]"
>
<slot />
</view>
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
<view
class="uv-grid-item"
:hover-stay-time="200"
@tap="clickHandler"
:class="classes"
:style="[itemStyle]"
>
<slot />
</view>
<!-- #endif -->
</template>
<script>
import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
import props from './props.js';
/**
* gridItem 提示
* @description 宫格组件一般用于同时展示多个同类项目的场景,可以给宫格的项目设置徽标组件(badge)或者图标等也可以扩展为左右滑动的轮播形式。搭配uv-grid使用
* @tutorial https://www.uvui.cn/components/grid.html
* @property {String | Number} name 宫格的name ( 默认 null )
* @property {String} bgColor 宫格的背景颜色 (默认 'transparent'
* @property {Object} customStyle 自定义样式,对象形式
* @event {Function} click 点击宫格触发
* @example <uv-grid-item></uv-grid-item>
*/
export default {
name: "uv-grid-item",
mixins: [mpMixin, mixin, props],
emits: ['$uvGridItem','click'],
data() {
return {
parentData: {
col: 3, // 父组件划分的宫格数
border: true, // 是否显示边框,根据父组件决定
},
// #ifdef APP-NVUE
width: 0, // nvue下才这么计算vue下放到computed中否则会因为延时造成闪烁
// #endif
classes: [], // 类名集合,用于判断是否显示右边和下边框
};
},
created() {
// 父组件的实例
this.updateParentData()
},
mounted() {
this.init()
},
computed: {
// #ifndef APP-NVUE
// vue下放到computed中否则会因为延时造成闪烁
width() {
return 100 / Number(this.parentData.col) + '%'
},
// #endif
itemStyle() {
const style = {
background: this.bgColor,
width: this.width
}
return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle))
}
},
methods: {
init() {
// 用于在父组件uv-grid的children中被添加入子组件时
// 重新计算item的边框
uni.$on('$uvGridItem', () => {
this.gridItemClasses()
})
// #ifdef APP-NVUE
// 获取元素该有的长度nvue下要延时才准确
this.$nextTick(function(){
this.getItemWidth()
})
// #endif
// 发出事件通知所有的grid-item都重新计算自己的边框
uni.$emit('$uvGridItem')
this.gridItemClasses()
},
// 获取父组件的参数
updateParentData() {
// 此方法写在mixin中
this.getParentData('uv-grid');
},
clickHandler() {
let name = this.name
// 如果没有设置name属性历遍父组件的children数组判断当前的元素是否和本实例this相等找出当前组件的索引
const children = this.parent?.children
if(children && this.name === null) {
name = children.findIndex(child => child === this)
}
// 调用父组件方法,发出事件
this.parent && this.parent.childClick(name)
this.$emit('click', name)
},
async getItemWidth() {
// 如果是nvue不能使用百分比只能使用固定宽度
let width = 0
if(this.parent) {
// 获取父组件宽度后除以栅格数得出每个item的宽度
const parentWidth = await this.getParentWidth()
width = parentWidth / Number(this.parentData.col) + 'px'
}
this.width = width
},
// 获取父元素的尺寸
getParentWidth() {
// #ifdef APP-NVUE
// 返回一个promise让调用者可以用await同步获取
const dom = uni.requireNativePlugin('dom')
return new Promise(resolve => {
// 调用父组件的ref
dom.getComponentRect(this.parent.$refs['uv-grid'], res => {
resolve(res.size.width)
})
})
// #endif
},
gridItemClasses() {
if(this.parentData.border) {
let classes = []
this.parent.children.map((child, index) =>{
if(this === child) {
const len = this.parent.children.length
// 贴近右边屏幕边沿的child并且最后一个比如只有横向2个的时候无需右边框
if((index + 1) % this.parentData.col !== 0 && index + 1 !== len) {
classes.push('uv-border-right')
}
// 总的宫格数量对列数取余的值
// 如果取余后值为0则意味着要将最后一排的宫格都不需要下边框
const lessNum = len % this.parentData.col === 0 ? this.parentData.col : len % this.parentData.col
// 最下面的一排child无需下边框
if(index < len - lessNum) {
classes.push('uv-border-bottom')
}
}
})
// 支付宝,头条小程序无法动态绑定一个数组类名,否则解析出来的结果会带有",",而导致失效
// #ifdef MP-ALIPAY || MP-TOUTIAO
classes = classes.join(' ')
// #endif
this.classes = classes
}
}
},
beforeDestroy() {
// 移除事件监听,释放性能
uni.$off('$uvGridItem')
}
};
</script>
<style lang="scss" scoped>
$show-border: 1;
$show-border-right: 1;
$show-border-bottom: 1;
@import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
@import '@/uni_modules/uv-ui-tools/libs/css/color.scss';
$uv-grid-item-hover-class-opcatiy:.5 !default;
$uv-grid-item-margin-top:1rpx !default;
$uv-grid-item-border-right-width:0.5px !default;
$uv-grid-item-border-bottom-width:0.5px !default;
$uv-grid-item-border-right-color:$uv-border-color !default;
$uv-grid-item-border-bottom-color:$uv-border-color !default;
.uv-grid-item {
align-items: center;
justify-content: center;
position: relative;
flex-direction: column;
/* #ifndef APP-NVUE */
box-sizing: border-box;
display: flex;
/* #endif */
/* #ifdef MP */
position: relative;
float: left;
/* #endif */
/* #ifdef MP-WEIXIN */
margin-top:$uv-grid-item-margin-top;
/* #endif */
&--hover-class {
opacity:$uv-grid-item-hover-class-opcatiy;
}
}
/* #ifdef APP-NVUE */
// 由于nvue不支持组件内引入app.vue中再引入的样式所以需要写在这里
.uv-border-right {
border-right-width:$uv-grid-item-border-right-width;
border-color: $uv-grid-item-border-right-color;
}
.uv-border-bottom {
border-bottom-width:$uv-grid-item-border-bottom-width;
border-color:$uv-grid-item-border-bottom-color;
}
/* #endif */
</style>

View File

@ -0,0 +1,20 @@
export default {
props: {
// 分成几列
col: {
type: [String, Number],
default: 3
},
// 是否显示边框
border: {
type: Boolean,
default: false
},
// 宫格对齐方式,表现为数量少的时候,靠左,居中,还是靠右
align: {
type: String,
default: 'left'
},
...uni.$uv?.props?.grid
}
}

View File

@ -0,0 +1,100 @@
<template>
<view
class="uv-grid"
ref='uv-grid'
:style="[gridStyle]"
>
<slot />
</view>
</template>
<script>
import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
import props from './props.js';
/**
* grid 宫格布局
* @description 宫格组件一般用于同时展示多个同类项目的场景,可以给宫格的项目设置徽标组件(badge),或者图标等,也可以扩展为左右滑动的轮播形式。
* @tutorial https://www.uvui.cn/components/grid.html
* @property {String | Number} col 宫格的列数(默认 3
* @property {Boolean} border 是否显示宫格的边框(默认 false
* @property {String} align 宫格对齐方式,表现为数量少的时候,靠左,居中,还是靠右 (默认 'left'
* @property {Object} customStyle 定义需要用到的外部样式
* @event {Function} click 点击宫格触发
* @example <uv-grid :col="3" @click="click"></uv-grid>
*/
export default {
name: 'uv-grid',
mixins: [mpMixin, mixin, props],
emits: ['click'],
data() {
return {
index: 0,
width: 0
}
},
watch: {
// 当父组件需要子组件需要共享的参数发生了变化,手动通知子组件
parentData() {
if (this.children.length) {
this.children.map(child => {
// 判断子组件(uv-radio)如果有updateParentData方法的话就就执行(执行的结果是子组件重新从父组件拉取了最新的值)
typeof(child.updateParentData) == 'function' && child.updateParentData();
})
}
},
},
created() {
// 如果将children定义在data中在微信小程序会造成循环引用而报错
this.children = []
},
computed: {
// 计算父组件的值是否发生变化
parentData() {
return [this.hoverClass, this.col, this.size, this.border];
},
// 宫格对齐方式
gridStyle() {
let style = {};
switch (this.align) {
case 'left':
style.justifyContent = 'flex-start';
break;
case 'center':
style.justifyContent = 'center';
break;
case 'right':
style.justifyContent = 'flex-end';
break;
default:
style.justifyContent = 'flex-start';
};
return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle));
}
},
methods: {
// 此方法由uv-grid-item触发用于在uv-grid发出事件
childClick(name) {
this.$emit('click', name)
}
}
};
</script>
<style lang="scss" scoped>
@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
$uv-grid-width:100% !default;
.uv-grid {
/* #ifdef MP */
width: $uv-grid-width;
position: relative;
box-sizing: border-box;
overflow: hidden;
display: block;
/* #endif */
justify-content: center;
@include flex;
flex-wrap: wrap;
align-items: center;
}
</style>