Vue3とElectronを使ったデスクトップアプリケーションの詳しい説明

Vue3とElectronを使ったデスクトップアプリケーションの詳しい説明

個人的なエッセイを記録するために、最近、markdown-it をベースにしたmarkdownエディターVueコンポーネント v-md-editor を使用したLaravelVue 3.0でブログ システムを構築しました。 markdownで書くときに使うととても便利だと思います。その後、私はこのコンポーネントをベースにしたmarkdownデスクトップ アプリケーションを Electron を使用して実装するというアイデアを思いつきました。これは私にとっても日常的な使用に適した選択肢です。

余談ですが、 VS Code はElectronで開発されたデスクトップ アプリケーションです。モバイル開発を除き、現在は他のすべての開発にVS Codeを使用しています。さまざまなプラグインを開発するのに非常に便利です。

次に、この機能を実装する手順を順を追って説明します。

Vue CLIはVueプロジェクトを構築します

選択したディレクトリでvue create electron-vue3-mark-downを実行します。

カスタムテンプレートを選択します(デフォルトのVue 3テンプレートを選択できます)

Vue3TypeScriptを選択し、プロジェクトに応じて他のオプションを選択します。

vue3 + タイプスクリプト

効果を確認するにはnpm run serveを実行します。

効果

Vue プロジェクトをマークダウンエディターに変換

v-md-editorをインストールするには、 npm i @kangc/v-md-editor@next -Sを実行します。

TypeScript型定義ファイルを追加する

v-md-editorライブラリにはTypeScript型定義ファイルがないため、 shims-vue.d.tsファイルの直後に追加しました。もちろん、新しいファイルを作成して宣言を追加することもできます ( tsconfig.json がこのファイルを見つけられる限り)。

モジュール「*.vue」を宣言します。
  "vue" から DefineComponent 型をインポートします。
  const コンポーネント: DefineComponent<{}, {}, any>;
  デフォルトコンポーネントをエクスポートします。
}

<!-- 追加されたコンテンツ -->
モジュール「@kangc/v-md-editor/lib/theme/vuepress.js」を宣言します。
モジュール "@kangc/v-md-editor/lib/plugins/copy-code/index" を宣言します。
モジュール「@kangc/v-md-editor/lib/plugins/line-number/index」を宣言します。
モジュール "@kangc/v-md-editor" を宣言します。
モジュール「prismjs」を宣言します。

App.vueの変換

<テンプレート>
  <div>
    <v-md-editor v-model="content" height="100vh"></v-md-editor>
  </div>
</テンプレート>

<script lang="ts">
// エディター import VMdEditor from "@kangc/v-md-editor";
"@kangc/v-md-editor/lib/style/base-editor.css" をインポートします。
「@kangc/v-md-editor/lib/theme/vuepress.js」からvuepressをインポートします。
"@kangc/v-md-editor/lib/theme/style/vuepress.css" をインポートします。
// ハイライト import Prism from "prismjs";
「prismjs/components/prism-json」をインポートします。
「prismjs/components/prism-dart」をインポートします。
「prismjs/components/prism-c」をインポートします。
「prismjs/components/prism-swift」をインポートします。
「prismjs/components/prism-kotlin」をインポートします。
「prismjs/components/prism-java」をインポートします。

// コードをすばやくコピーします import createCopyCodePlugin from "@kangc/v-md-editor/lib/plugins/copy-code/index";
"@kangc/v-md-editor/lib/plugins/copy-code/copy-code.css" をインポートします。
// 行番号 import createLineNumbertPlugin from "@kangc/v-md-editor/lib/plugins/line-number/index";
VMdEditor.use(vuepress, {
  プリズム、
})
  .use(コピーコードプラグインの作成())
  .use(createLineNumbertPlugin());

「vue」からdefineComponent、refをインポートします。
エクスポートデフォルトdefineComponent({
  名前:「アプリ」、
  コンポーネント: { VMdEditor },
  設定() {
    定数コンテンツ = ref("");

    {コンテンツ}を返します。
  },
});
</スクリプト>

