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
Inhaltsverzeichnis 1. Systemüberwachung 2. Dateio...
Inhaltsverzeichnis Verwenden bedingter Typen in g...
Überblick: Oracle Scott-Benutzer haben vier Tabel...
Webanwendungsklasse 1. DownFürAlleOderNurIch Mith...
Der erste Cutter in China github.com/chokcoco Hie...
Während der heutigen Vorlesung habe ich über den ...
Produktdesigner sind mit komplexen und großen Fert...
Vorwort In vielen Fällen werden wir virtuelle Mas...
Systemumgebung: centos7.4 1. Prüfen Sie, ob die D...
Verwenden Sie natives JS, um ein neuneckiges Rast...
Inhaltsverzeichnis 1 Mount-Verzeichnisse und Date...
Vorwort: Beim Übergeben von Daten zwischen überge...
Was sind Slots? Wir wissen, dass in Vue nichts in...
Die Methoden zur Installation von Nginx und mehre...
1. Einleitung Die bisherige Programmarchitektur k...