UniApp低代码-颜色选择器diy-color-picker-代码生成器

颜色选择器组件是一种用户界面元素,用于在用户界面中选择一个颜色。它广泛应用于网页设计、图形处理和创意软件中,允许用户以直观的方式从调色板中选择颜色。在不同的前端框架和库中,颜色选择器组件的实现可能有所不同,但它们的基本功能和目的是相同的。UniApp低代码-颜色选择器diy-color-picker-代码生成器兼容微信小程序、APP、H5。

 

  • 颜色选择器组件的功能

    • 颜色选择:颜色选择器组件通常提供一个可视化的颜色盘或颜色网格,用户可以从中选择颜色。这些颜色通常按照色彩空间(如RGB、HSV或HEX)进行组织。
    • 格式转换:组件支持不同的颜色格式,如HEX、RGB、HSL等,并能在这些格式之间进行转换。例如,当用户选择一个颜色时,颜色选择器可以显示其在不同格式下的值。
    • 透明度选择:一些颜色选择器还支持透明度的选择,允许用户调整颜色的alpha通道,这对于需要处理图像蒙层或颜色叠加的场景非常有用。
    • 颜色预览:在选择颜色时,颜色选择器通常提供即时预览,让用户看到所选颜色的效果,确保选择的准确性和满意度。
    • 预定义颜色:许多颜色选择器组件允许用户或开发人员设置预定义颜色,这些颜色可以根据特定的设计系统或品牌指南进行配置。
  • 颜色选择器的技术实现

    • 基于HTML5的颜色选择器:现代浏览器提供了原生的颜色选择器控件,可以通过HTML5的<input type="color">标签直接使用。这种颜色选择器简单易用,但样式和功能较为基础。
    • 基于JavaScript的颜色选择器:通过JavaScript和CSS,可以实现更复杂、定制化程度更高的颜色选择器。这些颜色选择器可以集成到现有的Web应用程序中,提供丰富的交互和配置选项。
    • 基于Vue的颜色选择器:在Vue等现代前端框架中,颜色选择器可以作为可重用的组件实现。例如,Ant Design、Vuetify、Element UI、Quasar等UI库提供了ColorPicker组件,这些组件可以轻松集成到Vue项目中。
  • 颜色选择器的应用场景

    • 网页设计:在网页设计工具中使用颜色选择器来设置背景色、字体色、边框色等,帮助设计师精确控制页面元素的视觉效果。兼容微信小程序、APP、H5
    • 用户界面设计:在设计用户界面时,颜色选择器用于设置控件的颜色、图标颜色等,确保界面美观且符合设计规范。
  • 颜色选择器的优势与挑战

    • 优势:颜色选择器提供了一种直观、便捷的颜色选择方式,大大减少了手动输入颜色代码的麻烦。兼容微信小程序、APP、H5
    • 挑战:尽管颜色选择器方便了颜色的选择和管理,但在不同设备和屏幕之间保持颜色的一致性仍然是一个挑战。此外,满足专业用户对颜色精度和灵活性的高级需求也需不断优化和更新。
  • diy-color-picker组件库实现

diy-color-picker兼容微信小程序、APP、H5