<スタイル>
/* いくつかのボタンを削除します */
.v-md-icon-save、
.v-md-アイコン-フルスクリーン {
  表示: なし;
}
</スタイル>

このファイルも非常にシンプルです。ページ全体がエディタです<v-md-editor v-model="content" height="100vh"></v-md-editor> 。このマークダウンエディタには、ハイライト、コード行番号表示、コードコピーボタンなどのプラグインがあります。もちろん、他のプラグインを追加してこのマークダウンエディタの機能を充実させるとより便利です。

効果は以下のとおりです

エディター効果

Vue CLI プラグイン Electron ビルダー

Vite 2.0 を使用してElectronプロジェクトを構築しようとしましたが、 ViteElectronをうまく組み合わせた同様のツールが見つからなかったため、 Vite 2.0の誘惑をあきらめました。何かおすすめがあれば、ぜひ共有してください。

インストールにはvue add electron-builderを使用します。私はElectronの最新バージョン13.0.0を選択しました。

私はいつも一番高いバージョンを選びます。実はこのバージョンには落とし穴があります。この落とし穴については後ほど紹介しようと思います(笑)。

効果

多くの新しい依存ライブラリが追加され、 background.tsファイルが追加されていることがわかります。簡単に説明すると、このファイルはメインスレッドで実行され、他のページはレンダリングスレッドで実行されます。レンダリング スレッドには多くの制限があり、一部の関数はメイン スレッドでのみ実行できますが、ここでは詳しく説明しません。

効果を確認するにはnpm run electron:serveを実行します。

効果

この時点で、デスクトップ アプリケーションの効果を確認でき、Vue コードを変更しながら、デスクトップ アプリケーションでも変更された効果をリアルタイムで確認できます。

最適化

全画面表示を開始

紹介画面

「electron」から { screen } をインポートします。

ウィンドウを作成するときに画面サイズを設定する

<!-- 背景.ts -->
非同期関数createWindow() {
  const { 幅、高さ } = screen.getPrimaryDisplay().workAreaSize;
  const win = 新しいブラウザウィンドウ({
    幅、
    身長、
    // 省略...
  });
    // 省略...
}

こうすることで、アプリケーションは起動時に全画面で表示されます。

メニューバーを変更する

メニューバーを定義する

<!-- 背景.ts -->

