WeChatアプレットキャンバスが署名機能を実装

WeChatアプレットキャンバスが署名機能を実装

WeChatアプレットプロジェクトでは、開発モジュールに手書き署名機能が含まれ、WeChatアプレットキャンバスがデビューします

序文

WeChatアプレットキャンバスが署名機能を実装

コアコンテンツの紹介:

(1)署名の実施、開始、移動、終了

(2)書き直し

(3)完了

(4)アップロード

1. WeChatアプレットキャンバスが署名機能を実装

効果のデモンストレーション:

(1)署名の実施

(2)書き直し

(3)完了

完了したら、対応する位置に画像を表示します

(4)ビジネスニーズに応じて、背景に写真をアップロードし、必要な場所に表示することができます。

2. コード

1. すべてのデモ

wxml

<!--pages/canvas-test/canvas-test.wxml-->

<view class="handCenter">

 <canvas class="handWriting" disabled-scroll="true" bindtouchstart="uploadScaleStart" bindtouchmove="uploadScaleMove"
 bindtouchend="uploadScaleEnd" bindtap="mouseDown" canvas-id="handWriting">
 </キャンバス>

</ビュー>


<view class="handBtn">
 <button catchtap="retDraw" class="delBtn">書き換え</button>
 <button catchtap="subCanvas" class="subBtn">完了</button> 
</ビュー>


<view class="preview"> 

 <画像 wx:if="{{tmpPath}}" style="width:100%;height:100%;" src="{{tmpPath}}"></画像>

</ビュー>

js

