You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
317 lines
7.5 KiB
317 lines
7.5 KiB
<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端,span,offset,pull,push的计算 |
|
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' > |
|
/* 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>
|
|
|