const テンプレート: Array<MenuItemConstructorOptions> = [
  {
    ラベル: "MarkDown",
    サブメニュー: [
      {
        ラベル: "About",
        アクセラレータ: "CmdOrCtrl+W",
        役割: "について",
      },
      {
        ラベル: "プログラムを終了",
        アクセラレータ: "CmdOrCtrl+Q",
        役割: 「終了」、
      },
    ]、
  },
  {
    ラベル: "ファイル",
    サブメニュー: [
      {
        ラベル: "ファイルを開く",
        アクセラレータ: "CmdOrCtrl+O",
        クリック: (
          項目: メニュー項目、
          focusedWindow: BrowserWindow | 未定義、
          _event: キーボードイベント
        ) => {
            // TODO: ファイルを開く},
      },
      {
        ラベル: 「ストレージ」、
        アクセラレータ: "CmdOrCtrl+S",
        クリック: (
          項目: メニュー項目、
          focusedWindow: BrowserWindow | 未定義、
          _event: キーボードイベント
        ) => {
          //TODO: コンテンツを保存する},
      },
    ]、
  },
  {
    ラベル: "編集",
    サブメニュー: [
      {
        ラベル: 「取り消し」、
        アクセラレータ: "CmdOrCtrl+Z",
        役割: 「元に戻す」、
      },
      {
        ラベル: 「やり直し」、
        アクセラレータ: "Shift+CmdOrCtrl+Z",
        役割: 「やり直し」、
      },
      {
        タイプ:「セパレータ」、
      },
      {
        ラベル: 「カット」、
        アクセラレータ: "CmdOrCtrl+X",
        役割: 「カット」、
      },
      {
        ラベル: "コピー",
        アクセラレータ: "CmdOrCtrl+C",
        役割: "コピー"、
      },
      {
        ラベル:「貼り付け」、
        アクセラレータ: "CmdOrCtrl+V",
        役割: 「貼り付け」、
      },
    ]、
  },
  {
    ラベル: "ウィンドウ",
    役割: "ウィンドウ"、
    サブメニュー: [
      {
        ラベル: 「最小化」、
        アクセラレータ: "CmdOrCtrl+M",
        役割: 「最小化」、
      },
      {
        ラベル:「最大化」、
        アクセラレータ: "CmdOrCtrl+M",
        クリック: (
          項目: メニュー項目、
          focusedWindow: BrowserWindow | 未定義、
          _event: キーボードイベント
        ) => {
          if (focusedWindow) {
            フォーカスウィンドウを最大化します。
          }
        },
      },
      {
        タイプ:「セパレータ」、
      },
      {
        ラベル: 「全画面に切り替える」、
        アクセラレータ: (function () {
          プロセスプラットフォームが「ダーウィン」の場合
            「Ctrl+Command+F」を返します。
          } それ以外 {
            「F11」を返します。
          }
        })(),
        クリック: (
          項目: メニュー項目、
          focusedWindow: BrowserWindow | 未定義、
          // eslint 次の行を無効にする @typescript-eslint/未使用変数なし
          _event: キーボードイベント
        ) => {
          if (focusedWindow) {
            focusWindow.setFullScreen(!focusedWindow.isFullScreen());
          }
        },
      },
    ]、
  },
  {
    ラベル: "ヘルプ",
    役割: "ヘルプ"、
    サブメニュー: [
      {
        ラベル: "詳細を見る",
        クリック: 関数 () {
          シェルを外部から開きます("http://electron.atom.io");
        },
      },
    ]、
  },
];

定義方法の詳細については、Electron メニューを参照してください。

ファイルのオープン保存はまだ実装されていませんが、後で実装される予定です。

メニューバーを設定する

"electron"から{Menu}をインポートします。
app.on("準備完了", 非同期() => {
  // 省略...
  // メニューを作成しますMenu.setApplicationMenu(Menu.buildFromTemplate(template));
});

readyフック関数でメニューを設定します。

効果

メニュー効果

エディターはmarkdonwファイルの内容を開きます

メインスレッドはファイルを選択し、ファイルパスをレンダリングスレッドに渡します。

<!-- 背景.ts -->
ダイアログ
  .showOpenDialog({
    プロパティ: ["openFile"],
    フィルター: [{ name: "カスタムファイルタイプ", 拡張子: ["md"] }],
  })
  .then((res) => {
    res && res["filePaths"].length > 0 の場合 {
      const filePath = res["filePaths"][0];
      // ファイルをレンダリングスレッドに渡す if (focusedWindow) {
        focusedWindow.webContents.send("open-file-path", filePath);
      }
    }
  })
  .catch((エラー) => {
    コンソールログ(エラー);
  });

showOpenDialogはファイルを開くメソッドです。ここでは md ファイルのみを開くように指定します。

ファイル パスを取得したら、 focusedWindow.webContents.send("open-file-path", filePath);メソッドを通じて、ファイル パスをレンダリング スレッドに渡します。

レンダリングスレッドはファイルパスを取得し、ファイルの内容を読み取り、それをマークダウンエディタに割り当てます。

<!-- App.vue -->
「electron」から { ipcRenderer } をインポートします。
「fs」から{readFileSync}をインポートします。