const アプリ = getApp()
const api = require('../../utils/request.js'); //相対パス const apiEev = require('../../config/config');
ページ({
 データ: {
 キャンバス名: '手書き',
 ctx: ''、
 キャンバス幅: 0,
 キャンバスの高さ: 0,
 transparent: 1, // 透明度 selectColor: 'black',
 lineColor: '#1A1A1A', // 色 lineSize: 1.5, // 複数行に注意してください lineMin: 0.5, // 最小ストローク半径 lineMax: 4, // 最大ストローク半径 pressure: 1, // デフォルトの圧力 Smoothness: 60, // 滑らかさ、速度を計算するために 60 距離を使用します currentPoint: {},
 currentLine: [], // 現在の行 firstTouch: true, // 最初のトリガー radius: 1, // 円の半径 cutArea: { top: 0, right: 0, bottom: 0, left: 0 }, // 切り取り領域 bethelPoint: [], // すべての行によって生成されたベジェ点を保存します。
 最終ポイント: 0,
 chirography: [], //handwritingcurrentChirography: {}, //現在の手書きlinePrack: [], //線の軌跡、生成された線の実際のポイントtmpPath:''
 },
 // 手書き開始 uploadScaleStart (e) {
 if (e.type != 'touchstart') は false を返します。
 ctx = this.data.ctx; とします。
 ctx.setFillStyle(this.data.lineColor); // 初期の線の色の設定 ctx.setGlobalAlpha(this.data.transparent); // 半透明度の設定 let currentPoint = {
 x: e.touches[0].x、
 y: e.touches[0].y
 }
 currentLine を this.data.currentLine とします。
 現在の行をシフト解除({
 時間: 新しいDate().getTime()、
 否定: 0,
 x: 現在のポイント.x、
 y: 現在のポイント.y
 })
 this.setData({
 現在のポイント、
 // 現在の行
 })
 if (this.data.firstTouch) {
 this.setData({
 カットエリア: { 上: currentPoint.y、右: currentPoint.x、下: currentPoint.y、左: currentPoint.x },
 ファーストタッチ: 偽
 })
 }
 this.pointToLine(現在の行);
 },
 // 手書きの動き uploadScaleMove(e) {
 e.type != 'touchmove' の場合は false を返します。
 if (e.cancelable) {
 // デフォルトの動作が無効になっているかどうかを確認します if (!e.defaultPrevented) {
 e.preventDefault();
 }
 }
 ポイント = {
 x: e.touches[0].x、
 y: e.touches[0].y
 }

 //カットをテストする if (point.y < this.data.cutArea.top) {
 this.data.cutArea.top = point.y;
 }
 point.y < 0 の場合、this.data.cutArea.top = 0;

 (ポイントx>this.data.cutArea.right)の場合{
 this.data.cutArea.right = point.x;
 }
 if (this.data.canvasWidth - point.x <= 0) {
 this.data.cutArea.right = this.data.canvasWidth;
 }
 (ポイントy>this.data.cutArea.bottom)の場合{
 this.data.cutArea.bottom = point.y;
 }
 if (this.data.canvasHeight - point.y <= 0) {
 this.data.cutArea.bottom = this.data.canvasHeight;
 }
 (ポイントxがthis.data.cutArea.leftの場合){
 this.data.cutArea.left = point.x;
 }
 point.x < 0 の場合、this.data.cutArea.left = 0;

 this.setData({
 最後のポイント: this.data.currentPoint、
 currentPoint: ポイント
 })
 currentLine = this.data.currentLine とします。
 現在の行をシフト解除({
 時間: 新しいDate().getTime()、
 dis: this.distance(this.data.currentPoint, this.data.lastPoint),
 x: ポイント.x,
 y: ポイント.y
 })
 // this.setData({
 // 現在の行
 // })
 this.pointToLine(現在の行);
 },
 // 手書きが終わる uploadScaleEnd (e) {
 e.type != 'touchend' の場合、0 を返します。
 ポイント = {
 x: e.changedTouches[0].x、
 y: e.changedTouches[0].y
 }
 this.setData({
 最後のポイント: this.data.currentPoint、
 currentPoint: ポイント
 })
 currentLine = this.data.currentLine とします。
 現在の行をシフト解除({
 時間: 新しいDate().getTime()、
 dis: this.distance(this.data.currentPoint, this.data.lastPoint),
 x: ポイント.x,
 y: ポイント.y
 })
 // this.setData({
 // 現在の行
 // })
 (現在の行の長さ > 2) の場合 {
 var info = (currentLine[0].time - currentLine[currentLine.length - 1].time) / currentLine.length;
 //$("#info").text(info.toFixed(2));
 }
 // ストロークが完了したら、手書きの座標点を保存し、クリアして、現在の手書きが手書き領域内にあるかどうかを確認するチェックを追加します。
 this.pointToLine(現在の行);
 var 現在の書体 = {
 行サイズ: this.data.lineSize、
 線の色: this.data.lineColor
 };
 var chirography = this.data.chirography
 chirography.unshift(現在のCirography);
 this.setData({
 筆跡
 })
 var linePrack = this.data.linePrack
 linePrack.unshift(this.data.currentLine);
 this.setData({
 ラインプラック、
 現在の行: []
 })
 },
 オンロード(){
 キャンバス名を this.data.canvasName とします
 ctx = wx.createCanvasContext(キャンバス名) とします。
 this.setData({
 ctx: ctx
 })
 var クエリ = wx.createSelectorQuery();
 クエリ.select('.handCenter').boundingClientRect(rect => {
 this.setData({
 キャンバス幅: rect.width、
 キャンバスの高さ: rect.height
 })
 }).exec();
 },

 サブキャンバス(){
 // let that = this を追加します
 ctx = this.data.ctx; とします。
 ctx.draw(true,setTimeout(function(){ //新しいタイマーとコールバック wx.canvasToTempFilePath({
 x: 0,
 y: 0,
 幅: 375,
 高さ: 152,
 キャンバスID: '手書き',
 ファイルタイプ: 'png',
 成功: function(res) {
 that.setData({
 tmpPath:res.tempファイルパス
 })
 console.log(that.data.tmpPath,'それが何であるかを確認してください')
 that.upImgs(that.data.tmpPath,0)
 }
 }, ctx)
 },1000))
 },

