So implementieren Sie die @person-Funktion über Vue

So implementieren Sie die @person-Funktion über Vue

Dieser Artikel verwendet Vue und fügt Mausklickereignisse und einige kleine Seitenoptimierungen hinzu

Grundstruktur

Erstellen Sie eine sandBox.vue-Datei, um die Grundstruktur der Funktion zu schreiben

 <div Klasse="Inhalt">
    <!--Textfeld-->
    <div
      Klasse="Herausgeber"
      ref="divRef"
      Inhalt editierbar
      @keyup="handkeKeyUp"
      @keydown="Tastennachunten bedienen"
    ></div>
    <!--Optionen-->
    <AtDialog
      v-if="Dialog anzeigen"
      :sichtbar="Dialog anzeigen"
      :position="Position"
      :Abfragezeichenfolge="Abfragezeichenfolge"
      @onPickUser="Benutzer auswählen"
      @onHide="handleHide"
      @onShow="Anzeigengriff"
    ></AtDialog>
  </div>
<Skript>
importiere AtDialog aus '../components/AtDialog'
Standard exportieren {
  Name: 'sandBox',
  Komponenten: { AtDialog },
  Daten () {
    zurückkehren {
      node: '', // Den Knoten abrufen user: '', // Den Inhalt des ausgewählten Elements endIndex: '', // Die letzte Cursorposition queryString: '', // Suchwert showDialog: false, // Ob das Popup-Fenster angezeigt werden soll position: {
        x: 0,
        j: 0
      }//Anzeigeposition des Popup-Fensters}
  },
  Methoden: {
    // Cursorposition abrufen getCursorIndex () {
      const Auswahl = Fenster.getSelection()
      return selection.focusOffset //Wählen Sie den Offset von focusNode am Anfang},
    //Knoten abrufen getRangeNode () {
      const Auswahl = Fenster.getSelection()
      return selection.focusNode // ausgewählter Endknoten},
    // Die Stelle, an der das Popup-Fenster erscheint getRangeRect () {
      const Auswahl = Fenster.getSelection()
      const range = selection.getRangeAt(0) // ist ein generisches Objekt zum Verwalten von Auswahlbereichen const rect = range.getClientRects()[0] // Wähle einen Text aus und erhalte den Bereich des ausgewählten Textes const LINE_HEIGHT = 30
      zurückkehren {
        x: Rechteck.x,
        y: Rechteck.y + Zeilenhöhe
      }
    },
    // Ob @ angezeigt werden soll
    zeigeAt() {
      const node = this.getRangeNode()
      wenn (!node || node.nodeType !== Node.TEXT_NODE) ​​​​false zurückgeben
      const Inhalt = node.textContent || ''
      const regx = /@([^@\s]*)$/
      const match = regx.exec(content.slice(0, this.getCursorIndex()))
      Rückgabewert: Übereinstimmung und Übereinstimmungslänge === 2
    },
    // Holen Sie sich @user getAtUser () {
      const content = this.getRangeNode().textContent || ''
      const regx = /@([^@\s]*)$/
      const match = regx.exec(content.slice(0, this.getCursorIndex()))
      wenn (Match && Matchlänge === 2) {
        Rückspiel[1]
      }
      Rückgabe undefiniert
    },
    // Erstelle ein Label createAtButton (Benutzer) {
      const btn = document.createElement('span')
      btn.style.display = "Inline-Block"
      btn.dataset.user = JSON.stringify(Benutzer)
      btn.className = "at-Schaltfläche"
      btn.contentEditable = "falsch"
      btn.textContent = `@${Benutzername}`
      const Wrapper = Dokument.createElement('span')
      wrapper.style.display = "Inline-Block"
      wrapper.contentEditable = "false"
      const spaceElem = document.createElement('span')
      spaceElem.style.whiteSpace = "vor"
      spaceElem.textContent = "\u200b"
      spaceElem.contentEditable = "false"
      const clonedSpaceElem = spaceElem.cloneNode(true)
      Wrapper.AnhängenUntergeordnetesElement(spaceElem)
      Wrapper.AnhängenKind(btn)
      Wrapper.appendChild(geklontesSpaceElem)
      Rücksendeverpackung
    },
    replaceString (roh, Ersetzer) {
      returniere raw.replace(/@([^@\s]*)$/, Ersetzer)
    },
    // Füge @tag replaceAtUser (Benutzer) { ein.
      const node = dieser.knoten
      if (Knoten && Benutzer) {
        const Inhalt = node.textContent || ''
        const endIndex = this.endIndex
        const preSlice = this.replaceString(content.slice(0, endIndex), '')
        const restSlice = content.slice(endIndex)
        const parentNode = node.parentNode
        const nextNode = node.nextSibling
        const vorherigerTextNode = neuer Text(preSlice)
        const nextTextNode = neuer Text('\u200b' + restSlice) // 0 breite Zeichen hinzufügen const atButton = this.createAtButton(Benutzer)
        übergeordneter Knoten.entfernenUntergeordnetesElement(Knoten)
        // In das Textfeld einfügen if (nextNode) {
          parentNode.insertBefore(vorherigerTextNode, nächsterNode)
          parentNode.insertBefore(atButton, nächsterNode)
          parentNode.insertBefore(nächsterTextNode, nächsterNode)
        } anders {
          übergeordneter Knoten.anhängendesKind(vorherigerTextknoten)
          parentNode.anhängenKind(atButton)
          parentNode.appendChild(nächsterTextNode)
        }
        // Cursorposition zurücksetzen const range = new Range()
        const Auswahl = Fenster.getSelection()
        range.setStart(nächsterTextNode, 0)
        range.setEnd(nächsterTextNode, 0)
        Auswahl.AlleBereicheentfernen()
        Auswahl.addRange(Bereich)
      }
    },
    //Tastatur hoch eventhandkeKeyUp () {
      wenn (this.showAt()) {
        const node = this.getRangeNode()
        const endIndex = this.getCursorIndex()
        dieser.Knoten = Knoten
        dies.endIndex = endIndex
        diese.position = diese.getRangeRect()
        this.queryString = this.getAtUser() || ''
        this.showDialog = true
      } anders {
        this.showDialog = false
      }
    },
    //Tastaturkürzel handleKeyDown (e) {
      wenn (dieser.showDialog) {
        wenn (e.code === 'PfeilNachOben' ||
          e.code === 'Pfeil nach unten' ||
          e.code === 'Eingeben') {
          e.preventDefault()
        }
      }
    },
    // Verstecke das Auswahlfeld nach dem Einfügen des Tags handlePickUser (user) {
      this.replaceAtUser(Benutzer)
      this.user = Benutzer
      this.showDialog = false
    },
    //Auswahlfeld ausblenden handleHide () {
      this.showDialog = false
    },
    //Zeige das Auswahlfeld handleShow () {
      this.showDialog = true
    }
  }
}
</Skript>
 