エクスポートデフォルトdefineComponent({
  // 省略...
  設定() {
    定数コンテンツ = ref("");
    
    マウント時(() => {
      // 1.
      ipcRenderer.on("open-file-path", (e, filePath: 文字列) => {
        ファイルパス && ファイルパス.長さ > 0 の場合 {
          // 2.
          content.value = readFileSync(filePath).toString();
        }
      });
    });

    {コンテンツ}を返します。
  },
});

Vue がノードサポートを追加

<!-- vue.config.js -->
モジュール.エクスポート = {
  プラグインオプション: {
    電子ビルダー: {
      ノード統合: true、
    },
  },
};

効果

レンダリング

markdonwの内容をファイルに保存する

メインスレッドはレンダリングスレッドにエディタコンテンツを取得する要求を開始します。

<!-- background.js -->
if (focusedWindow) {
    focusedWindow.webContents.send("get-content", "");
}

レンダリングスレッドはエディターのコンテンツをメインスレッドに返します。

<!-- App.vue -->
マウント時(() => {
    ipcRenderer.on("コンテンツを取得", () => {
        ipcRenderer.send("save-content", content.value);
    });
});

メインスレッドはコンテンツを受け取り、ファイルに保存します

<!-- 背景.ts -->
// ファイルを保存 ipcMain.on("save-content", (event: unknown, content: string) => {
  開いたファイルの長さが0より大きい場合
    // ファイルに直接保存する try {
      開いたファイルの内容を書き込む。
      console.log("正常に保存しました");
    } キャッチ(エラー){
      console.log("保存に失敗しました");
    }
  } それ以外 {
    定数オプション = {
      タイトル:「ファイルを保存」、
      デフォルトパス: "new.md",
      フィルター: [{ name: "カスタムファイルタイプ", 拡張子: ["md"] }],
    };
    定数 focusWindow = BrowserWindow.getFocusedWindow();
    if (focusedWindow) {
      ダイアログ
        .showSaveDialog(フォーカスされたウィンドウ、オプション)
        .then((結果: Electron.SaveDialogReturnValue) => {
          if (結果.ファイルパス) {
            試す {
              writeFileSync(結果.filePath、コンテンツ);
              console.log("正常に保存されました");
              開いたファイル = result.filePath;
            } キャッチ(エラー){
              console.log("保存に失敗しました");
            }
          }
        })
        .catch((エラー) => {
          コンソール.log(エラー);
        });
    }
  }
});

効果

レンダリング

パック

アプリケーションの名前と画像を設定する

<!-- vue.config.js -->
モジュール.エクスポート = {
  プラグインオプション: {
    電子ビルダー: {
      ノード統合: true、
      // 追加された設定 builderOptions: {
        アプリID: "com.johnny.markdown", 
        productName: "JJMarkDown", // アプリケーション名 copyright: "Copyright © 2021", // 著作権声明 mac: {
          アイコン: "./public/icon.icns", // アイコン
        },
      },
    },
  },
};

icon.icns 生成用の 1024*1024 の画像を準備し、同じディレクトリにicons.iconsetという名前のフォルダーを作成します。

さまざまなサイズの画像ファイルを作成する

sips -z 16 16 icon.png -o icons.iconset/icon_16x16.png
sips -z 32 32 icon.png -o icons.iconset/[email protected]
sips -z 32 32 icon.png -o icons.iconset/icon_32x32.png
sips -z 64 64 icon.png -o icons.iconset/[email protected]
sips -z 128 128 icon.png -o icons.iconset/icon_128x128.png
sips -z 256 256 icon.png -o icons.iconset/[email protected]
sips -z 256 256 icon.png -o icons.iconset/icon_256x256.png
sips -z 512 512 icon.png -o icons.iconset/[email protected]
sips -z 512 512 icon.png -o icons.iconset/icon_512x512.png
sips -z 1024 1024 icon.png -o icons.iconset/[email protected]

icon.icnsという名前のアイコンファイルを取得します。

アイコンユーティリティ -c icns icons.iconset -o icon.icns

パック

npm 実行 electron:build