// 保存した画像をファイルサーバーにアップロードするためのパスを追加します upImgs: function (imgurl, index) {
 console.log(imgurl,'パスを確認してください')
 var that = this;
 wx.uploadFile({
 url: apiEev.api + 'xxxx', //バックグラウンドアップロードパス filePath: imgurl,
 名前: 'ファイル',
 ヘッダー: {
 'コンテンツタイプ': 'マルチパート/フォームデータ'
 },
 フォームデータ: null、
 成功: 関数 (res) {
 console.log(res) //インターフェースはネットワークパスを返します var data = JSON.parse(res.data)
 console.log(data,'データが何であるかを確認します')
 if (data.code == "成功") {
 console.log('成功')
 }
 }
 })
},


 retDraw() {
 this.data.ctx.clearRect(0, 0, 700, 730)
 this.data.ctx.draw()
 this.setData({
 tmpPath:''
 })
 },
 

 // 2 つの点の間に線を描画します。パラメータは line で、最も近い 2 つの開始点を描画します。
 pointToLine (線) {
 this.calcBethelLine(行);
 戻る;
 },
 //補間方法を計算し、
 calcBethelLine (行) {
 (行の長さ<= 1)の場合{
 行[0].r = this.data.radius;
 戻る;
 }
 x0、x1、x2、y0、y1、y2、r0、r1、r2、len、lastRadius、dis = 0、time = 0、curveValue = 0.5 とします。
 行の長さが2以下の場合
 x0 = 行[1].x
 y0 = 行[1].y
 x2 = 線[1].x + (線[0].x - 線[1].x) * 曲線値;
 y2 = 線[1].y + (線[0].y - 線[1].y) * 曲線値;
 //x2 = 行[1].x;
 //y2 = 行[1].y;
 x1 = x0 + (x2 - x0) * 曲線値;
 y1 = y0 + (y2 - y0) * 曲線値;;

 } それ以外 {
 x0 = 線[2].x + (線[1].x - 線[2].x) * 曲線値;
 y0 = 線[2].y + (線[1].y - 線[2].y) * 曲線値;
 x1 = 行[1].x;
 y1 = 行[1].y;
 x2 = x1 + (line[0].x - x1) * 曲線値;
 y2 = y1 + (line[0].y - y1) * 曲線値;
 }
 // 計算式から、3 つの点は (x0, y0)、(x1, y1)、(x2, y2) です。(x1, y1) は制御点であり、曲線上には配置されません。実際、この点は手書きで取得した実際の点でもありますが、曲線上に配置されます。len = this.distance({ x: x2, y: y2 }, { x: x0, y: y0 });
 最後の半径 = this.data.radius;
 (n = 0; n < 行の長さ - 1; n++) の場合 {
 dis += 行[n].dis;
 時間 += 行[n].時間 - 行[n + 1].時間;
 if (dis > this.data.smoothness) break;
 }
 this.setData({
 半径: Math.min(time / len * this.data.pressure + this.data.lineMin, this.data.lineMax) * this.data.lineSize
 });
 行[0].r = this.data.radius;
 //手書きの半径を計算します。
 行の長さが2以下の場合
 r0 = (lastRadius + this.data.radius) / 2;
 r1 = r0;
 r2 = r1;
 //戻る;
 } それ以外 {
 r0 = (行[2].r + 行[1].r) / 2;
 r1 = 行[1].r;
 r2 = (行[1].r + 行[0].r) / 2;
 }
 n = 5 とします。
 ポイントを [] とします。
 (i = 0; i < n; i++ とします) {
 t = i / (n - 1)とします。
 x = (1 - t) * (1 - t) * x0 + 2 * t * (1 - t) * x1 + t * t * x2 とします。
 y = (1 - t) * (1 - t) * y0 + 2 * t * (1 - t) * y1 + t * t * y2 とします。
 r = lastRadius + (this.data.radius - lastRadius) / n * i とします。
 point.push({ x: x, y: y, r: r });
 ポイントの長さが3の場合
 a = this.ctaCalc(point[0].x, point[0].y, point[0].r, point[1].x, point[1].y, point[1].r, point[2].x, point[2].y, point[2].r);とします。
 a[0].color = this.data.lineColor;
 // bethelPoint を this.data.bethelPoint とします。
 // コンソール.log(a)
 // コンソールログ(this.data.bethelPoint)
 // bethelPoint = bethelPoint.push(a);
 描画する
 点 = [{ x: x, y: y, r: r }];
 }
 }
 this.setData({
 現在の行: 行
 })
 },
 // 2点間の距離を求める distance (a, b) {
 x = bx - ax とします。
 y = by - ayとします。
 Math.sqrt(x * x + y * y) を返します。
 },
 ctaCalc (x0, y0, r0, x1, y1, r1, x2, y2, r2) {
 a = [], vx01, vy01, norm, n_x0, n_y0, vx21, vy21, n_x2, n_y2とします。
 関数x1とx0の積。
 vy01 = y1 - y0;
 ノルム = Math.sqrt(vx01 * vx01 + vy01 * vy01 + 0.0001) * 2;
 vx01 = vx01 / ノルム * r0;
 vy01 = vy01 / ノルム * r0;
 0x0 ...
 y0 = -vx01; を出力します。
 vx21 = x1 - x2;
 vy21 = y1 - y2;
 ノルム = Math.sqrt(vx21 * vx21 + vy21 * vy21 + 0.0001) * 2;
 vx21 = vx21 / ノルム * r2;
 vy21 = vy21 / ノルム * r2;
 関数 n_x2 = -vy21;
 y2 = vx21; のようになります。
 a.push({ mx: x0 + n_x0, my: y0 + n_y0, 色: "#1A1A1A" });
 a.push({ c1x: x1 + n_x0, c1y: y1 + n_y0, c2x: x1 + n_x2, c2y: y1 + n_y2, ex: x2 + n_x2, ey: y2 + n_y2 });
 a.push({ c1x: x2 + n_x2 - vx21, c1y: y2 + n_y2 - vy21, c2x: x2 - n_x2 - vx21, c2y: y2 - n_y2 - vy21, ex: x2 - n_x2, ey: y2 - n_y2 });
 a.push({ c1x: x1 - n_x2, c1y: y1 - n_y2, c2x: x1 - n_x0, c2y: y1 - n_y0, ex: x0 - n_x0, ey: y0 - n_y0 });
 a.push({ c1x: x0 - n_x0 - vx01, c1y: y0 - n_y0 - vy01, c2x: x0 + n_x0 - vx01, c2y: y0 + n_y0 - vy01, ex: x0 + n_x0, ey: y0 + n_y0 });
 1. 固定長のmxを0にする。
 文字列をparse(0)します。
 a[0].my = a[0].my.toFixed(1);
 a[0].my = parseFloat(a[0].my);
 (i = 1; i < a.length; i++ とします) {
 1. 固定長のc1xを固定長のc1xに変換する。
 パースフロート
 1. 固定長のc1yを出力します。
 a[i].c1y = parseFloat(a[i].c1y);
 1. 固定長のc2xをa[i]に代入する。
 パースフロート
 1. 固定長のc2yを出力します。
 python 4.0 では、 ...
 a[i].ex = a[i].ex.toFixed(1);
 パースフロート
 a[i].ey = a[i].ey.toFixed(1);
 a[i].ey = parseFloat(a[i].ey);
 }
 を返します。
 },
 bethelDraw (ポイント、is_fill、色) {
 // let that = this を追加します
 ctx = this.data.ctx; とします。
 ctx.beginPath();
 ctx.moveTo(ポイント[0].mx、ポイント[0].my);
 (未定義!=色)の場合{
 ctx.setFillStyle(色);
 ctx.setStrokeStyle(色);
 } それ以外 {
 ctx.setFillStyle(ポイント[0].color);
 ctx.setStrokeStyle(ポイント[0].color);
 }
 (i = 1 とします; i < point.length; i++) {
 ctx.bezierCurveTo(ポイント[i].c1x、ポイント[i].c1y、ポイント[i].c2x、ポイント[i].c2y、ポイント[i].ex、ポイント[i].ey);
 }
 ctx.stroke();
 (未定義!= is_fill)の場合{
 ctx.fill(); // グラフィックを塗りつぶします (後で描画したグラフィックは前のグラフィックを覆います。描画するときは順序に注意してください)
 }
 ctx.draw(true)
 },
 selectColorEvent (イベント) {
 console.log(イベント)
 var color = event.currentTarget.dataset.colorValue;
 var colorSelected = event.currentTarget.dataset.color;
 this.setData({
 選択色: 選択された色、
 線の色: 色
 })
 }
})
/* ページ/canvas-test2/canvas-test2.wxss */
.キャンバスID {
 位置: 絶対;
 左: 50%;
 上: 0;
 変換: 翻訳(-50%);
 zインデックス: 1;
 境界線: 2px 破線 #ccc;
 境界線の半径: 8px;
 下部マージン: 66px;
}

