├── .babelrc ├── .gitignore ├── README.md ├── _config.yml ├── components.json ├── demo └── imgs │ ├── 001.png │ ├── 002.png │ ├── 003.png │ ├── 004.png │ └── 005.png ├── docs ├── _config.yml ├── build.07471056.js ├── build.13516fd5.js ├── build.28f4a363.js ├── build.563c5626.js ├── build.626e3994.js ├── build.68f0d83b.js ├── build.dcdf5a70.js ├── build.e83af9d5.js ├── favicon.ico ├── iconfont.ttf ├── iconfont.woff ├── iconfont.woff2 └── index.html ├── favicon.ico ├── index.html ├── karma.conf.js ├── package-lock.json ├── package.json ├── packages ├── exportKbBoard.js ├── exportKbInput.js └── index.js ├── src ├── App.vue ├── assets │ ├── dissableBodyScroll.js │ └── js │ │ └── ueHorizontalScreen.js ├── demo │ ├── Customkeyboard.vue │ ├── KeyboardAwareScrollView1.vue │ ├── KeyboardAwareScrollView2.vue │ ├── KeyboardAwareScrollView3.vue │ ├── adaptiveHeight.vue │ ├── breakWrap.vue │ ├── canSwitchOtherBoard.vue │ ├── customKeyboardMap │ │ └── boardMaps.js │ ├── disabledInputUpdateMixKeyBoardLang.vue │ ├── event.vue │ ├── hideHead.vue │ ├── horizontalScreen.vue │ ├── horizontalScreen2.vue │ ├── index.vue │ ├── inputDisabled.vue │ ├── inputFuncSelect.vue │ ├── inputMaxLength.vue │ ├── inputSlot.vue │ ├── noEmoji.vue │ ├── showFixedInput.vue │ └── type.vue ├── dev │ ├── KeyboardAwareScrollView.vue │ ├── assets │ │ ├── font │ │ │ ├── iconfont.ttf │ │ │ ├── iconfont.woff │ │ │ └── iconfont.woff2 │ │ ├── images │ │ │ ├── hearts │ │ │ │ ├── 10_sparkling_heart.png │ │ │ │ ├── 11_revolving_hearts.png │ │ │ │ ├── 12_cupid.png │ │ │ │ ├── 13_love_letter.png │ │ │ │ ├── 14_kiss.png │ │ │ │ ├── 15_ring.png │ │ │ │ ├── 16_gem.png │ │ │ │ ├── 1_yellow_heart.png │ │ │ │ ├── 2_blue_heart.png │ │ │ │ ├── 3_purple_heart.png │ │ │ │ ├── 4_green_heart.png │ │ │ │ ├── 5_heart.png │ │ │ │ ├── 6_broken_heart.png │ │ │ │ ├── 7_heartpulse.png │ │ │ │ ├── 8_heartbeat.png │ │ │ │ └── 9_two_hearts.png │ │ │ ├── person │ │ │ │ ├── 10_disappointed.png │ │ │ │ ├── 10_kissing.png │ │ │ │ ├── 11_kissing_smiling_eyes.png │ │ │ │ ├── 12_stuck_out_tongue_winking_eye.png │ │ │ │ ├── 13_stuck_out_tongue_closed_eyes.png │ │ │ │ ├── 14_stuck_out_tongue.png │ │ │ │ ├── 15_flushed.png │ │ │ │ ├── 16_grin.png │ │ │ │ ├── 17_pensive.png │ │ │ │ ├── 18_relieved.png │ │ │ │ ├── 19_unamused.png │ │ │ │ ├── 1_smile.png │ │ │ │ ├── 20_fearful.png │ │ │ │ ├── 20_persevere.png │ │ │ │ ├── 21_cry.png │ │ │ │ ├── 22_joy.png │ │ │ │ ├── 23_sob.png │ │ │ │ ├── 24_sleepy.png │ │ │ │ ├── 25_cold_sweat.png │ │ │ │ ├── 25_disappointed_relieved.png │ │ │ │ ├── 26_sweat_smile.png │ │ │ │ ├── 27_sweat.png │ │ │ │ ├── 28_weary.png │ │ │ │ ├── 29_tired_face.png │ │ │ │ ├── 2_smiley.png │ │ │ │ ├── 30_scream.png │ │ │ │ ├── 31_angry.png │ │ │ │ ├── 32_rage.png │ │ │ │ ├── 33_confounded.png │ │ │ │ ├── 33_triumph.png │ │ │ │ ├── 34_laughing.png │ │ │ │ ├── 35_yum.png │ │ │ │ ├── 36_mask.png │ │ │ │ ├── 37_sunglasses.png │ │ │ │ ├── 38_sleeping.png │ │ │ │ ├── 39_dizzy_face.png │ │ │ │ ├── 3_grinning.png │ │ │ │ ├── 40_astonished.png │ │ │ │ ├── 41_worried.png │ │ │ │ ├── 42_frowning.png │ │ │ │ ├── 43_anguished.png │ │ │ │ ├── 44_neutral_face.png │ │ │ │ ├── 45_confused.png │ │ │ │ ├── 46_no_mouth.png │ │ │ │ ├── 47_innocent.png │ │ │ │ ├── 48_smirk.png │ │ │ │ ├── 49_expressionless.png │ │ │ │ ├── 4_blush.png │ │ │ │ ├── 5_relaxed.png │ │ │ │ ├── 6_wink.png │ │ │ │ ├── 7_heart_eyes.png │ │ │ │ ├── 8_kissing_heart.png │ │ │ │ └── 9_kissing_closed_eyes.png │ │ │ └── symbol │ │ │ │ ├── 10_ten.png │ │ │ │ ├── 11_x.png │ │ │ │ ├── 12_bangbang.png │ │ │ │ ├── 13_interrobang.png │ │ │ │ ├── 14_exclamation.png │ │ │ │ ├── 15_question.png │ │ │ │ ├── 1_one.png │ │ │ │ ├── 2_two.png │ │ │ │ ├── 3_three.png │ │ │ │ ├── 4_four.png │ │ │ │ ├── 5_five.png │ │ │ │ ├── 6_six.png │ │ │ │ ├── 7_seven.png │ │ │ │ ├── 8_eight.png │ │ │ │ └── 9_zero.png │ │ └── js │ │ │ └── requestAnimationFrame.js │ ├── board.vue │ ├── boardMaps.js │ ├── copyPaste.js │ ├── cursor.js │ ├── emoji.vue │ ├── emojiImages.js │ ├── emojiItem.vue │ ├── eventKeys.js │ ├── index.vue │ ├── input.vue │ ├── inputFilterRegx.js │ ├── lowercaseMemory.js │ ├── memory.js │ ├── mixins │ │ └── btnPress.js │ ├── operation.vue │ ├── tools.js │ └── zh.js ├── main.js └── router │ ├── index.js │ └── routes.js ├── test ├── Tools.spec.js ├── copyPaste.spec.js ├── cursor.spec.js ├── index.vue.base.spec.js ├── index.vue.cn.spec.js ├── index.vue.tab.spec.js ├── input.vue.event.spec.js ├── input.vue.props.spec.js ├── inputFilterRegx.spec.js ├── lowercaseMemory.spec.js └── memory.spec.js ├── webpack.components.js ├── webpack.config.js ├── webpack.demo.js └── webpack.libs.dist.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "presets": [ 4 | ["@babel/preset-env", 5 | { 6 | "useBuiltIns": "usage", 7 | "corejs":3, 8 | "modules": false 9 | } 10 | ] 11 | 12 | ], 13 | "env":{ 14 | "test":{ 15 | "plugins":[ 16 | "@babel/plugin-transform-modules-commonjs", 17 | [ 18 | "istanbul", 19 | { 20 | "useInlinesSourceMaps":true, 21 | "exclude":[ 22 | "**/*.spec.js" 23 | ] 24 | } 25 | ] 26 | ] 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | /coverage 5 | /.nyc_output 6 | .nyc_output 7 | 8 | # local env files 9 | .env.local 10 | .env.*.local 11 | 12 | # Log files 13 | npm-debug.log* 14 | yarn-debug.log* 15 | yarn-error.log* 16 | pnpm-debug.log* 17 | 18 | # Editor directories and files 19 | .idea 20 | .vscode 21 | *.suo 22 | *.ntvs* 23 | *.njsproj 24 | *.sln 25 | *.sw? 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-keyboard-cn 2 | - Provide custom input elements 3 | - Provide Chinese input keyboard 4 | - Provide English input keyboard 5 | - Provide numeric input keyboard 6 | - Only supports mobile web pages 7 | - Friendly to horizontal screen apps 8 | - [demo](https://mtttm.github.io/vue-keyboard-cn/#/home) 9 | - [中文wiki](https://github.com/MTTTM/vue-keyboard-cn/wiki) 10 | 11 | ## Installation 12 | 13 | ```javascript 14 | 15 | npm i vue-keyboard-cn 16 | 17 | ``` 18 | 19 | ### Usage 20 | 21 | *** 22 | 23 | #### main.js 24 | 25 | ```javascript 26 | import { KyInput, KyBoard,KeyboardAwareScrollView } from "vue-keyboard-cn"; 27 | import "vue-keyboard-cn/dist/index.css" 28 | Vue.component("ky-input",KyInput) 29 | Vue.component("key-board",KyBoard) 30 | Vue.component("key-board-aware-scroll-view", KeyboardAwareScrollView) 31 | 32 | ``` 33 | 34 | #### demo.vue 35 | 36 | ```javascript 37 | 38 | 39 | 45 | 46 | 62 | 63 | 64 | 65 | 66 | 67 | ``` 68 | 69 | ## props 70 | 71 | *** 72 | 73 | ### kyInput 74 | | key | desc | default | required | 75 | | -------------- | ------------------------------------------------------------------------ | -------- | -------- | 76 | | type | Any one of [int,float,cn,en,mix] | mix | FALSE | 77 | | decimal | It will only take effect when the type is float | 2 | FALSE | 78 | | regx | a regular object of literal | -- | FALSE | 79 | | allowEnter | Can enter | FALSE | FALSE | 80 | | keyBoard | Keyboard component $ref | -- | FALSE | 81 | | canSwitchOtherBoard | Can switch other keyboards | TRUE | FALSE | 82 | | inputLang | Keyboard display input method, cn or en can be selected | cn | FALSE | 83 | | showFixedInput | Whether to display the input box fixed at the bottom of the keyboard - | FALSE | FALSE | 84 | | placeholder | placeholder Text | --- | FALSE | 85 | | docBodyAutoScroll | Whether to trigger the body to scroll, let the input enter the visual area | TRUE | FALSE | 86 | | scrollWrap | Selector for scrollable dom container, replace document body scroll,like "#box",only work when you set props rotate | -- | FALSE | 87 | | rotate | Horizontal screen app rotation angle,Choose between [0,90,-90].Only for horizontal screen app | -- | FALSE | 88 | 89 | 90 | ### keyBoard 91 | | key | desc | default | required | 92 | | -------------- | ------------------------------------------------------------------------ | -------- | -------- | 93 | | emojiMap | Emoji data [reference](https://github.com/MTTTM/vue-keyboard-cn/blob/main/src/dev/emojiImages.js]) | -- | FALSE | 94 | | disabledInputUpdateMixKeyBoardLang | Prohibit the input component from switching input methods | FALSE | FALSE | 95 | | keyBoardMaps | Keyboard table of contents [reference](https://github.com/MTTTM/vue-keyboard-cn/blob/main/src/dev/boardMaps.js) | object | FALSE | 96 | | hideHead | hide top tab header | FALSE | FALSE | 97 | | rotate | Horizontal screen app rotation angle,Choose between [0,90,-90] | FALSE | FALSE | 98 | 99 | 100 | ## Events 101 | 102 | *** 103 | 104 | ### keyBoard 105 | 106 | #### @show 107 | 108 | - params 109 | 110 | ``` javascript 111 | { 112 | show:true, 113 | el:dom 114 | } 115 | ``` 116 | 117 | ### kyInput 118 | 119 | - @submit 120 | - @input 121 | - @blur 122 | - @focus 123 | 124 | 125 | 126 | ## slots 127 | 128 | *** 129 | 130 | ### kyInput 131 | 132 | - prepend 133 | - append 134 | - prependFixed 135 | - appendFixed 136 | 137 | ## Select input content 138 | 139 | *** 140 | 141 | ```html 142 | 143 | 144 | 145 | ``` 146 | 147 | ```javascript 148 | 149 | this.$refs["inputElement"].select(); 150 | this.$refs["inputElement"].unSelect(); 151 | 152 | ``` 153 | 154 | ## Q&A 155 | 156 | *** 157 | 158 | - Q:The input box is covered by the keyboard 159 | - A:Use KeyboardAwareScrollView component to wrap form elements 160 | 161 | - Q:Scrollable container is not a body node 162 | - A:The input component should use the props scrollWrap.Only in this way will the input component appear in the visual area when the keyboard is processed 163 | - Q:What to do if the app is a horizontal screen app.May be you like it [vue-horizontal-screen](https://www.npmjs.com/package/vue-horizontal-screen) 164 | - A:Add the props rotate to the KyInput element,and add the props isHscreenApp to KyBoard element 165 | 166 | 167 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-slate -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "inputElement":"./packages/exportKbInput.js", 3 | "keyBoardElement":"./packages/exportKbBoard.js" 4 | } -------------------------------------------------------------------------------- /demo/imgs/001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/demo/imgs/001.png -------------------------------------------------------------------------------- /demo/imgs/002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/demo/imgs/002.png -------------------------------------------------------------------------------- /demo/imgs/003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/demo/imgs/003.png -------------------------------------------------------------------------------- /demo/imgs/004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/demo/imgs/004.png -------------------------------------------------------------------------------- /demo/imgs/005.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/demo/imgs/005.png -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-slate -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/docs/favicon.ico -------------------------------------------------------------------------------- /docs/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/docs/iconfont.ttf -------------------------------------------------------------------------------- /docs/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/docs/iconfont.woff -------------------------------------------------------------------------------- /docs/iconfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/docs/iconfont.woff2 -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue-keyboard-cn example 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/favicon.ico -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue-keyboard-cn example 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | var webpackConfig = require('./webpack.config.js') 2 | 3 | module.exports = function(config) { 4 | config.set({ 5 | frameworks: ['mocha'], 6 | 7 | files: [ 8 | 'test/**/*.spec.js', 9 | // 'src/dev/**/*.js', 10 | // 'src/dev/**/*.vue' 11 | ], 12 | /** 13 | * 我们用到了babel-plugin-istanbul 14 | * 它要求不要再这里加coverage,因为它已经集成了, 15 | * 如果再添加corverage,会修改原来的打桩, 16 | * 导致打桩代码无法找到原来的对象 17 | * https://github.com/istanbuljs/babel-plugin-istanbul 18 | */ 19 | preprocessors: { 20 | '**/*.spec.js': ['webpack', 'sourcemap'], 21 | 'src/dev/**/*.js':['webpack', 'sourcemap',], 22 | 'src/dev/**/*.vue':['webpack', 'sourcemap'], 23 | }, 24 | webpack: webpackConfig, 25 | 26 | reporters: ['progress', 'coverage'], 27 | coverageReporter: { 28 | type : 'html', 29 | dir : 'coverage/' 30 | }, 31 | 32 | browsers: ['Chrome'], 33 | singleRun:true 34 | }) 35 | } 36 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-keyboard-cnxx", 3 | "description": "vue virtual keyboard for wap", 4 | "version": "0.0.2", 5 | "author": "MTTTM", 6 | "license": "MIT", 7 | "private": false, 8 | "files": [ 9 | "dist" 10 | ], 11 | "main": "./dist/index.es.min.js", 12 | "keywords": [ 13 | "vue", 14 | "keyboard", 15 | "virtual", 16 | "keyboard-key", 17 | "virtual keyboard" 18 | ], 19 | "scripts": { 20 | "dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot --host 0.0.0.0", 21 | "build": "cross-env NODE_ENV=production webpack --progress --hide-modules", 22 | "test": "cross-env BABEL_ENV=test nyc --reporter=lcov --reporter=text karma start", 23 | "coverage": "nyc report --reporter=text-lcov | coveralls", 24 | "distDemo": "cross-env NODE_ENV=production webpack --config webpack.demo.js", 25 | "distLibs": "cross-env NODE_ENV=production webpack --config webpack.components.js", 26 | "dist": "cross-env NODE_ENV=production webpack --config webpack.libs.dist.js" 27 | }, 28 | "dependencies": { 29 | "@babel/core": "^7.14.3", 30 | "@babel/preset-env": "^7.14.2", 31 | "core-js": "^3.13.1", 32 | "disable-body-scroll": "^0.1.6", 33 | "html-webpack-plugin": "^2.24.1", 34 | "node-sass": "^4.14.1", 35 | "sass": "^1.34.0", 36 | "vue": "^2.5.11", 37 | "vue-horizontal-screen": "^0.1.18", 38 | "vue-router": "^3.5.1" 39 | }, 40 | "browserslist": [ 41 | "> 1%", 42 | "last 2 versions", 43 | "not ie <= 8" 44 | ], 45 | "devDependencies": { 46 | "@babel/plugin-transform-modules-commonjs": "^7.14.0", 47 | "@vue/test-utils": "^1.0.0-beta.10", 48 | "babel-core": "^7.0.0-bridge.0", 49 | "babel-loader": "^7.1.2", 50 | "babel-plugin-istanbul": "^4.1.6", 51 | "babel-preset-env": "^1.6.0", 52 | "babel-preset-stage-3": "^6.24.1", 53 | "chai": "^4.1.2", 54 | "cross-env": "^5.1.3", 55 | "css-loader": "^0.28.7", 56 | "extract-text-webpack-plugin": "^3.0.2", 57 | "file-loader": "^1.1.4", 58 | "karma": "^2.0.0", 59 | "karma-chai": "^0.1.0", 60 | "karma-chrome-launcher": "^2.2.0", 61 | "karma-coverage": "^1.1.1", 62 | "karma-mocha": "^1.3.0", 63 | "karma-sourcemap-loader": "^0.3.7", 64 | "karma-spec-reporter": "0.0.32", 65 | "karma-webpack": "^2.0.9", 66 | "mocha": "^5.0.0", 67 | "nyc": "^15.1.0", 68 | "optimize-css-assets-webpack-plugin": "^3.2.0", 69 | "sass-loader": "^7.3.1", 70 | "vue-loader": "^13.0.5", 71 | "vue-template-compiler": "^2.4.4", 72 | "webpack": "^3.6.0", 73 | "webpack-dev-server": "^2.9.1" 74 | }, 75 | "nyc": { 76 | "include": [ 77 | "src/dev/**/*.js", 78 | "src/dev/**/*.vue" 79 | ], 80 | "sourceMap": false, 81 | "instrument": false 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /packages/exportKbBoard.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 单独打包keyboard组件 3 | */ 4 | import KbBoard from "../src/dev/index.vue"; 5 | KbBoard.install = function(Vue) { 6 | Vue.component('kb-Board', KbBoard) 7 | } 8 | export default KbBoard; 9 | -------------------------------------------------------------------------------- /packages/exportKbInput.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * 单独打包kbinput组件 4 | */ 5 | import KbInput from '../src/dev/input.vue'; 6 | KbInput.install = function(Vue) { 7 | Vue.component('kb-Input', KbInput) 8 | } 9 | export default KbInput 10 | -------------------------------------------------------------------------------- /packages/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * npm包入口文件 3 | */ 4 | import KyInputComponent from '../src/dev/input.vue'; 5 | import KyBoardComponent from "../src/dev/index.vue"; 6 | require("../src/dev/assets/js/requestAnimationFrame.js"); 7 | export const KyInput = KyInputComponent; 8 | export const KyBoard = KyBoardComponent; 9 | export default { 10 | KyInput, 11 | KyBoard 12 | } -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 48 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /src/assets/dissableBodyScroll.js: -------------------------------------------------------------------------------- 1 | 2 | let isScrolledToBottom = (dom) => dom.scrollHeight <= (dom.scrollTop + dom.offsetHeight); 3 | let isScrolledToTop = (dom) => dom.scrollTop === 0; 4 | var ua = navigator.userAgent.toLowerCase(); 5 | let isIpad = ua.match(/ipad/i) == "ipad" 6 | /** 7 | * @params dom {dom} 8 | * @params swipeDir {string} top|bottom 手指滑动方向 9 | * **/ 10 | function disabledDefault(dom, swipeDir = "moveToTop") { 11 | console.log("dir", swipeDir, "isScrolledToTop", isScrolledToTop(dom), 'isScrolledToBottom', isScrolledToBottom(dom)) 12 | console.log("isScrollBottom", dom.scrollHeight, (dom.scrollTop + dom.offsetHeight)) 13 | if (swipeDir == "moveToBottom" && isScrolledToTop(dom)) { 14 | return true; 15 | } 16 | else if (swipeDir == "moveToTop" && isScrolledToBottom(dom)) { 17 | return true; 18 | } 19 | else { 20 | return false; 21 | } 22 | } 23 | function removeDocumentStartEvent(el) { 24 | el.removeEventListener("touchstart", el.$documentTouchStart); 25 | el.removeEventListener("mousemove", el.$movefunction) 26 | el.removeEventListener("mouseup", el.$upFunction) 27 | } 28 | /** 29 | * 30 | * @param {*} dom model scroll dom 31 | */ 32 | export const disabledBodyScroll = function (dom, binding) { 33 | let rotate = binding.value; 34 | let status = binding.arg === 'disabled' ? 'disabled' : 'working'; 35 | console.log("status", status) 36 | let startY = 0; 37 | let startX = 0; 38 | function fixEvent(e) { 39 | let position = {}; 40 | if (e.targetTouches && e.targetTouches[0]) { 41 | // var rect = dom.getBoundingClientRect(); 42 | var x = e.targetTouches[0].pageX //- rect.left; 43 | var y = e.targetTouches[0].pageY// - rect.top; 44 | position = { 45 | offsetX: x, 46 | offsetY: y, 47 | e: e 48 | } 49 | } 50 | else { 51 | position = { 52 | offsetX: e.offsetX, 53 | offsetY: e.offsetY, 54 | e: e 55 | } 56 | } 57 | return position; 58 | } 59 | function movefunction(e) { 60 | e.stopPropagation(); 61 | let position = fixEvent(e); 62 | let disY = position.offsetY - startY; 63 | let disX = position.offsetX - startX; 64 | //dir是手指滑动方向 65 | let dir = disY < 0 ? "moveToTop" : "moveToBottom"; 66 | console.log("rotate", rotate) 67 | //一定要画图,或者看了demo再确定 68 | if (rotate == 90) { 69 | dir = disX > 0 ? "moveToTop" : "moveToBottom"; 70 | console.log("90") 71 | } 72 | else if (rotate == -90) { 73 | console.log("-90") 74 | dir = disX < 0 ? "moveToTop" : "moveToBottom"; 75 | } 76 | let disabled = disabledDefault(dom, dir); 77 | console.log("dir!!!!====", dir, "disY", disY, "disabled", disabled) 78 | //status为working情况下才考虑是否执行 79 | if (status === 'working' && disabled && e.cancelable) { 80 | e.preventDefault(); 81 | } 82 | 83 | } 84 | function upFunction(e) { 85 | e.stopPropagation(); 86 | dom.removeEventListener("mousemove", dom.$movefunction) 87 | dom.removeEventListener("mouseup", dom.$upFunction) 88 | } 89 | function documentTouchStart(e) { 90 | e.stopPropagation(); 91 | 92 | //It needs to grab the priority of the scrollable body at ipad 93 | //其实就这一个步骤就可以通过主动触发滚动元素的滚动,来阻止触发外部滚动 94 | // if (dom && dom.style && dom.style.display !== "none" && scrollOnePxWhenTouch) { 95 | // if (isScrolledToBottom(dom)) { 96 | // dom.scrollBy(0, -1) 97 | // } 98 | // else if (isScrolledToTop(dom)) { 99 | // dom.scrollBy(0, 1) 100 | // } 101 | // } 102 | let position = fixEvent(e); 103 | startY = position.offsetY; 104 | startX = position.offsetX; 105 | dom.addEventListener("touchmove", dom.$movefunction, false) 106 | dom.addEventListener("touchend", dom.$upFunction, false) 107 | } 108 | dom.$movefunction = movefunction; 109 | dom.$upFunction = upFunction; 110 | dom.$documentTouchStart = documentTouchStart 111 | dom.addEventListener("touchstart", dom.$documentTouchStart, false); 112 | } 113 | export const directive = { 114 | bind: disabledBodyScroll,//v2 115 | beforeMount: disabledBodyScroll,//v3 116 | unbind: removeDocumentStartEvent,//v2 117 | unmounted: removeDocumentStartEvent//v3 118 | } -------------------------------------------------------------------------------- /src/assets/js/ueHorizontalScreen.js: -------------------------------------------------------------------------------- 1 | export var getDir = function () { return document.documentElement.clientWidth > document.documentElement.clientHeight ? 1 : 0 }; export var isMobile = function () { var t = navigator.userAgent.toLowerCase(), e = "ontouchstart" in window && "ontouchstart" in document; return !(!/mobile/i.test(t) && !e) }; var dispatch = function (t, e, n) { void 0 === n && (n = null), t.data = { data: e }, n ? 1 == n.nodeType && "function" == typeof n.dispatchEvent && n.dispatchEvent(t) : window.dispatchEvent(t) }; function fixParamsRotate(t) { return [90, -90].indexOf(t) > -1 ? t : 90 } function createEvent(t) { var e = document.createEvent("HTMLEvents"); return e.initEvent(t, !1, !0), e } function eventFix(t) { return t.touches ? t.targetTouches[0] : t || window.event } function preventDefault(t, e) { t && t.$prevent && e.preventDefault() } function stopPropagation(t, e) { t && t.$stop && e.stopPropagation() } function fnStartParams(t, e) { return void 0 === t && (t = {}), function (n) { stopPropagation(e, n), preventDefault(e, n); var i = eventFix(n); t.startX = i.clientX, t.startY = i.clientY, t.disX = 0, t.disY = 0, t.disc = t.distance } } function fnMoveParams(t, e) { return void 0 === t && (t = {}), function (n) { stopPropagation(e, n), preventDefault(e, n); var i = eventFix(n), o = i.clientX, a = i.clientY; t.disX = o - t.startX, t.disY = a - t.startY } } function fnEndParams(t, e, n, i, o) { void 0 === t && (t = ""), void 0 === e && (e = {}), void 0 === n && (n = {}); var a = { win: function (t, e) { n[t] && n[t] instanceof Event ? dispatch(n[t], e) : console.error("events [" + t + "] of window is no reigstered") }, doms: function (t, e) { i(e, o) } }, r = function (e, n) { var i = n.disY, o = n.disX, r = n.rotate, s = n.isHsAdapetAndMobile, d = 0; d = "swipeLeft" == e || "swipeRight" == e ? s ? Math.abs(i) : Math.abs(o) : s ? Math.abs(o) : Math.abs(i), a[t](e, { dis: d, type: e, rotate: r }) }; return function (t) { stopPropagation(o, t), preventDefault(o, t); var n = e, i = n.disY, a = n.distance, s = n.disX, d = n.rotate, c = getDir(), v = Object.assign({}, e, { isHsAdapetAndMobile: 1 !== c && isMobile() }); if (1 != c && isMobile()) { var u = ""; i < 0 && i < -a ? u = 90 === d ? "swipeLeft" : "swipeRight" : i > 0 && i > a && (u = 90 === d ? "swipeRight" : "swipeLeft"), u && r(u, v); var p = ""; s < 0 && s < -a ? p = 90 === d ? "swipeBottom" : "swipeTop" : s > 0 && s > a && (p = 90 === d ? "swipeTop" : "swipeBottom"), p && r(p, v) } else i < 0 && i < -a ? r("swipeTop", v) : i > 0 && i > a && r("swipeBottom", v), s < 0 && s < -a ? r("swipeLeft", v) : s > 0 && s > a && r("swipeRight", v) } } function hsLayoutFunc(t, e) { void 0 === t && (t = {}); var n = t, i = n.oneTimesWidth, o = n.oneTimesHeight, a = n.cssVar, r = n.setWrapAttr, s = n.adaptEvent, d = n.adaptedCallback, c = n.el, v = n.binding, u = n.vnode, p = n.rotate, w = window.innerWidth, f = window.innerHeight, m = (w > f ? w : f) / i, l = !isMobile(), h = v.instance ? v.instance : u.context; c.$hsAdapted = !1, 1 == getDir() || l ? m * o > f && (m = f / o) : m * o > w && (m = w / o), document.querySelector("html").style.setProperty("--" + a, m), null != window.orientation && 180 !== window.orientation && 0 !== window.orientation || l ? (90 === window.orientation || -90 === window.orientation || l) && (c.style.webkitTransform = c.style.transform = "rotate(0)", r && (c.style.width = w + "px", c.style.height = f + "px")) : (c.style.webkitTransform = c.style.transform = "rotate(" + p + "deg)", 90 == p ? c.style.webkitTransformOrigin = c.style.transformOrigin = w / 2 + "px center" : -90 == p && (c.style.webkitTransformOrigin = c.style.transformOrigin = " center " + f / 2 + "px"), r && (c.style.width = f + "px", c.style.height = w + "px")), c.$hsAdapted = !0, !1 !== e && (dispatch(s, c.$hsAdapted), "function" == typeof d ? d(c, !0) : h && "function" == typeof h[d] && h[d](c, !0)) } function directiveBindfunction(t, e, n) { var i = e.value, o = i.cssVar, a = i.width, r = i.height, s = i.times, d = i.triggerTime, c = i.AdaptEventName, v = i.setWrapAttr, u = i.adaptedCallback, p = i.rotate; p = fixParamsRotate(p), s || (s = 1, console.warn("times is required!!")); var w = a / s, f = r / s; o || (o = "hs-var"), c || (c = "hsAdapt"), d || (d = 1e3), "setWrapAttr" in e.value || (v = !0); var m, l = { oneTimesWidth: w, oneTimesHeight: f, el: t, cssVar: o, setWrapAttr: v, adaptEvent: createEvent(c), adaptedCallback: u, binding: e, vnode: n, rotate: p }; t.$hsLayout = function (t) { void 0 === t && (t = !1), hsLayoutFunc(l, t) }, t.$delayLayout = function (t) { void 0 === t && (t = !1), clearTimeout(m), m = setTimeout((function () { return hsLayoutFunc(l, t) }), d) }, t.$hsAdapted = !1, t.$hsLayout(!1), "onorientationchange" in window ? (window.removeEventListener("orientationchange", t.$delayLayout), window.addEventListener("orientationchange", t.$delayLayout, !1)) : (window.removeEventListener("resize", t.$hsLayout), window.addEventListener("resize", t.$hsLayout, !1)) } function directiveUnBind(t) { window.removeEventListener("resize", t.$hsLayout), window.removeEventListener("orientationchange", t.$delayLayout), t.$hsLayout = null } function directiveForDomfunction(t, e) { var n = e.value, i = e.modifiers, o = i.stop, a = i.prevent, r = i.clockwise, s = 90; i.counterclockwise ? s = -90 : r && (s = 90); var d = { startX: 0, startY: 0, disX: 0, distance: 1, rotate: s }; t.$stop = o, t.$prevent = a; var c = fnStartParams(d, t), v = fnMoveParams(d, t), u = fnEndParams("doms", d, {}, n, t); isMobile() ? (t.addEventListener("touchstart", c, !1), t.addEventListener("touchmove", v, !1), t.addEventListener("touchend", u, !1)) : (t.addEventListener("mousedown", c, !1), t.addEventListener("mousemove", v, !1), t.addEventListener("mouseup", u, !1)) } export var directive = { bind: directiveBindfunction, unbind: directiveUnBind, beforeMount: directiveBindfunction, unmounted: directiveUnBind }; export var directiveForDom = { bind: directiveForDomfunction, beforeMount: directiveForDomfunction }; var eventInited = !1; export var event = function (t) { if (void 0 === t && (t = { distance: 50, pre: "" }), !eventInited) { var e = t, n = e.pre, i = e.distance, o = e.rotate; n = n || ""; var a = { startX: 0, startY: 0, disX: 0, distance: i = i || 50, rotate: o = fixParamsRotate(o) }, r = { swipeLeft: createEvent(n + "swipeLeft"), swipeRight: createEvent(n + "swipeRight"), swipeTop: createEvent(n + "swipeTop"), swipeBottom: createEvent(n + "swipeBottom") }; isMobile() ? (window.addEventListener("touchstart", fnStartParams(a), !1), window.addEventListener("touchmove", fnMoveParams(a), !1), window.addEventListener("touchend", fnEndParams("win", a, r), !1)) : (window.addEventListener("mousedown", fnStartParams(a), !1), window.addEventListener("mousemove", fnMoveParams(a), !1), window.addEventListener("mouseup", fnEndParams("win", a, r), !1)), eventInited = !0 } }; -------------------------------------------------------------------------------- /src/demo/Customkeyboard.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 65 | 66 | 72 | -------------------------------------------------------------------------------- /src/demo/KeyboardAwareScrollView1.vue: -------------------------------------------------------------------------------- 1 | 134 | 135 | 175 | 176 | 198 | -------------------------------------------------------------------------------- /src/demo/KeyboardAwareScrollView2.vue: -------------------------------------------------------------------------------- 1 | 134 | 135 | 178 | 179 | 201 | -------------------------------------------------------------------------------- /src/demo/KeyboardAwareScrollView3.vue: -------------------------------------------------------------------------------- 1 | 124 | 125 | 168 | 169 | 171 | -------------------------------------------------------------------------------- /src/demo/adaptiveHeight.vue: -------------------------------------------------------------------------------- 1 | 44 | 45 | 84 | 85 | 91 | -------------------------------------------------------------------------------- /src/demo/breakWrap.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 51 | 52 | 58 | -------------------------------------------------------------------------------- /src/demo/canSwitchOtherBoard.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 55 | 56 | 62 | -------------------------------------------------------------------------------- /src/demo/customKeyboardMap/boardMaps.js: -------------------------------------------------------------------------------- 1 | 2 | const textMap=(lan="cn")=>{ 3 | //  4 | let t=[ 5 | [ 6 | { 7 | text: "Q", 8 | isText: true 9 | }, 10 | { 11 | text: "W", 12 | isText: true 13 | }, 14 | { 15 | text: "E", 16 | isText: true 17 | }, 18 | { 19 | text: "R", 20 | isText: true 21 | }, 22 | { 23 | text: "T", 24 | isText: true 25 | }, 26 | { 27 | text: "Y", 28 | isText: true 29 | }, 30 | { 31 | text: "U", 32 | isText: true 33 | }, 34 | { 35 | text: "I", 36 | isText: true 37 | }, 38 | { 39 | text: "O", 40 | isText: true 41 | }, 42 | { 43 | text: "P", 44 | isText: true 45 | } 46 | ], 47 | [ 48 | { 49 | text: "A", 50 | isText: true 51 | }, 52 | { 53 | text: "S", 54 | isText: true 55 | }, 56 | { 57 | text: "D", 58 | isText: true 59 | }, 60 | { 61 | text: "F", 62 | isText: true 63 | }, 64 | { 65 | text: "G", 66 | isText: true 67 | }, 68 | { 69 | text: "H", 70 | isText: true 71 | }, 72 | { 73 | text: "J", 74 | isText: true 75 | }, 76 | { 77 | text: "K", 78 | isText: true 79 | }, 80 | { 81 | text: "L", 82 | isText: true 83 | } 84 | ], 85 | [ 86 | { 87 | hideText:true, 88 | isBigBtn:true, 89 | classString:"icon iconfont icon-editor-to-lowercase", 90 | activeClassString:"icon iconfont icon-editor-to-capitalize", 91 | text: "大写", 92 | operate: "changeCapital", 93 | }, 94 | { 95 | text: "Z", 96 | isText: true 97 | }, 98 | { 99 | text: "X", 100 | isText: true 101 | }, 102 | { 103 | text: "C", 104 | isText: true 105 | }, 106 | { 107 | text: "V", 108 | isText: true 109 | }, 110 | { 111 | text: "B", 112 | isText: true 113 | }, 114 | { 115 | text: "N", 116 | isText: true 117 | }, 118 | { 119 | text: "M", 120 | isText: true 121 | }, 122 | { 123 | text: "删除", 124 | isBigBtn:true, 125 | classString:"icon iconfont icon-delete", 126 | hideText:true, 127 | operate: "delete" 128 | } 129 | ], 130 | [ 131 | { 132 | text: "!?#", 133 | operate: "symbol" 134 | }, 135 | { 136 | text: "123", 137 | operate: "changeNumber" 138 | }, 139 | { 140 | text: function(){ 141 | return lan=='cn'?',':',' 142 | }, 143 | }, 144 | { 145 | text: " ",//解析html时候会有问题 146 | otherText:"space", 147 | classString:"icon iconfont icon-Spacebar", 148 | hideText:true 149 | }, 150 | { 151 | text: function(){ 152 | return lan=='cn'?'。':'.' 153 | }, 154 | }, 155 | { 156 | operate: "changeLan", 157 | classString:"icon iconfont icon-theearth2diqiu", 158 | }, 159 | { 160 | text:"\r\n", 161 | otherText:"enter", 162 | hideText:true, 163 | classString:"icon iconfont icon-enter", 164 | 165 | } 166 | ] 167 | ] 168 | return t; 169 | } 170 | export default { 171 | cnMap: textMap("cn"), 172 | enMap:textMap("en"), 173 | cnSymbolMap: [ 174 | [ 175 | { 176 | text: "【" 177 | }, 178 | { 179 | text: "】" 180 | }, 181 | { 182 | text: "{" 183 | }, 184 | { 185 | text: "}" 186 | }, 187 | { 188 | text: "#" 189 | }, 190 | { 191 | text: "%" 192 | }, 193 | { 194 | text: "^" 195 | }, 196 | { 197 | text: "*" 198 | }, 199 | { 200 | text: "+" 201 | }, 202 | { 203 | text: "=" 204 | } 205 | ], 206 | [ 207 | { 208 | text: ":" 209 | }, 210 | { 211 | text: "-" 212 | }, 213 | { 214 | text: "\\" 215 | }, 216 | { 217 | text: "|" 218 | }, 219 | { 220 | text: "~" 221 | }, 222 | { 223 | text: "@" 224 | }, 225 | { 226 | text: "《" 227 | }, 228 | { 229 | text: "》" 230 | }, 231 | { 232 | text: "¥" 233 | }, 234 | { 235 | text: "&" 236 | }, 237 | 238 | ], 239 | [ 240 | { 241 | text: "(", 242 | }, 243 | { 244 | text: ")", 245 | }, 246 | { 247 | text: "·" 248 | }, 249 | { 250 | text: "?" 251 | }, 252 | { 253 | text: "!" 254 | }, 255 | { 256 | text: "“" 257 | }, 258 | { 259 | text: "”" 260 | }, 261 | { 262 | text: "delete", 263 | classString:"icon iconfont icon-delete", 264 | hideText:true, 265 | isBigBtn:true, 266 | operate: "delete" 267 | } 268 | ], 269 | [ 270 | { 271 | text: "返回", 272 | hideText:true, 273 | classString:"icon iconfont icon-back", 274 | operate: "back" 275 | }, 276 | { 277 | text: "," 278 | }, 279 | { 280 | text: "。" 281 | }, 282 | { 283 | text:"\r\n", 284 | otherText:"enter", 285 | hideText:true, 286 | classString:"icon iconfont icon-enter" 287 | 288 | } 289 | ] 290 | ], 291 | enSymbolMap: [ 292 | [ 293 | { 294 | text: "[" 295 | }, 296 | { 297 | text: "]" 298 | }, 299 | { 300 | text: "{" 301 | }, 302 | { 303 | text: "}" 304 | }, 305 | { 306 | text: "#" 307 | }, 308 | { 309 | text: "%" 310 | }, 311 | { 312 | text: "^" 313 | }, 314 | { 315 | text: "*" 316 | }, 317 | { 318 | text: "+" 319 | }, 320 | { 321 | text: "=" 322 | } 323 | ], 324 | [ 325 | { 326 | text: "_" 327 | }, 328 | { 329 | text: "-" 330 | }, 331 | { 332 | text: "\\" 333 | }, 334 | { 335 | text: "|" 336 | }, 337 | { 338 | text: "~" 339 | }, 340 | { 341 | text: "@" 342 | }, 343 | { 344 | text: "<" 345 | }, 346 | { 347 | text: ">" 348 | }, 349 | { 350 | text: "$" 351 | }, 352 | { 353 | text: "/" 354 | }, 355 | { 356 | text: "&" 357 | } 358 | ], 359 | [ 360 | { 361 | text: "(", 362 | }, 363 | { 364 | text: ")", 365 | }, 366 | { 367 | text: ":" 368 | }, 369 | { 370 | text: "?" 371 | }, 372 | { 373 | text: "!" 374 | }, 375 | { 376 | text: "\"" 377 | }, 378 | { 379 | text: "\"" 380 | }, 381 | { 382 | text: "delete", 383 | classString:"icon iconfont icon-delete", 384 | hideText:true, 385 | isBigBtn:true, 386 | operate: "delete" 387 | } 388 | ], 389 | [ 390 | { 391 | text: "返回", 392 | hideText:true, 393 | classString:"icon iconfont icon-back", 394 | operate: "back" 395 | }, 396 | 397 | { 398 | text: "," 399 | }, 400 | { 401 | text: "." 402 | }, 403 | { 404 | text:"\r\n", 405 | otherText:"enter", 406 | hideText:true, 407 | classString:"icon iconfont icon-enter" 408 | } 409 | ] 410 | ], 411 | numberMap: [ 412 | [ 413 | { 414 | text: 1 415 | }, 416 | { 417 | text: 2 418 | }, 419 | { 420 | text: 3 421 | }, 422 | { 423 | text: "delete", 424 | classString:"icon iconfont icon-delete", 425 | hideText:true, 426 | operate: "delete" 427 | } 428 | ], 429 | [ 430 | { 431 | text: 4 432 | }, 433 | { 434 | text: 5 435 | }, 436 | { 437 | text: 6 438 | }, 439 | { 440 | text: "." 441 | } 442 | ], 443 | [ 444 | 445 | { 446 | text: 7 447 | }, 448 | { 449 | text: 8 450 | }, 451 | { 452 | text: 9 453 | }, 454 | { 455 | text: "no thing",//解析html时候会有问题 456 | operate: "noThing" 457 | } 458 | ] 459 | ], 460 | }; 461 | -------------------------------------------------------------------------------- /src/demo/disabledInputUpdateMixKeyBoardLang.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 63 | 64 | 70 | -------------------------------------------------------------------------------- /src/demo/event.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 53 | 54 | 60 | -------------------------------------------------------------------------------- /src/demo/hideHead.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 41 | 42 | 48 | -------------------------------------------------------------------------------- /src/demo/horizontalScreen.vue: -------------------------------------------------------------------------------- 1 | 67 | 68 | 112 | 113 | 133 | -------------------------------------------------------------------------------- /src/demo/horizontalScreen2.vue: -------------------------------------------------------------------------------- 1 | 69 | 70 | 117 | 118 | 138 | -------------------------------------------------------------------------------- /src/demo/index.vue: -------------------------------------------------------------------------------- 1 | 25 | -------------------------------------------------------------------------------- /src/demo/inputDisabled.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 49 | 50 | 56 | -------------------------------------------------------------------------------- /src/demo/inputFuncSelect.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 42 | 43 | 49 | -------------------------------------------------------------------------------- /src/demo/inputMaxLength.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 48 | 49 | 55 | -------------------------------------------------------------------------------- /src/demo/inputSlot.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 73 | 74 | 91 | -------------------------------------------------------------------------------- /src/demo/noEmoji.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 46 | 47 | 53 | -------------------------------------------------------------------------------- /src/demo/showFixedInput.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 56 | 57 | 63 | -------------------------------------------------------------------------------- /src/demo/type.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 68 | 69 | 75 | -------------------------------------------------------------------------------- /src/dev/KeyboardAwareScrollView.vue: -------------------------------------------------------------------------------- 1 | 7 | 57 | -------------------------------------------------------------------------------- /src/dev/assets/font/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/font/iconfont.ttf -------------------------------------------------------------------------------- /src/dev/assets/font/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/font/iconfont.woff -------------------------------------------------------------------------------- /src/dev/assets/font/iconfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/font/iconfont.woff2 -------------------------------------------------------------------------------- /src/dev/assets/images/hearts/10_sparkling_heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/hearts/10_sparkling_heart.png -------------------------------------------------------------------------------- /src/dev/assets/images/hearts/11_revolving_hearts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/hearts/11_revolving_hearts.png -------------------------------------------------------------------------------- /src/dev/assets/images/hearts/12_cupid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/hearts/12_cupid.png -------------------------------------------------------------------------------- /src/dev/assets/images/hearts/13_love_letter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/hearts/13_love_letter.png -------------------------------------------------------------------------------- /src/dev/assets/images/hearts/14_kiss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/hearts/14_kiss.png -------------------------------------------------------------------------------- /src/dev/assets/images/hearts/15_ring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/hearts/15_ring.png -------------------------------------------------------------------------------- /src/dev/assets/images/hearts/16_gem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/hearts/16_gem.png -------------------------------------------------------------------------------- /src/dev/assets/images/hearts/1_yellow_heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/hearts/1_yellow_heart.png -------------------------------------------------------------------------------- /src/dev/assets/images/hearts/2_blue_heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/hearts/2_blue_heart.png -------------------------------------------------------------------------------- /src/dev/assets/images/hearts/3_purple_heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/hearts/3_purple_heart.png -------------------------------------------------------------------------------- /src/dev/assets/images/hearts/4_green_heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/hearts/4_green_heart.png -------------------------------------------------------------------------------- /src/dev/assets/images/hearts/5_heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/hearts/5_heart.png -------------------------------------------------------------------------------- /src/dev/assets/images/hearts/6_broken_heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/hearts/6_broken_heart.png -------------------------------------------------------------------------------- /src/dev/assets/images/hearts/7_heartpulse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/hearts/7_heartpulse.png -------------------------------------------------------------------------------- /src/dev/assets/images/hearts/8_heartbeat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/hearts/8_heartbeat.png -------------------------------------------------------------------------------- /src/dev/assets/images/hearts/9_two_hearts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/hearts/9_two_hearts.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/10_disappointed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/10_disappointed.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/10_kissing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/10_kissing.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/11_kissing_smiling_eyes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/11_kissing_smiling_eyes.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/12_stuck_out_tongue_winking_eye.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/12_stuck_out_tongue_winking_eye.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/13_stuck_out_tongue_closed_eyes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/13_stuck_out_tongue_closed_eyes.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/14_stuck_out_tongue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/14_stuck_out_tongue.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/15_flushed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/15_flushed.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/16_grin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/16_grin.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/17_pensive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/17_pensive.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/18_relieved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/18_relieved.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/19_unamused.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/19_unamused.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/1_smile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/1_smile.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/20_fearful.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/20_fearful.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/20_persevere.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/20_persevere.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/21_cry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/21_cry.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/22_joy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/22_joy.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/23_sob.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/23_sob.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/24_sleepy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/24_sleepy.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/25_cold_sweat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/25_cold_sweat.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/25_disappointed_relieved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/25_disappointed_relieved.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/26_sweat_smile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/26_sweat_smile.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/27_sweat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/27_sweat.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/28_weary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/28_weary.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/29_tired_face.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/29_tired_face.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/2_smiley.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/2_smiley.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/30_scream.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/30_scream.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/31_angry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/31_angry.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/32_rage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/32_rage.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/33_confounded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/33_confounded.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/33_triumph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/33_triumph.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/34_laughing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/34_laughing.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/35_yum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/35_yum.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/36_mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/36_mask.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/37_sunglasses.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/37_sunglasses.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/38_sleeping.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/38_sleeping.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/39_dizzy_face.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/39_dizzy_face.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/3_grinning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/3_grinning.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/40_astonished.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/40_astonished.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/41_worried.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/41_worried.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/42_frowning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/42_frowning.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/43_anguished.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/43_anguished.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/44_neutral_face.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/44_neutral_face.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/45_confused.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/45_confused.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/46_no_mouth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/46_no_mouth.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/47_innocent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/47_innocent.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/48_smirk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/48_smirk.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/49_expressionless.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/49_expressionless.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/4_blush.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/4_blush.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/5_relaxed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/5_relaxed.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/6_wink.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/6_wink.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/7_heart_eyes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/7_heart_eyes.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/8_kissing_heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/8_kissing_heart.png -------------------------------------------------------------------------------- /src/dev/assets/images/person/9_kissing_closed_eyes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/person/9_kissing_closed_eyes.png -------------------------------------------------------------------------------- /src/dev/assets/images/symbol/10_ten.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/symbol/10_ten.png -------------------------------------------------------------------------------- /src/dev/assets/images/symbol/11_x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/symbol/11_x.png -------------------------------------------------------------------------------- /src/dev/assets/images/symbol/12_bangbang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/symbol/12_bangbang.png -------------------------------------------------------------------------------- /src/dev/assets/images/symbol/13_interrobang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/symbol/13_interrobang.png -------------------------------------------------------------------------------- /src/dev/assets/images/symbol/14_exclamation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/symbol/14_exclamation.png -------------------------------------------------------------------------------- /src/dev/assets/images/symbol/15_question.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/symbol/15_question.png -------------------------------------------------------------------------------- /src/dev/assets/images/symbol/1_one.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/symbol/1_one.png -------------------------------------------------------------------------------- /src/dev/assets/images/symbol/2_two.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/symbol/2_two.png -------------------------------------------------------------------------------- /src/dev/assets/images/symbol/3_three.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/symbol/3_three.png -------------------------------------------------------------------------------- /src/dev/assets/images/symbol/4_four.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/symbol/4_four.png -------------------------------------------------------------------------------- /src/dev/assets/images/symbol/5_five.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/symbol/5_five.png -------------------------------------------------------------------------------- /src/dev/assets/images/symbol/6_six.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/symbol/6_six.png -------------------------------------------------------------------------------- /src/dev/assets/images/symbol/7_seven.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/symbol/7_seven.png -------------------------------------------------------------------------------- /src/dev/assets/images/symbol/8_eight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/symbol/8_eight.png -------------------------------------------------------------------------------- /src/dev/assets/images/symbol/9_zero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/c81ffbeeb40cf7a5bef38d05ecdc3fad274d37e2/src/dev/assets/images/symbol/9_zero.png -------------------------------------------------------------------------------- /src/dev/assets/js/requestAnimationFrame.js: -------------------------------------------------------------------------------- 1 | //来之:https://github.com/darius/requestAnimationFrame 2 | if (!Date.now) 3 | Date.now = function () { return new Date().getTime(); }; 4 | 5 | (function () { 6 | 'use strict'; 7 | let vendors = ['webkit', 'moz']; 8 | for (let i = 0; i < vendors.length && !window.requestAnimationFrame; ++i) { 9 | let vp = vendors[i]; 10 | window.requestAnimationFrame = window[vp + 'RequestAnimationFrame']; 11 | window.cancelAnimationFrame = (window[vp + 'CancelAnimationFrame'] 12 | || window[vp + 'CancelRequestAnimationFrame']); 13 | } 14 | if (/iP(ad|hone|od).*OS 6/.test(window.navigator.userAgent) // iOS6 is buggy 15 | || !window.requestAnimationFrame || !window.cancelAnimationFrame) { 16 | let lastTime = 0; 17 | window.requestAnimationFrame = function (callback) { 18 | let now = Date.now(); 19 | let nextTime = Math.max(lastTime + 16, now); 20 | return setTimeout(function () { callback(lastTime = nextTime); }, 21 | nextTime - now); 22 | }; 23 | window.cancelAnimationFrame = clearTimeout; 24 | } 25 | }()); -------------------------------------------------------------------------------- /src/dev/boardMaps.js: -------------------------------------------------------------------------------- 1 | 2 | const textMap=(lan="cn")=>{ 3 | //  4 | let t=[ 5 | [ 6 | { 7 | text: "Q", 8 | isText: true 9 | }, 10 | { 11 | text: "W", 12 | isText: true 13 | }, 14 | { 15 | text: "E", 16 | isText: true 17 | }, 18 | { 19 | text: "R", 20 | isText: true 21 | }, 22 | { 23 | text: "T", 24 | isText: true 25 | }, 26 | { 27 | text: "Y", 28 | isText: true 29 | }, 30 | { 31 | text: "U", 32 | isText: true 33 | }, 34 | { 35 | text: "I", 36 | isText: true 37 | }, 38 | { 39 | text: "O", 40 | isText: true 41 | }, 42 | { 43 | text: "P", 44 | isText: true 45 | } 46 | ], 47 | [ 48 | { 49 | text: "A", 50 | isText: true 51 | }, 52 | { 53 | text: "S", 54 | isText: true 55 | }, 56 | { 57 | text: "D", 58 | isText: true 59 | }, 60 | { 61 | text: "F", 62 | isText: true 63 | }, 64 | { 65 | text: "G", 66 | isText: true 67 | }, 68 | { 69 | text: "H", 70 | isText: true 71 | }, 72 | { 73 | text: "J", 74 | isText: true 75 | }, 76 | { 77 | text: "K", 78 | isText: true 79 | }, 80 | { 81 | text: "L", 82 | isText: true 83 | } 84 | ], 85 | [ 86 | { 87 | hideText:true, 88 | isBigBtn:true, 89 | classString:"icon iconfont icon-editor-to-lowercase", 90 | activeClassString:"icon iconfont icon-editor-to-capitalize", 91 | text: "大写", 92 | operate: "changeCapital", 93 | }, 94 | { 95 | text: "Z", 96 | isText: true 97 | }, 98 | { 99 | text: "X", 100 | isText: true 101 | }, 102 | { 103 | text: "C", 104 | isText: true 105 | }, 106 | { 107 | text: "V", 108 | isText: true 109 | }, 110 | { 111 | text: "B", 112 | isText: true 113 | }, 114 | { 115 | text: "N", 116 | isText: true 117 | }, 118 | { 119 | text: "M", 120 | isText: true 121 | }, 122 | { 123 | text: "删除", 124 | isBigBtn:true, 125 | classString:"icon iconfont icon-delete", 126 | hideText:true, 127 | operate: "delete" 128 | } 129 | ], 130 | [ 131 | { 132 | text: "!?#", 133 | operate: "symbol" 134 | }, 135 | { 136 | text: "123", 137 | operate: "changeNumber" 138 | }, 139 | { 140 | text: function(){ 141 | return lan=='cn'?',':',' 142 | }, 143 | }, 144 | { 145 | text: " ",//解析html时候会有问题 146 | otherText:"space", 147 | classString:"icon iconfont icon-Spacebar", 148 | hideText:true 149 | }, 150 | { 151 | text: function(){ 152 | return lan=='cn'?'。':'.' 153 | }, 154 | }, 155 | { 156 | operate: "changeLan", 157 | classString:"icon iconfont icon-theearth2diqiu", 158 | }, 159 | { 160 | text:"\r\n", 161 | otherText:"enter", 162 | hideText:true, 163 | classString:"icon iconfont icon-enter", 164 | 165 | } 166 | ] 167 | ] 168 | return t; 169 | } 170 | export default { 171 | cnMap: textMap("cn"), 172 | enMap:textMap("en"), 173 | cnSymbolMap: [ 174 | [ 175 | { 176 | text: "【" 177 | }, 178 | { 179 | text: "】" 180 | }, 181 | { 182 | text: "{" 183 | }, 184 | { 185 | text: "}" 186 | }, 187 | { 188 | text: "#" 189 | }, 190 | { 191 | text: "%" 192 | }, 193 | { 194 | text: "^" 195 | }, 196 | { 197 | text: "*" 198 | }, 199 | { 200 | text: "+" 201 | }, 202 | { 203 | text: "=" 204 | } 205 | ], 206 | [ 207 | { 208 | text: ":" 209 | }, 210 | { 211 | text: "-" 212 | }, 213 | { 214 | text: "\\" 215 | }, 216 | { 217 | text: "|" 218 | }, 219 | { 220 | text: "~" 221 | }, 222 | { 223 | text: "@" 224 | }, 225 | { 226 | text: "《" 227 | }, 228 | { 229 | text: "》" 230 | }, 231 | { 232 | text: "¥" 233 | }, 234 | { 235 | text: "&" 236 | }, 237 | 238 | ], 239 | [ 240 | { 241 | text: "(", 242 | }, 243 | { 244 | text: ")", 245 | }, 246 | { 247 | text: "·" 248 | }, 249 | { 250 | text: "?" 251 | }, 252 | { 253 | text: "!" 254 | }, 255 | { 256 | text: "“" 257 | }, 258 | { 259 | text: "”" 260 | }, 261 | { 262 | text: "delete", 263 | classString:"icon iconfont icon-delete", 264 | hideText:true, 265 | isBigBtn:true, 266 | operate: "delete" 267 | } 268 | ], 269 | [ 270 | { 271 | text: "返回", 272 | hideText:true, 273 | classString:"icon iconfont icon-back", 274 | operate: "back" 275 | }, 276 | { 277 | text: "," 278 | }, 279 | { 280 | text: "。" 281 | }, 282 | { 283 | text:"\r\n", 284 | otherText:"enter", 285 | hideText:true, 286 | classString:"icon iconfont icon-enter" 287 | 288 | } 289 | ] 290 | ], 291 | enSymbolMap: [ 292 | [ 293 | { 294 | text: "[" 295 | }, 296 | { 297 | text: "]" 298 | }, 299 | { 300 | text: "{" 301 | }, 302 | { 303 | text: "}" 304 | }, 305 | { 306 | text: "#" 307 | }, 308 | { 309 | text: "%" 310 | }, 311 | { 312 | text: "^" 313 | }, 314 | { 315 | text: "*" 316 | }, 317 | { 318 | text: "+" 319 | }, 320 | { 321 | text: "=" 322 | } 323 | ], 324 | [ 325 | { 326 | text: "_" 327 | }, 328 | { 329 | text: "-" 330 | }, 331 | { 332 | text: "\\" 333 | }, 334 | { 335 | text: "|" 336 | }, 337 | { 338 | text: "~" 339 | }, 340 | { 341 | text: "@" 342 | }, 343 | { 344 | text: "<" 345 | }, 346 | { 347 | text: ">" 348 | }, 349 | { 350 | text: "$" 351 | }, 352 | { 353 | text: "/" 354 | }, 355 | { 356 | text: "&" 357 | } 358 | ], 359 | [ 360 | { 361 | text: "(", 362 | }, 363 | { 364 | text: ")", 365 | }, 366 | { 367 | text: ":" 368 | }, 369 | { 370 | text: "?" 371 | }, 372 | { 373 | text: "!" 374 | }, 375 | { 376 | text: "\"" 377 | }, 378 | { 379 | text: "\"" 380 | }, 381 | { 382 | text: "delete", 383 | classString:"icon iconfont icon-delete", 384 | hideText:true, 385 | isBigBtn:true, 386 | operate: "delete" 387 | } 388 | ], 389 | [ 390 | { 391 | text: "返回", 392 | hideText:true, 393 | classString:"icon iconfont icon-back", 394 | operate: "back" 395 | }, 396 | 397 | { 398 | text: "," 399 | }, 400 | { 401 | text: "." 402 | }, 403 | { 404 | text:"\r\n", 405 | otherText:"enter", 406 | hideText:true, 407 | classString:"icon iconfont icon-enter" 408 | } 409 | ] 410 | ], 411 | numberMap: [ 412 | [ 413 | { 414 | text: "%" 415 | }, 416 | { 417 | text: 1 418 | }, 419 | { 420 | text: 2 421 | }, 422 | { 423 | text: 3 424 | }, 425 | { 426 | text: "delete", 427 | classString:"icon iconfont icon-delete", 428 | hideText:true, 429 | operate: "delete" 430 | } 431 | ], 432 | [ 433 | { 434 | text: "+" 435 | }, 436 | { 437 | text: "4" 438 | }, 439 | { 440 | text: 5 441 | }, 442 | { 443 | text: 6 444 | }, 445 | { 446 | text: "." 447 | } 448 | ], 449 | [ 450 | { 451 | text: "-" 452 | }, 453 | { 454 | text: 7 455 | }, 456 | { 457 | text: 8 458 | }, 459 | { 460 | text: 9 461 | }, 462 | { 463 | text: "=" 464 | } 465 | ], 466 | [ 467 | { 468 | text: "/" 469 | }, 470 | { 471 | text: "返回", 472 | hideText:true, 473 | classString:"icon iconfont icon-back", 474 | operate: "back" 475 | }, 476 | { 477 | text: "0" 478 | }, 479 | { 480 | text: " ",//解析html时候会有问题 481 | classString:"icon iconfont icon-Spacebar", 482 | hideText:true 483 | }, 484 | { 485 | text:"\r\n", 486 | otherText:"enter", 487 | hideText:true, 488 | classString:"icon iconfont icon-enter" 489 | } 490 | ] 491 | ], 492 | }; 493 | -------------------------------------------------------------------------------- /src/dev/copyPaste.js: -------------------------------------------------------------------------------- 1 | 2 | import EventKeys from "./eventKeys"; 3 | import {labelStringRemoveLabelExceptImg} from "./tools.js" 4 | let hasListenerCopy=false; 5 | let localStorageKey="vue-keyboard-copy"; 6 | 7 | /** 8 | * 保存复制列表 9 | * @param {array} array 10 | * @param {boolean} isClean 11 | */ 12 | export const saveCopyList=(array=[],isClean=false)=>{ 13 | console.log("saveCopyList",array); 14 | try{ 15 | if(array.length||(array.length==0&&isClean)){ 16 | localStorage.setItem( 17 | localStorageKey, 18 | JSON.stringify(array) 19 | ); 20 | } 21 | 22 | }catch(e){ 23 | console.error(e.getMessage()) 24 | } 25 | 26 | } 27 | /** 28 | * 获取复制列表, 29 | * @returns [] 30 | */ 31 | export const getCopyLocalStorage=() =>{ 32 | let copyTextArray=[]; 33 | try { 34 | let store = localStorage.getItem(localStorageKey); 35 | console.log("store",store) 36 | if (store) { 37 | let storeParse = JSON.parse(store); 38 | if (Array.isArray(storeParse)) { 39 | copyTextArray = storeParse.filter(item=>item); 40 | } 41 | } 42 | 43 | } catch (e) { 44 | console.error("解析复制列表不报错",e) 45 | } 46 | return copyTextArray; 47 | }; 48 | /** 49 | * 新增一条 50 | * 并返回结果数组 51 | * @param {*} str 52 | * @returns [] 53 | */ 54 | export const addOne=(str)=>{ 55 | let copylist=getCopyLocalStorage(); 56 | //限制只存20条 57 | if (copylist.length > 20) { 58 | copylist.pop(); 59 | } 60 | console.log("copylist::",copylist) 61 | copylist.unshift(str); 62 | saveCopyList(copylist);//保存 63 | return getCopyLocalStorage(); 64 | } 65 | 66 | /** 67 | * 监听复制 68 | * @param {*} vm 69 | * @returns 70 | */ 71 | export const copyEventListener=(vm)=>{ 72 | if(hasListenerCopy){return;} 73 | document.addEventListener("copy", ()=>{ 74 | let copyedStr= window.getSelection(0).toString(); 75 | if(copyedStr){ 76 | console.log("复制",copyedStr) 77 | addOne(copyedStr); 78 | vm.$root.$emit(EventKeys["vue-keyboard-cn-natice-copy"],copyedStr); 79 | } 80 | 81 | }); 82 | hasListenerCopy=true; 83 | } 84 | /** 85 | * 复制的事件回调(监听原生,或非原生) 86 | * 如果内容已存在,就替换到第一个 87 | * @param {*} str 88 | */ 89 | export const onNaticeCopyEvent=(strx)=>{ 90 | //原生复制的地方就没有携带标签,不知道为何以前不是这样的 91 | //这样也不需要考虑自定义input的·自定义光标会被复制到· 92 | let str=labelStringRemoveLabelExceptImg(strx); 93 | if(!str){ 94 | return; 95 | } 96 | let copylist=getCopyLocalStorage(); 97 | copylist=copylist.filter(item=>item!=""&&item!=str); 98 | copylist.unshift(str); 99 | saveCopyList(copylist); 100 | } 101 | const copyToClipboard = str => { 102 | return new Promise((resolve)=>{ 103 | if(!navigator.clipboard||!navigator.clipboard.writeText){ 104 | resolve(false); 105 | } 106 | else{ 107 | navigator.clipboard.writeText(str).then(function() { 108 | resolve({text:str,suss:true}); 109 | }, function() { 110 | resolve(false); 111 | }); 112 | } 113 | }) 114 | }; 115 | /** 116 | * 用原生复制功能复制字符串 117 | * @param {*} str 118 | * @returns bool 119 | */ 120 | export const nativeCopyString=async (str)=>{ 121 | //未来兼容处理了 122 | if(typeof document.execCommand!=="function"){ 123 | return copyToClipboard(str); 124 | } 125 | else{ 126 | const input = document.createElement("input"); 127 | input.readOnly = 'readonly'; 128 | input.value = str; 129 | input.style.width="1px"; 130 | input.style.height="1px"; 131 | input.style.opacity=0; 132 | input.style.position="absolute"; 133 | document.body.appendChild(input); 134 | input.select(); 135 | input.setSelectionRange(0, input.value.length); 136 | var t=document.execCommand('copy'); 137 | document.body.removeChild(input); 138 | return Promise.resolve(t); 139 | } 140 | 141 | } -------------------------------------------------------------------------------- /src/dev/cursor.js: -------------------------------------------------------------------------------- 1 | //控制贯标的位置 2 | export const cursorStr='';//光标标签 3 | export const getNoCursorArr=(arr)=>arr.filter(item=>item!=cursorStr);//获取灭有光标的数组 4 | /** 5 | * 光标移动到第一个 6 | * @param {*} arr 7 | * @returns 8 | */ 9 | export const first=(arr=[])=>{ 10 | arr.unshift(cursorStr); 11 | return { 12 | index:0, 13 | arr:arr 14 | } 15 | } 16 | /** 17 | * 光标移动到最后 18 | * @param {*} arr 19 | * @returns 20 | */ 21 | export const last=(arr=[])=>{ 22 | if(arr[arr.lenght-1]==cursorStr){ 23 | return { 24 | index:arr.length-1, 25 | arr 26 | } 27 | } 28 | arr.push(cursorStr); 29 | return { 30 | index:arr.length-1, 31 | arr:arr 32 | } 33 | } 34 | /** 35 | * 光标移动到指定位置 36 | * @param {*} arr 37 | * @param {*} targetIndex 38 | * @returns 39 | */ 40 | export const moveTo=(arr=[],targetIndex)=>{ 41 | let filterCursorArr=getNoCursorArr(arr); 42 | filterCursorArr.splice(targetIndex,0,cursorStr) 43 | return { 44 | index:targetIndex, 45 | arr:filterCursorArr 46 | } 47 | } 48 | /** 49 | * 这里的targetIndex没有移除光标的 50 | * @param {*} arr 51 | * @param {*} dirStr left|right|top|bottom 52 | * @returns 53 | */ 54 | export const moveToFn=(arr=[],dirStr="bottom")=>{ 55 | let filterCursorArr=getNoCursorArr(arr); 56 | if(dirStr=="top"){ 57 | return first(filterCursorArr) 58 | } 59 | else if(dirStr=="bottom"){ 60 | return last(filterCursorArr) 61 | } 62 | else{ 63 | //这是光标位于东时候的位置 64 | let currCursorIndex=arr.findIndex(item=>item==cursorStr); 65 | let targetIndex=currCursorIndex-1; 66 | if(dirStr=="left"){ 67 | if(targetIndex<0){ 68 | return {}; 69 | } 70 | else{ 71 | 72 | return moveTo(filterCursorArr,targetIndex); 73 | } 74 | 75 | } 76 | else if(dirStr=="right"){ 77 | let targetIndex=currCursorIndex+1; 78 | if(targetIndex>arr.length-1){ 79 | return {}; 80 | } 81 | else{ 82 | 83 | return moveTo(filterCursorArr,targetIndex); 84 | } 85 | } 86 | return moveTo(filterCursorArr,dirStr); 87 | } 88 | } 89 | 90 | -------------------------------------------------------------------------------- /src/dev/emoji.vue: -------------------------------------------------------------------------------- 1 | 39 | 131 | -------------------------------------------------------------------------------- /src/dev/emojiImages.js: -------------------------------------------------------------------------------- 1 | const pathStr="https://raw.githubusercontent.com/MTTTM/vue-keyboard-cn/main/src/dev/assets/images/"; 2 | export const person={ 3 | text:"人物", 4 | list:[ 5 | { 6 | path:`${pathStr}/person/1_smile.png`, 7 | key:"smile" 8 | }, 9 | { 10 | path:`${pathStr}/person/3_grinning.png`, 11 | key:"grinning" 12 | }, 13 | { 14 | path:`${pathStr}/person/4_blush.png`, 15 | key:"blush" 16 | }, 17 | { 18 | path:`${pathStr}/person/6_wink.png`, 19 | key:"wink" 20 | }, 21 | { 22 | path:`${pathStr}/person/7_heart_eyes.png`, 23 | key:"heart_eyes" 24 | }, 25 | { 26 | path:`${pathStr}/person/8_kissing_heart.png`, 27 | key:"kissing_heart" 28 | }, 29 | { 30 | path:`${pathStr}/person/9_kissing_closed_eyes.png`, 31 | key:"kissing_closed_eyes" 32 | }, 33 | { 34 | path:`${pathStr}/person/10_disappointed.png`, 35 | key:"disappointed" 36 | }, 37 | { 38 | path:`${pathStr}/person/10_kissing.png`, 39 | key:"kissing" 40 | }, 41 | { 42 | path:`${pathStr}/person/11_kissing_smiling_eyes.png`, 43 | key:"kissing_smiling_eyes" 44 | }, 45 | { 46 | path:`${pathStr}/person/12_stuck_out_tongue_winking_eye.png`, 47 | key:"stuck_out_tongue_winking_eye" 48 | }, 49 | { 50 | path:`${pathStr}/person/13_stuck_out_tongue_closed_eyes.png`, 51 | key:"13_stuck_out_tongue_closed_eyes" 52 | }, 53 | { 54 | path:`${pathStr}/person/14_stuck_out_tongue.png`, 55 | key:"14_stuck_out_tongue" 56 | }, 57 | { 58 | path:`${pathStr}/person/15_flushed.png`, 59 | key:"15_flushed" 60 | }, 61 | { 62 | path:`${pathStr}/person/16_grin.png`, 63 | key:"16_grin" 64 | }, 65 | { 66 | path:`${pathStr}/person/17_pensive.png`, 67 | key:"17_pensive" 68 | }, 69 | { 70 | path:`${pathStr}/person/18_relieved.png`, 71 | key:"18_relieved" 72 | }, 73 | { 74 | path:`${pathStr}/person/19_unamused.png`, 75 | key:"19_unamused" 76 | }, 77 | { 78 | path:`${pathStr}/person/20_fearful.png`, 79 | key:"20_fearful" 80 | }, 81 | { 82 | path:`${pathStr}/person/20_persevere.png`, 83 | key:"20_persevere" 84 | }, 85 | 86 | { 87 | path:`${pathStr}/person/22_joy.png`, 88 | key:"22_joy" 89 | }, 90 | { 91 | path:`${pathStr}/person/23_sob.png`, 92 | key:"23_sob" 93 | }, 94 | { 95 | path:`${pathStr}/person/24_sleepy.png`, 96 | key:"24_sleepy" 97 | }, 98 | { 99 | path:`${pathStr}/person/25_cold_sweat.png`, 100 | key:"25_cold_sweat" 101 | }, 102 | { 103 | path:`${pathStr}/person/25_disappointed_relieved.png`, 104 | key:"25_disappointed_relieved" 105 | }, 106 | { 107 | path:`${pathStr}/person/26_sweat_smile.png`, 108 | key:"26_sweat_smile" 109 | }, 110 | { 111 | path:`${pathStr}/person/27_sweat.png`, 112 | key:"27_sweat" 113 | }, 114 | { 115 | path:`${pathStr}/person/28_weary.png`, 116 | key:"28_weary" 117 | }, 118 | { 119 | path:`${pathStr}/person/29_tired_face.png`, 120 | key:"29_tired_face" 121 | }, 122 | { 123 | path:`${pathStr}/person/30_scream.png`, 124 | key:"30_scream" 125 | }, 126 | { 127 | path:`${pathStr}/person/31_angry.png`, 128 | key:"31_angry" 129 | }, 130 | { 131 | path:`${pathStr}/person/32_rage.png`, 132 | key:"32_rage" 133 | }, 134 | { 135 | path:`${pathStr}/person/33_triumph.png`, 136 | key:"33_triumph" 137 | }, 138 | { 139 | path:`${pathStr}/person/34_laughing.png`, 140 | key:"34_laughing" 141 | }, 142 | { 143 | path:`${pathStr}/person/35_yum.png`, 144 | key:"35_yum" 145 | }, 146 | { 147 | path:`${pathStr}/person/36_mask.png`, 148 | key:"36_mask" 149 | }, 150 | { 151 | path:`${pathStr}/person/37_sunglasses.png`, 152 | key:"37_sunglasses" 153 | }, 154 | { 155 | path:`${pathStr}/person/38_sleeping.png`, 156 | key:"38_sleeping" 157 | }, 158 | { 159 | path:`${pathStr}/person/39_dizzy_face.png`, 160 | key:"39_dizzy_face" 161 | }, 162 | { 163 | path:`${pathStr}/person/40_astonished.png`, 164 | key:"40_astonished" 165 | }, 166 | { 167 | path:`${pathStr}/person/41_worried.png`, 168 | key:"41_worried" 169 | }, 170 | { 171 | path:`${pathStr}/person/42_frowning.png`, 172 | key:"42_frowning" 173 | }, 174 | { 175 | path:`${pathStr}/person/43_anguished.png`, 176 | key:"43_anguished" 177 | }, 178 | { 179 | path:`${pathStr}/person/44_neutral_face.png`, 180 | key:"44_neutral_face" 181 | }, 182 | { 183 | path:`${pathStr}/person/45_confused.png`, 184 | key:"45_confused" 185 | }, 186 | { 187 | path:`${pathStr}/person/46_no_mouth.png`, 188 | key:"46_no_mouth" 189 | }, 190 | { 191 | path:`${pathStr}/person/47_innocent.png`, 192 | key:"47_innocent" 193 | }, 194 | { 195 | path:`${pathStr}/person/48_smirk.png`, 196 | key:"48_smirk" 197 | }, 198 | { 199 | path:`${pathStr}/person/49_expressionless.png`, 200 | key:"49_expressionless" 201 | } 202 | ] 203 | } 204 | export const hearts={ 205 | text:"有爱", 206 | list:[ 207 | { 208 | path:`${pathStr}/hearts/1_yellow_heart.png`, 209 | key:"1_yellow_heart" 210 | }, 211 | { 212 | path:`${pathStr}/hearts/2_blue_heart.png`, 213 | key:"2_blue_heart" 214 | }, 215 | { 216 | path:`${pathStr}/hearts/3_purple_heart.png`, 217 | key:"3_purple_heart" 218 | }, 219 | { 220 | path:`${pathStr}/hearts/4_green_heart.png`, 221 | key:"4_green_heart" 222 | }, 223 | { 224 | path:`${pathStr}/hearts/5_heart.png`, 225 | key:"5_heart" 226 | }, 227 | { 228 | path:`${pathStr}/hearts/6_broken_heart.png`, 229 | key:"6_broken_heart" 230 | }, 231 | { 232 | path:`${pathStr}/hearts/7_heartpulse.png`, 233 | key:"7_heartpulse" 234 | }, 235 | { 236 | path:`${pathStr}/hearts/8_heartbeat.png`, 237 | key:"8_heartbeat" 238 | }, 239 | { 240 | path:`${pathStr}/hearts/9_two_hearts.png`, 241 | key:"9_two_hearts" 242 | }, 243 | { 244 | path:`${pathStr}/hearts/10_sparkling_heart.png`, 245 | key:"10_sparkling_heart" 246 | }, 247 | { 248 | path:`${pathStr}/hearts/11_revolving_hearts.png`, 249 | key:"11_revolving_hearts" 250 | }, 251 | { 252 | path:`${pathStr}/hearts/12_cupid.png`, 253 | key:"12_cupid" 254 | }, 255 | { 256 | path:`${pathStr}/hearts/13_love_letter.png`, 257 | key:"13_love_letter" 258 | }, 259 | { 260 | path:`${pathStr}/hearts/14_kiss.png`, 261 | key:"14_kiss" 262 | }, 263 | { 264 | path:`${pathStr}/hearts/15_ring.png`, 265 | key:"15_ring" 266 | }, 267 | { 268 | path:`${pathStr}/hearts/16_gem.png`, 269 | key:"16_gem" 270 | }, 271 | ] 272 | } 273 | export const symbo={ 274 | text:"符号", 275 | list:[ 276 | { 277 | path:`${pathStr}/symbol/1_one.png`, 278 | key:"1_one" 279 | }, 280 | { 281 | path:`${pathStr}/symbol/2_two.png`, 282 | key:"2_two" 283 | }, 284 | { 285 | path:`${pathStr}/symbol/3_three.png`, 286 | key:"3_three" 287 | }, 288 | { 289 | path:`${pathStr}/symbol/4_four.png`, 290 | key:"4_four" 291 | }, 292 | { 293 | path:`${pathStr}/symbol/5_five.png`, 294 | key:"5_five" 295 | }, 296 | { 297 | path:`${pathStr}/symbol/6_six.png`, 298 | key:"6_six" 299 | }, 300 | { 301 | path:`${pathStr}/symbol/7_seven.png`, 302 | key:"7_seven" 303 | }, 304 | { 305 | path:`${pathStr}/symbol/8_eight.png`, 306 | key:"8_eight" 307 | }, 308 | { 309 | path:`${pathStr}/symbol/9_zero.png`, 310 | key:"9_zero" 311 | }, 312 | { 313 | path:`${pathStr}/symbol/10_ten.png`, 314 | key:"10_ten" 315 | }, 316 | { 317 | path:`${pathStr}/symbol/11_x.png`, 318 | key:"11_x" 319 | }, 320 | { 321 | path:`${pathStr}/symbol/12_bangbang.png`, 322 | key:"12_bangbang" 323 | }, 324 | { 325 | path:`${pathStr}/symbol/13_interrobang.png`, 326 | key:"13_interrobang" 327 | }, 328 | { 329 | path:`${pathStr}/symbol/14_exclamation.png`, 330 | key:"14_exclamation" 331 | }, 332 | { 333 | path:`${pathStr}/symbol/15_question.png`, 334 | key:"15_question" 335 | }, 336 | 337 | ] 338 | } -------------------------------------------------------------------------------- /src/dev/emojiItem.vue: -------------------------------------------------------------------------------- 1 | 14 | 49 | -------------------------------------------------------------------------------- /src/dev/eventKeys.js: -------------------------------------------------------------------------------- 1 | export default{ 2 | "vue-keyboard-cn-focus":"vue-keyboard-cn-focus",//输入框获取焦点,发布通知 3 | "vue-keyboard-cn-no-me-will-blur":"vue-keyboard-cn-no-me-will-blur",//输入框获取焦点,发布通知 4 | "vue-keyboard-cn-update-value":"vue-keyboard-cn-update-value",//推送输入框的最新值,string 5 | 'vue-keyboard-cn-show':'vue-keyboard-cn-show',//键盘隐藏,发起通知 6 | 'vue-keyboard-cn-showed':'vue-keyboard-cn-showed',//键盘已完成显示或隐藏 7 | 'vue-keyboard-cn-append-item':'vue-keyboard-cn-append-item',//键盘确认内容,发起通知 8 | 'vue-keyboard-cn-append-delete':'vue-keyboard-cn-append-delete',//键盘提交删除 9 | 'vue-keyboard-cn-select-all':'vue-keyboard-cn-select-all',//全选,参数,true||false 10 | "vue-keyboard-cn-natice-copy":"vue-keyboard-cn-natice-copy",//推送输入框的最新值,string 11 | "vue-keyboard-cn-cursor-move":"vue-keyboard-cn-cursor-move",//方向键,移动光标,top|bottom|left|top 12 | "vue-keyboard-cn-submit":"vue-keyboard-cn-submit" //回车键,触发input提交(1,不允许换行input才会触发,默认都是不允许触发的) 13 | } -------------------------------------------------------------------------------- /src/dev/inputFilterRegx.js: -------------------------------------------------------------------------------- 1 | export default { 2 | "float": (text, decimal = 2) => { 3 | let reg = /^[0-9]+.?[0-9]*$/; 4 | let t = String(text); 5 | if (!isNaN(Number(decimal)) && decimal > 0) { 6 | let decimalNumber = t.split(".")[1]; 7 | console.log("decimalNumber.length", decimalNumber, "decimal", decimal) 8 | if (decimalNumber && decimalNumber.length > decimal) { 9 | 10 | return false; 11 | } 12 | else { 13 | return reg.test(t); 14 | } 15 | } 16 | else { 17 | return false; 18 | } 19 | }, 20 | "int": (text) => { 21 | return /^[0-9]*$/.test(text); 22 | }, 23 | "cn": (text) => { 24 | //支持中文和中文符号"·" 25 | let reg = new RegExp( 26 | "^([\u4E00-\u9FFF]|·)+$", 27 | "g" 28 | ); 29 | return reg.test(text); 30 | }, 31 | "en": (text) => { 32 | return /^[A-Za-z]+$/.test(text) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/dev/lowercaseMemory.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 永久记录大小写 3 | * @returns 4 | */ 5 | const localStoreKey = "vue-keyboard-cn-lowercase"; 6 | export const getCaseItem=()=>{ 7 | let store= localStorage.getItem(localStoreKey); 8 | return store==="lowercase"?"lowercase":"capitalize"; 9 | } 10 | export const setCaseItem=(index=0)=>{ 11 | let obj=["capitalize","lowercase"]; 12 | let t=obj[index]?obj[index]:obj[0]; 13 | localStorage.setItem(localStoreKey,t); 14 | } -------------------------------------------------------------------------------- /src/dev/memory.js: -------------------------------------------------------------------------------- 1 | import { getFullPingMatchObjKey } from "./tools.js"; 2 | const localStoreKey = "vue-keyboard-cn-store"; 3 | const clearTimeString="__$lastClearTime";//保存`清除热度小于2的词的时间戳`key 4 | /** 5 | * 返回清除超过7天并且热度小于2的词,后返回最新结果 6 | * @param {*} objx 7 | * @returns 8 | */ 9 | const clearMemory=(objx={})=>{ 10 | let obj=objx?objx:{} 11 | //如果没有清除时间 12 | if(!obj[clearTimeString]){ 13 | obj[clearTimeString]=new Date().getTime(); 14 | } 15 | else if(obj[clearTimeString]){ 16 | try{ 17 | //距离上一次清除热度小于2的时间间隔超过7天 18 | if(new Date().getTime()-Number(obj[clearTimeString])>(86400*7)){ 19 | for(let key in obj){ 20 | //因为__$lastClearTime,对应的是时间戳,不用处理 21 | if(Array.isArray(obj[key])){ 22 | obj[key]=obj[key].filter(item=>item.order>=2); 23 | 24 | } 25 | } 26 | obj[clearTimeString]=new Date().getTime(); 27 | } 28 | }catch(e){ 29 | console.log("删除 热度小于2的词失败",e); 30 | } 31 | } 32 | return obj; 33 | } 34 | /** 35 | * 存储的格式入: 36 | * { 37 | * __$lastClearTime:"时间戳", 38 | * nihao:[ 39 | * { 40 | * zh:"你好", 41 | * order:1 42 | * key:"nihao" 43 | * }, 44 | * { 45 | * zh:"拟好", 46 | * order:2, 47 | * key:"nihao" 48 | * } 49 | * ] 50 | * } 51 | * @returns 52 | */ 53 | 54 | export const getItem=(key=undefined)=>{ 55 | let storeStr= localStorage.getItem(localStoreKey); 56 | let store={}; 57 | try{ 58 | store=JSON.parse(storeStr); 59 | store=clearMemory(store); 60 | }catch(e){} 61 | let t=store?store:{}; 62 | if(key){ 63 | t=t[key]&&t[key].length>0?t[key]:{}; 64 | } 65 | return t; 66 | } 67 | const setItem=(obj={})=>{ 68 | try{ 69 | let jsonStr=JSON.stringify(obj); 70 | localStorage.setItem(localStoreKey,jsonStr) 71 | }catch(e){ 72 | console.warn(e); 73 | } 74 | } 75 | /** 76 | * 更新拼音和中文匹配的热度 77 | * @param {*} pingying 78 | * @param {*} zhStr 79 | */ 80 | export const setPingying=(pingying="",zhStr="")=>{ 81 | //热词长度限制 82 | if(!pingying||pingying.length>20){ 83 | return; 84 | } 85 | let store=getItem(); 86 | if(!store[pingying]){ 87 | store[pingying]=[]; 88 | store[pingying].push({ 89 | key:pingying, 90 | zh:zhStr, 91 | order:0//热度,每次用户输入都增加1 92 | }) 93 | } 94 | else{ 95 | let index=store[pingying].findIndex(item=>item.key==pingying&&item.zh==zhStr); 96 | if(index==-1){ 97 | store[pingying].push({ 98 | key:pingying, 99 | zh:zhStr, 100 | order:0//热度,每次用户输入都增加1 101 | }) 102 | } 103 | else{ 104 | store[pingying][index].order+=1; 105 | } 106 | } 107 | setItem(store) 108 | } 109 | /** 110 | * 根据输入的拼音,获取可能匹配的词 111 | * @param {*} pingyingStr 112 | */ 113 | export const matchHotPingying=(pingyingStr)=>{ 114 | let obj=getItem(); 115 | let getStore=Object.keys(obj); 116 | let arr=getFullPingMatchObjKey(pingyingStr,getStore)[0]; 117 | if(arr&&arr.key&&obj[arr.key]){ 118 | return obj[arr.key].sort((a,b)=>b.order-a.order).slice(0,3);//只返回最热的三条 119 | } 120 | else{ 121 | return [] 122 | } 123 | } -------------------------------------------------------------------------------- /src/dev/mixins/btnPress.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 给board.vue 3 | * 和operation.vue 4 | * 使用的 5 | */ 6 | import EventKeys from "../eventKeys"; 7 | export default{ 8 | props: { 9 | getInputInfo: { 10 | type: Object, 11 | required: true, 12 | }, 13 | }, 14 | methods: { 15 | /** 16 | * 不允许输入回车键 17 | * && 不存在待选的中文 18 | * 时候按回车键触发 input的submit事件 19 | */ 20 | enterBtnCallback(item){ 21 | let result={handle:false}; 22 | let isEnter=item.text === "\r\n"; 23 | if ( 24 | this.getInputInfo && 25 | this.getInputInfo.allowEnter == false && 26 | !this.showZhText && 27 | isEnter 28 | ) { 29 | this.$root.$emit(EventKeys["vue-keyboard-cn-submit"], ""); 30 | this.$emit("show", false); 31 | result={handle:true}; 32 | } 33 | else if(isEnter && this.showZhText){ 34 | //如果存在待选的中文,换行按钮就是确认按钮 35 | //把展示区域的拼音或”中文和拼音混合“字符串发送给input 36 | let t = ""; 37 | 38 | //有【拼音完全匹配到的"热词"】,并且没有已选的的中文,就用已匹配的热词 39 | let allPingyin=this.showZhMatchArr.every(e=>/^[a-zA-z]+$/.test(e.text)==true); 40 | if(allPingyin&& this.zhMemoryResult[0]){ 41 | t=this.zhMemoryResult[0].zh; 42 | } 43 | else if(this.showZhMatchArr.length==0&& this.zhSearchList[0]){ 44 | //有【拼音完全匹配到的"单字"】,并且没有已选的的中文,就用已匹配的单字 45 | t=this.zhSearchList[0]; 46 | } 47 | else if( this.showZhMatchArr.length){ 48 | //有已选的中文,或用拼音 49 | this.showZhMatchArr.forEach((e) => { 50 | t += e.text; 51 | }); 52 | } 53 | else{ 54 | t=this.tmpPingying; 55 | } 56 | this.appendStringItem(t); 57 | result={handle:true}; 58 | } 59 | else if(isEnter){ 60 | this.appendStringItem(item.text); 61 | result={handle:true}; 62 | } 63 | console.log("result",result) 64 | return result; 65 | }, 66 | appendStringItem(text) { 67 | if(this.tmpPingying){ 68 | this.tmpPingying = ""; 69 | } 70 | this.$root.$emit(EventKeys["vue-keyboard-cn-append-item"], text); 71 | }, 72 | }, 73 | } -------------------------------------------------------------------------------- /src/dev/tools.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 查找字符串在字符中出现的位置 3 | * @param {*} str 4 | * @param {*} subStr 5 | * @returns Array 6 | */ 7 | export const getIndexInArray=(str,subStr)=>{ 8 | var positions = new Array(); 9 | var pos = str.indexOf(subStr); 10 | if(pos>-1){ 11 | positions.push({ 12 | index:pos, 13 | text:subStr 14 | }); 15 | } 16 | return positions; 17 | } 18 | 19 | function matchPinyin(pinyin="",objKeys=[],matchResult){ 20 | console.log('受到的pingying',pinyin) 21 | //遍历词库的key,得到可能存在的分词组合, 22 | for (let i = 0; i < objKeys.length; i++) { 23 | let item = objKeys[i]; 24 | let indexArr = getIndexInArray(pinyin, item); 25 | if(indexArr[0]){ 26 | matchResult.push({ 27 | index: indexArr[0].index, 28 | key: item, 29 | }); 30 | } 31 | let validStr=pinyin.replace("_",""); 32 | if(indexArr[0]&&indexArr[0].index>-1&&validStr.length){ 33 | let arr=pinyin.split(""); 34 | let index=indexArr[0].index; 35 | let len=indexArr[0].text.length; 36 | //直接把匹配到的字符串替换为_ 37 | for(let i=index;i<(index+len);i++){ 38 | arr[i]="_"; 39 | } 40 | let endStr=arr.join(""); 41 | // console.log("pinyinfsadfsdfdfsd",pinyin,"new",endStr) 42 | matchPinyin(endStr,objKeys,matchResult) 43 | break; 44 | } 45 | } 46 | } 47 | /** 48 | * 词拼音在用户输入的拼音之中,分词 49 | * @param {*} pingyingStr 50 | * @param {*} objKeys 51 | * @returns 52 | */ 53 | 54 | export const getPingMatchObjKey=(pingyingStr="",objKeys=[])=>{ 55 | //如果没有匹配,就需要做分词处理 56 | let matchResult = []; 57 | matchPinyin(pingyingStr,objKeys,matchResult); 58 | matchResult=matchResult.sort((a,b)=>a.index-b.index) 59 | console.log("匹配到的词",matchResult) 60 | return matchResult; 61 | } 62 | /** 63 | * 历史输入记录的key和用户输入完全等同 64 | * @param {*} pingyingStr 65 | * @param {*} objKeys 66 | * @returns 67 | */ 68 | export const getFullPingMatchObjKey=(pingyingStr="",objKeys=[])=>{ 69 | //如果没有匹配,就需要做分词处理 70 | let matchResult = []; 71 | //遍历词库的key,得到可能存在的分词组合, 72 | //如果当前输入的拼音有对应山的,返回它在字符串中的索引index,否则为-1 73 | 74 | for (let i = 0; i < objKeys.length; i++) { 75 | let item = objKeys[i]; 76 | if(item===pingyingStr){ 77 | matchResult.push({ 78 | index: 0, 79 | key: item, 80 | }); 81 | } 82 | } 83 | return matchResult; 84 | } 85 | /** 86 | * 包裹单个字符串元素 87 | */ 88 | export const wrapStringSingleItem=(str)=>{ 89 | return `${str}`; 90 | } 91 | /** 92 | * 解析字符串为数组 93 | * @param {*} str 94 | * @params {boolean} alertEnter 95 | * @returns 96 | */ 97 | export const splitStringToArray=(str,alertEnter=false)=>{ 98 | if(String(str).length==1){ 99 | return [wrapStringSingleItem(str)]; 100 | } 101 | var tmpArr = String(str).split(""); 102 | var endArr = []; 103 | var tmpStr = ""; 104 | var findFlash = false; 105 | var findEnterStr=false;//换行符号,回车符发现 106 | for (let i = 0; i < tmpArr.length; i++) { 107 | let item = tmpArr[i]; 108 | //图片标签处理 109 | if (item == "<"&&tmpArr[i+1]=="i") { 110 | findFlash = true; 111 | } 112 | //匹配换行符 \r \n 或者 113 | //\r\n,\r \n 会被split当做一个字符处理 114 | else if(item=="\r"||item=="\n"){ 115 | findEnterStr=true; 116 | if(tmpArr[i+1]=="\n"){ 117 | if(item==="\n"){ 118 | if(alertEnter){ 119 | endArr.push("
"); 120 | } 121 | else{ 122 | endArr.push(wrapStringSingleItem(" ")); 123 | } 124 | 125 | findEnterStr=false; 126 | tmpStr = ""; 127 | } 128 | } 129 | else{ 130 | if(alertEnter){ 131 | endArr.push("
"); 132 | } 133 | else{ 134 | endArr.push(wrapStringSingleItem(" ")); 135 | } 136 | findEnterStr=false; 137 | tmpStr = ""; 138 | } 139 | } 140 | else if (!findFlash&&!findEnterStr) { 141 | endArr.push(wrapStringSingleItem(item)); 142 | } 143 | 144 | if (findFlash||findEnterStr) { 145 | tmpStr += item; 146 | } 147 | //tmpArr[i - 1] && tmpArr[i - 1] == "/" && 148 | if (findFlash&&item == ">") { 149 | endArr.push(tmpStr); 150 | findFlash = false; 151 | tmpStr = ""; 152 | } 153 | } 154 | return endArr; 155 | } 156 | /** 157 | * 获取dom在父级下的索引 158 | * @param {*} childElement 159 | * @returns number 160 | */ 161 | export const getElementIndexOnParent=(childElement)=>{ 162 | var parentNode =childElement.parentNode.childNodes; 163 | var childNodes=[]; 164 | for(var i=0; i{ 180 | let t=labelStr.replace(//ig,"\r\n"); 181 | return t.replace(/<[^>]+>/g,"") 182 | } 183 | /** 184 | * 移除字符串里面的html标签(除了键盘自定义的img标签) 185 | * @param {*} labelStr 186 | * @returns 187 | */ 188 | export const labelStringRemoveLabelExceptImg=(labelStr="")=>{ 189 | let t=labelStr.replace(/()/ig,"\r\n"); 190 | t=t.replace(/<[^(img)][^>]+>/g,""); 191 | return t; 192 | } 193 | /** 194 | * 提供uuid 195 | * @returns 196 | */ 197 | export const uuid=()=>{ 198 | function S4() { 199 | return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1); 200 | } 201 | return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4()); 202 | } -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | import Vue from 'vue' 5 | import App from './App.vue' 6 | 7 | import kyInput from "./dev/input.vue"; 8 | import keyBoard from "./dev/index.vue"; 9 | import KeyboardAwareScrollView from "./dev/KeyboardAwareScrollView.vue" 10 | import router from './router/index' 11 | // import { directive } from "disable-body-scroll"; 12 | import { directive as disabledBodyScroll } from "./assets/dissableBodyScroll.js"; 13 | 14 | import { directive, directiveForDom } from "vue-horizontal-screen"; 15 | // import { directive, event, directiveForDom } from "./assets/js/ueHorizontalScreen"; 16 | Vue.directive("horizontal-screen", { ...directive }); 17 | Vue.directive("hs-swipe", { ...directiveForDom }); 18 | 19 | Vue.directive("disabled-body-scroll", { ...disabledBodyScroll }); 20 | Vue.component("ky-input", kyInput) 21 | Vue.component("key-board", keyBoard) 22 | Vue.component("key-board-aware-scroll-view", KeyboardAwareScrollView) 23 | new Vue({ 24 | el: '#app', 25 | router, 26 | render: h => h(App) 27 | }) 28 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import VueRouter from 'vue-router'; 3 | import routes from './routes.js' 4 | 5 | Vue.use(VueRouter); 6 | 7 | export default new VueRouter({ 8 | mode: 'hash', 9 | routes, 10 | scrollBehavior() { 11 | return { x: 0, y: 0 } 12 | } 13 | }); 14 | 15 | -------------------------------------------------------------------------------- /src/router/routes.js: -------------------------------------------------------------------------------- 1 | import Home from '../demo/index'; 2 | import Type from "../demo/type" 3 | import BreakWrap from "../demo/breakWrap" 4 | import AdaptiveHeight from "../demo/adaptiveHeight" 5 | import EventCom from "../demo//event" 6 | import DisabledInputUpdateMixKeyBoardLang from "../demo/disabledInputUpdateMixKeyBoardLang.vue" 7 | import canSwitchOtherBoard from "../demo/canSwitchOtherBoard" 8 | import showFixedInput from "../demo/showFixedInput" 9 | import InputMaxLength from "../demo/inputMaxLength.vue" 10 | import Customkeyboard from "../demo/Customkeyboard.vue" 11 | import noEmoji from "../demo/noEmoji.vue" 12 | import hideHead from "../demo/hideHead.vue" 13 | import inputDisabled from "../demo/inputDisabled.vue" 14 | import inputSlot from "../demo/inputSlot.vue" 15 | import horizontalScreen from "../demo/horizontalScreen" 16 | import horizontalScreen2 from "../demo/horizontalScreen2" 17 | import inputFuncSelect from "../demo/inputFuncSelect.vue" 18 | 19 | import KeyboardAwareScrollView1 from "../demo/KeyboardAwareScrollView1" 20 | import KeyboardAwareScrollView2 from "../demo/KeyboardAwareScrollView2" 21 | import KeyboardAwareScrollView3 from "../demo/KeyboardAwareScrollView3" 22 | export default [ 23 | { 24 | path: '/', // 重定向到home页面 25 | redirect: '/home' 26 | }, 27 | { 28 | path: '/home', 29 | component: Home, 30 | title: "home", 31 | }, 32 | { 33 | path: "/type", 34 | component: Type, 35 | title: "input props type", 36 | }, 37 | { 38 | path: "/inputFuncSelect", 39 | component: inputFuncSelect, 40 | title: "input select function" 41 | }, 42 | { 43 | path: "/breakwrap", 44 | component: BreakWrap, 45 | title: "input breakwrap" 46 | }, 47 | { 48 | path: "/adaptiveHeight", 49 | component: AdaptiveHeight, 50 | title: "input adaptiveHeight" 51 | }, { 52 | path: "/event", 53 | component: EventCom, 54 | title: "input event" 55 | }, 56 | { 57 | path: "/disabledInputUpdateMixKeyBoardLang", 58 | component: DisabledInputUpdateMixKeyBoardLang, 59 | title: "keyBoard props disabledInputUpdateMixKeyBoardLang" 60 | }, 61 | { 62 | path: "/canSwitchOtherBoard", 63 | component: canSwitchOtherBoard, 64 | title: "input props canSwitchOtherBoard" 65 | }, 66 | 67 | { 68 | path: "/showFixedInput", 69 | component: showFixedInput, 70 | title: "input props showFixedInput" 71 | }, 72 | { 73 | path: "/inputMaxLength", 74 | component: InputMaxLength, 75 | title: "input props inputMaxLength" 76 | } 77 | , { 78 | path: "/customkeyboard", 79 | component: Customkeyboard, 80 | title: "custom keyboard" 81 | } 82 | , { 83 | path: "/noEmoji", 84 | component: noEmoji, 85 | title: "keyboard no Emoji" 86 | }, 87 | { 88 | path: "/hidehead", 89 | component: hideHead, 90 | title: "keyboard props hideHead" 91 | }, 92 | { 93 | path: "/inputDisabled", 94 | component: inputDisabled, 95 | title: "input props disabled" 96 | }, { 97 | path: "/inputSlot", 98 | component: inputSlot, 99 | title: "input name slot" 100 | }, { 101 | path: "/horizontalScreen", 102 | component: horizontalScreen, 103 | title: "horizontal screen rotate 90" 104 | }, { 105 | path: "/horizontalScreen2", 106 | component: horizontalScreen2, 107 | title: "horizontal screen rotate -90" 108 | }, 109 | { 110 | path: "/KeyboardAwareScrollView1", 111 | component: KeyboardAwareScrollView1, 112 | title: "1. KeyboardAwareScrollView components is scrollBox" 113 | }, 114 | { 115 | path: "/KeyboardAwareScrollView2", 116 | component: KeyboardAwareScrollView2, 117 | title: "2. KeyboardAwareScrollView components is scrollBox" 118 | }, 119 | { 120 | path: "/KeyboardAwareScrollView3", 121 | component: KeyboardAwareScrollView3, 122 | title: "3.KeyboardAwareScrollView.body is scrollBox" 123 | } 124 | ] 125 | -------------------------------------------------------------------------------- /test/Tools.spec.js: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | // import 'core-js'; 3 | import { 4 | getIndexInArray, 5 | getPingMatchObjKey, 6 | wrapStringSingleItem, 7 | splitStringToArray, 8 | getElementIndexOnParent, 9 | labelStringRemoveLabelExceptImg, 10 | uuid 11 | } from "../src/dev/tools" 12 | import {zhKeysArray} from "../src/dev/zh" 13 | 14 | describe('getIndexInArray', () => { 15 | it('getIndexInArray should be [{index:"1",text:"b"}]', () => { 16 | let t=getIndexInArray("abcdef",'b'); 17 | expect(t).to.be.an('array'). 18 | that.to.have.lengthOf(1). 19 | that.to.deep.equal([{index:1,text:"b"}]); 20 | }) 21 | 22 | }) 23 | 24 | describe('getPingMatchObjKey', () => { 25 | it('getPingMatchObjKey should be array', () => { 26 | let t=getPingMatchObjKey("nihaoma",zhKeysArray); 27 | expect(t).to.be.an('array'). 28 | that.to.have.lengthOf(3). 29 | that.to.deep.equal([ 30 | { 31 | index: 0, 32 | key: "ni" 33 | }, 34 | { 35 | index: 2, 36 | key: "hao" 37 | }, 38 | { 39 | index: 5, 40 | key: "ma" 41 | }, 42 | ]); 43 | }) 44 | 45 | }) 46 | describe('getFullPingMatchObjKey', () => { 47 | it('getFullPingMatchObjKey should be array', () => { 48 | let t=getPingMatchObjKey("nihao",["__$lastClearTime","nihao"]); 49 | expect(t).to.be.an('array'). 50 | that.to.have.lengthOf(1). 51 | that.to.deep.equal( 52 | [ 53 | { 54 | index: 0, 55 | key: "nihao" 56 | } 57 | ] 58 | ); 59 | }) 60 | 61 | it('getFullPingMatchObjKey should be empaty array', () => { 62 | let t=getPingMatchObjKey("nihao", ["__$lastClearTime"]); 63 | expect(t).to.be.an('array'). 64 | that.to.have.lengthOf(0). 65 | that.to.deep.equal([]); 66 | }) 67 | 68 | }) 69 | 70 | describe('wrapStringSingleItem', () => { 71 | it('wrapStringSingleItem should be html label string', () => { 72 | let t=wrapStringSingleItem("你"); 73 | expect(t).to.equal(``); 74 | }); 75 | }) 76 | 77 | describe('splitStringToArray', () => { 78 | it('splitStringToArray should be array with 1 element', () => { 79 | let t=splitStringToArray("1"); 80 | expect(t).to.be.an('array'). 81 | that.to.have.lengthOf(1). 82 | that.to.deep.equal([`1`]); 83 | }); 84 | 85 | it('splitStringToArray should be array with 3 element', () => { 86 | let param=`41`; 87 | let t=splitStringToArray(param); 88 | expect(t).to.be.an('array'). 89 | that.to.have.lengthOf(3). 90 | that.to.deep.equal([ 91 | '4', 92 | '', 93 | '1' 94 | ]); 95 | }); 96 | 97 | it('splitStringToArray should be array with 2 element when it allow enter keyboard', () => { 98 | let t=splitStringToArray(`0\r\n2`,true); 99 | expect(t).to.be.an('array'). 100 | that.to.have.lengthOf(3). 101 | that.to.deep.equal( 102 | [ 103 | '0', 104 | '
', 105 | '2' 106 | ] 107 | ); 108 | }); 109 | it('splitStringToArray should be array with 2 element when it no allow enter keyboard', () => { 110 | let t=splitStringToArray(`0\r\n2`,false); 111 | console.log("ttttttttttt",t) 112 | expect(t).to.be.an('array'). 113 | that.to.have.lengthOf(3). 114 | that.to.deep.equal( 115 | [ 116 | '0', 117 | ' ', 118 | '2' 119 | ] 120 | ); 121 | }); 122 | 123 | }) 124 | 125 | describe('getElementIndexOnParent', () => { 126 | it('getFullPingMatchObjKey should be array', () => { 127 | let wrap=document.createElement("div"); 128 | let createChild=function(elementName="p"){ 129 | let t=document.createElement("div"); 130 | wrap.appendChild(t); 131 | return t; 132 | } 133 | createChild("p"); 134 | createChild("p"); 135 | createChild("p"); 136 | let div=createChild("div"); 137 | document.body.appendChild(wrap) 138 | expect(getElementIndexOnParent(div)).to.equal(3); 139 | }) 140 | }) 141 | 142 | describe('labelStringRemoveLabelExceptImg', () => { 143 | it('labelStringRemoveLabelExceptImg should be 0', () => { 144 | let t=labelStringRemoveLabelExceptImg(`0`); 145 | expect(t).to.equal("0"); 146 | }) 147 | it('labelStringRemoveLabelExceptImg should be Html Label', () => { 148 | let t=labelStringRemoveLabelExceptImg(``); 149 | expect(t).to.equal(``); 150 | }) 151 | 152 | it('labelStringRemoveLabelExceptImg should be \r\n', () => { 153 | let t=labelStringRemoveLabelExceptImg(`
`); 154 | expect(t).to.equal(`\r\n`); 155 | }) 156 | }) 157 | 158 | describe('uuid', () => { 159 | it('uuid should be true', () => { 160 | let arr=[]; 161 | for(let i=0;i<100;i++){ 162 | arr.push(uuid()); 163 | } 164 | // console.log("uuid",arr) 165 | let end= new Set(arr).size === arr.length; 166 | expect(end).to.equal(true); 167 | }) 168 | 169 | }) 170 | 171 | 172 | -------------------------------------------------------------------------------- /test/copyPaste.spec.js: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import {saveCopyList,getCopyLocalStorage,addOne,nativeCopyString} from "../src/dev/copyPaste" 3 | 4 | // describe('nativeCopyString', () => { 5 | // it('nativeCopyString("abc") should be true', () => { 6 | // let t=nativeCopyString("abc") 7 | // expect(t).to.equal(true); 8 | // }) 9 | 10 | // }); 11 | 12 | describe('saveCopyList&&getCopyLocalStorage', () => { 13 | it('getCopyLocalStorage() should be ["a","b"]', () => { 14 | localStorage.clear(); 15 | saveCopyList(["a","b"]); 16 | expect(getCopyLocalStorage()).to.deep.equal(["a","b"]); 17 | }) 18 | 19 | }); 20 | 21 | describe('addOne', () => { 22 | it('addOne should be ["abc"]', () => { 23 | localStorage.clear(); 24 | let t=addOne("abc"); 25 | expect(t).to.deep.equal(["abc"]); 26 | }) 27 | 28 | it('addOne called mulit more than 20 should be array with item 20', () => { 29 | localStorage.clear(); 30 | localStorage.clear(); 31 | for(let i=0;i<20;i++){ 32 | addOne(i) 33 | } 34 | let t=addOne("最新的") 35 | let result=["最新的",19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1]; 36 | expect(t).to.deep.equal(result); 37 | }) 38 | 39 | }); 40 | 41 | describe('saveCopyList', () => { 42 | it('saveCopyList() should be ["a","b"]', () => { 43 | localStorage.clear(); 44 | saveCopyList(["a","b"]); 45 | let t=JSON.parse(localStorage.getItem("vue-keyboard-copy")) 46 | expect(t).to.deep.equal(["a","b"]); 47 | }) 48 | 49 | }); 50 | 51 | -------------------------------------------------------------------------------- /test/index.vue.base.spec.js: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import { mount } from '@vue/test-utils' 3 | import Index from '../src/dev/index.vue' 4 | import EventKeys from "../src/dev/eventKeys.js" 5 | 6 | describe('index.vue', () => { 7 | let wrapper; 8 | let data={} 9 | // beforeEach(() => alert("Before a test – enter a test")); 10 | // afterEach(() => alert("After a test – exit a test")); 11 | before(async () =>{ 12 | wrapper = mount(Index); 13 | data={ 14 | allowEnter: false, 15 | canSwitchOtherBoard: true, 16 | inputId: "input-id-1622704419302-dca9ef3c-5223-a721-8193-be5f99543b22", 17 | // inputLang: "cn",//默认就是cn输入法 18 | isFocus: true, 19 | tmpValueNoFlash: "1 3", 20 | type: "mix", 21 | } 22 | wrapper.vm.$root.$emit(EventKeys["vue-keyboard-cn-focus"],data) 23 | }); 24 | //判断整体是否展示 25 | it('index.vue trigger show', async () => { 26 | let board= wrapper.find(".key-board-box") 27 | await wrapper.vm.$nextTick() 28 | expect(board.isVisible()).to.equal(true) 29 | 30 | }) 31 | //默认大写 32 | it('index.vue has btn changeCapital and default is capital', async () => { 33 | await wrapper.vm.$refs["dynamicComponent"].$nextTick() 34 | 35 | let hasDom=wrapper.find(".key-board-btn-changeCapital").exists() 36 | &&wrapper.find(".key-board-btn-Q").text()==="Q" 37 | expect(hasDom).to.equal(true); 38 | 39 | }) 40 | //默认中文输入法 41 | it('index.vue default lang is cn', async () => { 42 | await wrapper.vm.$refs["dynamicComponent"].$nextTick() 43 | let dom=wrapper.find(".key-board-box-item-curr-text") 44 | let hasDom=dom.exists() &&dom.text()==="中" 45 | expect(hasDom).to.equal(true); 46 | 47 | }) 48 | //切换到小写 49 | it('index.vue Switch to lower case', async () => { 50 | await wrapper.vm.$refs["dynamicComponent"].$nextTick() 51 | let dom=wrapper.find(".key-board-btn-changeCapital") 52 | await dom.trigger("click"); 53 | let qDom=wrapper.find(".key-board-btn-Q .span-text"); 54 | expect(qDom.text()).to.equal("q"); 55 | }) 56 | //切换到大写 57 | it('index.vue Switch to capital case', async () => { 58 | await wrapper.vm.$refs["dynamicComponent"].$nextTick() 59 | let dom=wrapper.find(".key-board-btn-changeCapital") 60 | await dom.trigger("click"); 61 | let qDom=wrapper.find(".key-board-btn-Q .span-text"); 62 | expect(qDom.text()).to.equal("Q"); 63 | }) 64 | //切换到符号键盘 65 | it('index.vue Switch to symbol', async () => { 66 | await wrapper.vm.$refs["dynamicComponent"].$nextTick() 67 | let dom=wrapper.find(".key-board-btn-symbol") 68 | await dom.trigger("click"); 69 | let qDom=wrapper.find(".key-board-btn-【"); 70 | expect(qDom.exists()).to.equal(true); 71 | }) 72 | //切换回中文键盘 73 | it('index.vue Switch to cn case', async () => { 74 | await wrapper.vm.$refs["dynamicComponent"].$nextTick() 75 | let dom=wrapper.find(".key-board-btn-back") 76 | await dom.trigger("click"); 77 | let qDom=wrapper.find(".key-board-btn-symbol"); 78 | expect(qDom.exists()).to.equal(true); 79 | }) 80 | //切换到数字键盘 81 | it('index.vue Switch to number case', async () => { 82 | await wrapper.vm.$refs["dynamicComponent"].$nextTick() 83 | let dom=wrapper.find(".key-board-btn-changeNumber") 84 | await dom.trigger("click"); 85 | let qDom=wrapper.find(".key-board-btn-1"); 86 | expect(qDom.exists()).to.equal(true); 87 | }) 88 | //切换回到中文键盘 89 | it('index.vue Switch to cn case from number case', async () => { 90 | await wrapper.vm.$refs["dynamicComponent"].$nextTick() 91 | let dom=wrapper.find(".key-board-btn-back") 92 | await dom.trigger("click"); 93 | let qDom=wrapper.find(".key-board-btn-symbol"); 94 | expect(qDom.exists()).to.equal(true); 95 | }) 96 | }) 97 | -------------------------------------------------------------------------------- /test/index.vue.cn.spec.js: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import { mount,createWrapper } from '@vue/test-utils' 3 | import Index from '../src/dev/index.vue' 4 | import EventKeys from "../src/dev/eventKeys.js" 5 | 6 | describe('index.vue 中文输入法测试', () => { 7 | let wrapper=mount(Index); 8 | let data={ 9 | allowEnter: false, 10 | canSwitchOtherBoard: true, 11 | inputId: "input-id-1622704419302-dca9ef3c-5223-a721-8193-be5f99543b22", 12 | // inputLang: "cn",//默认就是cn输入法 13 | isFocus: true, 14 | tmpValueNoFlash: "1 3", 15 | type: "cn", 16 | } 17 | beforeEach(() =>{ 18 | wrapper.vm.$root.$emit(EventKeys["vue-keyboard-cn-focus"],data) 19 | }); 20 | 21 | 22 | //测试中文点击Q键后,删除 23 | it('clicked btn Q', async () => { 24 | await wrapper.vm.$nextTick() 25 | let btn= wrapper.find(".key-board-btn-Q") 26 | let deleteBtn=wrapper.find(".key-board-btn-delete"); 27 | await btn.trigger("click"); 28 | let cnDomHtml=wrapper.find(".zh-text-list-box .zh-text-item") 29 | expect(cnDomHtml.text()).to.equal("去"); 30 | await deleteBtn.trigger("click"); 31 | expect(wrapper.find(".zh-text-list-box").exists()).be.equal(false); 32 | 33 | }) 34 | 35 | //测试中文点击W键后,点击待选中文 36 | //测试中文点击W键后,点击回车 37 | it('clicked btn W', async () => { 38 | await wrapper.vm.$nextTick() 39 | let btn= wrapper.find(".key-board-btn-W") 40 | let enterBtn=wrapper.find(".key-board-btn-enter"); 41 | await btn.trigger("click"); 42 | let cnDomHtml=wrapper.find(".zh-text-list-box .zh-text-item") 43 | expect(cnDomHtml.text()).to.equal("我"); 44 | //输入一个拼音后回车 45 | await enterBtn.trigger("click"); 46 | const rootWrapper = createWrapper(wrapper.vm.$root); 47 | const rootAppendEvent=rootWrapper.emitted(EventKeys["vue-keyboard-cn-append-item"]); 48 | expect(rootAppendEvent).to.be.deep.include(['我']) 49 | 50 | }) 51 | //测试中文点击W键后,切换输入法 52 | it('clicked btn W and switch', async () => { 53 | await wrapper.vm.$nextTick() 54 | let btn= wrapper.find(".key-board-btn-W") 55 | let switchBtn=wrapper.find(".key-board-btn-changeLan"); 56 | await btn.trigger("click"); 57 | let cnDomHtml=wrapper.find(".zh-text-list-box .zh-text-item") 58 | expect(cnDomHtml.text()).to.equal("我"); 59 | await switchBtn.trigger("click"); 60 | cnDomHtml=wrapper.find(".zh-text-list-box .zh-text-item");//一定要重新获取,因为之前赋值的可能还没有及时销毁 61 | expect(cnDomHtml.exists()).to.equal(false); 62 | await switchBtn.trigger("click");//再回复中文输入法,否则后面都会受到影响 63 | }) 64 | 65 | it('clicked btn N and btn H,then click enter btn', async () => { 66 | await wrapper.vm.$nextTick() 67 | let enterBtn=wrapper.find(".key-board-btn-enter"); 68 | //输入两个辅音单词,再回车 69 | let btnN= wrapper.find(".key-board-btn-N") 70 | let btnH= wrapper.find(".key-board-btn-H") 71 | await btnN.trigger("click"); 72 | await btnH.trigger("click"); 73 | await enterBtn.trigger("click"); 74 | const rootWrapper = createWrapper(wrapper.vm.$root); 75 | const rootAppendEvent=rootWrapper.emitted(EventKeys["vue-keyboard-cn-append-item"]); 76 | console.log("event",rootAppendEvent) 77 | expect(rootAppendEvent).to.be.deep.include(['nh']) 78 | }) 79 | 80 | //测试热词 81 | it('test hot word menory', async () => { 82 | await wrapper.vm.$nextTick() 83 | let enterBtn=wrapper.find(".key-board-btn-enter"); 84 | //输入两个辅音单词,再回车 85 | let btnN= wrapper.find(".key-board-btn-N") 86 | let btnI= wrapper.find(".key-board-btn-I") 87 | let btnH= wrapper.find(".key-board-btn-H") 88 | let btnA= wrapper.find(".key-board-btn-A") 89 | let btnO= wrapper.find(".key-board-btn-O") 90 | //你 91 | await btnN.trigger("click"); 92 | await btnI.trigger("click"); 93 | //好 94 | await btnH.trigger("click"); 95 | await btnA.trigger("click"); 96 | await btnO.trigger("click"); 97 | //中文待选列表 98 | await wrapper.find(".zh-text-list-box .zh-text-item").trigger("click");//点击”你“字 99 | await wrapper.find(".zh-text-list-box .zh-text-item").trigger("click");//点击”好“字 100 | 101 | await enterBtn.trigger("click"); 102 | 103 | const rootWrapper = createWrapper(wrapper.vm.$root); 104 | const rootAppendEvent=rootWrapper.emitted(EventKeys["vue-keyboard-cn-append-item"]); 105 | expect(rootAppendEvent).to.be.deep.include(['你好']) 106 | 107 | /** 108 | * 在本地存在热词”你好“的缓存后再次输入nihao 109 | * 将会存在可选的”你好“选项 110 | * */ 111 | //你 112 | await btnN.trigger("click"); 113 | await btnI.trigger("click"); 114 | //好 115 | await btnH.trigger("click"); 116 | await btnA.trigger("click"); 117 | await btnO.trigger("click"); 118 | //中文待选列表 119 | await wrapper.find(".zh-text-list-box .zh-text-item").trigger("click");//点击”你好“字 120 | await enterBtn.trigger("click"); 121 | console.log("event",rootAppendEvent) 122 | let matchLength=0; 123 | rootAppendEvent.forEach(item=>{ 124 | if(item&&item[0]=="你好"){ 125 | matchLength++; 126 | } 127 | }) 128 | expect(matchLength).to.be.equal(2); 129 | 130 | }) 131 | 132 | 133 | //输入拼音,选中一部分后,还有未选择中文的拼音时候回车 134 | it('inputed nimena,then click enter btn', async () => { 135 | await wrapper.vm.$nextTick() 136 | let enterBtn=wrapper.find(".key-board-btn-enter"); 137 | //输入两个辅音单词,再回车 138 | let btnN= wrapper.find(".key-board-btn-N") 139 | let btnI= wrapper.find(".key-board-btn-I") 140 | let btnM= wrapper.find(".key-board-btn-M") 141 | let btnE= wrapper.find(".key-board-btn-E") 142 | let btnA= wrapper.find(".key-board-btn-A") 143 | //你 144 | await btnN.trigger("click"); 145 | await btnI.trigger("click"); 146 | //们 147 | await btnM.trigger("click"); 148 | await btnE.trigger("click"); 149 | await btnN.trigger("click"); 150 | //a 151 | await btnA.trigger("click"); 152 | //中文待选列表 153 | await wrapper.find(".zh-text-list-box .zh-text-item").trigger("click");//点击”你“字 154 | await wrapper.find(".zh-text-list-box .zh-text-item").trigger("click");//点击”们“字 155 | 156 | await enterBtn.trigger("click"); 157 | 158 | const rootWrapper = createWrapper(wrapper.vm.$root); 159 | const rootAppendEvent=rootWrapper.emitted(EventKeys["vue-keyboard-cn-append-item"]); 160 | expect(rootAppendEvent).to.be.deep.include(['你们a']) 161 | 162 | 163 | 164 | }) 165 | 166 | 167 | }) 168 | -------------------------------------------------------------------------------- /test/index.vue.tab.spec.js: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import { mount } from '@vue/test-utils' 3 | import Index from '../src/dev/index.vue' 4 | import EventKeys from "../src/dev/eventKeys.js" 5 | import { person, hearts, symbo } from "../src/dev/emojiImages.js"; 6 | let emoji={ 7 | person, 8 | hearts, 9 | symbo, 10 | } 11 | const tabTestFn=(type="cn")=>{ 12 | describe('index.tab.vue:'+type, async () => { 13 | let wrapper = mount(Index); 14 | await wrapper.setProps({ emojiMap: emoji}) 15 | let data={ 16 | allowEnter: false, 17 | canSwitchOtherBoard: true, 18 | inputId: "input-id-1622704419302-dca9ef3c-5223-a721-8193-be5f99543b22", 19 | // inputLang: "cn",//默认就是cn输入法 20 | isFocus: true, 21 | tmpValueNoFlash: "1 3", 22 | type: type, 23 | } 24 | wrapper.vm.$root.$emit(EventKeys["vue-keyboard-cn-focus"],data) 25 | //第一个选项高亮 26 | it('first tab has className active', async () => { 27 | await wrapper.vm.$nextTick() 28 | let board= wrapper.findAll('.key-board-box-head-op .head-op-icon').at(0) 29 | expect(board.classes()).to.be.an('array').that.include("active"); 30 | }) 31 | 32 | //表情选项是否可以点击 33 | if(type=="mix"){ 34 | it('emoji tab can click', async () => { 35 | await wrapper.vm.$nextTick() 36 | let board= wrapper.findAll('.key-board-box-head-op .head-op-icon').at(1) 37 | 38 | await board.trigger("click"); 39 | expect(board.classes()).to.be.an('array').that.include("active"); 40 | //emoji面板是否存在 41 | let isExists=wrapper.find(".emoji-wrap").exists() 42 | expect(isExists).to.equal(true); 43 | }) 44 | } 45 | else{ 46 | it('emoji tab cant click', async () => { 47 | await wrapper.vm.$nextTick() 48 | let board= wrapper.findAll('.key-board-box-head-op .head-op-icon').at(1) 49 | 50 | await board.trigger("click"); 51 | expect(board.classes()).to.be.an('array').that.does.not.include("active"); 52 | //emoji面板是否存在 53 | let isExists=wrapper.find(".emoji-wrap").exists() 54 | expect(isExists).to.equal(false); 55 | }) 56 | } 57 | 58 | 59 | //操作面板tab是否可以点击 60 | it('operating tab can click', async () => { 61 | await wrapper.vm.$nextTick() 62 | let board= wrapper.findAll('.key-board-box-head-op .head-op-icon').at(2) 63 | await board.trigger("click"); 64 | expect(board.classes()).to.be.an('array').that.include("active"); 65 | //操作面板是否存在 66 | let isExists=wrapper.find(".operation-wrap-left-pancel").exists() 67 | expect(isExists).to.equal(true); 68 | }) 69 | 70 | 71 | }) 72 | } 73 | 74 | 75 | 76 | tabTestFn("cn") 77 | tabTestFn("en") 78 | tabTestFn("int") 79 | tabTestFn("float") 80 | tabTestFn("mix") -------------------------------------------------------------------------------- /test/input.vue.event.spec.js: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import { mount,createWrapper } from '@vue/test-utils' 3 | import InputConpoment from '../src/dev/input.vue' 4 | import EventKeys from "../src/dev/eventKeys.js" 5 | describe('Input root event,int', async () => { 6 | 7 | it('input type int,valid value 1', async () => { 8 | let wrapper = mount(InputConpoment,{ 9 | propsData: { 10 | value: "", 11 | type:"int" 12 | } 13 | }); 14 | await wrapper.setData({ isFocus: true }) 15 | const rootWrapper = createWrapper(wrapper.vm.$root); 16 | rootWrapper.vm.$emit(EventKeys["vue-keyboard-cn-append-item"], 1) 17 | await wrapper.vm.$nextTick() 18 | let span=wrapper.findAll(".vue-keyboard-text-item") 19 | console.log("init html",wrapper.html()) 20 | let result=span.length==1&&span.at(0).text()==1 21 | expect(result).to.be.equal(true); 22 | }) 23 | 24 | it('input type int,invalid value 1.1', async () => { 25 | let wrapper = mount(InputConpoment,{ 26 | propsData: { 27 | value: "", 28 | type:"int" 29 | } 30 | }); 31 | await wrapper.setData({ isFocus: true }) 32 | await wrapper.vm.$nextTick() 33 | const rootWrapper = createWrapper(wrapper.vm.$root); 34 | rootWrapper.vm.$emit(EventKeys["vue-keyboard-cn-append-item"], 1.1) 35 | await wrapper.vm.$nextTick() 36 | let span=wrapper.findAll(".vue-keyboard-text-item") 37 | let result=span.length==0 38 | expect(result).to.be.equal(true); 39 | }) 40 | 41 | }) 42 | 43 | describe('Input root event,float', async () => { 44 | 45 | it('input type float,valid value 1.12', async () => { 46 | let wrapper = mount(InputConpoment,{ 47 | propsData: { 48 | value: "", 49 | type:"float" 50 | } 51 | }); 52 | await wrapper.setData({ isFocus: true }) 53 | const rootWrapper = createWrapper(wrapper.vm.$root); 54 | rootWrapper.vm.$emit(EventKeys["vue-keyboard-cn-append-item"], 1.12) 55 | await wrapper.vm.$nextTick() 56 | let span=wrapper.findAll(".vue-keyboard-text-item") 57 | console.log("init html",wrapper.html()) 58 | let result=span.length==4&&wrapper.find(".vue-keyboard-input-text").text()==1.12 59 | expect(result).to.be.equal(true); 60 | }) 61 | //1也是可以接受输入的,因为1.12是一个个按键输入的 62 | it('input type float,valid value 1,should be true', async () => { 63 | let wrapper = mount(InputConpoment,{ 64 | propsData: { 65 | value: "", 66 | type:"float" 67 | } 68 | }); 69 | await wrapper.setData({ isFocus: true }) 70 | await wrapper.vm.$nextTick() 71 | const rootWrapper = createWrapper(wrapper.vm.$root); 72 | rootWrapper.vm.$emit(EventKeys["vue-keyboard-cn-append-item"], 1) 73 | await wrapper.vm.$nextTick() 74 | let span=wrapper.findAll(".vue-keyboard-text-item") 75 | let result=span.length==1&&wrapper.find(".vue-keyboard-input-text").text()==1 76 | expect(result).to.be.equal(true); 77 | }) 78 | 79 | it('input type float,invalid value 1.134,should be false', async () => { 80 | let wrapper = mount(InputConpoment,{ 81 | propsData: { 82 | value: "", 83 | type:"float" 84 | } 85 | }); 86 | await wrapper.setData({ isFocus: true }) 87 | await wrapper.vm.$nextTick() 88 | const rootWrapper = createWrapper(wrapper.vm.$root); 89 | rootWrapper.vm.$emit(EventKeys["vue-keyboard-cn-append-item"], 1.134) 90 | await wrapper.vm.$nextTick() 91 | let span=wrapper.findAll(".vue-keyboard-text-item") 92 | let result=span.length==0 93 | expect(result).to.be.equal(true); 94 | }) 95 | it('input type float,valid value 1.34 and props decimal 3,should be true', async () => { 96 | let wrapper = mount(InputConpoment,{ 97 | propsData: { 98 | value: "", 99 | type:"float", 100 | decimal:3 101 | } 102 | }); 103 | await wrapper.setData({ isFocus: true }) 104 | await wrapper.vm.$nextTick() 105 | const rootWrapper = createWrapper(wrapper.vm.$root); 106 | rootWrapper.vm.$emit(EventKeys["vue-keyboard-cn-append-item"], 1.34) 107 | await wrapper.vm.$nextTick() 108 | let span=wrapper.findAll(".vue-keyboard-text-item") 109 | let result=span.length==4&&wrapper.find(".vue-keyboard-input-text").text()==1.34 110 | expect(result).to.be.equal(true); 111 | }) 112 | 113 | }) 114 | 115 | 116 | describe('Input root event,cn', async () => { 117 | 118 | it('input type cn,valid value 我', async () => { 119 | let wrapper = mount(InputConpoment,{ 120 | propsData: { 121 | value: "", 122 | type:"cn" 123 | } 124 | }); 125 | await wrapper.setData({ isFocus: true }) 126 | const rootWrapper = createWrapper(wrapper.vm.$root); 127 | rootWrapper.vm.$emit(EventKeys["vue-keyboard-cn-append-item"], "我") 128 | await wrapper.vm.$nextTick() 129 | let span=wrapper.findAll(".vue-keyboard-text-item") 130 | console.log("init html",wrapper.html()) 131 | let result=span.length==1&&span.at(0).text()=="我" 132 | expect(result).to.be.equal(true); 133 | }) 134 | it('input type cn,valid value ·', async () => { 135 | let wrapper = mount(InputConpoment,{ 136 | propsData: { 137 | value: "", 138 | type:"cn" 139 | } 140 | }); 141 | await wrapper.setData({ isFocus: true }) 142 | const rootWrapper = createWrapper(wrapper.vm.$root); 143 | rootWrapper.vm.$emit(EventKeys["vue-keyboard-cn-append-item"], "·") 144 | await wrapper.vm.$nextTick() 145 | let span=wrapper.findAll(".vue-keyboard-text-item") 146 | console.log("init html",wrapper.html()) 147 | let result=span.length==1&&span.at(0).text()=="·" 148 | expect(result).to.be.equal(true); 149 | }) 150 | 151 | it('input type cn,invalid value ,', async () => { 152 | let wrapper = mount(InputConpoment,{ 153 | propsData: { 154 | value: "", 155 | type:"cn" 156 | } 157 | }); 158 | await wrapper.setData({ isFocus: true }) 159 | await wrapper.vm.$nextTick() 160 | const rootWrapper = createWrapper(wrapper.vm.$root); 161 | rootWrapper.vm.$emit(EventKeys["vue-keyboard-cn-append-item"], ",") 162 | await wrapper.vm.$nextTick() 163 | let span=wrapper.findAll(".vue-keyboard-text-item") 164 | let result=span.length==0 165 | expect(result).to.be.equal(true); 166 | }) 167 | 168 | }) 169 | 170 | describe('Input root event,en', async () => { 171 | 172 | it('input type en,valid value A', async () => { 173 | let wrapper = mount(InputConpoment,{ 174 | propsData: { 175 | value: "", 176 | type:"en" 177 | } 178 | }); 179 | await wrapper.setData({ isFocus: true }) 180 | const rootWrapper = createWrapper(wrapper.vm.$root); 181 | rootWrapper.vm.$emit(EventKeys["vue-keyboard-cn-append-item"], 'A') 182 | await wrapper.vm.$nextTick() 183 | let span=wrapper.findAll(".vue-keyboard-text-item") 184 | console.log("init html",wrapper.html()) 185 | let result=span.length==1&&span.at(0).text()=='A' 186 | expect(result).to.be.equal(true); 187 | }) 188 | it('input type en,valid value A', async () => { 189 | let wrapper = mount(InputConpoment,{ 190 | propsData: { 191 | value: "", 192 | type:"en" 193 | } 194 | }); 195 | await wrapper.setData({ isFocus: true }) 196 | const rootWrapper = createWrapper(wrapper.vm.$root); 197 | rootWrapper.vm.$emit(EventKeys["vue-keyboard-cn-append-item"], 'a') 198 | await wrapper.vm.$nextTick() 199 | let span=wrapper.findAll(".vue-keyboard-text-item") 200 | console.log("init html",wrapper.html()) 201 | let result=span.length==1&&span.at(0).text()=='a' 202 | expect(result).to.be.equal(true); 203 | }) 204 | 205 | it('input type en,invalid value ","', async () => { 206 | let wrapper = mount(InputConpoment,{ 207 | propsData: { 208 | value: "", 209 | type:"en" 210 | } 211 | }); 212 | await wrapper.setData({ isFocus: true }) 213 | await wrapper.vm.$nextTick() 214 | const rootWrapper = createWrapper(wrapper.vm.$root); 215 | rootWrapper.vm.$emit(EventKeys["vue-keyboard-cn-append-item"], ",") 216 | await wrapper.vm.$nextTick() 217 | let span=wrapper.findAll(".vue-keyboard-text-item") 218 | let result=span.length==0 219 | expect(result).to.be.equal(true); 220 | }) 221 | 222 | }) 223 | 224 | describe('Input root event,Input rex test', async () => { 225 | 226 | it('input type int,rex', async () => { 227 | let wrapper = mount(InputConpoment,{ 228 | propsData: { 229 | value: "", 230 | type:"int", 231 | regx:/^[\d%+-/]+$/gi 232 | } 233 | }); 234 | await wrapper.setData({ isFocus: true }) 235 | await wrapper.vm.$nextTick() 236 | const rootWrapper = createWrapper(wrapper.vm.$root); 237 | rootWrapper.vm.$emit(EventKeys["vue-keyboard-cn-append-item"], "%") 238 | await wrapper.vm.$nextTick() 239 | let span=wrapper.findAll(".vue-keyboard-text-item") 240 | let result=span.length==1&&span.at(0).text()=="%"; 241 | expect(result).to.be.equal(true); 242 | }) 243 | 244 | it('input type cn,rex', async () => { 245 | let wrapper = mount(InputConpoment,{ 246 | propsData: { 247 | value: "", 248 | type:"cn", 249 | regx:/^[\d%+-/]+$/gi 250 | } 251 | }); 252 | await wrapper.setData({ isFocus: true }) 253 | await wrapper.vm.$nextTick() 254 | const rootWrapper = createWrapper(wrapper.vm.$root); 255 | rootWrapper.vm.$emit(EventKeys["vue-keyboard-cn-append-item"], "%") 256 | await wrapper.vm.$nextTick() 257 | let span=wrapper.findAll(".vue-keyboard-text-item") 258 | let result=span.length==1&&span.at(0).text()=="%"; 259 | expect(result).to.be.equal(true); 260 | }) 261 | 262 | it('input type en,rex', async () => { 263 | let wrapper = mount(InputConpoment,{ 264 | propsData: { 265 | value: "", 266 | type:"en", 267 | regx:/^[\d%+-/]+$/gi 268 | } 269 | }); 270 | await wrapper.setData({ isFocus: true }) 271 | await wrapper.vm.$nextTick() 272 | const rootWrapper = createWrapper(wrapper.vm.$root); 273 | rootWrapper.vm.$emit(EventKeys["vue-keyboard-cn-append-item"], "%") 274 | await wrapper.vm.$nextTick() 275 | let span=wrapper.findAll(".vue-keyboard-text-item") 276 | let result=span.length==1&&span.at(0).text()=="%"; 277 | expect(result).to.be.equal(true); 278 | }) 279 | 280 | }) -------------------------------------------------------------------------------- /test/input.vue.props.spec.js: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import { mount } from '@vue/test-utils' 3 | import InputConpoment from '../src/dev/input.vue' 4 | describe('Input props', async () => { 5 | 6 | 7 | it('input innerHtml is 1', async () => { 8 | let wrapper = mount(InputConpoment,{ 9 | propsData: { 10 | value: "1" 11 | } 12 | }); 13 | await wrapper.vm.$nextTick() 14 | let span=wrapper.findAll(".vue-keyboard-text-item") 15 | let result=span.length==1&&span.at(0).text()==1 16 | expect(result).to.be.equal(true); 17 | }) 18 | 19 | it('input innerHtml is " ",when it is not allow enter', async () => { 20 | let wrapper = mount(InputConpoment,{ 21 | propsData: { 22 | value: "\r\n" 23 | } 24 | }); 25 | await wrapper.vm.$nextTick() 26 | 27 | let span=wrapper.findAll(".vue-keyboard-text-item") 28 | let result=span.length==1&&span.at(0).text()=="" 29 | expect(result).to.be.equal(true); 30 | }) 31 | it('input innerHtml is "
",when it is allow enter', async () => { 32 | let wrapper = mount(InputConpoment,{ 33 | propsData: { 34 | value: "\r\n", 35 | allowEnter:true 36 | } 37 | }); 38 | await wrapper.vm.$nextTick() 39 | let span=wrapper.findAll(".vue-keyboard-text-item") 40 | let br=wrapper.findAll("br") 41 | let result=span.length==0&&br.length==1; 42 | expect(result).to.be.equal(true); 43 | }) 44 | 45 | it('input innerHtml is "
",when enter is allow enter', async () => { 46 | let wrapper = mount(InputConpoment,{ 47 | propsData: { 48 | value: ` 49 | 1`, 50 | allowEnter:true 51 | } 52 | }); 53 | await wrapper.vm.$nextTick() 54 | let span=wrapper.findAll(".vue-keyboard-text-item") 55 | let brLabel=wrapper.findAll("br"); 56 | let result=span.length==1&&span.at(0).text()==`1`&& 57 | brLabel.length==1; 58 | expect(result).to.be.equal(true); 59 | }) 60 | 61 | 62 | 63 | it('input innerHtml is img,when img was inputed', async () => { 64 | let path=`` 65 | let wrapper = mount(InputConpoment,{ 66 | propsData: { 67 | value: path 68 | } 69 | }); 70 | await wrapper.vm.$nextTick() 71 | let img=wrapper.findAll("img"); 72 | let span=wrapper.findAll(".vue-keyboard-text-item") 73 | let result=img.length==1&&span.length==0; 74 | expect(result).to.be.equal(true); 75 | }) 76 | 77 | }) -------------------------------------------------------------------------------- /test/inputFilterRegx.spec.js: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import Regx from "../src/dev/inputFilterRegx.js" 3 | 4 | 5 | describe('float', () => { 6 | it('float params 1 should be true', () => { 7 | expect(Regx.float(1)).to.equal(true); 8 | }) 9 | it('float params 1.1 should be true', () => { 10 | expect(Regx.float(1.1)).to.equal(true); 11 | }) 12 | it('float params "1.10" should be true', () => { 13 | //如果最后一个小数是0必须先传递字符串 14 | expect(Regx.float(1.10.toFixed(2))).to.equal(true); 15 | }) 16 | it('float params 1.11 should be true', () => { 17 | expect(Regx.float(1.11)).to.equal(true); 18 | }) 19 | it('float params (1.1,1) should be true', () => { 20 | expect(Regx.float(1.1,1)).to.equal(true); 21 | }) 22 | 23 | }) 24 | 25 | describe('int', () => { 26 | it('int params 1 should be true', () => { 27 | expect(Regx.int(1)).to.equal(true); 28 | }) 29 | it('int params 1.1 should be false', () => { 30 | expect(Regx.int(1.1)).to.equal(false); 31 | }) 32 | }) 33 | 34 | describe('cn', () => { 35 | it('cn params 1 should be false', () => { 36 | expect(Regx.cn(1)).to.equal(false); 37 | }) 38 | it('cn params `你好` should be true', () => { 39 | expect(Regx.cn(`你好`)).to.equal(true); 40 | }) 41 | it('cn params `你·好` should be true', () => { 42 | expect(Regx.cn(`你·好`)).to.equal(true); 43 | }) 44 | it('cn params `你好.` should be false', () => { 45 | expect(Regx.cn(`你好.`)).to.equal(false); 46 | }) 47 | it('cn params `hello` should be false', () => { 48 | expect(Regx.cn(`hello`)).to.equal(false); 49 | }) 50 | }) 51 | describe('en', () => { 52 | it('en params `hello` should be true', () => { 53 | expect(Regx.en(`hello`)).to.equal(true); 54 | }) 55 | it('en params `hello,world` should be false', () => { 56 | expect(Regx.en(`hello,world`)).to.equal(false); 57 | }) 58 | }) -------------------------------------------------------------------------------- /test/lowercaseMemory.spec.js: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import {getCaseItem,setCaseItem} from "../src/dev/lowercaseMemory" 3 | 4 | 5 | describe('getCaseItem', () => { 6 | it('getCaseItem() should be false', () => { 7 | localStorage.clear() 8 | expect(getCaseItem()).to.equal("capitalize"); 9 | }) 10 | it('after setCaseItem(),getCaseItem() should be false', () => { 11 | localStorage.clear() 12 | setCaseItem(); 13 | expect(getCaseItem()).to.equal("capitalize"); 14 | }) 15 | it('after setCaseItem("1"),getCaseItem() should be false', () => { 16 | localStorage.clear() 17 | setCaseItem("1") 18 | expect(getCaseItem()).to.equal("lowercase"); 19 | }) 20 | 21 | }) -------------------------------------------------------------------------------- /test/memory.spec.js: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import {getItem,matchHotPingying,setPingying} from "../src/dev/memory" 3 | 4 | describe('setPingying', () => { 5 | it('getItem() should be object with order 0', () => { 6 | localStorage.clear(); 7 | setPingying("nihao","你好") 8 | expect(getItem("nihao")).to.deep.equal([{ 9 | zh:"你好", 10 | order:0, 11 | key:"nihao" 12 | }]); 13 | }) 14 | it('getItem() should be object with order 1', () => { 15 | localStorage.clear(); 16 | setPingying("nihao","你好") 17 | setPingying("nihao","你好") 18 | expect(getItem("nihao")).to.deep.equal([{ 19 | zh:"你好", 20 | order:1, 21 | key:"nihao" 22 | }]); 23 | }) 24 | 25 | it('getItem() should be empty object', () => { 26 | localStorage.clear(); 27 | setPingying("meilijiangongheguohahahah","美利坚共和国xx") 28 | expect(getItem("meilijiangongheguohahahah")).to.deep.equal({}); 29 | }) 30 | 31 | 32 | 33 | it(' test last updateTime more than 7 day,getItem() should be {}', () => { 34 | localStorage.clear(); 35 | setPingying("nihao","你好") 36 | try{ 37 | let t= localStorage.getItem("vue-keyboard-cn-store"); 38 | let parseJons=JSON.parse(t); 39 | parseJons["__$lastClearTime"]=new Date().getTime()-(86400*7+200); 40 | let stringStore=JSON.stringify(parseJons); 41 | localStorage.setItem("vue-keyboard-cn-store",stringStore); 42 | setPingying("haha","哈哈") 43 | }catch(e){ 44 | console.log("报错了",e) 45 | } 46 | expect(getItem("nihao")).to.deep.equal({}); 47 | }) 48 | it(' test last updateTime more than 7 day,getItem("haha") should be valid object', () => { 49 | localStorage.clear(); 50 | setPingying("nihao","你好") 51 | try{ 52 | let t= localStorage.getItem("vue-keyboard-cn-store"); 53 | let parseJons=JSON.parse(t); 54 | parseJons["__$lastClearTime"]=new Date().getTime()-(86400*7+200); 55 | let stringStore=JSON.stringify(parseJons); 56 | localStorage.setItem("vue-keyboard-cn-store",stringStore); 57 | setPingying("haha","哈哈") 58 | }catch(e){ 59 | console.log("报错了",e) 60 | } 61 | expect(getItem("haha")).to.deep.equal([{ 62 | zh:"哈哈", 63 | order:0, 64 | key:"haha" 65 | }]); 66 | }) 67 | 68 | }); 69 | describe('matchHotPingying', () => { 70 | it('matchHotPingying call muli time,getItem() should be array with three element', () => { 71 | localStorage.clear(); 72 | setPingying("nihao","你好") 73 | setPingying("nihao","你好") 74 | setPingying("nihao","拟好") 75 | setPingying("nihao","拟好") 76 | setPingying("nihao","拟好") 77 | setPingying("nihao","你号") 78 | setPingying("nihao","你号") 79 | setPingying("nihao","你号") 80 | setPingying("nihao","你号") 81 | setPingying("nihao","(*´▽`)ノノ") 82 | expect(matchHotPingying("nihao")).to.deep.equal( [ 83 | { 84 | zh:"你号", 85 | order:3, 86 | key:"nihao" 87 | }, 88 | { 89 | zh:"拟好", 90 | order:2, 91 | key:"nihao" 92 | }, 93 | { 94 | zh:"你好", 95 | order:1, 96 | key:"nihao" 97 | }, 98 | ]); 99 | }) 100 | 101 | 102 | 103 | 104 | }); -------------------------------------------------------------------------------- /webpack.components.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack = require('webpack') 3 | const Components = require('./components.json'); 4 | module.exports = { 5 | entry: Components, 6 | output: { 7 | path: path.resolve(__dirname, './distComponents'), 8 | filename: '[name].min.js', 9 | chunkFilename: '[id].js', 10 | }, 11 | module: { 12 | rules: [ 13 | { 14 | test: /\.css$/, 15 | use: [ 16 | 'vue-style-loader', 17 | 'css-loader' 18 | ], 19 | }, 20 | { 21 | test: /\.scss$/, 22 | use: [ 23 | 'vue-style-loader', 24 | 'css-loader', 25 | 'sass-loader' 26 | ] 27 | }, 28 | { 29 | test: /\.vue$/, 30 | loader: 'vue-loader', 31 | options: { 32 | loaders: { 33 | } 34 | // other vue-loader options go here 35 | } 36 | }, 37 | { 38 | test: /\.js$/, 39 | loader: 'babel-loader', 40 | exclude: /node_modules/ 41 | }, 42 | { 43 | test: /\.(png|jpg|gif|svg|eot|woff|woff2?|ttf)$/, 44 | loader: 'file-loader', 45 | options: { 46 | name: '[name].[ext]?[hash]' 47 | } 48 | } 49 | ] 50 | }, 51 | resolve: { 52 | alias: { 53 | 'vue$': 'vue/dist/vue.esm.js' 54 | }, 55 | extensions: ['*', '.js', '.vue', '.json'] 56 | }, 57 | devServer: { 58 | historyApiFallback: true, 59 | noInfo: true, 60 | overlay: true 61 | }, 62 | performance: { 63 | hints: false 64 | }, 65 | devtool: 'hidden-source-map', 66 | } 67 | 68 | if (process.env.NODE_ENV === 'production') { 69 | module.exports.devtool = '#source-map' 70 | // http://vue-loader.vuejs.org/en/workflow/production.html 71 | module.exports.plugins = (module.exports.plugins || []).concat([ 72 | new webpack.DefinePlugin({ 73 | 'process.env': { 74 | NODE_ENV: '"production"' 75 | } 76 | }), 77 | new webpack.optimize.UglifyJsPlugin({ 78 | sourceMap: false, 79 | compress: { 80 | warnings: false, 81 | drop_debugger:true, 82 | drop_console:true, 83 | pure_funcs: ['console.log']//移除console 84 | } 85 | }), 86 | new webpack.LoaderOptionsPlugin({ 87 | minimize: true 88 | }) 89 | ]) 90 | } 91 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack = require('webpack') 3 | 4 | module.exports = { 5 | entry: './src/main.js', 6 | output: { 7 | path: path.resolve(__dirname, './dist'), 8 | publicPath: '/dist/', 9 | filename: 'build.js' 10 | }, 11 | module: { 12 | rules: [ 13 | { 14 | test: /\.css$/, 15 | use: [ 16 | 'vue-style-loader', 17 | 'css-loader' 18 | ], 19 | }, 20 | { 21 | test: /\.scss$/, 22 | use: [ 23 | 'vue-style-loader', 24 | 'css-loader', 25 | 'sass-loader' 26 | ] 27 | }, 28 | { 29 | test: /\.vue$/, 30 | loader: 'vue-loader', 31 | options: { 32 | loaders: { 33 | } 34 | // other vue-loader options go here 35 | } 36 | }, 37 | { 38 | test: /\.js$/, 39 | loader: 'babel-loader', 40 | exclude: /node_modules/ 41 | }, 42 | { 43 | test: /\.(png|jpg|gif|svg|eot|woff|woff2?|ttf)$/, 44 | loader: 'file-loader', 45 | options: { 46 | name: '[name].[ext]?[hash]' 47 | } 48 | } 49 | ] 50 | }, 51 | resolve: { 52 | alias: { 53 | 'vue$': 'vue/dist/vue.esm.js' 54 | }, 55 | extensions: ['*', '.js', '.vue', '.json'] 56 | }, 57 | devServer: { 58 | historyApiFallback: true, 59 | noInfo: true, 60 | overlay: true 61 | }, 62 | performance: { 63 | hints: false 64 | }, 65 | devtool: 'hidden-source-map', 66 | } 67 | 68 | if (process.env.NODE_ENV === 'production') { 69 | module.exports.devtool = '#source-map' 70 | // http://vue-loader.vuejs.org/en/workflow/production.html 71 | module.exports.plugins = (module.exports.plugins || []).concat([ 72 | new webpack.DefinePlugin({ 73 | 'process.env': { 74 | NODE_ENV: '"production"' 75 | } 76 | }), 77 | new webpack.optimize.UglifyJsPlugin({ 78 | sourceMap: true, 79 | compress: { 80 | warnings: false 81 | } 82 | }), 83 | new webpack.LoaderOptionsPlugin({ 84 | minimize: true 85 | }) 86 | ]) 87 | } 88 | -------------------------------------------------------------------------------- /webpack.demo.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack = require('webpack') 3 | var HtmlWebpackPlugin = require('html-webpack-plugin') 4 | module.exports = { 5 | entry: './src/main.js', 6 | output: { 7 | path: path.resolve(__dirname, './docs'), 8 | publicPath: 'https://mtttm.github.io/vue-keyboard-cn/', 9 | filename: 'build.js', 10 | filename: 'build.[chunkHash:8].js' 11 | }, 12 | module: { 13 | rules: [ 14 | { 15 | test: /\.css$/, 16 | use: [ 17 | 'vue-style-loader', 18 | 'css-loader' 19 | ], 20 | }, 21 | { 22 | test: /\.scss$/, 23 | use: [ 24 | 'vue-style-loader', 25 | 'css-loader', 26 | 'sass-loader' 27 | ] 28 | }, 29 | { 30 | test: /\.vue$/, 31 | loader: 'vue-loader', 32 | options: { 33 | loaders: { 34 | } 35 | // other vue-loader options go here 36 | } 37 | }, 38 | { 39 | test: /\.js$/, 40 | loader: 'babel-loader', 41 | exclude: /node_modules/ 42 | }, 43 | { 44 | test: /\.(png|jpg|gif|svg|eot|woff|woff2?|ttf)$/, 45 | loader: 'file-loader', 46 | options: { 47 | name: '[name].[ext]?[hash]' 48 | } 49 | } 50 | ] 51 | }, 52 | resolve: { 53 | alias: { 54 | 'vue$': 'vue/dist/vue.esm.js' 55 | }, 56 | extensions: ['*', '.js', '.vue', '.json'] 57 | }, 58 | devServer: { 59 | historyApiFallback: true, 60 | noInfo: true, 61 | overlay: true 62 | }, 63 | performance: { 64 | hints: false 65 | }, 66 | devtool: 'hidden-source-map', 67 | } 68 | 69 | if (process.env.NODE_ENV === 'production') { 70 | module.exports.devtool = '#source-map' 71 | // http://vue-loader.vuejs.org/en/workflow/production.html 72 | module.exports.plugins = (module.exports.plugins || []).concat([ 73 | new webpack.DefinePlugin({ 74 | 'process.env': { 75 | NODE_ENV: '"production"' 76 | } 77 | }), 78 | new webpack.optimize.UglifyJsPlugin({ 79 | sourceMap: false, 80 | compress: { 81 | warnings: false, 82 | drop_debugger:true, 83 | drop_console:true, 84 | pure_funcs: ['console.log']//移除console 85 | } 86 | }), 87 | new webpack.LoaderOptionsPlugin({ 88 | minimize: true 89 | }), 90 | //生成html模版文件 91 | new HtmlWebpackPlugin({ 92 | filename: 'index.html', 93 | template: 'index.html', 94 | favicon: 'favicon.ico', 95 | inject: true 96 | }) 97 | ]) 98 | } 99 | -------------------------------------------------------------------------------- /webpack.libs.dist.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack = require('webpack') 3 | var ExtractTextPlugin = require("extract-text-webpack-plugin") 4 | var OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin'); 5 | module.exports = { 6 | entry: "./packages/index.js", 7 | output: { 8 | path: path.resolve(__dirname, './dist'), 9 | filename: 'index.es.min.js', 10 | chunkFilename: '[id].js', 11 | libraryExport: 'default', 12 | library: "vue-keyboard-cn", 13 | libraryTarget: 'umd' 14 | }, 15 | module: { 16 | rules: [ 17 | { 18 | test: /\.css$/, 19 | use: [ 20 | 'vue-style-loader', 21 | 'css-loader' 22 | ], 23 | }, 24 | { 25 | test: /\.scss$/, 26 | use: [ 27 | 'vue-style-loader', 28 | 'css-loader', 29 | 'sass-loader' 30 | ] 31 | }, 32 | { 33 | test: /\.vue$/, 34 | loader: 'vue-loader', 35 | options: { 36 | extractCSS: true, // 会把vue中的样式文件提取出来 37 | loaders: { 38 | css: ExtractTextPlugin.extract({ 39 | use: 'css-loader', 40 | fallback: 'vue-style-loader' 41 | }), 42 | sass: ExtractTextPlugin.extract({ 43 | use: [ 44 | 'css-loader', 45 | 'sass-loader' 46 | ], 47 | fallback: 'vue-style-loader' 48 | }) 49 | } 50 | // other vue-loader options go here 51 | } 52 | }, 53 | { 54 | test: /\.js$/, 55 | loader: 'babel-loader', 56 | exclude: /node_modules/ 57 | }, 58 | { 59 | test: /\.(png|jpg|gif|svg|eot|woff|woff2?|ttf)$/, 60 | loader: 'file-loader', 61 | options: { 62 | name: '[name].[ext]?[hash]', 63 | publicPath: './' 64 | } 65 | } 66 | ] 67 | }, 68 | resolve: { 69 | alias: { 70 | 'vue$': 'vue/dist/vue.esm.js' 71 | }, 72 | extensions: ['*', '.js', '.vue', '.json'] 73 | }, 74 | devServer: { 75 | historyApiFallback: true, 76 | noInfo: true, 77 | overlay: true 78 | }, 79 | performance: { 80 | hints: false 81 | }, 82 | devtool: 'hidden-source-map', 83 | } 84 | 85 | if (process.env.NODE_ENV === 'production') { 86 | module.exports.devtool = '#source-map' 87 | // http://vue-loader.vuejs.org/en/workflow/production.html 88 | module.exports.plugins = (module.exports.plugins || []).concat([ 89 | new webpack.DefinePlugin({ 90 | 'process.env': { 91 | NODE_ENV: '"production"' 92 | } 93 | }), 94 | new ExtractTextPlugin("index.css"), 95 | new OptimizeCssAssetsPlugin({ 96 | cssProcessor: require('cssnano'), 97 | cssProcessorOptions: { safe: true, discardComments: { removeAll: true } }, 98 | canPrint: true 99 | }), 100 | // new webpack.optimize.UglifyJsPlugin({ 101 | // sourceMap: false, 102 | // compress: { 103 | // warnings: false, 104 | // drop_debugger: true, 105 | // drop_console: true, 106 | // pure_funcs: ['console.log']//移除console 107 | // } 108 | // }), 109 | new webpack.LoaderOptionsPlugin({ 110 | minimize: true 111 | }) 112 | ]) 113 | } 114 | --------------------------------------------------------------------------------