318 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
		
		
			
		
	
	
			318 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
|  | <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' 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> |