.handCenter{
 境界線: 1px 実線の赤;
}

.手書き{
 幅: 100%;
}

.プレビュー{
 幅: 375ピクセル;
 高さ: 152px;
}

2. 主要部品の分析

(1)署名、開始、移動、終了の基本実装

// 手書き開始 uploadScaleStart (e) {
 if (e.type != 'touchstart') は false を返します。
 ctx = this.data.ctx; とします。
 ctx.setFillStyle(this.data.lineColor); // 初期の線の色の設定 ctx.setGlobalAlpha(this.data.transparent); // 半透明度の設定 let currentPoint = {
 x: e.touches[0].x、
 y: e.touches[0].y
 }
 currentLine を this.data.currentLine とします。
 現在の行をシフト解除({
 時間: 新しいDate().getTime()、
 否定: 0,
 x: 現在のポイント.x、
 y: 現在のポイント.y
 })
 this.setData({
 現在のポイント、
 // 現在の行
 })
 if (this.data.firstTouch) {
 this.setData({
 カットエリア: { 上: currentPoint.y、右: currentPoint.x、下: currentPoint.y、左: currentPoint.x },
 ファーストタッチ: 偽
 })
 }
 this.pointToLine(現在の行);
 },
 // 手書きの動き uploadScaleMove(e) {
 e.type != 'touchmove' の場合は false を返します。
 if (e.cancelable) {
 // デフォルトの動作が無効になっているかどうかを確認します if (!e.defaultPrevented) {
 e.preventDefault();
 }
 }
 ポイント = {
 x: e.touches[0].x、
 y: e.touches[0].y
 }

 //カットをテストする if (point.y < this.data.cutArea.top) {
 this.data.cutArea.top = point.y;
 }
 point.y < 0 の場合、this.data.cutArea.top = 0;

 (ポイントx>this.data.cutArea.right)の場合{
 this.data.cutArea.right = point.x;
 }
 if (this.data.canvasWidth - point.x <= 0) {
 this.data.cutArea.right = this.data.canvasWidth;
 }
 (ポイントy>this.data.cutArea.bottom)の場合{
 this.data.cutArea.bottom = point.y;
 }
 if (this.data.canvasHeight - point.y <= 0) {
 this.data.cutArea.bottom = this.data.canvasHeight;
 }
 (ポイントxがthis.data.cutArea.leftの場合){
 this.data.cutArea.left = point.x;
 }
 point.x < 0 の場合、this.data.cutArea.left = 0;

 this.setData({
 最後のポイント: this.data.currentPoint、
 currentPoint: ポイント
 })
 currentLine = this.data.currentLine とします。
 現在の行をシフト解除({
 時間: 新しいDate().getTime()、
 dis: this.distance(this.data.currentPoint, this.data.lastPoint),
 x: ポイント.x,
 y: ポイント.y
 })
 // this.setData({
 // 現在の行
 // })
 this.pointToLine(現在の行);
 },
 // 手書きが終わる uploadScaleEnd (e) {
 e.type != 'touchend' の場合、0 を返します。
 ポイント = {
 x: e.changedTouches[0].x、
 y: e.changedTouches[0].y
 }
 this.setData({
 最後のポイント: this.data.currentPoint、
 currentPoint: ポイント
 })
 currentLine = this.data.currentLine とします。
 現在の行をシフト解除({
 時間: 新しいDate().getTime()、
 dis: this.distance(this.data.currentPoint, this.data.lastPoint),
 x: ポイント.x,
 y: ポイント.y
 })
 // this.setData({
 // 現在の行
 // })
 (現在の行の長さ > 2) の場合 {
 var info = (currentLine[0].time - currentLine[currentLine.length - 1].time) / currentLine.length;
 //$("#info").text(info.toFixed(2));
 }
 // ストロークが完了したら、手書きの座標点を保存し、クリアして、現在の手書きが手書き領域内にあるかどうかを確認するチェックを追加します。
 this.pointToLine(現在の行);
 var 現在の書体 = {
 行サイズ: this.data.lineSize、
 線の色: this.data.lineColor
 };
 var chirography = this.data.chirography
 chirography.unshift(現在のCirography);
 this.setData({
 筆跡
 })
 var linePrack = this.data.linePrack
 linePrack.unshift(this.data.currentLine);
 this.setData({
 ラインプラック、
 現在の行: []
 })
},