結果

ダメージ

取得した dmg ファイルは直接インストールして使用できます。

コード

<!-- 背景.ts -->
「厳密な使用」;

輸入 {
  アプリ、
  プロトコル、
  ブラウザウィンドウ、
  画面、
  メニュー、
  メニュー項目、
  シェル、
  ダイアログ、
  ipcメイン、
} から "electron" へ;
「electron/main」から KeyboardEvent と MenuItemConstructorOptions をインポートします。
「vue-cli-plugin-electron-builder/lib」から createProtocol をインポートします。
「electron-devtools-installer」から installExtension、{ VUEJS3_DEVTOOLS } をインポートします。
const isDevelopment = process.env.NODE_ENV !== "production";
「fs」から writeFileSync をインポートします。

開いたファイル = "";
// ファイルを保存 ipcMain.on("save-content", (event: unknown, content: string) => {
  開いたファイルの長さが0より大きい場合
    // ファイルに直接保存する try {
      開いたファイルの内容を書き込む。
      console.log("正常に保存しました");
    } キャッチ(エラー){
      console.log("保存に失敗しました");
    }
  } それ以外 {
    定数オプション = {
      タイトル:「ファイルを保存」、
      デフォルトパス: "new.md",
      フィルター: [{ name: "カスタムファイルタイプ", 拡張子: ["md"] }],
    };
    定数 focusWindow = BrowserWindow.getFocusedWindow();
    if (focusedWindow) {
      ダイアログ
        .showSaveDialog(フォーカスされたウィンドウ、オプション)
        .then((結果: Electron.SaveDialogReturnValue) => {
          if (結果.ファイルパス) {
            試す {
              writeFileSync(結果.filePath、コンテンツ);
              console.log("正常に保存しました");
              開いたファイル = result.filePath;
            } キャッチ(エラー){
              console.log("保存に失敗しました");
            }
          }
        })
        .catch((エラー) => {
          コンソール.log(エラー);
        });
    }
  }
});

