移動端 uniapp 寫一個可自由拖拽的小鍵盤

寫之前要考慮:

  1. 鍵盤展開后,不能超過手機邊緣
  2. 在底部展開鍵盤,鍵盤應出現在展開按鈕上方;以此類推
  3. 重復點擊展開按鈕,關閉鍵盤

效果:
在這里插入圖片描述

在這里插入圖片描述
代碼如下,有些按鍵邏輯還需要優化

<template><view class="container"><!-- 可拖動按鈕 --><viewclass="drag-btn":style="{left: btnLeft + 'px', top: btnTop + 'px'}"@touchstart="onTouchStart"@touchmove="onTouchMove"@touchend="onTouchEnd"@click="showKeyboard"><text>鍵盤</text></view><!-- 小鍵盤 --><viewv-if="isShowKeyBoard"class="keyboard":style="keyboardStyle"><view v-for="(row, rowIndex) in keyboardLayout" :key="rowIndex" class="keyboard-row"><viewv-for="(key, keyIndex) in row":key="keyIndex"class="key":class="key.className || ''"@click="onKeyPress($event,key.value)">{{ key.name }}</view></view></view></view>
</template><script>
export default {data () {return {btnLeft: 100, // 按鈕初始位置btnTop: 100,startX: 0, // 觸摸起始位置startY: 0,isDragging: false, // 是否正在拖動isShowKeyBoard: false, // 是否顯示鍵盤screenWidth: 375, // 屏幕寬度,會在onLoad中獲取實際值screenHeight: 667, // 屏幕高度keyboardWidth: 330, // 鍵盤寬度keyboardHeight: 170, // 鍵盤高度// 鍵盤布局keyboardLayout: [// 第一行[{name: 'Esc', value: 0x1},{name: '1', value: 0x2},{name: '2', value: 0x3},{name: '3', value: 0x4},{name: '4', value: 0x5},{name: '5', value: 0x6},{name: '6', value: 0x7},{name: '7', value: 0x8},{name: '8', value: 0x9},{name: '9', value: 0xa},{name: '0', value: 0xb},{name: '-', value: 0xc},{name: '=', value: 0xd},{name: '←', value: 0xe, className: 'wide-key'}],// 第二行[{name: 'Tab', value: 0xf, className: 'wide-key'},{name: 'q', value: 0x10},{name: 'w', value: 0x11},{name: 'e', value: 0x12},{name: 'r', value: 0x13},{name: 't', value: 0x14},{name: 'y', value: 0x15},{name: 'u', value: 0x16},{name: 'i', value: 0x17},{name: 'o', value: 0x18},{name: 'p', value: 0x19},{name: '[', value: 0x1a},{name: ']', value: 0x1b},{name: '\\', value: 0x2b}],// 第三行[{name: 'Caps', value: 0x3a, className: 'wide-key'},{name: 'a', value: 0x1e},{name: 's', value: 0x1f},{name: 'd', value: 0x20},{name: 'f', value: 0x21},{name: 'g', value: 0x22},{name: 'h', value: 0x23},{name: 'j', value: 0x24},{name: 'k', value: 0x25},{name: 'l', value: 0x26},{name: ';', value: 0x27},{name: '\'', value: 0x28},{name: 'Enter', value: 0x1c, className: 'wide-key'}],// 第四行[{name: 'Shift', value: 0x2a, className: 'extra-wide-key'},{name: 'z', value: 0x2c},{name: 'x', value: 0x2d},{name: 'c', value: 0x2e},{name: 'v', value: 0x2f},{name: 'b', value: 0x30},{name: 'n', value: 0x31},{name: 'm', value: 0x32},{name: ',', value: 0x33},{name: '.', value: 0x34},{name: '/', value: 0x35},{name: 'Shift', value: 0x36, className: 'extra-wide-key'}],// 第五行[{name: 'Ctrl', value: 0x1d, className: 'wide-key'},{name: 'Alt', value: 0x38, className: 'wide-key'},{name: '空格', value: 0x39, className: 'space-key'},{name: 'Alt', value: 0x138, className: 'wide-key'},{name: 'Ctrl', value: 0x11d, className: 'wide-key'}]]}},computed: {// 計算鍵盤位置樣式keyboardStyle () {let left = this.btnLeftlet top = this.btnTop + 50 // 默認在按鈕下方// 如果鍵盤會超出右邊界,則放在左側if (left + this.keyboardWidth > this.screenWidth) {left = this.btnLeft - this.keyboardWidth}// 如果鍵盤會超出下邊界,則放在上方if (top + this.keyboardHeight > this.screenHeight) {top = this.btnTop - this.keyboardHeight}// 確保不超出左邊界和上邊界left = Math.max(0, left)top = Math.max(0, top)return {left: left + 'px',top: top + 'px',width: this.keyboardWidth + 'px',height: this.keyboardHeight + 'px'}}},onLoad () {// 獲取屏幕尺寸uni.getSystemInfo({success: (res) => {this.screenWidth = res.windowWidththis.screenHeight = res.windowHeight// 初始位置設置為屏幕中間this.btnLeft = (res.windowWidth - 50) / 2this.btnTop = (res.windowHeight - 50) / 2}})},methods: {onTouchStart (e) {this.startX = e.touches[0].clientXthis.startY = e.touches[0].clientYthis.isDragging = false// 隱藏鍵盤// this.isShowKeyBoard = false},onTouchMove (e) {const moveX = e.touches[0].clientX - this.startXconst moveY = e.touches[0].clientY - this.startY// 移動距離大于5px才認為是拖動if (Math.abs(moveX) > 5 || Math.abs(moveY) > 5) {this.isDragging = true}// 計算新位置let newLeft = this.btnLeft + moveXlet newTop = this.btnTop + moveY// 限制不超出屏幕邊界newLeft = Math.max(0, Math.min(newLeft, this.screenWidth - 50))newTop = Math.max(0, Math.min(newTop, this.screenHeight - 50))// 更新位置this.btnLeft = newLeftthis.btnTop = newTop// 更新起始位置,實現連續拖動this.startX = e.touches[0].clientXthis.startY = e.touches[0].clientY// 阻止默認行為和冒泡e.preventDefault()e.stopPropagation()},onTouchEnd (e) {if (this.isDragging) {// 如果是拖動操作,阻止點擊事件e.preventDefault()e.stopPropagation()}this.isDragging = false},showKeyboard () {if (!this.isDragging) {this.isShowKeyBoard = !this.isShowKeyBoard}},onKeyPress (e, key) {this.$emit('onKeyPress', e, key)// spiceInterface.onKeyUpdate(Number(key), true)// spiceInterface.onKeyUpdate(Number(key), false)// 這里可以添加按鍵處理邏輯// 例如:uni.vibrateShort() 震動反饋}}
}
</script><style scoped>
.container {position: relative;/* width: 100%;height: 100vh; */
}.drag-btn {position: fixed;width: 45px;height: 45px;background-color: #007AFF;border-radius: 25px;display: flex;justify-content: center;align-items: center;color: white;font-size: 12px;z-index: 999;touch-action: none; /* 防止觸摸事件的默認行為 */
}.keyboard {position: fixed;background-color: #f0f0f0;border-radius: 8px;padding: 8px;box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);z-index: 998;
}.keyboard-row {display: flex;justify-content: center;margin-bottom: 5px;
}.key {width: 25px;height: 30px;margin: 0 2px;background-color: white;border-radius: 4px;display: flex;justify-content: center;align-items: center;font-size: 14px;box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
}
.wide-key {width: 45px !important; /* 比普通鍵寬 */
}.extra-wide-key {width: 80px !important; /* 更寬的鍵 */
}.space-key {width: 200px !important; /* 空格鍵特別寬 */
}
</style>

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

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

相關文章

《二分枚舉答案(配合數據結構)》題集

文章目錄 1、模板題集2、課內題集3、課后題集1. 字符串哈希2. 并查集3. ST表 1、模板題集 分巧克力 2、課內題集 倒水 冶煉金屬 連續子序列的個數 3、課后題集 括號內的整數代表完整代碼行數。 1. 字符串哈希 你猜猜是啥題(60) 2. 并查集 拯救萌萌(72) 3. ST表 GCD不小…

PY32F030單片機,優勢替代ST GD,主頻48MHz,帶LED數碼管驅動

PY32F030是一款高性能32位單片機&#xff0c;采用ARM Cortex-M0內核&#xff0c;工作頻率高達48MHz&#xff0c;具備64KB Flash和8KB SRAM。它支持1.7V~5.5V寬電壓范圍&#xff0c;集成多路I2C、SPI、USART通訊外設&#xff0c;配備12位ADC、16位定時器和比較器&#xff0c;適用…

Rockchip Uboot中修改固件探測的存儲介質

Rockchip Uboot中修改固件探測的存儲介質 Rockchip uboot中支持從 eMMC、SDcard、NAND 、SPI_NAND、SPI_NOR等存儲介質引導固件。 uboot的spl啟動的時候會默認呢都會去探測這些介質&#xff0c;這樣會導致探測時間變長&#xff0c;在實際產品中可以根據產品需求進行個性化的配…

動手學Python:從零開始構建一個“文字冒險游戲”

動手學Python&#xff1a;從零開始構建一個“文字冒險游戲” 大家好&#xff0c;我是你的技術向導。今天&#xff0c;我們不聊高深的框架&#xff0c;也不談復雜的算法&#xff0c;我們來做一點“復古”又極具趣味性的事情——用Python親手打造一個屬于自己的文字冒險游戲&…

基于Kafka實現企業級大數據遷移的完整指南

在大數據時代&#xff0c;數據遷移已成為企業數字化轉型過程中的常見需求。本文將詳細介紹如何利用Kafka構建高可靠、高性能的大數據遷移管道&#xff0c;涵蓋從設計到實施的完整流程。 一、為什么選擇Kafka進行數據遷移&#xff1f; Kafka作為分布式消息系統&#xff0c;具有…

GEO引領品牌大模型種草:邁向Web3.0與元宇宙的認知新空間

在數字技術的演進歷程中&#xff0c;我們正經歷著從Web2.0到Web3.0、從平面互聯網到沉浸式元宇宙的范式轉變。這一轉變不僅重塑了數字空間的形態和交互方式&#xff0c;更深刻改變了品牌與用戶的連接模式和價值創造邏輯。而在這個新興的數字疆域中&#xff0c;生成式引擎優化&a…

【機器學習與數據挖掘實戰 | 醫療】案例18:基于Apriori算法的中醫證型關聯規則分析

【作者主頁】Francek Chen 【專欄介紹】 ? ? ?機器學習與數據挖掘實戰 ? ? ? 機器學習是人工智能的一個分支,專注于讓計算機系統通過數據學習和改進。它利用統計和計算方法,使模型能夠從數據中自動提取特征并做出預測或決策。數據挖掘則是從大型數據集中發現模式、關聯…

83、高級特性-自定義starter細節

83、高級特性-自定義starter細節 自定義Spring Boot Starter可以將通用功能封裝成可復用的模塊&#xff0c;簡化其他項目的配置和使用。以下是創建自定義Starter的詳細步驟和關鍵細節&#xff1a; ### 1. 項目結構 通常&#xff0c;自定義Starter包含兩個模塊&#xff1a; ####…

專注推理查詢(ARQs):一種提升大型語言模型指令遵循度、決策準確性和防止幻覺的結構化方法

大型語言模型&#xff08;LLMs&#xff09;在客戶服務、自動化內容創作和數據檢索方面變得至關重要。然而&#xff0c;它們的有效性常常因其在多次交互中無法始終如一地遵循詳細指令而受到限制。在金融服務和客戶支持系統等高風險環境中&#xff0c;嚴格遵循指南是必不可少的&a…

華為云Flexus+DeepSeek征文 | DeepSeek驅動的醫療AI Agent:智能問診系統開發完整指南

華為云FlexusDeepSeek征文 | DeepSeek驅動的醫療AI Agent&#xff1a;智能問診系統開發完整指南 &#x1f31f; 嗨&#xff0c;我是IRpickstars&#xff01; &#x1f30c; 總有一行代碼&#xff0c;能點亮萬千星辰。 &#x1f50d; 在技術的宇宙中&#xff0c;我愿做永不停歇…

【大模型水印論文閱讀2】前綴文本編碼、均勻性約束

TOC &#x1f308;你好呀&#xff01;我是 是Yu欸 &#x1f680; 感謝你的陪伴與支持~ 歡迎添加文末好友 &#x1f30c; 在所有感興趣的領域擴展知識&#xff0c;不定期掉落福利資訊(*^▽^*) 寫在最前面 版權聲明&#xff1a;本文為原創&#xff0c;遵循 CC 4.0 BY-SA 協議。…

破繭時刻,與光同行

凌晨五點的鬧鐘刺破薄霧&#xff0c;我摸黑打開臺燈。攤開的數學錯題本上&#xff0c;函數圖像在暖黃的光暈里舒展&#xff0c;像等待破譯的密碼。這樣的清晨已持續三百多個日夜&#xff0c;我知道&#xff0c;在無數個相似的時刻里&#xff0c;總有千萬盞臺燈在黑暗中次第亮起…

Learning PostgresSQL讀書筆記: 第8章 Triggers and Rules

本章將討論以下內容&#xff1a; ? 探索 PostgreSQL 中的規則 ? 管理 PostgreSQL 中的觸發器 ? 事件觸發器 探索 PostgreSQL 中的規則 文檔中的這段話闡述了rule和trigger的區別&#xff1a; PostgreSQL 規則系統允許定義在數據庫表中插入、更新或刪除時執行的替代操作。粗…

信創國產化替代中的開發語言選擇分析

在信息技術應用創新(信創)國產化替代過程中&#xff0c;選擇合適的開發語言至關重要。以下是適合信創環境的開發語言及其優勢分析&#xff1a; 主流適合信創的編程語言 1. Java 優勢&#xff1a;跨平臺特性(JVM)、豐富的生態體系、企業級應用成熟 信創適配&#xff1a;國內有…

Android 中 函數實現多個返回值的幾種方式

在編程中&#xff0c;函數通常只能返回一個值。但通過使用對象封裝、Pair、Triple、數組、列表或 Bundle 方式&#xff0c;可以輕松地返回多個值。 1、對象封裝方式 創建數據類來封裝需要返回的多個值。 data class Result(val code: Int, val message: String)fun getMultiV…

Leetcode百題斬-DP

又到了最好玩的dp了&#xff0c;各種玄學轉移也算是其樂無窮。前段時間剛做的LCA正是這種題的小試牛刀&#xff0c;如果當時就把這個專題刷完了&#xff0c;或許我現在已經從西溪園區跑到云谷園區了。 不過&#xff0c;恐怖如斯的dp專題居然只給了一道hard&#xff0c;基本也沒…

策略模式與工廠模式的黃金組合:從設計到實戰

策略模式和工廠模式是軟件開發中最常用的兩種設計模式&#xff0c;當它們結合使用時&#xff0c;能產生11>2的效果。本文將通過實際案例&#xff0c;闡述這兩種模式的協同應用&#xff0c;讓代碼架構更優雅、可維護性更強。 一、為什么需要組合使用&#xff1f; 單獨使用的…

SAP PP模塊與MM模塊作用詳解

SAP PP模塊與MM模塊作用詳解 一、PP模塊&#xff08;Production Planning&#xff09;—— 生產計劃與執行中樞 核心作用&#xff1a;將銷售需求轉化為可執行的生產指令&#xff0c;管控從計劃到完工的全過程。 關鍵功能 功能說明業務價值主數據管理維護BOM&#xff08;物料…

Linux tcp_info:監控TCP連接的秘密武器

深入解析 Linux tcp_info&#xff1a;TCP 狀態的實時監控利器 在開發和運維網絡服務時&#xff0c;我們常常遇到這些問題&#xff1a; 我的 TCP 連接為什么速度慢&#xff1f;是發生了重傳&#xff0c;還是窗口太小&#xff1f;擁塞控制到底有沒有生效&#xff1f; 這些問題…

CVE-2015-5531源碼分析與漏洞復現(Elasticsearch目錄遍歷漏洞)

概述 漏洞名稱&#xff1a;Elasticsearch 快照API目錄遍歷漏洞 CVE 編號&#xff1a;CVE-2015-5531 CVSS 評分&#xff1a;7.5 影響版本&#xff1a; Elasticsearch 1.0.0–1.6.0&#xff08;1.5.1及以前版本無需配置即可觸發&#xff1b;1.5.2–1.6.0需配置path.repo&#xf…