vue中實(shí)現(xiàn)div可編輯并插入指定元素與樣式
前言:
vue中實(shí)現(xiàn)一個(gè)既可以編輯內(nèi)容,有可以動(dòng)態(tài)編輯內(nèi)容插入一個(gè)帶有樣式的內(nèi)容,改變默認(rèn)內(nèi)容后,這個(gè)樣式消失的效果,這里來(lái)整理下調(diào)研與解決實(shí)現(xiàn)問(wèn)題之路。
實(shí)現(xiàn)最終效果:圖2為默認(rèn)內(nèi)容
1、可以光標(biāo)點(diǎn)擊任意地方,然后點(diǎn)擊按鈕,插入帶有span的內(nèi)容
2、默認(rèn)span是有樣式,但是一旦內(nèi)容與我們的默認(rèn)內(nèi)容不同就取消樣式
3、獲取的時(shí)候,可以拿到帶有標(biāo)簽的內(nèi)容,也可以拿到純文本內(nèi)容
4、默認(rèn)內(nèi)容,支持帶標(biāo)簽內(nèi)容
探索之路:
1、剛開(kāi)始從網(wǎng)上查找了很多資料,但是都有不同的缺陷,下面是我根據(jù)網(wǎng)上資料實(shí)現(xiàn)的效果
1)封裝一個(gè) inputDiv.vue
<template> <div ref="divInput" class="edit-div" style="-webkit-user-select: auto" :contenteditable="canEdit" @blur="onBlur" @input="changeText($event)" @keyup.space="changeSpace($event)" @keyup.enter="changeEnter($event)" @paste="onPaste" @focus="onFocus" placeholder="請(qǐng)輸入消息內(nèi)容" slot="title" v-html="innerText" ></div> </template> <script> export default { props: { value: { type: String, default: "", }, canEdit: { type: Boolean, default: true, }, }, data() { return { innerText: this.value, isLocked: false, } }, watch: { value() { if (!this.isLocked && !this.innerHTML) { this.innerText = this.value } }, }, methods: { getRefBlur() { this.$refs.divInput.blur() }, getRefFocus() { this.$refs.divInput.focus() }, onBlur() { this.$emit("onblurChange", this.$el.innerHTML) this.isLocked = false }, // 主要用于處理光標(biāo)得定位問(wèn)題 keepLastIndex(obj) { console.log(obj); if (window.getSelection) { obj.focus() let range = window.getSelection() range.selectAllChildren(obj) range.collapseToEnd() } else if (document.selection) { let range = document.selection.createRange() //創(chuàng)建選擇對(duì)象 range.moveToElementText(obj) //range定位到obj range.collapse(false) //光標(biāo)移至最后 range.select() } }, changeSpace(e) { setTimeout(() => { this.keepLastIndex(e.target) }, 30) this.$emit("keyupSpace", this.$el.innerHTML) }, changeEnter(e) { setTimeout(() => { this.keepLastIndex(e.target) }, 30) this.$emit("keyupEnter", this.$el.innerHTML) }, // 實(shí)時(shí)監(jiān)聽(tīng)當(dāng)前內(nèi)容 changeText(e) { console.log(e) if(e.data){ console.log('數(shù)據(jù):'+this.$el.innerHTML) setTimeout(() => { this.keepLastIndex(e.target) }, 30) this.$emit("input", this.$el.innerHTML) } }, // 輸入框粘貼事件 onPaste(event) { this.$emit("onPaste", event) }, // onFocus(event) { this.$emit("onFocus", event) }, } } </script> <style scoped> </style>
2)父級(jí)中使用:
結(jié)果:{{editInputVal}}-{{mrEditInputVal}} <el-button @click = 'addStrBtnFun'>{{addBtnText}}</el-button> <inputDiv ref="imitate" id="imitate" class="imitate-input imitate-placeholder js-imitate-input" @onblurChange="onblurChange($event)" @onFocus="getFocus" @onPaste="onPaste" v-html="mrEditInputVal" @input="contentedInput($event)" @keyupSpace="contentedKeySpace($event)" @keyupEnter="contentedKeyEnter($event)" @changeKeyup="changeKeyup($event)" ></inputDiv>
js部分: import inputDiv from './components/inputDiv' components: { inputDiv, }, data() { return { mrEditInputVal:'', editInputVal:'', addBtnText:'插入員工昵稱(chēng)', abc:'', teamContent: "<p>幸福 人和 測(cè)試增加數(shù)據(jù) 在加1111222</p>" } }, methods: { onblurChange(val){ // debugger }, getFocus(val){ // debugger }, onPaste(val){ // debugger }, contentedInput(val){ if(val.indexOf('<span')!= -1){ let arr1 = val.split('<span') let arr2 = arr1[1].split('/span>') let arr3 = arr2[0].split('>') let arr4 = arr3[1].split('<') if(arr4[0] != this.addBtnText){ let val = this.editInputVal = arr1[0]+arr4[0]+arr2[1] this.mrEditInputVal = JSON.parse(JSON.stringify(val)) return } } this.editInputVal = val }, contentedKeySpace(val){ // debugger }, contentedKeyEnter(val){ // debugger }, changeKeyup(val){ // debugger }, addStrBtnFun(){ let index = this.getCursorPosition() let insertStr = (soure,start, newStr) => { return soure.slice(0, start) + newStr + soure.slice(start) } let newStr = insertStr(this.editInputVal,index,'<span class="selColor">'+this.addBtnText+'</span>') this.mrEditInputVal = newStr }, getCursorPosition(){ const selection = window.getSelection(); const range = selection.getRangeAt(0); const cursorPos = range.startOffset; return cursorPos },
3)最終實(shí)現(xiàn)效果
1、實(shí)現(xiàn)了不同內(nèi)容的時(shí)候可以正常監(jiān)聽(tīng)
2、點(diǎn)擊按鈕,可以正常插入并修改樣式
缺點(diǎn):
1、點(diǎn)擊多個(gè)插入,位置有問(wèn)題
2、每次輸入第二個(gè)字符的時(shí)候,光標(biāo)都移動(dòng)到了最后一位
2、繼續(xù)努力實(shí)現(xiàn)效果,效果圖實(shí)現(xiàn)步驟:
注意:
不能實(shí)時(shí)獲取它的數(shù)據(jù),它的光標(biāo)位置會(huì)出現(xiàn)問(wèn)題,目前官方提供的方法,默認(rèn)是回到第一個(gè),可以修改到回到最后一個(gè),但是我們?nèi)绻侵虚g輸入內(nèi)容,光標(biāo)會(huì)異常,故而不建議實(shí)時(shí)獲取數(shù)據(jù)
1、div+contenteditable="true" 來(lái)實(shí)現(xiàn)div的可編輯,v-html來(lái)實(shí)現(xiàn)對(duì)他默認(rèn)值的修改
<div class="edit" contenteditable="true" @input="editInput" placeholder="請(qǐng)輸入消息內(nèi)容" v-html="innerHtml" > </div>
2、初始化方法
// 這一步是保留住edit編輯框中的選區(qū)的范圍對(duì)象。否則失焦后,getSelection()方法返回的選區(qū)對(duì)象已經(jīng)不再是編輯框了,已經(jīng)獲取不到編輯框中的范圍對(duì)象了。
initEditFun(){ editDiv = document.getElementsByClassName("edit")[0] editDiv.addEventListener("blur", () => { // 這一步是保留住edit編輯框中的選區(qū)的范圍對(duì)象。否則失焦后,getSelection()方法返回的選區(qū)對(duì)象已經(jīng)不再是編輯框了,已經(jīng)獲取不到編輯框中的范圍對(duì)象了。 range = window.getSelection().getRangeAt(0) }) },
3、點(diǎn)擊按鈕時(shí)候,給可編輯區(qū)域中增加一個(gè)帶有顏色的span
記得在你的功能樣式中添加,可在app.vue,也可以在你項(xiàng)目其他公共區(qū)域
.selColor{ color: red; }
點(diǎn)擊事件:
window.getSelection() 獲取他的光標(biāo)選取
selection.selectAllChildren(editDiv) // selectAllChildren把指定元素的所有子元素設(shè)為選中區(qū)域,并取消之前的選中區(qū)域。不包括node節(jié)點(diǎn)本身。
selection.collapseToEnd() //Selection.collapseToEnd() 方法的作用是取消當(dāng)前選區(qū),并把光標(biāo)定位在原選區(qū)的最末尾處,如果此時(shí)光標(biāo)所處的位置是可編輯的,且它獲得了焦點(diǎn),則光標(biāo)會(huì)在原地閃爍。(想查看更多屬性,點(diǎn)擊鏈接,去看官方api)
range = window.getSelection().getRangeAt(0) // 保存當(dāng)前編輯框的選區(qū)對(duì)象
let sel = window.getSelection()range.insertNode(span) // insertNode方法,在range選區(qū)開(kāi)頭插入一個(gè)節(jié)點(diǎn)
sel.removeAllRanges() //removeAllRanges方法:刪除之前的所有選區(qū)。sel.addRange(range) // 這一步就是添加當(dāng)前區(qū)域?qū)ο蟮竭x區(qū)對(duì)象中
addStrBtnFun(){ const span = document.createElement("span") span.innerText = this.addBtnText span.className = 'selColor' // 如果在頁(yè)面刷新再點(diǎn)擊編輯框之前就點(diǎn)擊了按鈕,此時(shí)range中并沒(méi)有選區(qū)范圍對(duì)象 if (range === "") { let selection = window.getSelection() selection.selectAllChildren(editDiv) // selectAllChildren把指定元素的所有子元素設(shè)為選中區(qū)域,并取消之前的選中區(qū)域。不包括node節(jié)點(diǎn)本身。 /* Selection.collapseToEnd() 方法的作用是取消當(dāng)前選區(qū),并把光標(biāo)定位在原選區(qū)的最末尾處,如果此時(shí)光標(biāo)所處的位置是可編輯的,且它獲得了焦點(diǎn),則光標(biāo)會(huì)在原地閃爍。 以上selectAllChildren方法,將div中子節(jié)點(diǎn)全部選中,collapseToEnd方法將選中區(qū)域取消,并且將光標(biāo)定位到原區(qū)的末尾。 */ selection.collapseToEnd() range = window.getSelection().getRangeAt(0) // 無(wú)論哪一步都需要保存當(dāng)前編輯框的選區(qū)對(duì)象 } let sel = window.getSelection() range.insertNode(span) // insertNode方法,在range選區(qū)開(kāi)頭插入一個(gè)節(jié)點(diǎn) /* removeAllRanges方法:刪除之前的所有選區(qū)。 這一步的意義:因?yàn)楫?dāng)我們點(diǎn)擊其他區(qū)域時(shí),選區(qū)對(duì)象已經(jīng)改變,不再是編輯框中的選區(qū)對(duì)象,這時(shí)候我們接下來(lái)的操作都不會(huì)符合我們想象中的樣子 */ sel.removeAllRanges() sel.addRange(range) // 這一步就是添加當(dāng)前區(qū)域?qū)ο蟮竭x區(qū)對(duì)象中,所以選區(qū)對(duì)象會(huì)再次指向編輯框中的選區(qū),不會(huì)出現(xiàn)別的錯(cuò)誤操作。 sel.collapseToEnd() },
4、我們修改span內(nèi)容,讓他的樣式消失方法
1)首先要用到 他的@input事件
@input="editInput"
editInput(e) { console.log(e); console.log(e.target.children); },
這是它的默認(rèn)拿到的數(shù)據(jù)
如果插入span以后,可以看到e.target.children多了span信息
拿我們頁(yè)面的edit div下面所有的span,如果哪個(gè)內(nèi)容被改變,就去掉它的class
editInput(e) { console.log(e); console.log(e.target.children); if(e.target.children.length>0){ this.editSpanClass() } }, editSpanClass(){ let spanAll = document.querySelectorAll('.edit span') spanAll.forEach(item=>{ if(item.innerHTML != this.addBtnText){ item.className = '' } }) },
源碼分享:tinymce.vue
<template> <div class="chitchat"> <div style="width:32px;height:32px;"> <img src="../../../../assets/images/microcode/touxiang.png" alt="" width="100%" height="100%" > </div> <div id="editDivBody" :class="isInspection?'Inspection':''"> <div style="margin-bottom:12px"> <el-button class="nickname" @click ="addStrBtnFun(addBtnText)">{{addBtnText}}</el-button> <el-button class="nickname" @click = "addStrBtnFun(serviceConsultant)">{{serviceConsultant}}</el-button> <el-button class="nickname" @click = "addStrBtnFun(departments)">{{ departments }}</el-button> <!-- <el-button @click="getSpecialContent">點(diǎn)我</el-button>--> <!-- <el-button @click="checkIsNonData">是否空</el-button>--> </div> <div class="headPortrait" v-if="uploadHtml"> <div :disabled="textSize >= maxNum" ref="editInput" class="edit" id="editSelDiv" contenteditable="true" @input="editInput" placeholder="請(qǐng)輸入消息內(nèi)容" v-html="innerHtml" @paste="handlePaste" > </div> <!-- 實(shí)時(shí)數(shù)據(jù)1:--> <!-- {{nowHtmlT}}--> <!-- <hr>--> <!-- 實(shí)時(shí)數(shù)據(jù)2:{{nowText}}--> </div> </div> <div class="limit">{{textSize}}/{{maxNum}}</div> <p v-if="isInspection" class="Contentfilling">請(qǐng)?zhí)顚?xiě)消息內(nèi)容</p> </div> </template> <script> let editDiv = null //編輯元素 let range = "" //選區(qū) export default { data () { return { addBtnText:'客戶(hù)昵稱(chēng)', serviceConsultant:'所屬顧問(wèn)', departments:'所屬部門(mén)', // 賦值 innerHtml:'',// 初始化賦值 innerHtmlBf:'',//備份數(shù)據(jù) nowHtmlT:'',// 實(shí)時(shí)html-動(dòng)態(tài)變量 nowText:'',// 實(shí)時(shí)文本 // 獲取當(dāng)前最新數(shù)據(jù) getDataTime:1000, getDataTimeInter:null, textSize:0, maxNum:500, isInspection:false, uploadHtml:true, } }, mounted() { this.initEditFun() }, methods:{ initEditFun(){ editDiv = document.getElementById("editSelDiv") editDiv.addEventListener("blur", () => { // 這一步是保留住edit編輯框中的選區(qū)的范圍對(duì)象。 // 否則失焦后,getSelection()方法返回的選區(qū)對(duì)象已經(jīng)不再是編輯框了,已經(jīng)獲取不到編輯框中的范圍對(duì)象了。 range = window.getSelection()?window.getSelection().getRangeAt(0):'' }) document.addEventListener('selectionchange', (e) => { let selection = document.getSelection(); let rangeVal = selection && selection.rangCount>0?selection.getRangeAt(0):'' if ( (rangeVal && this.hasAncestorWithId(rangeVal.commonAncestorContainer,'editSelDiv')) ) { range = window.getSelection()?window.getSelection().getRangeAt(0):'' } }); }, // 遞歸判斷是否有父級(jí)id = editSelDiv hasAncestorWithId(element, id) { if (!element) return false; if (element.id === id) return true; if (element.parentNode) { return this.hasAncestorWithId(element.parentNode, id); } return false; }, editInput(e) { // console.log(e); this.getNowContent() //獲取最新內(nèi)容 if(e.target.children.length>0){ this.editSpanClass() } if(e.target.innerText == ''){ range = '' e.target.innerHtml = '' this.innerHtml = '' this.innerHtmlBf = '' } }, editSpanClass(){ let spanAll = document.querySelectorAll('.edit span') spanAll.forEach(item=>{ let nowVal = item.childNodes[0].data if( nowVal && nowVal.trim() != this.addBtnText && nowVal.trim() != this.serviceConsultant && nowVal.trim() != this.departments ){ item.className = 'mrClass' } }) }, // 粘貼 handlePaste(e){ e.preventDefault(); // 阻止默認(rèn)粘貼操作 const clipboardData = e.clipboardData || window.clipboardData; const text = clipboardData.getData('text/plain'); // 獲取純文本內(nèi)容 document.execCommand('insertHTML', false, text); // 將文本插入 contenteditable 元素中 }, addStrBtnFun(Text){ const innerText = this.$refs.editInput.innerText const now_length = innerText.split('\u200B').join('').length const length = now_length + Text.length //當(dāng)前長(zhǎng)度+按鈕文字長(zhǎng)度 if(length > this.maxNum){ return } const span = document.createElement("span") span.innerText = Text span.className = 'selColor' // 如果在頁(yè)面刷新再點(diǎn)擊編輯框之前就點(diǎn)擊了按鈕,此時(shí)range中并沒(méi)有選區(qū)范圍對(duì)象 if (range === "") { let selection = window.getSelection() selection.selectAllChildren(editDiv) // selectAllChildren把指定元素的所有子元素設(shè)為選中區(qū)域,并取消之前的選中區(qū)域。不包括node節(jié)點(diǎn)本身。 /* Selection.collapseToEnd() 方法的作用是取消當(dāng)前選區(qū),并把光標(biāo)定位在原選區(qū)的最末尾處,如果此時(shí)光標(biāo)所處的位置是可編輯的,且它獲得了焦點(diǎn),則光標(biāo)會(huì)在原地閃爍。 以上selectAllChildren方法,將div中子節(jié)點(diǎn)全部選中,collapseToEnd方法將選中區(qū)域取消,并且將光標(biāo)定位到原區(qū)的末尾。 */ selection.collapseToEnd() range = window.getSelection()?window.getSelection().getRangeAt(0):''// 無(wú)論哪一步都需要保存當(dāng)前編輯框的選區(qū)對(duì)象 } let sel = window.getSelection() let space = document.createTextNode('\u200B'); // 創(chuàng)建 ​ 實(shí)體字符節(jié)點(diǎn) range.insertNode(space) range.insertNode(span) // insertNode方法,在range選區(qū)開(kāi)頭插入一個(gè)節(jié)點(diǎn) /* removeAllRanges方法:刪除之前的所有選區(qū)。 這一步的意義:因?yàn)楫?dāng)我們點(diǎn)擊其他區(qū)域時(shí),選區(qū)對(duì)象已經(jīng)改變,不再是編輯框中的選區(qū)對(duì)象,這時(shí)候我們接下來(lái)的操作都不會(huì)符合我們想象中的樣子 */ sel.removeAllRanges() sel.addRange(range) // 這一步就是添加當(dāng)前區(qū)域?qū)ο蟮竭x區(qū)對(duì)象中,所以選區(qū)對(duì)象會(huì)再次指向編輯框中的選區(qū),不會(huì)出現(xiàn)別的錯(cuò)誤操作。 sel.collapseToEnd() this.editSpanClass() this.getNowContent() }, resevedSelDiv(){ range = document.createRange(); range.selectNode(document.getElementById("editSelDiv").lastChild); window.getSelection().removeAllRanges(); window.getSelection().addRange(range); let selection = window.getSelection() selection.selectAllChildren(editDiv) selection.collapseToEnd() range = window.getSelection()?window.getSelection().getRangeAt(0):'' console.log(333); }, // 獲取最新的內(nèi)容 getNowContent(){ const innerText = this.$refs.editInput.innerText const length = innerText.split('\u200B').join('').length if(length<= this.maxNum){ this.innerHtmlBf = this.$refs.editInput.innerHTML this.nowText = this.$refs.editInput.innerText this.textSize = length this.isInspection=false }else{ this.uploadHtml = false this.$nextTick(() => { this.innerHtml = this.innerHtmlBf this.uploadHtml = true setTimeout(()=>{ this.resevedSelDiv() },1) }); } }, // 獲取帶符號(hào)的內(nèi)容 getSpecialContent(){ let spanAll = document.querySelectorAll('.edit span') let mrArr = [] spanAll.forEach(item=>{ let nowVal = item.childNodes[0].data mrArr.push(nowVal) if(item.className == 'selColor'){ if(nowVal == this.addBtnText){ item.childNodes[0].data = '${customerNickname}' //客戶(hù)昵稱(chēng) }else if(nowVal == this.serviceConsultant){ item.childNodes[0].data = '${affiliatedConsultant}'//所屬顧問(wèn) }else if(nowVal == this.departments){ item.childNodes[0].data = '${department}' //所屬部門(mén) } } }) this.nowHtmlT = this.$refs.editInput.innerText this.nowHtmlT = this.replaceText(this.nowHtmlT,this.addBtnText,"${customerNickname}") this.nowHtmlT = this.replaceText(this.nowHtmlT,this.serviceConsultant,"${affiliatedConsultant}") this.nowHtmlT = this.replaceText(this.nowHtmlT,this.departments,"${department}") spanAll.forEach((item,i)=>{ item.childNodes[0].data = mrArr[i] }) this.$emit('nowHtmlT',this.nowHtmlT) }, replaceText(text, oldStr, newStr) { // 檢查是否為字符串類(lèi)型 if (typeof text !== 'string') { text = String(text); } // 替換字符 text = text.replace(new RegExp(oldStr, "g"), newStr); // 處理子級(jí) if (text.includes('<') && text.includes('>')) { const start = text.indexOf('<'); const end = text.indexOf('>') + 1; let subtext = text.substring(start, end); while (start >= 0 && end >= 0 && end > start) { const subtextNew = replaceText(subtext, oldStr, newStr); text = text.substring(0, start) + subtextNew + text.substring(end); subtext = text.substring(start, end); } } return text; }, checkIsNonData(){ const innerText = this.$refs.editInput.innerText const length = innerText.split('\u200B').join('').length if(innerText == '' || innerText == '\n' || length == 0){ this.isInspection = true }else{ this.isInspection = false } }, }, beforeDestroy() { editDiv = null //編輯元素 range = "" //選區(qū) } } </script> <style lang="scss" scoped> .edit{ width: 100%; height:auto; min-height: 130px; max-height: 135px; overflow-y: auto; } .edit:focus { outline: 0; border-color: #409EFF; } #editDivBody{ width: 100%; //height:203px; overflow-y: auto; background: #FAFBFC; border-radius: 4px; border: 1px solid #DCDEE6; padding: 12px 12px 20px 13px; margin-left: 8px; position: relative; } ::-webkit-scrollbar { /*滾動(dòng)條整體樣式*/ width: 5px; /*高寬分別對(duì)應(yīng)橫豎滾動(dòng)條的尺寸*/ height: 1px; } ::-webkit-scrollbar-thumb { /*滾動(dòng)條里面小方塊*/ border-radius: 5px; background-color: #D8D8D8; } ::-webkit-scrollbar-track { background-color: #f6f6f6; } ::-webkit-scrollbar-thumb, ::-webkit-scrollbar-track { border: 0; } .Inspection{ border: 1px solid #FF4949!important; } .nickname{ background: #FFFFFF; border-radius: 4px; border: 1px solid #DCDFE6; font-size: 12px; font-weight: 400; color: #1890FF; line-height: 17px; padding: 4px 8px; } .chitchat{ display: flex; position: relative; width: 79%; } .Contentfilling{ width: 84px; height: 17px; font-size:12px; line-height: 17px; color: #FF4949; position: absolute; bottom: -18px; left: 41px; margin: 0; } /deep/.selColor{ color: #1890FF; font-size: 14px; } /deep/.mrClass{ color: #000; font-size: 14px; } .limit{ position: absolute; bottom: 0; right:0; padding: 0 8px; line-height: 22px; font-size: 14px; color: #86909C; } .headPortrait{ position: relative; font-size: 14px; } </style>
總結(jié)
到此這篇關(guān)于vue中實(shí)現(xiàn)div可編輯并插入指定元素與樣式的文章就介紹到這了,更多相關(guān)vue實(shí)現(xiàn)div可編輯內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue.js如何在網(wǎng)頁(yè)中實(shí)現(xiàn)一個(gè)金屬拋光質(zhì)感的按鈕
這篇文章主要給大家介紹了關(guān)于vue.js如何在網(wǎng)頁(yè)中實(shí)現(xiàn)一個(gè)金屬拋光質(zhì)感的按鈕的相關(guān)資料,文中給出了詳細(xì)的實(shí)例代碼以及圖文將實(shí)現(xiàn)的方法介紹的非常詳細(xì),需要的朋友可以參考下2023-04-04vue-cli 腳手架基于Nightwatch的端到端測(cè)試環(huán)境的過(guò)程
這篇文章主要介紹了vue-cli 腳手架基于Nightwatch的端到端測(cè)試環(huán)境的過(guò)程,需要的朋友可以參考下2018-09-09vue3 component is 不顯示的問(wèn)題及解決
這篇文章主要介紹了vue3 component is 不顯示的問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03vue隨機(jī)驗(yàn)證碼組件的封裝實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹了如何封裝一個(gè)隨機(jī)驗(yàn)證碼的VUE組件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-02-02Vue如何實(shí)現(xiàn)分頁(yè)功能代碼實(shí)例
這篇文章主要給大家介紹了關(guān)于Vue如何實(shí)現(xiàn)分頁(yè)功能的相關(guān)資料,Vue分頁(yè)功能的實(shí)現(xiàn)需要前端和后端共同配合完成,文中通過(guò)代碼實(shí)例介紹的非常詳細(xì),需要的朋友可以參考下2023-09-09vuex中五大屬性和使用說(shuō)明(包括輔助函數(shù))
這篇文章主要介紹了vuex中五大屬性和使用說(shuō)明(包括輔助函數(shù)),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-05-05