最初にonloadで初期化することを忘れないでください

コードを取得して直接使用する

(2)再署名

簡単に言えば、キャンバスをクリアすることを意味します。

retDraw() {
 this.data.ctx.clearRect(0, 0, 700, 730)
 this.data.ctx.draw()
 this.setData({
 tmpPath:''
 })
},

(3)署名完了

サブキャンバス(){
 // let that = this を追加します
 ctx = this.data.ctx; とします。
 ctx.draw(true,setTimeout(function(){ //新しいタイマーとコールバック wx.canvasToTempFilePath({
 x: 0,
 y: 0,
 幅: 375,
 高さ: 152,
 キャンバスID: '手書き',
 ファイルタイプ: 'png',
 成功: function(res) {
 that.setData({
 tmpPath:res.tempファイルパス
 })
 console.log(that.data.tmpPath,'それが何であるかを確認してください')
 that.upImgs(that.data.tmpPath,0)
 }
 }, ctx)
 },1000))
 },

内部のコールバックの方が重要です:

キャンバスのコンテンツが失われないように、遅延を設定できます。
wx.canvasToTempFilePath メソッドはキャンバス イメージのコンテンツを取得します。

(4)ビジネスニーズに応じて、背景に写真をアップロードし、必要な場所に表示することができます。