const テンプレート: Array<MenuItemConstructorOptions> = [
  {
    ラベル: "MarkDown",
    サブメニュー: [
      {
        ラベル: "About",
        アクセラレータ: "CmdOrCtrl+W",
        役割: "について",
      },
      {
        ラベル: "プログラムを終了",
        アクセラレータ: "CmdOrCtrl+Q",
        役割: 「終了」、
      },
    ]、
  },
  {
    ラベル: "ファイル",
    サブメニュー: [
      {
        ラベル: "ファイルを開く",
        アクセラレータ: "CmdOrCtrl+O",
        クリック: (
          項目: メニュー項目、
          focusedWindow: BrowserWindow | 未定義、
          // eslint 次の行を無効にする @typescript-eslint/未使用変数なし
          _event: キーボードイベント
        ) => {
          ダイアログ
            .showOpenDialog({
              プロパティ: ["openFile"],
              フィルター: [{ name: "カスタムファイルタイプ", 拡張子: ["md"] }],
            })
            .then((res) => {
              res && res["filePaths"].length > 0 の場合 {
                定数ファイルパス = res["ファイルパス"][0];
                // レンダリングスレッドにファイルを渡す if (focusedWindow) {
                  focusedWindow.webContents.send("open-file-path", filePath);
                  開かれたファイル = ファイルパス;
                }
              }
            })
            .catch((エラー) => {
              コンソールログ(エラー);
            });
        },
      },
      {
        ラベル: 「ストレージ」、
        アクセラレータ: "CmdOrCtrl+S",
        クリック: (
          項目: メニュー項目、
          focusedWindow: BrowserWindow | 未定義、
          // eslint 次の行を無効にする @typescript-eslint/未使用変数なし
          _event: キーボードイベント
        ) => {
          if (focusedWindow) {
            focusedWindow.webContents.send("get-content", "");
          }
        },
      },
    ]、
  },
  {
    ラベル: "編集",
    サブメニュー: [
      {
        ラベル: 「取り消し」、
        アクセラレータ: "CmdOrCtrl+Z",
        役割: 「元に戻す」、
      },
      {
        ラベル: 「やり直し」、
        アクセラレータ: "Shift+CmdOrCtrl+Z",
        役割: 「やり直し」、
      },
      {
        タイプ:「セパレータ」、
      },
      {
        ラベル: 「カット」、
        アクセラレータ: "CmdOrCtrl+X",
        役割: 「カット」、
      },
      {
        ラベル: "コピー",
        アクセラレータ: "CmdOrCtrl+C",
        役割: "コピー"、
      },
      {
        ラベル:「貼り付け」、
        アクセラレータ: "CmdOrCtrl+V",
        役割: 「貼り付け」、
      },
    ]、
  },
  {
    ラベル: "ウィンドウ",
    役割: "ウィンドウ"、
    サブメニュー: [
      {
        ラベル: 「最小化」、
        アクセラレータ: "CmdOrCtrl+M",
        役割: 「最小化」、
      },
      {
        ラベル: "最大化",
        アクセラレータ: "CmdOrCtrl+M",
        クリック: (
          項目: メニュー項目、
          focusedWindow: BrowserWindow | 未定義、
          // eslint 次の行を無効にする @typescript-eslint/未使用変数なし
          _event: キーボードイベント
        ) => {
          if (focusedWindow) {
            フォーカスウィンドウを最大化します。
          }
        },
      },
      {
        タイプ:「セパレータ」、
      },
      {
        ラベル: 「全画面に切り替える」、
        アクセラレータ: (function () {
          プロセスプラットフォームが「ダーウィン」の場合
            「Ctrl+Command+F」を返します。
          } それ以外 {
            「F11」を返します。
          }
        })(),
        クリック: (
          項目: メニュー項目、
          focusedWindow: BrowserWindow | 未定義、
          // eslint 次の行を無効にする @typescript-eslint/未使用変数なし
          _event: キーボードイベント
        ) => {
          if (focusedWindow) {
            focusWindow.setFullScreen(!focusedWindow.isFullScreen());
          }
        },
      },
    ]、
  },
  {
    ラベル: "ヘルプ",
    役割: "ヘルプ"、
    サブメニュー: [
      {
        ラベル: "詳細を見る",
        クリック: 関数 () {
          シェルを外部から開きます("http://electron.atom.io");
        },
      },
    ]、
  },
];

プロトコル.registerSchemesAsPrivileged([
  { スキーム: "app"、権限: { secure: true、 standard: true } }、
]);

非同期関数createWindow() {
  const { 幅、高さ } = screen.getPrimaryDisplay().workAreaSize;
  const win = 新しいブラウザウィンドウ({
    幅、
    身長、
    ウェブ設定: {
      ノード統合: true、
      コンテキスト分離: false、
    },
  });

  プロセス環境のWEBPACK_DEV_SERVER_URLの場合{
    // 開発モードの場合は開発サーバーの URL をロードします
    win.loadURL(process.env.WEBPACK_DEV_SERVER_URL を文字列として) を待機します。
    プロセス環境がIS_TESTの場合、win.webContents.openDevTools();
  } それ以外 {
    プロトコルを作成します("アプリ");
    // 開発中でないときにindex.htmlをロードする
    win.loadURL("app://./index.html");
  }
}

// すべてのウィンドウが閉じられたら終了します。
app.on("ウィンドウがすべて閉じました", () => {
  // macOSではアプリケーションとそのメニューバーでよく使われる
  // ユーザーがCmd + Qで明示的に終了するまでアクティブのままにします
  プロセスプラットフォームが "darwin" の場合
    アプリを終了します。
  }
});

app.on("アクティブ化", () => {
  // macOSでは、アプリが終了してもウィンドウを再作成するのが一般的です。
  // ドックアイコンがクリックされ、他のウィンドウは開いていません。
  BrowserWindow.getAllWindows().length === 0 の場合、createWindow();
});