<template>
	<view v-show="show" class="t-wrapper" @touchmove.stop.prevent="moveHandle">
		<view class="t-mask active" :class="{active:active}" @click.stop="close"></view>
		<view class="t-box" :class="{active:active}">
			<view class="t-header">
				<view class="t-header-button" @click.stop="close">取消</view>
				<view class="t-header-button">{{hex}}</view>
				<view class="t-header-button" @click.stop="confirm">确认</view>
			</view>
			<view class="t-color__box" :style="{ background: 'rgb(' + bgcolor.r + ',' + bgcolor.g + ',' + bgcolor.b + ')'}">
				<view class="t-background boxs" @touchstart="touchstart($event, 0)" @touchmove="touchmove($event, 0)" @touchend="touchend($event, 0)">
					<view class="t-color-mask"></view>
					<view class="t-pointer" :style="{ top: site[0].top - 8 + 'px', left: site[0].left - 8 + 'px' }"></view>
				</view>
			</view>
			<view class="t-control__box">
				<view class="t-control__color">
					<view class="t-control__color-content" :style="{ background: 'rgba(' + rgba.r + ',' + rgba.g + ',' + rgba.b + ',' + rgba.a + ')' }"></view>
				</view>
				<view class="t-control-box__item">
					<view class="t-controller boxs" @touchstart="touchstart($event, 1)" @touchmove="touchmove($event, 1)" @touchend="touchend($event, 1)">
						<view class="t-hue">
							<view class="t-circle" :style="{ left: site[1].left - 12 + 'px' }"></view>
						</view>
					</view>
					<view class="t-controller boxs" @touchstart="touchstart($event, 2)" @touchmove="touchmove($event, 2)" @touchend="touchend($event, 2)">
						<view class="t-transparency">
							<view class="t-circle" :style="{ left: site[2].left - 12 + 'px' }"></view>
						</view>
					</view>
				</view>
			</view>
			<view class="t-alternative">
				<view class="t-alternative__item" v-for="(item,index) in colorList" :key="index">
					<view class="t-alternative__item-content" :style="{ background: 'rgba(' + item.r + ',' + item.g + ',' + item.b + ',' + item.a + ')' }" @click="selectColor(item)">
					</view>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
	import Emitter from "../../libs/util/emitter.js";
	
	export default {
		mixins: [Emitter],
		emits: ["update:modelValue", "change","confirm"],
		props: {
			value: {
				type: Boolean,
				default: false
			},
			modelValue: {
				type: Boolean,
				default: false
			},
			color: {
				type: Object,
				default: null
			},
			hexcolor: {
				type: String,
				default: ''
			},
			spareColor: {
				type: Array,
				default () {
					return []
				}
			}
		},
		computed: {
			valueCom() {
				// #ifndef VUE3
				return this.value;
				// #endif
		
				// #ifdef VUE3
				return this.modelValue;
				// #endif
			}
		},
	 
		mounted() {
			// 组件渲染完成时,检查value是否为true,如果是,弹出popup
			if(this.valueCom){
				this.open()
			}
		},
		data() {
			return {
				show: false,
				active: false,
				// rgba 颜色
				rgba: {
					r: 0,
					g: 0,
					b: 0,
					a: 1
				},
				// hsb 颜色
				hsb: {
					h: 0,
					s: 0,
					b: 0
				},
				site: [{
					top: 0,
					left: 0
				}, {
					left: 0
				}, {
					left: 0
				}],
				index: 0,
				bgcolor: {
					r: 255,
					g: 0,
					b: 0,
					a: 1
				},
				hex: '#000000',
				mode: true,
				colorList: [{
					r: 244,
					g: 67,
					b: 54,
					a: 1
				}, {
					r: 233,
					g: 30,
					b: 99,
					a: 1
				}, {
					r: 156,
					g: 39,
					b: 176,
					a: 1
				}, {
					r: 103,
					g: 58,
					b: 183,
					a: 1
				}, {
					r: 63,
					g: 81,
					b: 181,
					a: 1
				}, {
					r: 33,
					g: 150,
					b: 243,
					a: 1
				}, {
					r: 3,
					g: 169,
					b: 244,
					a: 1
				}, {
					r: 0,
					g: 188,
					b: 212,
					a: 1
				}, {
					r: 0,
					g: 150,
					b: 136,
					a: 1
				}, {
					r: 76,
					g: 175,
					b: 80,
					a: 1
				}, {
					r: 139,
					g: 195,
					b: 74,
					a: 1
				}, {
					r: 205,
					g: 220,
					b: 57,
					a: 1
				}, {
					r: 255,
					g: 235,
					b: 59,
					a: 1
				}, {
					r: 255,
					g: 193,
					b: 7,
					a: 1
				}, {
					r: 255,
					g: 152,
					b: 0,
					a: 1
				}, {
					r: 255,
					g: 87,
					b: 34,
					a: 1
				}, {
					r: 121,
					g: 85,
					b: 72,
					a: 1
				}, {
					r: 158,
					g: 158,
					b: 158,
					a: 1
				}, {
					r: 0,
					g: 0,
					b: 0,
					a: 0.5
				}, {
					r: 0,
					g: 0,
					b: 0,
					a: 0
				}, ]
			};
		},
		created() {
			// if(this.color){}
			// console.log(this.color);
			// this.rgba = this.color;
			if (this.spareColor.length !== 0) {
				this.colorList = this.spareColor;
			}
		},
		methods: {
			/**
			 * 初始化
			 */
			init() {
				// hsb 颜色
				if(this.color){
					this.rgba=this.color;
					this.hsb = this.rgbToHex(this.rgba);
				}else if(this.hexcolor){
					let hsb=this.hexcolor;//.replace('#','');
					let rgba=this.hexToRgba(hsb);
					this.rgba=rgba;
					this.hsb = hsb;
				}
				// this.setColor();
				this.setValue(this.rgba);
			},
			moveHandle() {},
			open() {
				this.show = true;
				this.$nextTick(() => {
					this.init();
					setTimeout(() => {
						this.active = true;
						setTimeout(() => {
							this.getSelectorQuery();
						}, 400)
					}, 5)
				})
			},
			close() {
				this.active = false;
				this.$nextTick(() => {
					setTimeout(() => {
						this.show = false;
						this.$emit("update:modelValue", false);
					}, 300)
				})
			},
			confirm() {
				this.close();
				this.$emit('confirm', {
					rgba: this.rgba,
					hex: this.hex
				})
			},
			// 选择模式
			select() {
				this.mode = !this.mode
			},
			// 常用颜色选择
			selectColor(item) {
				this.setColorBySelect(item)
			},
			//触摸开始事件
			touchstart(e, index) {
				const {
					pageX,
					pageY
				} = e.touches[0];
				this.pageX = pageX;
				this.pageY = pageY;
				this.setPosition(pageX, pageY, index);
			},
			//手指滑动过程
			touchmove(e, index) {
				const {
					pageX,
					pageY
				} = e.touches[0];
				this.moveX = pageX;
				this.moveY = pageY;
				this.setPosition(pageX, pageY, index);
			},
			//触摸结束事件
			touchend(e, index) {},
			/**
			 * 设置位置
			 */
			setPosition(x, y, index) {
				this.index = index;
				const {
					top,
					left,
					width,
					height
				} = this.position[index];
				// 设置最大最小值

				this.site[index].left = Math.max(0, Math.min(parseInt(x - left), width));
				if (index === 0) {
					this.site[index].top = Math.max(0, Math.min(parseInt(y - top), height));

					// 设置颜色
					this.hsb.s = parseInt((100 * this.site[index].left) / width);
					this.hsb.b = parseInt(100 - (100 * this.site[index].top) / height);
					this.setColor();
					this.setValue(this.rgba);
				} else {
					this.setControl(index, this.site[index].left);
				}
			},
			/**
			 * 设置 rgb 颜色
			 */
			setColor() {
				const rgb = this.HSBToRGB(this.hsb);
				this.rgba.r = rgb.r;
				this.rgba.g = rgb.g;
				this.rgba.b = rgb.b;
			},
			/**
			 * 设置二进制颜色
			 * @param {Object} rgb
			 */
			setValue(rgb) {
				this.hex = '#' + this.rgbToHex(rgb);
			},
			//设置透明度
			setControl(index, x) {
				const {
					top,
					left,
					width,
					height
				} = this.position[index];

				if (index === 1) {
					this.hsb.h = parseInt((360 * x) / width);
					this.bgcolor = this.HSBToRGB({
						h: this.hsb.h,
						s: 100,
						b: 100
					});
					this.setColor()
				} else {
					this.rgba.a = (x / width).toFixed(1);
				}
				this.setValue(this.rgba);
			},
			/**
			 * @param {Object} hex hex转RGB
			 */
			hexToRgba(hex) {
				// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
				let shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
				hex = hex.replace(shorthandRegex, function(m, r, g, b) {
					return r + r + g + g + b + b;
				});
				let result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i.exec(hex);
				return result ? {
					r: parseInt(result[1], 16),
					g: parseInt(result[2], 16),
					b: parseInt(result[3], 16),
					a: result[4] ? parseInt(result[4], 16) / 255 : 1,
				} : null;
			},
			/**
			 * rgb 转 二进制 hex
			 * @param {Object} rgb
			 */
			rgbToHex(rgb) {
				let hex = [rgb.r.toString(16), rgb.g.toString(16), rgb.b.toString(16)];
				hex.map(function(str, i) {
					if (str.length == 1) {
						hex[i] = '0' + str;
					}
				});
				return hex.join('');
			},
			setColorBySelect(getrgb) {
				const {
					r,
					g,
					b,
					a
				} = getrgb;
				let rgb = {}
				rgb = {
					r: r ? parseInt(r) : 0,
					g: g ? parseInt(g) : 0,
					b: b ? parseInt(b) : 0,
					a: a ? a : 0,
				};
				this.rgba = rgb;
				this.hsb = this.rgbToHsb(rgb);
				this.changeViewByHsb();
			},
			changeViewByHsb() {
				// console.log("changeViewByHsb");
				const [a, b, c] = this.position;
				this.site[0].left = parseInt(this.hsb.s * a.width / 100);
				this.site[0].top = parseInt((100 - this.hsb.b) * a.height / 100);
				this.setColor(this.hsb.h);
				this.setValue(this.rgba);
				this.bgcolor = this.HSBToRGB({
					h: this.hsb.h,
					s: 100,
					b: 100
				});

				this.site[1].left = this.hsb.h / 360 * b.width;
				this.site[2].left = this.rgba.a * c.width;

			},
			/**
			 * hsb 转 rgb
			 * @param {Object} 颜色模式  H(hues)表示色相,S(saturation)表示饱和度,B(brightness)表示亮度
			 */
			HSBToRGB(hsb) {

				let rgb = {};
				let h = Math.round(hsb.h);
				let s = Math.round((hsb.s * 255) / 100);
				let v = Math.round((hsb.b * 255) / 100);
				if (s == 0) {
					rgb.r = rgb.g = rgb.b = v;
				} else {
					let t1 = v;
					let t2 = ((255 - s) * v) / 255;
					let t3 = ((t1 - t2) * (h % 60)) / 60;
					if (h == 360) h = 0;
					if (h < 60) {
						rgb.r = t1;
						rgb.b = t2;
						rgb.g = t2 + t3;
					} else if (h < 120) {
						rgb.g = t1;
						rgb.b = t2;
						rgb.r = t1 - t3;
					} else if (h < 180) {
						rgb.g = t1;
						rgb.r = t2;
						rgb.b = t2 + t3;
					} else if (h < 240) {
						rgb.b = t1;
						rgb.r = t2;
						rgb.g = t1 - t3;
					} else if (h < 300) {
						rgb.b = t1;
						rgb.g = t2;
						rgb.r = t2 + t3;
					} else if (h < 360) {
						rgb.r = t1;
						rgb.g = t2;
						rgb.b = t1 - t3;
					} else {
						rgb.r = 0;
						rgb.g = 0;
						rgb.b = 0;
					}
				}
				return {
					r: Math.round(rgb.r),
					g: Math.round(rgb.g),
					b: Math.round(rgb.b)
				};
			},
			rgbToHsb(rgb) {
				let hsb = {
					h: 0,
					s: 0,
					b: 0
				};
				let min = Math.min(rgb.r, rgb.g, rgb.b);
				let max = Math.max(rgb.r, rgb.g, rgb.b);
				let delta = max - min;
				hsb.b = max;
				hsb.s = max != 0 ? 255 * delta / max : 0;
				if (hsb.s != 0) {
					if (rgb.r == max) hsb.h = (rgb.g - rgb.b) / delta;
					else if (rgb.g == max) hsb.h = 2 + (rgb.b - rgb.r) / delta;
					else hsb.h = 4 + (rgb.r - rgb.g) / delta;
				} else hsb.h = -1;
				hsb.h *= 60;
				if (hsb.h < 0) hsb.h = 0;
				hsb.s *= 100 / 255;
				hsb.b *= 100 / 255;
				return hsb;
			},
			getSelectorQuery() {
				const views = uni.createSelectorQuery().in(this);
				views
					.selectAll('.boxs')
					.boundingClientRect(data => {
						if (!data || data.length === 0) {
							setTimeout(() => this.getSelectorQuery(), 20)
							return
						}
						this.position = data;
						// this.site[0].top = data[0].height;
						// this.site[0].left = 0;
						// this.site[1].left = data[1].width;
						// this.site[2].left = data[2].width;
						this.setColorBySelect(this.rgba);
					})
					.exec();
			}
		},
		watch: {
			valueCom(val){
				if(val){
					this.open()
				}else{
					this.close()
				}
			},
			spareColor(newVal) {
				this.colorList = newVal;
			}
		}
	};