重要なのはバックグラウンドにアップロードする方法です

// 保存した画像をファイルサーバーにアップロードするためのパスを追加します upImgs: function (imgurl, index) {
 console.log(imgurl,'パスを確認してください')
 var that = this;
 wx.uploadFile({
 url: apiEev.api + 'xxxx', //バックグラウンドファイルアップロードパスインターフェース filePath: imgurl,
 名前: 'ファイル',
 ヘッダー: {
 'コンテンツタイプ': 'マルチパート/フォームデータ'
 },
 フォームデータ: null、
 成功: 関数 (res) {
 console.log(res) //インターフェースはネットワークパスを返します var data = JSON.parse(res.data)
 console.log(data,'データが何であるかを確認します')
 if (data.code == "成功") {
 console.log('成功')
 }
 }
 })
},

要約する

WeChat ミニプログラム キャンバスは署名機能を実装します。

特別な注意:実機デバッグおよび体験版では遅延が発生する可能性があります。可能であれば、プレリリース版にリリースして、パフォーマンスに影響があるかどうかを確認してください。

以上がこの記事の全内容です。皆様の勉強のお役に立てれば幸いです。また、123WORDPRESS.COM を応援していただければ幸いです。

以下もご興味があるかもしれません:
  • Uniapp が WeChat アプレットの電子署名効果を実装 (デモ付き)
  • WeChat アプレットに手書き署名を実装するためのサンプル コード
  • WeChatアプレットはシンプルな手書き署名コンポーネントを実装します
  • 電子署名を実装するWeChatミニプログラム
  • WeChatミニプログラムが電子署名機能を実装
  • WeChatアプレットは電子署名を実装し、画像をエクスポートします
  • Java が WeChat アプレット「支払い検証署名に失敗しました」問題に遭遇した解決策
  • .NET WeChat アプレットのユーザーデータ署名検証および復号化コード
  • WeChatアプレットが横画面と縦画面の署名機能を実装

