如何通過Vue實(shí)現(xiàn)@人的功能_第1頁(yè)
如何通過Vue實(shí)現(xiàn)@人的功能_第2頁(yè)
如何通過Vue實(shí)現(xiàn)@人的功能_第3頁(yè)
如何通過Vue實(shí)現(xiàn)@人的功能_第4頁(yè)
如何通過Vue實(shí)現(xiàn)@人的功能_第5頁(yè)
已閱讀5頁(yè),還剩7頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第如何通過Vue實(shí)現(xiàn)@人的功能本文采用vue,同時(shí)增加鼠標(biāo)點(diǎn)擊事件和一些頁(yè)面小優(yōu)化

基本結(jié)構(gòu)

新建一個(gè)sandBox.vue文件編寫功能的基本結(jié)構(gòu)

div

!--文本框--

ref="divRef"

contenteditable

@keyup="handkeKeyUp"

@keydown="handleKeyDown"

/div

!--選項(xiàng)--

AtDialog

v-if="showDialog"

:visible="showDialog"

:position="position"

:queryString="queryString"

@onPickUser="handlePickUser"

@onHide="handleHide"

@onShow="handleShow"

/AtDialog

/div

script

importAtDialogfrom'../components/AtDialog'

exportdefault{

name:'sandBox',

components:{AtDialog},

data(){

return{

node:'',//獲取到節(jié)點(diǎn)

user:'',//選中項(xiàng)的內(nèi)容

endIndex:'',//光標(biāo)最后停留位置

queryString:'',//搜索值

showDialog:false,//是否顯示彈窗

position:{

x:0,

y:0

}//彈窗顯示位置

methods:{

//獲取光標(biāo)位置

getCursorIndex(){

constselection=window.getSelection()

returnselection.focusOffset//選擇開始處focusNode的偏移量

//獲取節(jié)點(diǎn)

getRangeNode(){

constselection=window.getSelection()

returnselection.focusNode//選擇的結(jié)束節(jié)點(diǎn)

//彈窗出現(xiàn)的位置

getRangeRect(){

constselection=window.getSelection()

constrange=selection.getRangeAt(0)//是用于管理選擇范圍的通用對(duì)象

constrect=range.getClientRects()[0]//擇一些文本并將獲得所選文本的范圍

constLINE_HEIGHT=30

return{

x:rect.x,

y:rect.y+LINE_HEIGHT

//是否展示@

showAt(){

constnode=this.getRangeNode()

if(!node||node.nodeType!==Node.TEXT_NODE)returnfalse

constcontent=node.textContent||''

constregx=/@([^@\s]*)$/

constmatch=regx.exec(content.slice(0,this.getCursorIndex()))

returnmatchmatch.length===2

//獲取@用戶

getAtUser(){

constcontent=this.getRangeNode().textContent||''

constregx=/@([^@\s]*)$/

constmatch=regx.exec(content.slice(0,this.getCursorIndex()))

if(matchmatch.length===2){

returnmatch[1]

returnundefined

//創(chuàng)建標(biāo)簽

createAtButton(user){

constbtn=document.createElement('span')

btn.style.display='inline-block'

btn.dataset.user=JSON.stringify(user)

btn.className='at-button'

btn.contentEditable='false'

btn.textContent=`@${}`

constwrapper=document.createElement('span')

wrapper.style.display='inline-block'

wrapper.contentEditable='false'

constspaceElem=document.createElement('span')

spaceElem.style.whiteSpace='pre'

spaceElem.textContent='\u200b'

spaceElem.contentEditable='false'

constclonedSpaceElem=spaceElem.cloneNode(true)

wrapper.appendChild(spaceElem)

wrapper.appendChild(btn)

wrapper.appendChild(clonedSpaceElem)

returnwrapper

replaceString(raw,replacer){

returnraw.replace(/@([^@\s]*)$/,replacer)

//插入@標(biāo)簽

replaceAtUser(user){

constnode=this.node

if(nodeuser){

constcontent=node.textContent||''

constendIndex=this.endIndex

constpreSlice=this.replaceString(content.slice(0,endIndex),'')

constrestSlice=content.slice(endIndex)

constparentNode=node.parentNode

constnextNode=node.nextSibling

constpreviousTextNode=newText(preSlice)

constnextTextNode=newText('\u200b'+restSlice)//添加0寬字符

constatButton=this.createAtButton(user)

parentNode.removeChild(node)

//插在文本框中

if(nextNode){

parentNode.insertBefore(previousTextNode,nextNode)

parentNode.insertBefore(atButton,nextNode)

parentNode.insertBefore(nextTextNode,nextNode)

}else{

parentNode.appendChild(previousTextNode)

parentNode.appendChild(atButton)

parentNode.appendChild(nextTextNode)

//重置光標(biāo)的位置

constrange=newRange()

constselection=window.getSelection()

range.setStart(nextTextNode,0)

range.setEnd(nextTextNode,0)

selection.removeAllRanges()

selection.addRange(range)

//鍵盤抬起事件

handkeKeyUp(){

if(this.showAt()){

constnode=this.getRangeNode()

constendIndex=this.getCursorIndex()

this.node=node

this.endIndex=endIndex

this.position=this.getRangeRect()

this.queryString=this.getAtUser()||''

this.showDialog=true

}else{

this.showDialog=false

//鍵盤按下事件

handleKeyDown(e){

if(this.showDialog){

if(e.code==='ArrowUp'||

e.code==='ArrowDown'||

e.code==='Enter'){

e.preventDefault()

//插入標(biāo)簽后隱藏選擇框

handlePickUser(user){

this.replaceAtUser(user)

this.user=user

this.showDialog=false

//隱藏選擇框

handleHide(){

this.showDialog=false

//顯示選擇框

handleShow(){

this.showDialog=true

/script

stylescopedlang="scss"

.content{

font-family:sans-serif;

text-align:center;

.editor{

margin:0auto;

width:600px;

height:150px;

background:#fff;

border:1pxsolidblue;

border-radius:5px;

text-align:left;

padding:10px;

overflow:auto;

line-height:30px;

:focus{

outline:none;

/style

如果添加了點(diǎn)擊事件,節(jié)點(diǎn)和光標(biāo)位置獲取,需要在【鍵盤抬起事件】中獲取,并保存到data

//鍵盤抬起事件

handkeKeyUp(){

if(this.showAt()){

constnode=this.getRangeNode()//獲取節(jié)點(diǎn)

constendIndex=this.getCursorIndex()//獲取光標(biāo)位置

this.node=node

this.endIndex=endIndex

this.position=this.getRangeRect()

this.queryString=this.getAtUser()||''

this.showDialog=true

}else{

this.showDialog=false

},

新建一個(gè)組件,編輯彈窗選項(xiàng)

template

:style="{position:'fixed',top:position.y+'px',left:position.x+'px'}"

divv-if="!mockList.length"無搜索結(jié)果/div

v-for="(item,i)inmockList"

:key="item.id"

:class="{'active':i===index}"

ref="usersRef"

@click="clickAt($event,item)"

@mouseenter="hoverAt(i)"

div{{}}/div

/div

/div

/template

script

constmockData=[

{name:'HTML',id:'HTML'},

{name:'CSS',id:'CSS'},

{name:'Java',id:'Java'},

{name:'JavaScript',id:'JavaScript'}

exportdefault{

name:'AtDialog',

props:{

visible:Boolean,

position:Object,

queryString:String

data(){

return{

users:[],

index:-1,

mockList:mockData

watch:{

queryString(val){

valthis.mockList=mockData.filter(({name})=name.startsWith(val)):this.mockList=mockData.slice(0)

mounted(){

document.addEventListener('keyup',this.keyDownHandler)

destroyed(){

document.removeEventListener('keyup',this.keyDownHandler)

methods:{

keyDownHandler(e){

if(e.code==='Escape'){

this.$emit('onHide')

return

//鍵盤按下=↓

if(e.code==='ArrowDown'){

if(this.index=this.mockList.length-1){

this.index=0

}else{

this.index=this.index+1

//鍵盤按下=↑

if(e.code==='ArrowUp'){

if(this.index=0){

this.index=this.mockList.length-1

}else{

this.index=this.index-1

//鍵盤按下=回車

if(e.code==='Enter'){

if(this.mockList.length){

constuser={

name:this.mockList[this.index].name,

id:this.mockList[this.index].id

this.$emit('onPickUser',user)

this.index=-1

clickAt(e,item){

constuser={

name:,

id:item.id

this.$emit('onPickUser',user)

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論