mall-app-t/uni_modules/uni-row/components/uni-col/uni-col.vue

318 lines
7.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<!-- #ifndef APP-NVUE -->
<view :class="['uni-col', sizeClass, pointClassList]" :style="{
paddingLeft:`${Number(gutter)}rpx`,
paddingRight:`${Number(gutter)}rpx`,
}">
<slot></slot>
</view>
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
<!-- 在nvue上类名样式不生效换为style -->
<!-- 设置right正值失效设置 left 负值 -->
<view :class="['uni-col']" :style="{
paddingLeft:`${Number(gutter)}rpx`,
paddingRight:`${Number(gutter)}rpx`,
width:`${nvueWidth}rpx`,
position:'relative',
marginLeft:`${marginLeft}rpx`,
left:`${right === 0 ? left : -right}rpx`
}">
<slot></slot>
</view>
<!-- #endif -->
</template>
<script>
/**
* Col 布局-列
* @description 搭配uni-row使用构建布局。
* @tutorial https://ext.dcloud.net.cn/plugin?id=3958
*
* @property {span} type = Number 栅格占据的列数
* 默认 24
* @property {offset} type = Number 栅格左侧的间隔格数
* @property {push} type = Number 栅格向右移动格数
* @property {pull} type = Number 栅格向左移动格数
* @property {xs} type = [Number, Object] <768px 响应式栅格数或者栅格属性对象
* @description Number时表示在此屏幕宽度下栅格占据的列数。Object时可配置多个描述{span: 4, offset: 4}
* @property {sm} type = [Number, Object] ≥768px 响应式栅格数或者栅格属性对象
* @description Number时表示在此屏幕宽度下栅格占据的列数。Object时可配置多个描述{span: 4, offset: 4}
* @property {md} type = [Number, Object] ≥992px 响应式栅格数或者栅格属性对象
* @description Number时表示在此屏幕宽度下栅格占据的列数。Object时可配置多个描述{span: 4, offset: 4}
* @property {lg} type = [Number, Object] ≥1200px 响应式栅格数或者栅格属性对象
* @description Number时表示在此屏幕宽度下栅格占据的列数。Object时可配置多个描述{span: 4, offset: 4}
* @property {xl} type = [Number, Object] ≥1920px 响应式栅格数或者栅格属性对象
* @description Number时表示在此屏幕宽度下栅格占据的列数。Object时可配置多个描述{span: 4, offset: 4}
*/
const ComponentClass = 'uni-col';
// -1 默认值因为在微信小程序端只给Number会有默认值0
export default {
name: 'uniCol',
// #ifdef MP-WEIXIN
options: {
virtualHost: true // 在微信小程序中将组件节点渲染为虚拟节点更加接近Vue组件的表现
},
// #endif
props: {
span: {
type: Number,
default: 24
},
offset: {
type: Number,
default: -1
},
pull: {
type: Number,
default: -1
},
push: {
type: Number,
default: -1
},
xs: [Number, Object],
sm: [Number, Object],
md: [Number, Object],
lg: [Number, Object],
xl: [Number, Object]
},
data() {
return {
gutter: 0,
sizeClass: '',
parentWidth: 0,
nvueWidth: 0,
marginLeft: 0,
right: 0,
left: 0
}
},
created() {
// 字节小程序中在computed中读取$parent为undefined
let parent = this.$parent;
while (parent && parent.$options.componentName !== 'uniRow') {
parent = parent.$parent;
}
this.updateGutter(parent.gutter)
parent.$watch('gutter', (gutter) => {
this.updateGutter(gutter)
})
// #ifdef APP-NVUE
this.updateNvueWidth(parent.width)
parent.$watch('width', (width) => {
this.updateNvueWidth(width)
})
// #endif
},
computed: {
sizeList() {
let {
span,
offset,
pull,
push
} = this;
return {
span,
offset,
pull,
push
}
},
// #ifndef APP-NVUE
pointClassList() {
let classList = [];
['xs', 'sm', 'md', 'lg', 'xl'].forEach(point => {
const props = this[point];
if (typeof props === 'number') {
classList.push(`${ComponentClass}-${point}-${props}`)
} else if (typeof props === 'object' && props) {
Object.keys(props).forEach(pointProp => {
classList.push(
pointProp === 'span' ?
`${ComponentClass}-${point}-${props[pointProp]}` :
`${ComponentClass}-${point}-${pointProp}-${props[pointProp]}`
)
})
}
});
// 支付宝小程序使用 :class=[ ['a','b'] ],渲染错误
return classList.join(' ');
}
// #endif
},
methods: {
updateGutter(parentGutter) {
parentGutter = Number(parentGutter);
if (!isNaN(parentGutter)) {
this.gutter = parentGutter / 2
}
},
// #ifdef APP-NVUE
updateNvueWidth(width) {
// 用于在nvue端spanoffsetpullpush的计算
this.parentWidth = width;
['span', 'offset', 'pull', 'push'].forEach(size => {
const curSize = this[size];
if ((curSize || curSize === 0) && curSize !== -1) {
let RPX = 1 / 24 * curSize * width
RPX = Number(RPX);
switch (size) {
case 'span':
this.nvueWidth = RPX
break;
case 'offset':
this.marginLeft = RPX
break;
case 'pull':
this.right = RPX
break;
case 'push':
this.left = RPX
break;
}
}
});
}
// #endif
},
watch: {
sizeList: {
immediate: true,
handler(newVal) {
// #ifndef APP-NVUE
let classList = [];
for (let size in newVal) {
const curSize = newVal[size];
if ((curSize || curSize === 0) && curSize !== -1) {
classList.push(
size === 'span' ?
`${ComponentClass}-${curSize}` :
`${ComponentClass}-${size}-${curSize}`
)
}
}
// 支付宝小程序使用 :class=[ ['a','b'] ],渲染错误
this.sizeClass = classList.join(' ');
// #endif
// #ifdef APP-NVUE
this.updateNvueWidth(this.parentWidth);
// #endif
}
}
}
}
</script>
<style lang='scss' scoped>
/* breakpoints */
$--sm: 768px !default;
$--md: 992px !default;
$--lg: 1200px !default;
$--xl: 1920px !default;
$breakpoints: ('xs' : (max-width: $--sm - 1),
'sm' : (min-width: $--sm),
'md' : (min-width: $--md),
'lg' : (min-width: $--lg),
'xl' : (min-width: $--xl));
$layout-namespace: ".uni-";
$col: $layout-namespace+"col";
@function getSize($size) {
/* TODO 1/24 * $size * 100 * 1%; 使用计算后的值,为了解决 vue3 控制台报错 */
@return 0.04166666666 * $size * 100 * 1%;
}
@mixin res($key, $map:$breakpoints) {
@if map-has-key($map, $key) {
@media screen and #{inspect(map-get($map,$key))} {
@content;
}
}
@else {
@warn "Undeinfed point: `#{$key}`";
}
}
/* #ifndef APP-NVUE */
#{$col} {
float: left;
box-sizing: border-box;
}
#{$col}-0 {
/* #ifdef APP-NVUE */
width: 0;
height: 0;
margin-top: 0;
margin-right: 0;
margin-bottom: 0;
margin-left: 0;
/* #endif */
/* #ifndef APP-NVUE */
display: none;
/* #endif */
}
@for $i from 0 through 24 {
#{$col}-#{$i} {
width: getSize($i);
}
#{$col}-offset-#{$i} {
margin-left: getSize($i);
}
#{$col}-pull-#{$i} {
position: relative;
right: getSize($i);
}
#{$col}-push-#{$i} {
position: relative;
left: getSize($i);
}
}
@each $point in map-keys($breakpoints) {
@include res($point) {
#{$col}-#{$point}-0 {
display: none;
}
@for $i from 0 through 24 {
#{$col}-#{$point}-#{$i} {
width: getSize($i);
}
#{$col}-#{$point}-offset-#{$i} {
margin-left: getSize($i);
}
#{$col}-#{$point}-pull-#{$i} {
position: relative;
right: getSize($i);
}
#{$col}-#{$point}-push-#{$i} {
position: relative;
left: getSize($i);
}
}
}
}
/* #endif */
</style>