<<:  Mysql 5.7.17 をインストールした後、MySQL にログインするチュートリアル

>>:  CentOS7 ファイアウォールとオープンポートの簡単な使い方の簡単な紹介

推薦する

Vue3はCSSの無限シームレススクロール効果を実装します

この記事では、CSS無限シームレススクロール効果を実現するためのvue3の具体的なコードを参考までに...

VMware Workstation のインストール Linux システム

始める段階から初心者になるまで、Linux オペレーティング システムは不可欠です。最初のステップは...

vue.js でよく使われる v 命令の解析

目次Vue でのモデルバインド表示の if の v-text の説明v-html: v-オンv-if...

Vue3の組み込みコンポーネントであるTeleportの使い方を詳しく説明します

目次1. テレポートの使用2. モーダルダイアログコンポーネントを完成させる3. コンポーネントのレ...

MySQL 並列レプリケーションの簡単な分析

01 並列レプリケーションの概念MySQL のマスター スレーブ レプリケーション アーキテクチャで...

CentOS はローカル yum ソースを使用して LAMP 環境を構築するグラフィック チュートリアル

この記事では、ローカル yum ソースを使用して CentOS 上に LAMP 環境を構築する方法に...

Dockerはnextcloudを使用してプライベートBaiduクラウドディスクを構築します

突然、ドキュメントの保存と共同作業のためのプライベート サービスを構築する必要がありました。多くの場...

Linux NFSメカニズムの動作原理と例の分析

NFS とは何ですか?ネットワークファイルシステムネットワーク上でファイルを保存および整理するための...

MySQL デッドロックのトラブルシューティングの全プロセス記録

【著者】 Liu Bo: Ctrip テクニカル サポート センターのシニア データベース マネージ...

Docker を使用した JMeter+Grafana+Influxdb 監視プラットフォームの構築に関する詳細なチュートリアル

Jmeter がネイティブの結果表示機能を提供していることは誰もが知っています。ネイティブの結果表示...

MySQL の基本クイックスタート知識のまとめ (マインドマップ付き)

目次序文1. データベースの基礎知識1. データベースとは何ですか? 2. データベースの分類3. ...

JSでHTML本文のスタイルを変更する

目次1. 本来の定義2. JS操作、幅の変更を例に3. 効果: 幅が変更されました 1. 本来の定義...

HTML と CSS に関する基本的なメモ (フロントエンドでは必読)

HTMLに触れた当初はレイアウトにいつもテーブルを使っていましたが、とても面倒で見た目も悪かったの...

Linux ディスクのシーケンシャル書き込みとランダム書き込みの方法

1. はじめに● ランダム書き込みではヘッドがトラックを頻繁に変更するため、効率が大幅に低下します。...

MySQLで全角文字と半角文字を保存する場合の違い

残念ながら、社内の IM のテスト中に MYSQL_DATA_TRUNCATED エラーが再び発生し...