<style scoped lang="scss">
  .Inhalt {
    Schriftfamilie: serifenlos;
    h1{
      Textausrichtung: zentriert;
    }
  }
  .Editor {
    Rand: 0 automatisch;
    Breite: 600px;
    Höhe: 150px;
    Hintergrund: #fff;
    Rand: 1px durchgehend blau;
    Rahmenradius: 5px;
    Textausrichtung: links;
    Polsterung: 10px;
    Überlauf: automatisch;
    Zeilenhöhe: 30px;
    &:Fokus {
      Gliederung: keine;
    }
  }
</Stil>

Wenn ein Klickereignis hinzugefügt wird, müssen die Knoten- und Cursorposition im [Keyboard Up Event] ermittelt und in den Daten gespeichert werden

 //Tastatur hoch eventhandkeKeyUp () {
      wenn (this.showAt()) {
        const node = this.getRangeNode() // Den Knoten abrufen const endIndex = this.getCursorIndex() // Die Cursorposition abrufen this.node = node 
        dies.endIndex = endIndex 
        diese.position = diese.getRangeRect()
        this.queryString = this.getAtUser() || ''
        this.showDialog = true
      } anders {
        this.showDialog = false
      }
    },

Erstellen Sie eine neue Komponente und bearbeiten Sie die Popup-Optionen 

<Vorlage>
<div
  Klasse="Wrapper"
  :style="{position:'fest',oben:position.y +'px',links:position.x+'px'}">
  <div v-if="!mockList.length" class="empty">Keine Suchergebnisse</div>
  <div
    v-für="(Element,i) in MockList"
    :Schlüssel="Artikel-ID"
    Klasse="Artikel"
    :Klasse="{'aktiv': i === index}"
    ref="BenutzerRef"
    @click="klickenBei($event,item)"
    @mouseenter="hoverAt(i)"
  >
    <div Klasse="name">{{item.name}}</div>
  </div>
</div>
</Vorlage>
 