// このメソッドはElectronが終了したときに呼び出されます
// 初期化が完了し、ブラウザ ウィンドウを作成する準備が整いました。
// 一部の API はこのイベントが発生した後にのみ使用できます。
app.on("準備完了", 非同期() => {
  if (isDevelopment && !process.env.IS_TEST) {
    // Vue Devtools をインストール
    試す {
      VUEJS3_DEVTOOLS のインストールを待機します。
    } キャッチ (e) {
      console.error("Vue Devtools のインストールに失敗しました:", e.toString());
    }
  }
  ウィンドウを作成します。
  // メニューを作成しますMenu.setApplicationMenu(Menu.buildFromTemplate(template));
});

// 開発モードで親プロセスからの要求に応じて正常に終了します。
if (isDevelopment) {
  プロセスプラットフォームが "win32" の場合
    process.on("メッセージ", (データ) => {
      if (data === "graceful-exit") {
        アプリを終了します。
      }
    });
  } それ以外 {
    プロセス.on("SIGTERM", () => {
      アプリを終了します。
    });
  }
}

デスクトップアプリケーションを実装するための Vue3 と Electron の詳細な説明については、この記事で終わります。Vue3 Electron デスクトップアプリケーションの関連コンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、次の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • Vite+ElectronでVUE3デスクトップアプリケーションを素早く構築
  • Electron + Vueでデスクトップをパッケージ化する操作手順の詳細説明
  • vue + Electron でデスクトップ アプリケーションを作成するためのサンプル コード

<<:  MySQLのページング制限のパフォーマンス問題についての簡単な説明

>>:  Linux ログ表示方法 6 つのまとめ

推薦する

Docker で nginx の https を設定する方法

https をサポートしていない Web サイトは、ブラウザによって徐々に安全でないとマークされるた...

Dockeにredisをインストールする方法

1. redisイメージを検索する docker 検索 redis 2. Redisイメージをダウン...

MySQL における INSERT INTO SET の利点

MySQL データベースにデータを挿入します。以前はよく使われていた INSERT INTO テーブ...

MySQL の instr を使用したファジー クエリ メソッドの紹介

MySQL の内部関数instrを使用すると、従来の like クエリ メソッドを置き換えることがで...

CSS3 はアニメーション属性を使用してクールな効果を実現します (推奨)

animation-name アニメーション名。複数のアニメーションがバインドされていることを示す...

docker compose を使用してハーバープライベートウェアハウスをインストールする詳細なチュートリアル

概要港とは何ですか?英語の単語の意味は「港」です。 Harborはコンテナ(貨物)を保管するために使...

TomcatをダウンロードしてLinuxにインストールする詳細な手順

Linux に触れたばかりの方には、この内容が役に立つかもしれません。Linux にしばらく触れてい...

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

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

MySQLにログインする際のエラー「ERROR 1045 (28000)」を解決する方法

今日はサーバーにログインして、データベース内のいくつかのものを変更する準備をしました。しかし、パスワ...

Vue ページ状態の永続化の詳細な説明

目次コード:補充:要約する要件: 左のツリーと右のテーブル。組織ツリーでノードを選択した後、詳細ペー...

MySQLステートメントの記述と実行順序を理解するだけです

MySQL ステートメントの書き込み順序と実行順序には大きな違いがあります。書き順、mysql の一...

VMware Workstation 14 Pro は CentOS 7.0 をインストールします

VMware Workstation 14 ProにCentOS 7.0をインストールする具体的な方...

MySQL/MariaDB ルートパスワードリセットチュートリアル

序文パスワードを忘れることは、よく遭遇する問題です。MySQL または MariaDB データベース...

Vueシャトルボックスは上下の動きを実現します

この記事の例では、vueシャトルボックスを上下に動かすための具体的なコードを参考までに共有しています...