【sgKeyboard】自定义组件:虚拟键盘

sgKeyboard

html 复制代码
<template>
  <div :class="$options.name">
    <div class="keyboard">
      <div class="key-row">
        <div class="key" v-for="(a, i) in rows[0]" :key="i" @mousedown="mousedown(a)">
          {{ a }}
        </div>
      </div>
      <div class="key-row" v-for="(a, i) in rows" :key="i">
        <div
          class="key"
          v-for="(key, subIndex) in rows[i + 1]"
          :key="subIndex"
          @mousedown="mousedown(getChar(key))"
        >
          {{ getChar(key) }}
        </div>
      </div>
      <div class="key-row">
        <div
          class="key key-wide capsLock"
          :capsLock="capsLock"
          :active="capsLock"
          @mousedown="toggleCaps"
        >
          切换为{{ capsLock ? `小` : `大` }}写
        </div>
        <div class="key key-space" @mousedown="mousedown(` `)">空格</div>
        <div class="key key-wide back-btn" @mousedown="handleBackspace">退格</div>
        <div class="key key-wide clear-btn" @mousedown="clearAll">清空</div>
      </div>
      <div class="close-btn" @click="$emit(`close`, true)" v-if="showCloseBtn">
        <i class="el-icon-close" />
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: `sgKeyboard`,
  data() {
    return {
      keyword: ``,
      capsLock: false,
      rows: [
        [1, 2, 3, 4, 5, 6, 7, 8, 9, 0],
        [`a`, `b`, `c`, `d`, `e`, `f`, `g`, `h`, `i`, `j`],
        [`k`, `l`, `m`, `n`, `o`, `p`, `q`, `r`, `s`, `t`],
        [`u`, `v`, `w`, `x`, `y`, `z`],
      ],
      showCloseBtn: false,
    };
  },
  props: [`value`, `data`],
  watch: {
    value: {
      handler(d) {
        this.keyword = d;
      },
      deep: true,
      immediate: true,
    },
    keyword(d) {
      this.$emit(`input`, d);
    },
    data: {
      handler(newValue, oldValue) {
        //console.log(`深度监听${this.$options.name}:`, newValue, oldValue);
        if (Object.keys(newValue || {}).length) {
          this.form = this.$g.deepCopy(newValue);
          this.$g.cF2CP(`disabled`, this);
          this.$g.cF2CP(`showCloseBtn`, this);
        }
      },
      deep: true,
      immediate: true,
    },
  },
  methods: {
    getChar(char) {
      return this.capsLock ? char.toUpperCase() : char;
    },
    mousedown(char) {
      this.keyword += char;
    },
    handleBackspace() {
      this.keyword.length > 0 &&
        (this.keyword = this.keyword.slice(0, this.keyword.length - 1));
    },
    toggleCaps() {
      this.capsLock = !this.capsLock;
    },
    clearAll() {
      this.keyword = ``;
    },
  },
};
</script>

<style lang="scss" scoped>
.sgKeyboard {
  .keyboard {
    position: relative;
    width: max-content;
    height: max-content;
    box-sizing: border-box;
    border: 1px solid #c6d1de;
    box-shadow: 0 5px 11px 0 #00000033;
    padding: 10px;
    background-color: #efefef;
    border-radius: 6px;
    color: #5e6d82;
    .key-row {
      display: flex;
      gap: 4px;
      margin-bottom: 4px;
    }
    .key {
      display: flex;
      justify-content: center;
      align-items: center;
      min-width: 36px;
      height: 36px;
      text-align: center;
      background-color: #fff;
      border: none;
      border-radius: 4px;
      font-size: 14px;
      font-family: Microsoft YaHei;
      box-shadow: 0 3px 5px 0 #00000044;
      cursor: pointer;
      box-sizing: border-box;
      border: 1px solid transparent;
      &:hover {
        background-color: #fafafa;
      }
      &:active,
      &[active] {
        transform: translate(0px, 1px);
        /*从上往下线性渐变背景*/
        background: linear-gradient(white, lightgray);
        box-shadow: 0 2px 3px 0 #00000022;
      }
      &[active] {
        border-color: #555;
        border-top: none;
      }
    }
    .key-wide {
      padding: 0 10px;
    }
    .capsLock {
      &[capsLock] {
        color: white;
        background: #7d7d7d;
      }
    }
    .key-space {
      flex-grow: 1;
    }
    .back-btn {
      width: 50px;
    }
    .clear-btn {
      width: 50px;
    }
    .close-btn {
      position: absolute;
      right: -10px;
      top: -10px;

      color: #c6d1de;
      background-color: white;
      box-sizing: border-box;
      border: 1px solid #c6d1de;
      box-shadow: 0 5px 10px 0 #00000033;
      border-radius: 88px;
      box-sizing: border-box;
      width: 20px;
      height: 20px;
      display: flex;
      justify-content: center;
      align-items: center;
      cursor: pointer;
      i {
        font-size: 12px;
      }
      &:hover {
        color: white;
        background-color: #c6d1de;
      }
      &:active {
        transform: translate(1px, 1px);
        opacity: 0.618;
      }
    }
  }
}
</style>

demo

html 复制代码
<template>
  <div :class="$options.name">
    <el-input v-model="value" :placeholder="`输入内容`" clearable />
    <el-link
      type="primary"
      :underline="false"
      @click="show_sgKeyboard = !show_sgKeyboard"
      style="margin-top: 10px; margin-bottom: 10px"
      >{{ show_sgKeyboard ? `隐藏` : `使用` }}虚拟键盘</el-link
    >
    <sgKeyboard v-model="value" v-if="show_sgKeyboard" />
  </div>
</template>
<script>
import sgKeyboard from "@/vue/components/admin/sgKeyboard";
export default {
  name: `demo`,
  components: { sgKeyboard },
  data() {
    return { value: ``, show_sgKeyboard: true };
  },
};
</script>
<style lang="scss" scoped>
.demo {
  box-sizing: border-box;
  padding: 20px;
}
</style>
相关推荐
掘金酱1 小时前
【10.24 特别活动】AI 时代,程序员的新饭碗在哪里?
前端·人工智能·后端
excel1 小时前
多进程环境下使用 PM2 部署 Socket.IO:需要注意什么
前端
IT_陈寒2 小时前
Redis的原子性竟然失效了?记一次分布式锁翻车实录
前端·人工智能·后端
_菜鸟果果3 小时前
高德地图 JS API 2.0 在国产 Linux/ARM 电脑上渲染失败 的排查与解决
linux·开发语言·javascript
时间的情敌3 小时前
《回顾 2018 前端:Vue2 成熟期,Webpack4 发布,PWA 大火》
前端
Java后端的Ai之路4 小时前
前端技术Vue-09-webpack-vuejs-实战
前端·vue.js·webpack
LMT流氓兔4 小时前
第五单元——第4课:给工具参数加校验
java·前端·算法·ai·langchain
涛涛ing4 小时前
React Compiler正式“Rust化”:你项目里的Babel插件,正在被编译进打包器
前端
迷途小羔羊4 小时前
项目概述
java·javascript·后端