</script>

<style>
	.t-wrapper {
		position: fixed;
		top: 0;
		bottom: 0;
		left: 0;
		width: 100%;
		box-sizing: border-box;
		z-index: 999999;
	}

	.t-box {
		width: 100%;
		position: absolute;
		bottom: 0;
		padding: 30upx 0;
		padding-top: 0;
		background: #fff;
		transition: all 0.3s;
		transform: translateY(100%);
	}

	.t-box.active {
		transform: translateY(0%);
	}

	.t-header {
		display: flex;
		justify-content: space-between;
		width: 100%;
		height: 100upx;
		border-bottom: 1px #eee solid;
		box-shadow: 1px 0 2px rgba(0, 0, 0, 0.1);
		background: #fff;
	}

	.t-header-button {
		display: flex;
		align-items: center;
		width: 150upx;
		height: 100upx;
		font-size: 30upx;
		color: #666;
		padding-left: 20upx;
	}

	.t-header-button:last-child {
		justify-content: flex-end;
		padding-right: 20upx;
	}

	.t-mask {
		position: absolute;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		background: rgba(0, 0, 0, 0.6);
		z-index: -1;
		transition: all 0.3s;
		opacity: 0;
	}

	.t-mask.active {
		opacity: 1;
	}

	.t-color__box {
		position: relative;
		height: 400upx;
		background: rgb(255, 0, 0);
		overflow: hidden;
		box-sizing: border-box;
		margin: 0 20upx;
		margin-top: 20upx;
		box-sizing: border-box;
	}

	.t-background {
		position: absolute;
		z-index: 16777271;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		background: linear-gradient(to right, #fff, rgba(255, 255, 255, 0));
	}

	.t-color-mask {
		position: absolute;
		z-index: 16777271;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		width: 100%;
		height: 400upx;
		background: linear-gradient(to top, #000, rgba(0, 0, 0, 0));
	}

	.t-pointer {
		position: absolute;
		bottom: -8px;
		left: -8px;
		z-index: 2;
		width: 15px;
		height: 15px;
		border: 1px #eee solid;
		border-radius: 50%;
	}

	.t-show-color {
		width: 100upx;
		height: 50upx;
	}

	.t-control__box {
		margin-top: 50upx;
		width: 100%;
		display: flex;
		padding-left: 20upx;
		box-sizing: border-box;
	}

	.t-control__color {
		flex-shrink: 0;
		width: 100upx;
		height: 100upx;
		border-radius: 50%;
		background-color: #fff;
		background-image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee),
			linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee);
		background-size: 36upx 36upx;
		background-position: 0 0, 18upx 18upx;
		border: 1px #eee solid;
		overflow: hidden;
	}

	.t-control__color-content {
		width: 100%;
		height: 100%;
	}

	.t-control-box__item {
		display: flex;
		flex-direction: column;
		justify-content: space-between;
		width: 100%;
		padding: 0 30upx;
	}

	.t-controller {
		position: relative;
		z-index: 16777271;
		width: 100%;
		height: 16px;
		background-color: #fff;
		background-image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee),
			linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee);
		background-size: 32upx 32upx;
		background-position: 0 0, 16upx 16upx;
	}

	.t-hue {
		width: 100%;
		height: 100%;
		background: linear-gradient(to right, #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%);
	}

	.t-transparency {
		width: 100%;
		height: 100%;
		background: linear-gradient(to right, rgba(0, 0, 0, 0) 0%, rgb(0, 0, 0));
	}

	.t-circle {
		position: absolute;
		/* right: -10px; */
		top: -2px;
		width: 20px;
		height: 20px;
		box-sizing: border-box;
		border-radius: 50%;
		background: #fff;
		box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.1);
	}

	.t-result__box {
		margin-top: 20upx;
		padding: 10upx;
		width: 100%;
		display: flex;
		box-sizing: border-box;
	}

	.t-result__item {
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		padding: 10upx;
		width: 100%;
		box-sizing: border-box;
	}

	.t-result__box-input {
		padding: 10upx 0;
		width: 100%;
		font-size: 28upx;
		box-shadow: 0 0 1px 1px rgba(0, 0, 0, 0.1);
		color: #999;
		text-align: center;
		background: #fff;
	}

	.t-result__box-text {
		margin-top: 10upx;
		font-size: 28upx;
		line-height: 2;
	}

	.t-select {
		flex-shrink: 0;
		width: 150upx;
		padding: 0 30upx;
	}

	.t-select .t-result__box-input {
		border-radius: 10upx;
		border: none;
		color: #999;
		box-shadow: 1px 1px 2px 1px rgba(0, 0, 0, 0.1);
		background: #fff;
	}

	.t-select .t-result__box-input:active {
		box-shadow: 0px 0px 1px 0px rgba(0, 0, 0, 0.1);
	}

	.t-alternative {
		display: flex;
		flex-wrap: wrap;
		/* justify-content: space-between; */
		width: 100%;
		padding-right: 10upx;
		box-sizing: border-box;
	}

	.t-alternative__item {
		margin-left: 12upx;
		margin-top: 10upx;
		width: 50upx;
		height: 50upx;
		border-radius: 10upx;
		background-color: #fff;
		background-image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee),
			linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee);
		background-size: 36upx 36upx;
		background-position: 0 0, 18upx 18upx;
		border: 1px #eee solid;
		overflow: hidden;
	}

	.t-alternative__item-content {
		width: 50upx;
		height: 50upx;
		background: rgba(255, 0, 0, 0.5);
	}

	.t-alternative__item:active {
		transition: all 0.3s;
		transform: scale(1.1);
	}
