微信小程序?qū)崿F(xiàn)之手勢鎖功能實例代碼
設(shè)計思路流程圖

1、全局常量
constructor(page,opts){
// 初始化全局常量數(shù)據(jù)
this.page = page;
this.width = opts.width || 300;
this.height = opts.height || 300;
this.canvasId = opts.canvasId || 'lock';
this.type = opts.type || 3;
this.cleColor = opts.cleColor || 'rgba(0,136,204,1)';
this.size = this.width / this.type / 2;//坐標(biāo)點之間的半間距
this.R = this.size / 2;//外圓半徑
this.r = this.size / 4;//內(nèi)圓半徑
// 判斷是否在緩存中存在密碼,如果存在,直接進行第二步驟:解碼,如果不存在,進行初始化,設(shè)置密碼
this.pswObj = wx.getStorageSync('password') ? {
step: 2,
password: JSON.parse(wx.getStorageSync('password'))
} : { step: 0 };
// 啟動手勢鎖初始化
this.init();
}
2、全局變量
init(){
const _this = this;
// 定義全局變量,標(biāo)記start,手勢鎖的每個坐標(biāo)的中心點數(shù)組,記錄選中數(shù)組
_this.flag = false;
_this.locationArr = [];
_this.lastPoint = [];
_this.restPoint = [];
// 設(shè)置canvas的寬高
_this.page.setData({
width : _this.width,
height : _this.height
});
this.ctx = wx.createCanvasContext(this.canvasId, this);
// 初始化中心坐標(biāo)數(shù)組
this.location();
// 初始化繪制圖形圓
this.drawPo();
// 初始化綁定事件
this.bindEvent();
}
3、初始化坐標(biāo)數(shù)組locationArr 和restPoint
location(){
// 計算坐標(biāo)的x,y坐標(biāo),同時記錄當(dāng)前位置代表的數(shù)
let count = 0,arr = [],arr0 = [];
for(let i = 0; i < this.type; i++){
for(let j = 0 ; j < this.type; j++){
count++;
arr.push({
x: this.size * ((j + 1) * 2 - 1),//奇數(shù)個坐標(biāo)間半間距
y: this.size * ((i + 1) * 2 - 1),//奇數(shù)個坐標(biāo)間半間距
count: count//每個坐標(biāo)代表的數(shù)
});
arr0.push({
x: this.size * ((j + 1) * 2 - 1),//奇數(shù)個坐標(biāo)間半間距
y: this.size * ((i + 1) * 2 - 1),//奇數(shù)個坐標(biāo)間半間距
count: count//每個坐標(biāo)代表的數(shù)
});
}
}
this.locationArr = arr;
this.restPoint = arr0;
}
4、繪制手勢鎖矩陣
繪制圓函數(shù)(bool值判斷當(dāng)前繪制的是空心還是實心)
drawCle(x, y, r, bool){
// 設(shè)置邊框顏色。
bool ? this.ctx.setStrokeStyle(this.cleColor) : this.ctx.setFillStyle(this.cleColor);; // 注意用set
// 設(shè)置線條的寬度。
this.ctx.setLineWidth(2); // 注意用set
// 開始創(chuàng)建一個路徑,需要調(diào)用fill或者stroke才會使用路徑進行填充或描邊。
this.ctx.beginPath();
// 畫一條弧線。
this.ctx.arc(x, y, r, 0, Math.PI * 2, true);
// 關(guān)閉一個路徑
this.ctx.closePath();
// 畫出當(dāng)前路徑的邊框。默認顏色色為黑色。
bool ? this.ctx.stroke():this.ctx.fill();
// 將之前在繪圖上下文中的描述(路徑、變形、樣式)畫到 canvas 中。
this.ctx.draw(true);
}
矩陣?yán)L制
drawPo(){
// 繪制空心圓,繪制之前,清空canvas,防止重復(fù)繪制
this.ctx.clearRect(0, 0, this.width, this.height);
this.locationArr.forEach(current => {
this.drawCle(current.x, current.y, this.R, true);
});
}
5、觸發(fā)move時線的繪制函數(shù)
drawLine(po) {// 解鎖軌跡
this.ctx.beginPath();
// 線寬
this.ctx.lineWidth = 3;
// 起始點
this.ctx.moveTo(this.lastPoint[0].x, this.lastPoint[0].y);
// 中間轉(zhuǎn)換的點
for (var i = 1; i < this.lastPoint.length; i++) {
this.ctx.lineTo(this.lastPoint[i].x, this.lastPoint[i].y);
}
// 正在移動選擇的點
if (po) { this.ctx.lineTo(po.x, po.y);}
this.ctx.stroke();
this.ctx.closePath();
this.ctx.draw(true);
}
6、獲取當(dāng)前位置的坐標(biāo)點函數(shù)
getPosition(e) { // 獲取touch點相對于canvas的坐標(biāo)
return {
x: e.touches[0].x,
y: e.touches[0].y
};
}
7、觸發(fā)touchstart事件處理
_this.page.onTouchStart = function(e){
let po = _this.getPosition(e);//獲取當(dāng)前準(zhǔn)確坐標(biāo)
for (let [key,val] of _this.locationArr.entries()){//循環(huán)對比最近的坐標(biāo)
if (Math.abs(val.x - po.x) < _this.r && Math.abs(val.y - po.y) < _this.r){
_this.flag = true;//進入判斷,觸發(fā)touchstart事件成功
_this.drawCle(val.x, val.y, _this.r, false);//繪制該點的實心內(nèi)圓
_this.lastPoint.push(val);//記錄該點坐標(biāo)到lastPoint
_this.restPoint.splice(key,1);//刪除記錄數(shù)組restPoint的該點坐標(biāo)
break;//找到坐標(biāo),跳出循環(huán)
}
}
}
8、觸發(fā)touchmove事件處理
_this.page.onTouchMove = function (e) {
_this.flag && _this.updata(_this.getPosition(e));
}
判斷是否觸發(fā)touchstart,如果觸發(fā),執(zhí)行updata函數(shù)。
更新最后點坐標(biāo)函數(shù)
updata(po){
//清空canvas
this.ctx.clearRect(0, 0, this.width, this.height);
//重新繪制矩陣
for (let val of this.locationArr) {
this.drawCle(val.x, val.y, this.R, true);
}
//繪制已記錄坐標(biāo)的實心圓
for (let val of this.lastPoint) {
this.drawCle(val.x, val.y, this.r ,false);
}
//繪制解鎖路線
this.drawLine(po);
//找到移動中的還未落點的精確坐標(biāo)
for (let [key, val] of this.restPoint.entries()) {
if (Math.abs(po.x - val.x) < this.r && Math.abs(po.y - val.y) < this.r) {
this.drawCle(val.x, val.y, this.r, false);
this.lastPoint.push(val);
this.restPoint.splice(key, 1);
break;
}
}
}
9、觸發(fā)touchend事件處理
_this.page.onTouchEnd = function (e) {
if(_this.flag){
_this.flag = false;
_this.endData();
_this.checkPassword(_this.lastPoint);
setTimeout(function () {
_this.reset();
}, 500);
}
}
通過流程圖,可以更加清楚的認識到做一個功能需要創(chuàng)建的變量和函數(shù),流程步驟更加清楚,當(dāng)然也需要制作的過程進行優(yōu)化。建議制作一些大的功能的時候,如果流程不清楚,最好繪制流程圖,思路清晰,開發(fā)更快,考慮更周全。
總結(jié)
以上所述是小編給大家介紹的微信小程序?qū)崿F(xiàn)之手勢鎖詳解,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關(guān)文章
js中for...in循環(huán)對象時輸出key值順序混亂問題解決
很久之前就有前輩告訴我用for...in循環(huán)對象屬性的順序不是固定的,xiam?這篇文章主要給大家介紹了關(guān)于js中for...in循環(huán)對象時輸出key值順序混亂問題解決方法,需要的朋友可以參考下2023-11-11
JavaScript面向?qū)ο笕齻€基本特征實例詳解【封裝、繼承與多態(tài)】
這篇文章主要介紹了JavaScript面向?qū)ο笕齻€基本特征,結(jié)合實例形式詳細分析了JavaScript面向?qū)ο笕齻€基本特征封裝、繼承與多態(tài)的概念、原理、用法與操作注意事項,需要的朋友可以參考下2020-05-05
javascript中return,return true,return false三者的用法及區(qū)別
這篇文章主要介紹了javascript中return,return true,return false三者的用法及區(qū)別的相關(guān)資料,需要的朋友可以參考下2015-11-11
vscode錄音及語音實時轉(zhuǎn)寫插件開發(fā)并在工作區(qū)生成本地mp3文件附踩坑日記!
以目前的vscode版本來說,作者并沒有開放訪問本地媒體權(quán)限,所以插件市場里面的所有語音相關(guān)插件也并沒有直接獲取vscode的媒體權(quán)限,這篇文章主要介紹了vscode錄音及語音實時轉(zhuǎn)寫插件開發(fā)并在工作區(qū)生成本地mp3文件?踩坑日記!,需要的朋友可以參考下2023-05-05
淺談函數(shù)調(diào)用的不同方式,以及this的指向
下面小編就為大家?guī)硪黄獪\談函數(shù)調(diào)用的不同方式,以及this的指向。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-09-09
javascript parseInt() 函數(shù)的進制轉(zhuǎn)換注意細節(jié)
parseInt(string, radix) 有2個參數(shù),第一個string 是傳入的數(shù)值,第二個radix是 傳入數(shù)值的進制,參數(shù)radix 可以忽略,默認為 10,各種進制的數(shù)轉(zhuǎn)換為 十進制整數(shù),接下來詳細介紹,感興趣的朋友可以了解下哦2013-01-01

