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:
|
<<: Bootstrap 3.0 Studiennotizen CSS-bezogene Ergänzung
>>: Tutorial zur Samba-Konfiguration für die Dateifreigabe im Linux-System
1. Einleitung Durch Aktivieren des Slow Query Log...
Umsetzungsideen: Verwenden Sie text-shadow in CSS...
Inhaltsverzeichnis 2 Lösungen für den Dateiupload...
Heute zeigen wir Ihnen, wie Sie das lokale Docker...
Vorwort Im realen Geschäftsleben ist Paging eine ...
1. Klicken Sie unten in IDEA auf Terminal und geb...
Nginx kann im Allgemeinen für siebenschichtigen L...
Wenn wir beim Schreiben einiger UI-Komponenten di...
Projektszenario: Dark Horse Vue Projektmanagement...
Docker-Funktionen 1) Schneller Einstieg Benutzer ...
Inhaltsverzeichnis 1. Der Unterschied zwischen me...
mktemp Erstellen Sie auf sichere Weise temporäre ...
Inhaltsverzeichnis Die Reihenfolge, in der MySQL ...
Die Trennung von Lese- und Schreibzugriffen in Da...
Ich weiß nicht, ob Sie das Frameset-Attribut in I...