<Skript>
const mockData = [
  { Name: 'HTML', ID: 'HTML' },
  { Name: "CSS", ID: "CSS" },
  { Name: 'Java', ID: 'Java' },
  { Name: 'JavaScript', ID: 'JavaScript' }
]
Standard exportieren {
  Name: "AtDialog",
  Requisiten: {
    sichtbar: Boolean,
    Position: Objekt,
    queryString: Zeichenfolge
  },
  Daten () {
    zurückkehren {
      Benutzer: [],
      Index: -1,
      mockList: mockData
    }
  },
  betrachten:
    Abfragezeichenfolge (Wert) {
      Wert? this.mockList = mockData.filter(({ name }) => name.startsWith(val)) : this.mockList = mockData.slice(0)
    }
  },
  montiert () {
    document.addEventListener('keyup', dieser.keyDownHandler)
  },
  zerstört () {
    document.removeEventListener('keyup', this.keyDownHandler)
  },
  Methoden: {
    keyDownHandler (e) {
      wenn (e.code === 'Escape') {
        dies.$emit('onHide')
        zurückkehren
      }
      //Tastatur gedrückt => ↓
      wenn (e.code === 'PfeilNachUnten') {
        wenn (dieser.index >= diese.mockList.length - 1) {
          dieser.index = 0
        } anders {
          dieser.index = dieser.index + 1
        }
      }
      //Tastatur gedrückt => ↑
      wenn (e.code === 'PfeilNachOben') {
        wenn (dieser.index <= 0) {
          dieser.index = diese.mockList.length - 1
        } anders {
          dieser.index = dieser.index - 1
        }
      }
      //Tastatur gedrückt => Enterif (e.code === 'Enter') {
        wenn (diese.mockList.length) {
          const Benutzer = {
            Name: diese.mockList[dieser.index].name,
            ID: diese.mockList[diesen.index].id
          }
          dies.$emit('onPickUser', Benutzer)
          dieser.index = -1
        }
      }
    },
    clickAt (e, Artikel) {
      const Benutzer = {
        Name: Artikelname,
        ID: Artikel-ID
      }
      dies.$emit('onPickUser', Benutzer)
      dieser.index = -1
    },
    hoverAt (Index) {
      dieser.index = index
    }
  }
}
</Skript>
 
<style scoped lang="scss">
  .wrapper {
    Breite: 238px;
    Rand: 1px durchgezogen #e4e7ed;
    Rahmenradius: 4px;
    Hintergrundfarbe: #fff;
    Kastenschatten: 0 2px 12px 0 RGB (0 0 0 / 10 %);
    Box-Größe: Rahmenbox;
    Polsterung: 6px 0;
  }
  .leer{
    Schriftgröße: 14px;
    Polsterung: 0 20px;
    Farbe: #999;
  }
  .Artikel {
    Schriftgröße: 14px;
    Polsterung: 0 20px;
    Zeilenhöhe: 34px;
    Cursor: Zeiger;
    Farbe: #606266;
    &.aktiv {
      Hintergrund: #f5f7fa;
      Farbe: blau;
      .Ausweis {
        Farbe: blau;
      }
    }
    &:erstes-Kind {
      Rahmenradius: 5px 5px 0 0;
    }
    &:letztes-Kind {
      Rahmenradius: 0 0 5px 5px;
    }
    .Ausweis {
      Schriftgröße: 12px;
      Farbe: rgb(83, 81, 81);
    }
  }
</Stil>

Oben finden Sie Einzelheiten zur Implementierung der @人-Funktion über Vue. Weitere Informationen zur Vue @人-Funktion finden Sie in den anderen verwandten Artikeln auf 123WORDPRESS.COM!

Das könnte Sie auch interessieren:
  • Verwenden Sie vue3, um ein Mensch-Katze-Kommunikations-Applet zu implementieren
  • Realisierung der intelligenten Roboter-Antwortfunktion von Vue+AI
  • Vue.js implementiert h5-Roboter-Chat (Betaversion)
  • Vue+tracking.js implementiert die Gesichtserkennungsfunktion im Front-End
  • Mehrpersonen-Online-Chatroom basierend auf Vue und WebSocket
  • Eine Single-Page-Anwendungsfunktion, die mobiles QQ basierend auf Vue2 imitiert (Zugriff auf Chatbot)

<<:  Bootstrap 3.0 Studiennotizen CSS-bezogene Ergänzung

>>:  Tutorial zur Samba-Konfiguration für die Dateifreigabe im Linux-System

Artikel empfehlen

Beispielerklärung für langsame MySQL-Abfragen und -Protokolle

1. Einleitung Durch Aktivieren des Slow Query Log...

CSS zum Erzielen von leuchtendem Text und ein paar JS-Spezialeffekten

Umsetzungsideen: Verwenden Sie text-shadow in CSS...

So veröffentlichen Sie ein lokal erstelltes Docker-Image auf Dockerhub

Heute zeigen wir Ihnen, wie Sie das lokale Docker...

Optimierungsanalyse der Limit-Abfrage in MySQL-Optimierungstechniken

Vorwort Im realen Geschäftsleben ist Paging eine ...

So führen Sie das Springboot-Projekt im Docker aus

1. Klicken Sie unten in IDEA auf Terminal und geb...

React implementiert dynamische Popup-Fensterkomponente

Wenn wir beim Schreiben einiger UI-Komponenten di...

Vue-Konfigurationsdetails für mehrere Seiten

Inhaltsverzeichnis 1. Der Unterschied zwischen me...

Detaillierte Erklärung von mktemp, einem grundlegenden Linux-Befehl

mktemp Erstellen Sie auf sichere Weise temporäre ...

Details zur Reihenfolge, in der MySQL my.cnf liest

Inhaltsverzeichnis Die Reihenfolge, in der MySQL ...

Implementierungsprinzip und Konfiguration der MySql Master-Slave-Replikation

Die Trennung von Lese- und Schreibzugriffen in Da...