Vue で @person 関数を実装する方法

Vue で @person 関数を実装する方法

この記事ではvueを使用し、マウスクリックイベントといくつかの小さなページの最適化を追加します。

基本構造

関数の基本構造を記述するためのsandBox.vueファイルを作成する

 <div class="content">
    <!--テキストボックス-->
    <div
      クラス="エディター"
      ref="divRef"
      コンテンツ編集可能
      @keyup="handkeKeyUp"
      @keydown="ハンドルキーダウン"
    </div>
    <!--オプション-->
    <ダイアログ
      v-if="showDialog"
      :visible="ダイアログを表示"
      :position="位置"
      :queryString="クエリ文字列"
      @onPickUser="ハンドルPickUser"
      @onHide="ハンドルを非表示"
      @onShow="ハンドル表示"
    </ダイアログ>
  </div>
<スクリプト>
'../components/AtDialog' から AtDialog をインポートします。
エクスポートデフォルト{
  名前: 'サンドボックス',
  コンポーネント: { AtDialog },
  データ () {
    戻る {
      node: '', // ノードを取得 user: '', // 選択された項目の内容 endIndex: '', // 最後のカーソル位置 queryString: '', // 検索値 showDialog: false, // ポップアップウィンドウを表示するかどうか position: {
        x: 0,
        年: 0
      }//ポップアップウィンドウの表示位置}
  },
  メソッド: {
    // カーソル位置を取得する getCursorIndex () {
      定数選択 = window.getSelection()
      return selection.focusOffset // 先頭の focusNode のオフセットを選択します},
    // ノードを取得する getRangeNode () {
      定数選択 = window.getSelection()
      return selection.focusNode // 選択された終了ノード},
    // ポップアップウィンドウが表示される場所 getRangeRect () {
      定数選択 = window.getSelection()
      const range = selection.getRangeAt(0) // 選択範囲を管理するための汎用オブジェクトです const rect = range.getClientRects()[0] // テキストを選択し、選択されたテキストの範囲を取得します const LINE_HEIGHT = 30
      戻る {
        x: 矩形x、
        y: rect.y + LINE_HEIGHT
      }
    },
    // @を表示するかどうか
    表示At() {
      定数ノード = this.getRangeNode()
      if (!node || node.nodeType !== Node.TEXT_NODE) ​​falseを返す
      定数コンテンツ = node.textContent || ''
      定数regx = /@([^@\s]*)$/
      定数マッチ = regx.exec(content.slice(0, this.getCursorIndex()))
      マッチ&&match.length === 2を返す
    },
    // @user を取得する getAtUser () {
      const コンテンツ = this.getRangeNode().textContent || ''
      定数regx = /@([^@\s]*)$/
      定数マッチ = regx.exec(content.slice(0, this.getCursorIndex()))
      マッチ&&マッチ.長さ=== 2の場合{
        リターンマッチ[1]
      }
      未定義を返す
    },
    // ラベルを作成する createAtButton (user) {
      const btn = document.createElement('span')
      btn.style.display = 'インラインブロック'
      btn.dataset.user = JSON.stringify(user)
      btn.className = 'at-button'
      btn.contentEditable = 'false'
      btn.textContent = `@${user.name}`
      const ラッパー = document.createElement('span')
      wrapper.style.display = 'インラインブロック'
      wrapper.contentEditable = 'false'
      定数スペース要素 = document.createElement('span')
      spaceElem.style.whiteSpace = 'pre'
      スペース要素.textContent = '\u200b'
      spaceElem.contentEditable = 'false'
      const clonedSpaceElem = spaceElem.cloneNode(true)
      wrapper.appendChild(スペース要素)
      wrapper.appendChild(btn)
      wrapper.appendChild(クローンされたスペース要素)
      返品ラッパー
    },
    replaceString (raw, replacer) {
      raw.replace(/@([^@\s]*)$/, replacer) を返します
    },
    // @ タグを挿入 replaceAtUser (user) {
      定数ノード = this.node
      if (ノード && ユーザー) {
        定数コンテンツ = node.textContent || ''
        定数 endIndex = this.endIndex
        const preSlice = this.replaceString(content.slice(0, endIndex), '')
        const restSlice = content.slice(endIndex)
        定数 parentNode = ノード.parentNode
        定数 nextNode = node.nextSibling
        const previousTextNode = 新しい Text(preSlice)
        const nextTextNode = new Text('\u200b' + restSlice) // 0 個のワイド文字を追加 const atButton = this.createAtButton(user)
        親ノードの子ノードを削除します。
        // テキストボックスに挿入 if (nextNode) {
          親ノード。前のテキストノード、次のノードの前に挿入します。
          親ノード。ボタンの前に挿入します。次のノード。
          親ノード。次のテキストノードの前に挿入します。
        } それ以外 {
          親ノード.appendChild(前のテキストノード)
          親ノード.appendChild(ボタン上)
          親ノード。次のテキストノードに子を追加します。
        }
        // カーソル位置をリセットする const range = new Range()
        定数選択 = window.getSelection()
        範囲.setStart(次のテキストノード、0)
        範囲.setEnd(次のテキストノード、0)
        選択範囲をすべて削除()
        選択範囲を追加します(範囲)
      }
    },
    //キーボードアップイベントhandkeKeyUp() {
      if (this.showAt()) {
        定数ノード = this.getRangeNode()
        定数 endIndex = this.getCursorIndex()
        this.node = ノード
        this.endIndex = 終了インデックス
        this.position = this.getRangeRect()
        this.queryString = this.getAtUser() || ''
        this.showDialog = true
      } それ以外 {
        this.showDialog = false
      }
    },
    //キーボード押下イベント handleKeyDown (e) {
      ダイアログを表示する
        if (e.code === 'ArrowUp' ||
          e.code === '矢印下' ||
          e.code === 'Enter') {
          e.preventDefault()
        }
      }
    },
    // タグを挿入した後、選択ボックスを非表示にする handlePickUser (user) {
      this.replaceAtUser(ユーザー)
      this.user = ユーザー
      this.showDialog = false
    },
    //選択ボックスを非表示にするhandleHide() {
      this.showDialog = false
    },
    // 選択ボックスを表示する handleShow () {
      this.showDialog = true
    }
  }
}
</スクリプト>
 
