weex手機端安全鍵盤
阿新 • • 發佈:2018-11-13
github地址:weexSafeKeyboard
效果圖:
技術依賴:
框架:weex+vue
彈出層:weex-ui
圖示:iconfont
說明:
1、如果不想用到weex-ui,可以把inputkey.vue檔案裡的wxc-popup元件去掉,按自己的彈窗實現即可;
2、刪除、大小寫、空格圖示用的是iconfont;如不想用請自行替換;
本專案是放在本地,以安卓為例:android/app/src/main/assets/iconfont
3、密碼可見、不可見圖示按鈕用的是common.js裡的getImageUrl方法獲取的路徑,請自行替換
宣告:
如有需要,請參考實現的思路,消化成自己的東西,勿直接複製,會消化不良。
實際呼叫頁面:index.vue 程式碼如下:
<template> <div> <div class="cell"> <div class="cell_label"> <text class="label">密碼</text> </div> <div class="cell_input"> <inputkey @inputVal="inputVal" :inputstyle="inputstyle" :textstyle="textstyle" type=true placeholder="請輸入登入密碼"></inputkey> </div> </div> </div> </template> <style> .cell {width: 750px;height: 120px;border-bottom-width: 2px;border-bottom-color: #C9C5C4;flex-direction: row;align-items: center;justify-content: center;} .cell_label {justify-content: center;align-items: center;} .label{font-size: 34px;font-weight: 600px;color:#000;} .cell_input {justify-content: center;align-items: center;margin-left: 30px;} </style> <script> import inputkey from './components/inputkey.vue'; export default { data: { inputstyle:{width:'550px',height:'50px',margin:'5px',fontSize:'36px'}, textstyle:{fontSize:'34px',fontWeight:'600',color:'#999'}, password:'', }, components: { inputkey }, created: function () { }, methods:{ inputVal(e){ this.password = e.inputVal; } } } </script>
元件:components/inputkey.vue 程式碼如下:
<template> <div> <div> <div style="flex-direction:row;position:relative;" :style="inputstyle" @click="onfocus"> //placeholder內容 <text class="placeholder" v-if="blank">{{placeholder}}</text> //把輸入內容顯示為* <text v-if="type" :style="textstyle">{{passwordInput}}</text> <text v-if="!type" :style="textstyle">{{input}}</text> //游標“|” <text v-if="cursor=='true'" :style="mrTextstyle" style="color:blue;">|</text> //可不可見圖示 <div class="imagearea" @click="lookPwd"> <image :src="imageUrl" class="image"></image> </div> </div> </div> //weex-ui 裡的 wxc-popup 彈窗,可改為自己的 <wxc-popup popup-color="#fff" :show="isBottomShow" @wxcPopupOverlayClicked="popupMenu" pos="bottom" :height="popupHeight"> <div class="title"> <div class="btn" @click="changeState('abc')"> <text>Abc</text> </div> <div class="btn" @click="changeState('symbol')"> <text>符</text> </div> <div class="btn" @click="changeState('num')"> <text>123</text> </div> <div class="btn2" @click="randomAbc"> <text>安全鍵盤</text> </div> <div class="btn" @click="popupMenu"> <text>完成</text> </div> </div> <div class="content"> //abc介面 <div class="row" v-for="item in charList" v-if="state == 'abc'"> <div class="button" v-for="ite in item" @click="ite=='top'?lowerToUpper(): btnClick(ite)"> <text v-if="ite === 'top'" style="fontFamily:iconfont;color:red;" v-bind:style="{backgroundColor:charState=='lower'?'':'#999999'}">&#xe685;</text> <text v-else-if="ite === 'blank'" style="fontFamily:iconfont;color:red;">&#xe66e;</text> <text v-else-if="ite === 'del'" style="fontFamily:iconfont;color:red;">&#xe629;</text> <text v-else>{{ite}}</text> </div> </div> //特殊符號介面 <div class="row" v-for="item in symbolList" v-if="state == 'symbol'"> <div class="button" v-for="ite in item" v-bind:style="{flex:ite==='blank'?6:1}" @click="btnClick(ite)"> <text v-if="ite === 'blank'" style="fontFamily:iconfont;color:red;">&#xe66e;</text> <text v-else-if="ite === 'del'" style="fontFamily:iconfont;color:red;">&#xe629;</text> <text v-else>{{ite}}</text> </div> </div> //數字介面 <div class="row" v-for="item in numList" v-if="state == 'num'"> <div class="button" v-for="ite in item" v-bind:style="{flex:ite==='blank'?6:1}" @click="btnClick(ite)"> <text v-if="ite === 'blank'" style="fontFamily:iconfont;color:red;">&#xe66e;</text> <text v-else-if="ite === 'del'" style="fontFamily:iconfont;color:red;">&#xe629;</text> <text v-else>{{ite}}</text> </div> </div> </div> </wxc-popup> </div> </template> <style> .placeholder{color:#999999;font-size:36px;} .title{flex-direction:row;justify-content:space-between;align-items:center;padding:10px;border-bottom-width:1px;} .btn{height:70px;flex:1;align-items:center;justify-content:center;} .btn2{height:70px;flex:4;align-items:center;justify-content:center;} .content{padding-top:10px;padding-left:10px;} .row{flex-direction:row;} .button{height:65px;border-width:1px;flex:1;justify-content:center;align-items:center;margin-right:10px;margin-bottom:10px;padding-top:10px;padding-bottom:10px;} .button:active{background-color: #999999;} .image{width:48px;height:32px;} .imagearea{width:48px;height:32px;position:absolute;top:9px;right:0;} </style> <script> import common from '../common/common'; import { WxcPopup } from 'weex-ui'; var domModule = weex.requireModule('dom'); export default { props: { inputstyle:Object, textstyle:Object, type:{ type: Boolean, default: true }, placeholder:{ type: String, default: '請輸入密碼' } }, components: {WxcPopup}, data: function(){ return { input:'', //實際輸入值 passwordInput:'', //實際輸入值轉為* char: ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p','a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'z', 'x', 'c', 'v', 'b', 'n', 'm'], charInit: [], symbolList: [ ['&','"',';','^',',','|','$','*',':','\''], ['?','{','[','~','#','}','.',']','\\','!'], ['(','%','-','_','+','/',')','=','<','`'], ['>','@','blank','del'] ], num:['1','2','3','4','5','6','7','8','9','0'], numInit:[], charRandom:'0', //字母隨機標記 numRandom:'0', //數字隨機標記 state:'abc', charState:'lower', isBottomShow:false, popupHeight:'400', cursor:'', interval:'', blank:true, imageUrl:'' } }, created: function () { var self = this; //字母初始值深拷貝 self.charInit = common.copy(self.char,'deep'); //數字初始值深拷貝 self.numInit = common.copy(self.num,'deep'); //iconfont引入 domModule.addRule('fontFace',{ 'fontFamily':'iconfont', //呼叫本地ttf 'src':"url('local:///iconfont/iconfont.ttf')" }); //可不可見圖片,可改變自己的 self.imageUrl=common.getImageUrl(self)+'login/bukejian.png'; }, methods:{ //聚焦事件,控制游標閃爍 onfocus(){ var self = this; self.blank = false; this.interval = setInterval(function() { if(self.cursor == 'true'){ self.cursor = '' }else{ self.cursor = 'true' } },500); this.isBottomShow = true; }, //關閉彈窗,取消閃爍 popupMenu(){ clearInterval(this.interval); this.cursor = ''; this.isBottomShow = false; this.$emit('inputVal', { inputVal: this.input }); if(!this.input){ this.blank = true; } }, //陣列資料隨機,恢復 randomArr(arr, name, init){ var self = this; if(Array.isArray(arr)){ if(self[name] == '0'){ self[name] = '1'; return arr.sort(function() { return (0.5-Math.random()); }); }else{ self[name] = '0'; self.charState = 'lower'; return common.copy(self[init],'deep'); } }else{ return arr; } }, //安全鍵盤點選事件 randomAbc(){ var self = this; if(this.state == 'abc'){ this.char = this.randomArr(this.char, 'charRandom', 'charInit'); }else if(this.state == 'num'){ this.num = this.randomArr(this.num, 'numRandom', 'numInit'); } }, //大小寫轉換 lowerToUpper(){ var self = this; var arr = []; for(var i=0;i<self.char.length;i++){ if(self.char[i] >= 'a' && self.char[i] <= 'z'){ arr[i] = self.char[i].toUpperCase(); self.charState = 'upper'; }else{ arr[i] = self.char[i].toLowerCase(); self.charState = 'lower'; } } self.char = arr; }, //字母、符號、數字切換事件 btnClick(ite){ if(ite == 'blank'){ this.input += ' ' this.passwordInput += '*' }else if(ite == 'del'){ this.input = this.input.slice(0,this.input.length -1); this.passwordInput = this.passwordInput.slice(0,this.passwordInput.length -1) }else{ this.input += ite; this.passwordInput += '*' } }, changeState(state){ this.state = state; }, //密碼可不可見切換 lookPwd(){ var self = this; this.isBottomShow=false; this.type=!(this.type); self.imageUrl=common.getImageUrl(self)+(self.type?'login/bukejian.png':'login/kejian.png'); } }, computed: { //字母頁面動態資料 charList () { var self = this; var arr = []; arr[0] = ['1','2','3','4','5','6','7','8','9','0',]; arr[1] = self.char.slice(0,10); arr[2] = ['top'].concat(self.char.slice(10,19)); arr[3] = ['blank'].concat(self.char.slice(19,26)).concat(['del']); return arr; }, //數字頁面動態資料 numList(){ var self = this; var arr = []; arr[0] = self.num.slice(0,3); arr[1] = self.num.slice(3,6); arr[2] = self.num.slice(6,9); arr[3] = ['.'].concat(self.num.slice(9,10)).concat(['del']); return arr; }, //游標的樣式同輸入字型樣式相同,顏色為藍色 mrTextstyle(){ const {textstyle} =this; const mrBtnStyle = { ...textstyle, color: "blue" }; return mrBtnStyle; } } } </script>
公用方法:common/common.js 程式碼如下:
exports.bundleUrl = function (self) {
var bundleUrl = self.$getConfig().bundleUrl;
return bundleUrl;
};
//判斷系統,安卓返回'android',ios返回'iOS',h5返回'web'
exports.androidOrIos = function (self) {
return self.$getConfig().env.platform;
};
//獲取圖片完整路徑字首
exports.getImageUrl = function (self) {
var androidOrIos = this.androidOrIos(self);
var bundleUrl = this.bundleUrl(self);
var isHttp = bundleUrl.indexOf('http://') >= 0;
var imageUrl;
if (isHttp) {
var i = bundleUrl.indexOf('/dist/');
if (androidOrIos == "android") {
imageUrl = bundleUrl.slice(0, i) + '/images/';
} else if (androidOrIos == "iOS") {
imageUrl = bundleUrl.slice(0, i) + '/images.bundle/';
}
} else {
if (androidOrIos == "android") {
imageUrl = 'assets:';
} else if (androidOrIos == "iOS") {
var i = bundleUrl.indexOf('XDPT.app');
//vue語法中讀取圖片資源放在.bundle檔案中
//不然會出現The requested URL was not found on this server.
imageUrl = bundleUrl.slice(0, i + 8) + '/images.bundle/';
}
}
return imageUrl;
}
//物件型別判斷,下面深,淺拷貝用
//深淺拷貝來源百度,太懶沒自己寫
exports.util = (function () {
var class2type = {};
["Null", "Undefined", "Number", "Boolean", "String", "Object", "Function", "Array", "RegExp", "Date"].forEach(function (item) {
class2type["[object " + item + "]"] = item.toLowerCase();
})
function isType(obj, type) {
return getType(obj) === type;
}
function getType(obj) {
return class2type[Object.prototype.toString.call(obj)] || "object";
}
return {
isType: isType,
getType: getType
}
})();
//物件深,淺拷貝
exports.copy = function (obj, deep) {
if (obj === null || typeof obj !== "object") {
return obj;
}
var i, target = this.util.isType(obj, "array") ? [] : {}, value, valueType;
for (i in obj) {
value = obj[i];
valueType = this.util.getType(value);
if (deep && (valueType === "array" || valueType === "object")) {
target[i] = this.copy(value);
} else {
target[i] = value;
}
}
return target;
}
原文地址:https://segmentfault.com/a/1190000013109794