小程序難調的組件

背景。做小程序用到了自定義表單。前后端都是分開寫的,沒有使用web-view。所以要做到功能對稱

  • 時間選擇器。需要區分datetime, year, day等類型使用uview組件較方便
<template><view class="u-date-picker" v-if="visible"><view class="label-container"><text v-if="required" class="required-mark">*</text><text class="label">{{ label }}</text></view><view class="picker-container" :class="{ 'picker-disabled': disabled }" @click="showPicker"><text class="picker-text" :class="{ 'text-disabled': disabled }">{{ displayText }}</text><text class="picker-arrow" :class="{ 'arrow-disabled': disabled }">></text></view><!-- 日期選擇器彈窗 --><u-pickerv-model="showPickerFlag"mode="time":params="pickerParams":default-time="defaultTime":start-year="startYear":end-year="endYear":show-time-tag="showTimeTag"@confirm="onConfirm"@cancel="onCancel"></u-picker></view>
</template><script>
export default {name: 'UDatePicker',props: {/*** 標簽文本*/label: {type: String,default: '選擇日期'},/*** 占位符文本*/placeholder: {type: String,default: '請選擇日期'},/*** 當前選中的值*/value: {type: String,default: ''},/*** 日期類型:date-僅日期,datetime-日期時間*/type: {type: String,default: 'date'},/*** 開始年份*/startYear: {type: [String, Number],default: 1950},/*** 結束年份*/endYear: {type: [String, Number],default: 2050},/*** 是否顯示時間標簽(年月日時分秒)*/showTimeTag: {type: Boolean,default: true},/*** 日期格式*/format: {type: String,default: 'YYYY-MM-DD'},/*** 是否禁用*/disabled: {type: Boolean,default: false},/*** 是否必填*/required: {type: Boolean,default: false},/*** 是否可見*/visible: {type: Boolean,default: true}},data() {return {showPickerFlag: false,pickerParams: this.getPickerParams(),defaultTime: '',selectedDate: ''};},computed: {/*** 顯示的文本*/displayText() {if (this.value) {const t = (this.type || 'date').toLowerCase();if (t === 'year') {// 年份類型:直接顯示年份return this.value;} else if (t === 'month') {// 月份類型:顯示年月return this.value;} else if (t === 'date') {// 日期類型:顯示完整日期return this.value;} else if (t === 'week') {// 周類型:顯示日期并計算周數try {const date = new Date(this.value);if (!isNaN(date.getTime())) {const weekNumber = this.getWeekNumber(date);return `${this.value} (第${weekNumber}周)`;}} catch (e) {console.error('日期解析錯誤:', e);}return this.value;} else if (t === 'datetime') {// 日期時間類型:顯示完整日期時間return this.value;} else if (t.indexOf('time') !== -1) {// 時間類型:顯示時間return this.value;}return this.value;}return this.placeholder;},/*** 根據類型確定選擇器模式*/pickerMode() {const t = (this.type || 'date').toLowerCase();if (t === 'year') return 'date';if (t === 'month') return 'date';if (t === 'week') return 'date';if (t === 'date') return 'date';if (t.indexOf('time') !== -1) return 'time';if (t === 'datetime') return 'date'; // datetime 降級為 datereturn 'date';}},watch: {/*** 監聽類型變化,更新選擇器參數*/type: {handler(newType) {this.pickerParams = this.getPickerParams();},immediate: true},/*** 監聽值變化,更新默認時間*/value: {handler(newValue) {if (newValue) {this.defaultTime = newValue;}},immediate: true}},methods: {/*** 根據類型獲取選擇器參數*/getPickerParams() {const t = (this.type || 'date').toLowerCase();if (t === 'year') {// 年份選擇:只顯示年份return {year: true,month: false,day: false,hour: false,minute: false,second: false};} else if (t === 'month') {// 月份選擇:顯示年月return {year: true,month: true,day: false,hour: false,minute: false,second: false};} else if (t === 'date') {// 日期選擇:顯示年月日return {year: true,month: true,day: true,hour: false,minute: false,second: false};} else if (t === 'week') {// 周選擇:顯示年月日(周選擇需要完整日期來計算周數)return {year: true,month: true,day: true,hour: false,minute: false,second: false};} else if (t === 'datetime') {// 日期時間選擇:顯示年月日時分秒return {year: true,month: true,day: true,hour: true,minute: true,second: true};} else if (t.indexOf('time') !== -1) {// 時間選擇:只顯示時分秒return {year: false,month: false,day: false,hour: true,minute: true,second: true};} else {// 默認日期選擇return {year: true,month: true,day: true,hour: false,minute: false,second: false};}},/*** 顯示選擇器*/showPicker() {if (this.disabled) {return;}this.showPickerFlag = true;},/*** 確認選擇* @param {Object} e 選擇結果*/onConfirm(e) {const { year, month, day, hour, minute, second } = e;console.log('onConfirm', e)// 格式化日期let formattedDate = '';const t = (this.type || 'date').toLowerCase();if (t === 'year') {// 年份選擇:只返回年份formattedDate = `${year}`;} else if (t === 'month') {// 月份選擇:返回年月formattedDate = `${year}-${this.formatNumber(month)}`;} else if (t === 'date') {// 日期選擇:返回完整日期formattedDate = `${year}-${this.formatNumber(month)}-${this.formatNumber(day)}`;} else if (t === 'week') {// 周選擇:返回完整日期(用于計算周數)const date = new Date(year, month - 1, day);const weekNumber = this.getWeekNumber(date);formattedDate = `${year}-${this.formatNumber(month)}-${this.formatNumber(day)}`;// 可以添加周數信息到返回值中console.log(`${weekNumber}`);} else if (t === 'datetime') {// 日期時間選擇:返回完整日期時間formattedDate = `${year}-${this.formatNumber(month)}-${this.formatNumber(day)} ${this.formatNumber(hour)}:${this.formatNumber(minute)}:${this.formatNumber(second)}`;} else if (t.indexOf('time') !== -1) {// 時間選擇:返回時間formattedDate = `${this.formatNumber(hour)}:${this.formatNumber(minute)}:${this.formatNumber(second)}`;} else {// 默認日期格式formattedDate = `${year}-${this.formatNumber(month)}-${this.formatNumber(day)}`;}this.selectedDate = formattedDate;this.$emit('input', formattedDate);this.$emit('change', formattedDate);this.showPickerFlag = false;},/*** 取消選擇*/onCancel() {this.showPickerFlag = false;},/*** 格式化數字,補零* @param {Number} num 數字* @returns {String} 格式化后的字符串*/formatNumber(num) {return num < 10 ? `${num}` : `${num}`;},/*** 計算周數* @param {Date} date 日期對象* @returns {Number} 周數*/getWeekNumber(date) {const firstDayOfYear = new Date(date.getFullYear(), 0, 1);const pastDaysOfYear = (date - firstDayOfYear) / 86400000;return Math.ceil((pastDaysOfYear + firstDayOfYear.getDay() + 1) / 7);}}
};
</script><style lang="scss" scoped>
.u-date-picker {margin-bottom: 20rpx;.label-container {display: flex;align-items: center;margin-bottom: 10rpx;.required-mark {color: #ff4757;font-size: 28rpx;margin-right: 8rpx;font-weight: bold;}.label {font-size: 28rpx;color: #333;font-weight: 500;}}.picker-container {display: flex;align-items: center;justify-content: space-between;padding: 20rpx;background-color: #fff;border-radius: 8rpx;border: 1rpx solid #e0e0e0;transition: all 0.3s ease;min-height: 88rpx;box-sizing: border-box;&.picker-disabled {background-color: #f5f5f5;border-color: #d9d9d9;cursor: not-allowed;}.picker-text {flex: 1;font-size: 28rpx;color: #333;line-height: 1.5;&.text-disabled {color: #999;}}.picker-arrow {font-size: 24rpx;color: #999;margin-left: 10rpx;font-weight: bold;&.arrow-disabled {color: #ccc;}}}
}
</style>
  • checkbox選擇器,帶著其他輸入框
<template><view class="dynamic-checkbox"><view class="checkbox-label"><text v-if="required" class="required-mark">*</text><text class="label-text">{{ label }}</text></view><u-checkbox-group :disabled="disabled":active-color="activeColor":size="checkboxSize"><u-checkboxv-for="opt in localOptions"v-model="opt.checked":name="opt.value":disabled="disabled":active-color="activeColor":size="checkboxSize"@change="(value) => handleCheckboxChange(opt, value)"><text class="checkbox-text">{{ opt.label }}</text></u-checkbox><!-- 其他選項的輸入框 --></u-checkbox-group><view v-if="otherChoose" class="other-input-container"><u-inputv-model="otherValue":placeholder="otherPlaceholder || '請輸入其他內容'"class="other-input":border="true"@input="handleOtherChange"/></view></view>
</template><script>
export default {name: 'DynamicCheckBox',props: {/** 標簽文本 */label: {type: String,default: ''},/** 當前選中的值 */value: {type: Array,default: () => []},/** 選項配置數組 */options: {type: Array,default: () => []},/** 是否禁用 */disabled: {type: Boolean,default: false},/** 是否必填 */required: {type: Boolean,default: false},/** 排列方式. horizontal: 水平排列, vertical: 垂直排列 */alignDirection: {type: String,default: 'vertical'},/** 其他選項:輸入框提示 */otherPlaceholder: {type: String,default: ''}},data() {return {checkboxValues: [],activeColor: '#2979ff',checkboxSize: 34,localOptions: [], // 本地選項數據,包含checked狀態otherValue: '',// 其他輸入框值      };},computed: {otherChoose() {// 判斷checkboxValues中是否包含-99,如果包含,則返回true\let flag = false;if (this.checkboxValues.length > 0) {flag = this.checkboxValues.some(opt => opt.value === -99 || opt.value === '-99');}console.log('otherChoose:', flag);return flag;}},watch: {value: {handler(newVal) {// 判斷newVal與this.checkboxValues是否相等, 若相等, 則不進行更新if (JSON.stringify(newVal) === JSON.stringify(this.checkboxValues)) {return;}// 確保value是數組類型const valueArray = Array.isArray(newVal) ? newVal : [];this.checkboxValues = [...valueArray];// 更新本地選項的checked狀態this.updateLocalOptions();},immediate: true},options: {handler(newVal) {console.log('watch.options:', this.checkboxValues );this.localOptions = (newVal || []).map(option => ({...option,checked: false}));this.updateLocalOptions();},immediate: true}},methods: {/*** 更新本地選項的checked狀態*/updateLocalOptions() {console.log('updateLocalOptions.checkboxValues:', this.checkboxValues);// 判斷this.localOptions中是否有checkboxValues相等的值,  若有, 則將checked設置為truethis.localOptions.forEach(option => {if (this.checkboxValues.some(opt => opt.value === option.value)) {option.checked = true;}});// 遍歷this.checkboxValues, 若value == '-99', 則將otherValue賦值給this.otherValuethis.checkboxValues.forEach(opt => {if (opt.value == '-99') {this.otherValue = opt.otherValue;}});},/*** 處理單個checkbox變化事件* @param {Object} option 選項對象* @param {Number} index 選項索引* @param {Boolean} value 是否選中*/handleCheckboxChange(option, value) {// 當option.checked為true時,將option.name添加到checkboxValues中if (value.value) {this.checkboxValues.push({...option});} else {// this.checkboxValues.splice(this.checkboxValues.indexOf({...option}), 1);// 檢查checkboxValues數組中是否有value.name的值,有則刪除// this.checkboxValues.splice(this.checkboxValues.indexOf({...option}), 1);// 對checkboxvalues重新賦值, 若value.name的值在checkboxvalues中存在則刪除this.checkboxValues = this.checkboxValues.filter(opt => opt.value !== option.value);}console.log('單個checkbox變化:', option, value, this.checkboxValues);this.emitChange();},/*** 觸發change事件*/emitChange() {this.$emit('change', this.checkboxValues);},/*** 處理其他選項輸入框的輸入事件* @param {String} value 輸入的值*/handleOtherChange(value) {this.otherValue = value;// 輪詢checkboxValues數組,找到value=='-99'的對象添加otherValuethis.checkboxValues.forEach(opt => {if (opt.value === '-99') {opt.otherValue = this.otherValue;}});console.log('handleOtherChange:', value, this.checkboxValues);this.emitChange();},/*** 處理其他選項輸入框獲得焦點事件* @param {Number} index 選項索引*/handleOtherFocus(index) {console.log(`其他選項輸入框獲得焦點,索引: ${index}`);},/*** 處理其他選項輸入框失去焦點事件* @param {Number} index 選項索引*/handleOtherBlur(index) {console.log(`其他選項輸入框失去焦點,索引: ${index}`);// 失焦時也觸發change事件,確保數據同步// this.emitChange();},}
};
</script><style scoped>
.dynamic-checkbox {background-color: #fff;border-radius: 12rpx;padding: 30rpx;margin-bottom: 20rpx;box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
}.checkbox-label {display: flex;align-items: center;margin-bottom: 20rpx;
}.required-mark {color: #ff4757;font-size: 28rpx;margin-right: 8rpx;font-weight: bold;
}.label-text {font-size: 28rpx;color: #333;font-weight: 500;
}.checkbox-container {display: flex;flex-direction: column;gap: 40rpx;
}.checkbox-container.checkbox-horizontal {flex-direction: row;flex-wrap: wrap;gap: 20rpx;
}.checkbox-container.checkbox-vertical {flex-direction: column;gap: 40rpx;
}.checkbox-item {display: flex;flex-direction: column;align-items: flex-start;padding: 16rpx;border-radius: 8rpx;transition: all 0.2s ease;border: 2rpx solid transparent;min-width: 200rpx;
}.checkbox-item:not(.checkbox-disabled):hover {background-color: #f8f9fa;border-color: #e9ecef;
}.checkbox-item.checkbox-disabled {opacity: 0.6;cursor: not-allowed;
}.checkbox-item.checkbox-checked {background-color: #f0f8ff;border-color: #2979ff;
}.checkbox-option {display: flex;align-items: center;cursor: pointer;width: 100%;
}.checkbox-text {font-size: 28rpx;color: #333;margin-left: 12rpx;user-select: none;flex: 1;line-height: 1.4;
}/* 其他選項輸入框樣式 */
.other-input-container {width: 100%;margin-top: 16rpx;
}.other-input {width: 100%;
}/* 選中狀態下的其他選項樣式 */
.checkbox-item.checkbox-checked .other-input {border-color: #2979ff;background-color: #f8f9ff;
}/* 水平排列時的樣式優化 */
.checkbox-container.checkbox-horizontal .checkbox-item {flex: 0 0 auto;min-width: 180rpx;max-width: 300rpx;
}.checkbox-container.checkbox-horizontal .other-input-container {margin-top: 12rpx;
}
</style>

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/92348.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/92348.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/92348.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

從零構建TransformerP2-新聞分類Demo

歡迎來到啾啾的博客&#x1f431;。 記錄學習點滴。分享工作思考和實用技巧&#xff0c;偶爾也分享一些雜談&#x1f4ac;。 有很多很多不足的地方&#xff0c;歡迎評論交流&#xff0c;感謝您的閱讀和評論&#x1f604;。 目錄引言1 一個完整的Transformer模型2 需要準備的“工…

qt qml實現電話簿 通訊錄

qml實現電話簿&#xff0c;基于github上開源代碼修改而來&#xff0c;增加了搜索和展開&#xff0c;效果如下 代碼如下 #include <QGuiApplication> #include <QQmlApplicationEngine>int main(int argc, char *argv[]) {QCoreApplication::setAttribute(Qt::AA_…

順序表——C語言

順序表實現代碼解析與學習筆記一、順序表基礎概念順序表是線性表的一種順序存儲結構&#xff0c;它使用一段連續的內存空間&#xff08;數組&#xff09;存儲數據元素&#xff0c;通過下標直接訪問元素&#xff0c;具有隨機訪問的特性。其核心特點是&#xff1a;元素在內存中連…

【Oracle篇】Oracle Data Pump遠程備份技術:直接從遠端數據庫備份至本地環境

&#x1f4ab;《博主主頁》&#xff1a;    &#x1f50e; CSDN主頁__奈斯DB    &#x1f50e; IF Club社區主頁__奈斯、 &#x1f525;《擅長領域》&#xff1a;擅長阿里云AnalyticDB for MySQL(分布式數據倉庫)、Oracle、MySQL、Linux、prometheus監控&#xff1b;并對…

Linux系統--文件系統

大家好&#xff0c;我們今天繼續來學習Linux系統部分。上一次我們學習了內存級的文件&#xff0c;下面我們來學習磁盤級的文件。那么話不多說&#xff0c;我們開始今天的學習&#xff1a; 目錄 Ext系列?件系統 1. 理解硬件 1-1 磁盤、服務器、機柜、機房 1-2 磁盤物理結構…

KUKA庫卡焊接機器人氬氣節氣設備

在焊接生產過程中&#xff0c;氬氣作為一種重要的保護氣體被廣泛應用于KUKA庫卡焊接機器人的焊接操作中。氬氣的消耗往往是企業生產成本的一個重要組成部分&#xff0c;因此實現庫卡焊接機器人節氣具有重要的經濟和環保意義。WGFACS節氣裝置的出現為解決這一問題提供了有效的方…

遠程連接----ubuntu ,rocky 等Linux系統,WindTerm_2.7.0

新一代開源免費的終端工具-WindTerm github 27.5k? https://github.com/kingToolbox/WindTerm/releases/download/2.7.0/WindTerm_2.7.0_Windows_Portable_x86_64.zip 主機填寫你自己要連接的主機ip 端口默認 22 改成你ssh文件配置的端口 輸入遠程的 用戶名 與密碼 成功連接…

筆試——Day32

文章目錄第一題題目思路代碼第二題題目&#xff1a;思路代碼第三題題目&#xff1a;思路代碼第一題 題目 素數回文 思路 模擬 構建新的數字&#xff0c;判斷該數是否為素數 代碼 第二題 題目&#xff1a; 活動安排 思路 區間問題的貪?&#xff1a;排序&#xff0c;然…

超高車輛如何影響城市立交隧道安全?預警系統如何應對?

超高車輛對立交隧道安全的潛在威脅在城市立交和隧道中&#xff0c;限高設施的設計通常考慮到大部分正常通行的貨車和運輸車輛。然而&#xff0c;一些超高的貨車、集裝箱車或特殊車輛如果未經有效監測而進入限高區域&#xff0c;就可能對道路設施造成極大的安全隱患。尤其在立交…

解決 MinIO 上傳文件時報 S3 API Requests must be made to API port錯誤

在使用 MinIO 進行文件上傳時&#xff0c;我遇到了一個比較坑的問題。錯誤日志如下&#xff1a; io.minio.errors.InvalidResponseException: Non-XML response from server. Response code: 400, Content-Type: text/xml; charsetutf-8, body: <?xml version"1.0&quo…

linux_https,udp,tcp協議(更新中)

目錄 https 加密類型 對稱加密 非對稱加密 加密方案 只用對程加密 只用非對程加密 雙方都是用非對程加密 非對稱對稱加密 非對稱對稱加密證書 流程圖 校驗流程圖 udp udp協議格式 特點 UDP緩沖區 tcp tcp協議格式 32位序號及確認序號 4位首部 6位標志位 1…

web端-登錄頁面驗證碼的實現(springboot+vue前后端分離)超詳細

目錄 一、項目技術棧 二、實現效果圖 ?三、實現路線 四、驗證碼的實現步驟 五、完整代碼 1.前端 2.后端 一、項目技術棧 登錄頁面暫時涉及到的技術棧如下: 前端 Vue2 Element UI Axios&#xff0c;后端 Spring Boot 2 MyBatis MySQL JWT Maven 二、實現效果圖…

瘋狂星期四文案網第33天運營日記

網站運營第33天&#xff0c;點擊觀站&#xff1a; 瘋狂星期四 crazy-thursday.com 全網最全的瘋狂星期四文案網站 運營報告 今日訪問量 今日搜索引擎收錄情況 必應收錄239個頁面&#xff0c;還在持續增加中&#xff0c;已經獲得必應的認可&#xff0c;逐漸收錄所有頁面 百度…

客戶端利用MinIO對服務器數據進行同步

MinIO 是一款高性能、開源的對象存儲服務&#xff0c;專為海量數據存儲設計&#xff0c;兼容 Amazon S3 API&#xff08;即與 AWS S3 協議兼容&#xff09;&#xff0c;可用于構建私有云存儲、企業級數據湖、備份歸檔系統等場景。它以輕量、靈活、高效為核心特點&#xff0c;廣…

WPF 雙擊行為實現詳解:DoubleClickBehavior 源碼分析與實戰指南

WPF 雙擊行為實現詳解:DoubleClickBehavior 源碼分析與實戰指南 文章目錄 WPF 雙擊行為實現詳解:DoubleClickBehavior 源碼分析與實戰指南 引言 一、行為(Behavior)基礎概念 1.1 什么是行為? 1.2 行為的優勢 二、DoubleClickBehavior 源碼分析 2.1 類定義與依賴屬性 2.2 雙…

零知開源——基于STM32F103RBT6的TDS水質監測儀數據校準和ST7789顯示實戰教程

?零知開源是一個真正屬于國人自己的開源軟硬件平臺&#xff0c;在開發效率上超越了Arduino平臺并且更加容易上手&#xff0c;大大降低了開發難度。零知開源在軟件方面提供了完整的學習教程和豐富示例代碼&#xff0c;讓不懂程序的工程師也能非常輕而易舉的搭建電路來創作產品&…

luogu P3387 【模板】縮點

原題鏈接 原題再現 題目描述 給定一個 n 個點 m 條邊有向圖&#xff0c;每個點有一個權值&#xff0c;求一條路徑&#xff0c;使路徑經過的點權值之和最大。你只需要求出這個權值和。 允許多次經過一條邊或者一個點&#xff0c;但是&#xff0c;重復經過的點&#xff0c;權…

P1119 災后重建【題解】

P1119 災后重建 題目背景 B 地區在地震過后&#xff0c;所有村莊都造成了一定的損毀&#xff0c;而這場地震卻沒對公路造成什么影響。但是在村莊重建好之前&#xff0c;所有與未重建完成的村莊的公路均無法通車。換句話說&#xff0c;只有連接著兩個重建完成的村莊的公路才能通…

Horse3D引擎研發筆記(二):基于QtOpenGL使用仿Three.js的BufferAttribute結構重構三角形繪制

在Horse3D引擎的研發過程中&#xff0c;我們致力于構建一個高效、靈活且易于擴展的3D圖形引擎。在本篇博客中&#xff0c;我們將詳細記錄如何基于QtOpenGL框架&#xff0c;使用仿Three.js的BufferAttribute結構&#xff0c;重構三角形繪制流程。通過這一過程&#xff0c;我們希…

MCU程序段的分類

程序的下載&#xff08;燒錄到存儲器中&#xff09;通常是按照程序文件分段&#xff08;Code段、RO_data段、RW_data段、ZI_data段&#xff09;的方式存儲的&#xff0c;但運行時內存的布局會按照程序進程分段&#xff08;TEXT段、DATA段、BSS段、堆棧段&#xff09;進行組織。…