<スタイル スコープ lang="scss">
  。コンテンツ {
    フォントファミリー: サンセリフ;
    h1{
      テキスト配置: 中央;
    }
  }
  .エディター{
    マージン: 0 自動;
    幅: 600ピクセル;
    高さ: 150px;
    背景: #fff;
    境界線: 1px 青
    境界線の半径: 5px;
    テキスト配置: 左;
    パディング: 10px;
    オーバーフロー:自動;
    行の高さ: 30px;
    &:集中 {
      アウトライン: なし;
    }
  }
</スタイル>

クリックイベントが追加された場合、ノードとカーソルの位置は[キーボードアップイベント]で取得され、データに保存される必要があります。

 //キーボードアップイベントhandkeKeyUp() {
      if (this.showAt()) {
        const node = this.getRangeNode() // ノードを取得 const endIndex = this.getCursorIndex() // カーソルの位置を取得 this.node = node 
        this.endIndex = 終了インデックス 
        this.position = this.getRangeRect()
        this.queryString = this.getAtUser() || ''
        this.showDialog = true
      } それ以外 {
        this.showDialog = false
      }
    },

新しいコンポーネントを作成し、ポップアップオプションを編集します 

<テンプレート>
<div
  クラス="ラッパー"
  :style="{位置:'固定'、上:位置.y +'px'、左:位置.x+'px'}">
  <div v-if="!mockList.length" class="empty">検索結果はありません</div>
  <div
    v-for="(item,i) in mockList"
    :key="アイテムID"
    クラス="アイテム"
    :class="{'アクティブ': i === インデックス}"
    ref="ユーザー参照"
    @click="clickAt($event,item)"
    @mouseenter="hoverAt(i)"
  >
    <div class="name">{{item.name}}</div>
  </div>
</div>
</テンプレート>
 
<スクリプト>
const モックデータ = [
  { 名前: 'HTML'、 ID: 'HTML' },
  { 名前: 'CSS'、 ID: 'CSS' },
  { 名前: 'Java'、 ID: 'Java' },
  { 名前: 'JavaScript'、 ID: 'JavaScript' }
]
エクスポートデフォルト{
  名前: 'AtDialog',
  小道具: {
    表示: ブール値、
    位置: オブジェクト、
    クエリ文字列: 文字列
  },
  データ () {
    戻る {
      ユーザー: [],
      インデックス: -1,
      モックリスト: モックデータ
    }
  },
  時計:
    クエリ文字列 (値) {
      val ? this.mockList = mockData.filter(({ name }) => name.startsWith(val)) : this.mockList = mockData.slice(0)
    }
  },
  マウントされた(){
    document.addEventListener('keyup'、this.keyDownHandler) は、
  },
  破壊された(){
    document.removeEventListener('keyup'、this.keyDownHandler) を削除します。
  },
  メソッド: {
    キーダウンハンドラ(e) {
      if (e.code === 'エスケープ') {
        これを$emit('onHide')
        戻る
      }
      //キーボードが押された => ↓
      if (e.code === 'ArrowDown') {
        this.index >= this.mockList.length - 1 の場合 {
          this.index = 0
        } それ以外 {
          this.index = this.index + 1
        }
      }
      //キーボードが押された => ↑
      if (e.code === 'ArrowUp') {
        (this.index <= 0)の場合{
          this.index = this.mockList.length - 1
        } それ以外 {
          this.index = this.index - 1
        }
      }
      //キーボードが押された => Enterif (e.code === 'Enter') {
        if (this.mockList.length) {
          定数ユーザー = {
            名前: this.mockList[this.index].name,
            id: this.mockList[this.index].id
          }
          this.$emit('onPickUser', ユーザー)
          this.index = -1
        }
      }
    },
    clickAt (e, アイテム) {
      定数ユーザー = {
        名前: アイテム名、
        id: アイテム.id
      }
      this.$emit('onPickUser', ユーザー)
      this.index = -1
    },
    hoverAt (インデックス) {
      this.index = インデックス
    }
  }
}
</スクリプト>
 