</style>
  • 组件使用

<template>
	<view class="container container23285">
		<u-form-item class="diygw-col-24" label="选择颜色" prop="colorinput">
			<u-input @tap="showColorinput = true" placeholder="请输入颜色值" v-model="colorinput"></u-input>
			<text class="diygw-text-lg diy-icon-colorlens" @tap="showColorinput = true" :style="{ color: colorinput }"></text>
			<diy-color-picker v-model="showColorinput" :hexcolor="colorinput" @confirm="changeColorinput"></diy-color-picker>
		</u-form-item>
		<view class="clearfix"></view>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				//用户全局信息
				userInfo: {},
				//页面传参
				globalOption: {},
				//自定义全局变量
				globalData: {},
				showColorinput: false,
				colorinput: ''
			};
		},
		onShow() {
			this.setCurrentPage(this);
		},
		onLoad(option) {
			this.setCurrentPage(this);
			if (option) {
				this.setData({
					globalOption: this.getOption(option)
				});
			}

			this.init();
		},
		methods: {
			async init() {},
			changeColorinput(evt) {
				let result = evt.hex;
				this.colorinput = result;
			}
		}
	};
</script>

<style lang="scss" scoped>
	.container23285 {
	}
</style>

总的来说,颜色选择器组件在现代数字设计和开发中扮演着重要角色,从基本的网页颜色设置到专业的图形处理软件都离不开它。通过不断的技术创新和应用优化,颜色选择器不仅提升了用户体验,也提高了设计和开发的效率。

  • 13
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值