<スタイル スコープ lang="scss">
  .ラッパー{
    幅: 238ピクセル;
    境界線: 1px 実線 #e4e7ed;
    境界線の半径: 4px;
    背景色: #fff;
    ボックスシャドウ: 0 2px 12px 0 rgb(0 0 0 / 10%);
    ボックスのサイズ: 境界線ボックス;
    パディング: 6px 0;
  }
  。空の{
    フォントサイズ: 14px;
    パディング: 0 20px;
    色: #999;
  }
  。アイテム {
    フォントサイズ: 14px;
    パディング: 0 20px;
    行の高さ: 34px;
    カーソル: ポインタ;
    色: #606266;
    &。アクティブ {
      背景: #f5f7fa;
      色: 青;
      .id {
        色: 青;
      }
    }
    &:最初の子 {
      境界線の半径: 5px 5px 0 0;
    }
    &:最後の子 {
      境界線の半径: 0 0 5px 5px;
    }
    .id {
      フォントサイズ: 12px;
      色: rgb(83, 81, 81);
    }
  }
</スタイル>

以上がVueで@人機能を実装する方法の詳細です。Vueの@人機能の詳細については、123WORDPRESS.COMの他の関連記事に注目してください。

以下もご興味があるかもしれません:
  • vue3を使用して人間と猫のコミュニケーションアプレットを実装する
  • Vue+AI知能ロボット返信機能の実現
  • Vue.js は h5 ロボット チャットを実装します (ベータ版)
  • Vue+tracking.jsはフロントエンドの顔検出機能を実装します
  • Vue と Websocket をベースにした複数人用オンライン チャット ルーム
  • Vue2ベースのモバイルQQを模倣したシングルページアプリケーション機能(チャットボットへのアクセス)

<<:  Bootstrap 3.0 学習ノート CSS関連補足

>>:  Linux システムファイル共有 samba 設定チュートリアル

推薦する

HTMLを圧縮しない理由はいくつかある

理由は簡単です。 HTML ドキュメントでは、複数の空白文字は 1 つの空白文字と同等です。つまり、...

「さらに表示」ボタンによる複数行テキストの切り捨てに関する考察

最近、たまたまこの小さな要件に遭遇しました。昔、JS を使用してこれを処理したことを覚えていますが、...

innerHTML アプリケーション

ブランクのブログ: http://www.planabc.net/ innerHTML プロパティは...

jQuery はパーセンテージスコアリングの進捗バーを実装します

この記事では、パーセンテージスコアリングプログレスバーを実現するためのjQueryの具体的なコードを...

React スキャフォールディングの構築方法を学ぶ

1. フロントエンドエンジニアリングの複雑さいくつかの小さなデモ プログラムを開発するだけであれば、...

HTML 内の CSS および JS リンクのバージョン番号 (キャッシュを更新)

背景検索エンジンで「.htaccess キャッシュ」というキーワードを検索すると、ウェブサイトのファ...

MySQL エラー コード 1064 の解決策

SQL ステートメント内の単語が mysql のキーワードと競合する場合は、`` (タブ キーの上)...

Vue が Ref を使用してレベル間でコンポーネントを取得する手順

VueはRefを使用してレベル間でコンポーネントインスタンスを取得します例の紹介開発プロセスでは、レ...

MySQL で指定した桁数の乱数を生成する方法と、バッチで乱数を生成する方法

1. まず、よく使われるMySQL関数をいくつか紹介しますRAND() は 0 から 1 (0<...

CSSスタイルの記述順序と命名規則と注意事項

書き順の重要性ブラウザのリフローを減らし、ブラウザのDOMレンダリングパフォーマンスを向上させる①:...

CSSを使用してAndroidシステムの読み込みアニメーションを実装する

Web には一般的な読み込みアイコンが 2 つあります。1 つは iOS の「菊」、もう 1 つは ...

Linux C++ マルチスレッド同期の非常に詳細な説明

目次1. ミューテックス1. ミューテックスの初期化2. ミューテックスロックの関連特性と分類3. ...

CSSを使用して、頻繁に表示される奇妙なボタンを簡単に実装します。

背景グループでは、CSS を使用してインセット コーナー ボタンを実装する方法や、矢印付きのボタンを...

コードの互換性を高めるために、HTMLを次のように記述します。

たとえば、スクリーン リーダー ソフトウェアを必要とするユーザーなどです。フロントエンド開発者として...

K8S クラスターを構築し、Hyper-V で Docker をインストールする方法

Win10 システムをインストールしていて、k8s クラスターを構築する場合、Win10 に付属する...