vue中实现div可编辑,并插入指定元素,样式

这篇具有很好参考价值的文章主要介绍了vue中实现div可编辑,并插入指定元素,样式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言:

        vue中实现一个既可以编辑内容,有可以动态编辑内容插入一个带有样式的内容,改变默认内容后,这个样式消失的效果,这里来整理下调研与解决实现问题之路。

实现最终效果:图2为默认内容

1、可以光标点击任意地方,然后点击按钮,插入带有span的内容

2、默认span是有样式,但是一旦内容与我们的默认内容不同就取消样式

3、获取的时候,可以拿到带有标签的内容,也可以拿到纯文本内容

4、默认内容,支持带标签内容

vue动态新增div,vue.js,javascript,前端,光标位置,可编辑div

 vue动态新增div,vue.js,javascript,前端,光标位置,可编辑div

 探索之路:

1、刚开始从网上查找了很多资料,但是都有不同的缺陷,下面是我根据网上资料实现的效果

1)封装一个  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="请输入消息内容"
    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
    },
    // 主要用于处理光标得定位问题
    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() //创建选择对象
        range.moveToElementText(obj) //range定位到obj
        range.collapse(false) //光标移至最后
        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)
    },
    // 实时监听当前内容
    changeText(e) {
      console.log(e)
      if(e.data){
        console.log('数据:'+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)父级中使用:

结果:{{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:'插入员工昵称',
      abc:'',
      teamContent: "<p>幸福 人和 测试增加数据 在加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)最终实现效果

1、实现了不同内容的时候可以正常监听

2、点击按钮,可以正常插入并修改样式

缺点:

1、点击多个插入,位置有问题

2、每次输入第二个字符的时候,光标都移动到了最后一位

vue动态新增div,vue.js,javascript,前端,光标位置,可编辑div

 2、继续努力实现效果,效果图实现步骤:

注意:

        不能实时获取它的数据,它的光标位置会出现问题,目前官方提供的方法,默认是回到第一个,可以修改到回到最后一个,但是我们如果是中间输入内容,光标会异常,故而不建议实时获取数据

1、div+contenteditable="true"  来实现div的可编辑,v-html来实现对他默认值的修改

 <div
      class="edit"
      contenteditable="true"
      @input="editInput"
      placeholder="请输入消息内容"
      v-html="innerHtml"
    >
    </div>

2、初始化方法

// 这一步是保留住edit编辑框中的选区的范围对象。否则失焦后,getSelection()方法返回的选区对象已经不再是编辑框了,已经获取不到编辑框中的范围对象了。

initEditFun(){
      editDiv = document.getElementsByClassName("edit")[0]

      editDiv.addEventListener("blur", () => {
        // 这一步是保留住edit编辑框中的选区的范围对象。否则失焦后,getSelection()方法返回的选区对象已经不再是编辑框了,已经获取不到编辑框中的范围对象了。
        range = window.getSelection().getRangeAt(0)
      })

    },

3、点击按钮时候,给可编辑区域中增加一个带有颜色的span

记得在你的功能样式中添加,可在app.vue,也可以在你项目其他公共区域

.selColor{
  color: red;
}
点击事件:

window.getSelection()  获取他的光标选取

 selection.selectAllChildren(editDiv) // selectAllChildren把指定元素的所有子元素设为选中区域,并取消之前的选中区域。不包括node节点本身。

 selection.collapseToEnd()   //Selection.collapseToEnd() 方法的作用是取消当前选区,并把光标定位在原选区的最末尾处,如果此时光标所处的位置是可编辑的,且它获得了焦点,则光标会在原地闪烁。(想查看更多属性,点击链接,去看官方api)

range = window.getSelection().getRangeAt(0) // 保存当前编辑框的选区对象

 let sel = window.getSelection()
range.insertNode(span)  // insertNode方法,在range选区开头插入一个节点

 sel.removeAllRanges()  //removeAllRanges方法:删除之前的所有选区。
sel.addRange(range)    // 这一步就是添加当前区域对象到选区对象中

addStrBtnFun(){
      const span = document.createElement("span")
      span.innerText = this.addBtnText
      span.className = 'selColor'
      // 如果在页面刷新再点击编辑框之前就点击了按钮,此时range中并没有选区范围对象
      if (range === "") {
        let selection = window.getSelection()
        selection.selectAllChildren(editDiv) // selectAllChildren把指定元素的所有子元素设为选中区域,并取消之前的选中区域。不包括node节点本身。
        /*
          Selection.collapseToEnd() 方法的作用是取消当前选区,并把光标定位在原选区的最末尾处,如果此时光标所处的位置是可编辑的,且它获得了焦点,则光标会在原地闪烁。
          以上selectAllChildren方法,将div中子节点全部选中,collapseToEnd方法将选中区域取消,并且将光标定位到原区的末尾。
        */
        selection.collapseToEnd()
        range = window.getSelection().getRangeAt(0) // 无论哪一步都需要保存当前编辑框的选区对象
      }
      let sel = window.getSelection()
      range.insertNode(span) // insertNode方法,在range选区开头插入一个节点
      /*
      removeAllRanges方法:删除之前的所有选区。
      这一步的意义:因为当我们点击其他区域时,选区对象已经改变,不再是编辑框中的选区对象,这时候我们接下来的操作都不会符合我们想象中的样子
     */
      sel.removeAllRanges()
      sel.addRange(range) // 这一步就是添加当前区域对象到选区对象中,所以选区对象会再次指向编辑框中的选区,不会出现别的错误操作。
      sel.collapseToEnd()
    },

4、我们修改span内容,让他的样式消失方法

1)首先要用到  他的@input事件
@input="editInput"
 editInput(e) {
      console.log(e);
      console.log(e.target.children);
},
这是它的默认拿到的数据 

vue动态新增div,vue.js,javascript,前端,光标位置,可编辑div

如果插入span以后,可以看到e.target.children多了span信息

vue动态新增div,vue.js,javascript,前端,光标位置,可编辑div文章来源地址https://www.toymoban.com/news/detail-685332.html

 拿我们页面的edit  div下面所有的span,如果哪个内容被改变,就去掉它的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">点我</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="请输入消息内容"
          v-html="innerHtml"
          @paste="handlePaste"
        >
        </div>
<!--                实时数据1:-->
<!--                {{nowHtmlT}}-->
<!--                <hr>-->
<!--                实时数据2:{{nowText}}-->
      </div>

    </div>
    <div class="limit">{{textSize}}/{{maxNum}}</div>
    <p v-if="isInspection" class="Contentfilling">请填写消息内容</p>
  </div>
</template>

<script>
let editDiv = null //编辑元素
let range = "" //选区
export default {
  data () {
    return {
      addBtnText:'客户昵称',
      serviceConsultant:'所属顾问',
      departments:'所属部门',
      // 赋值
      innerHtml:'',// 初始化赋值
      innerHtmlBf:'',//备份数据
      nowHtmlT:'',// 实时html-动态变量
      nowText:'',// 实时文本
      // 获取当前最新数据
      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编辑框中的选区的范围对象。
        // 否则失焦后,getSelection()方法返回的选区对象已经不再是编辑框了,已经获取不到编辑框中的范围对象了。
        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):''
        }

      });
    },
    // 递归判断是否有父级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() //获取最新内容
      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(); // 阻止默认粘贴操作
      const clipboardData = e.clipboardData || window.clipboardData;
      const text = clipboardData.getData('text/plain'); // 获取纯文本内容
      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 //当前长度+按钮文字长度
      if(length > this.maxNum){
        return
      }
      const span = document.createElement("span")
      span.innerText = Text
      span.className = 'selColor'
      // 如果在页面刷新再点击编辑框之前就点击了按钮,此时range中并没有选区范围对象
      if (range === "") {
        let selection = window.getSelection()
        selection.selectAllChildren(editDiv) // selectAllChildren把指定元素的所有子元素设为选中区域,并取消之前的选中区域。不包括node节点本身。
        /*
          Selection.collapseToEnd() 方法的作用是取消当前选区,并把光标定位在原选区的最末尾处,如果此时光标所处的位置是可编辑的,且它获得了焦点,则光标会在原地闪烁。
          以上selectAllChildren方法,将div中子节点全部选中,collapseToEnd方法将选中区域取消,并且将光标定位到原区的末尾。
        */
        selection.collapseToEnd()
        range = window.getSelection()?window.getSelection().getRangeAt(0):''// 无论哪一步都需要保存当前编辑框的选区对象
      }
      let sel = window.getSelection()
      let space = document.createTextNode('\u200B'); // 创建 &ZeroWidthSpace; 实体字符节点
      range.insertNode(space)
      range.insertNode(span) // insertNode方法,在range选区开头插入一个节点
      /*
      removeAllRanges方法:删除之前的所有选区。
      这一步的意义:因为当我们点击其他区域时,选区对象已经改变,不再是编辑框中的选区对象,这时候我们接下来的操作都不会符合我们想象中的样子
     */
      sel.removeAllRanges()
      sel.addRange(range) // 这一步就是添加当前区域对象到选区对象中,所以选区对象会再次指向编辑框中的选区,不会出现别的错误操作。
      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);
    },
    // 获取最新的内容
    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)
        });
      }
    },
    // 获取带符号的内容
    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}' //客户昵称
          }else if(nowVal == this.serviceConsultant){
            item.childNodes[0].data = '${affiliatedConsultant}'//所属顾问
          }else if(nowVal == this.departments){
            item.childNodes[0].data = '${department}' //所属部门
          }
        }
      })
      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) {
      // 检查是否为字符串类型
      if (typeof text !== 'string') {
        text = String(text);
      }
      // 替换字符
      text = text.replace(new RegExp(oldStr, "g"), newStr);
      // 处理子级
      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 = "" //选区
  }
}
</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 {
  /*滚动条整体样式*/
  width: 5px; /*高宽分别对应横竖滚动条的尺寸*/
  height: 1px;
}

::-webkit-scrollbar-thumb {
  /*滚动条里面小方块*/
  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>

到了这里,关于vue中实现div可编辑,并插入指定元素,样式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • react动态插入样式

    在开发组件过程中,偶尔需要动态的插入css,比如在在iframe中渲染组件后,iframe中是没有样式的,所以需要手动插入样式。 通常是在useLayoutEffect中动态创建 style 标签 useStyle使用一个动态插入style的hook,将上面的代码进行了封装,方便使用。

    2024年02月06日
    浏览(68)
  • video全屏操作栏自定义样式&&js 指定元素全屏&&视频截图下载

    目录 1. 页面结构 2. 全屏方法 3. 截图方法 4. 样式代码 5. 效果截图 6. 附上完整代码 最近遇到的需求就是重新video标签的控制栏的样式,包括进度条、音量、倍速、全屏等样式,在正常状态下,可以将原生样式隐藏掉自定义新的控制栏元素定位上去,但是全屏后样式失效,出现

    2024年02月12日
    浏览(45)
  • 算法:O(1) 时间插入、删除和获取随机元素---哈希表+动态数组

    1、题目: 实现 RandomizedSet 类: RandomizedSet() 初始化 RandomizedSet 对象 bool insert(int val) 当元素 val 不存在时,向集合中插入该项,并返回 true ;否则,返回 false 。 bool remove(int val) 当元素 val 存在时,从集合中移除该项,并返回 true ;否则,返回 false 。 int getRandom() 随机返回现有

    2024年02月08日
    浏览(51)
  • Vue教程:如何使用Div标签实现单选框与多选框按钮以便我们随意调整样式

    前言: 在写Vue项目时,我们经常会用到单选框以及复选框,以往我们常用的是Element里面的单选框以及复选框,但是呢这里面的选框都不容易调整,假如我们需要不同的样式以及大小,就很难去实现想要的结果,本章教程就为大家讲解,如何使用div标签去实现单选,多选的这

    2024年01月18日
    浏览(35)
  • 动态规划Day16(编辑距离,删除元素待写完)

    目录 583. 两个字符串的删除操作 看到题目的第一想法                看到代码随想录之后的想法 自己实现过程中遇到的困难(看代码) 72. 编辑距离 看到题目的第一想法                看到代码随想录之后的想法 自己实现过程中遇到的困难(看代码) 力扣题目链接(opens new

    2024年01月24日
    浏览(53)
  • Python Selenium 获取动态网页指定元素的超链接

    本文是个人使用Python Selenium 获取动态网页指定元素的超链接的电子笔记,由于水平有限,难免出现错漏,敬请批评改正。 更多精彩内容,可点击进入Python日常小操作专栏或我的个人主页查看 熟悉Python 熟悉Requests 熟悉XPath 熟悉Selenium Python是一种跨平台的计算机程序设计语言。

    2024年01月19日
    浏览(73)
  • 【Go】excelize库实现excel导入导出封装(一),自定义导出样式、隔行背景色、自适应行高、动态导出指定列、动态更改表头

    最近在学go操作excel,毕竟在web开发里,操作excel是非常非常常见的。这里我选择用 excelize 库来实现操作excel。 为了方便和通用,我们需要把导入导出进行封装,这样以后就可以很方便的拿来用,或者进行扩展。 我参考的是这篇文章:【GO】excelize导入导出封装 这个导入导出封

    2024年02月04日
    浏览(49)
  • vue中动态添加class修改div宽高无法触发addEventListener(“resize“)

    在触发事件动态修改class发现resize没有触发。 具体原因没有找到--------无语 因为不知道什么原因只能替代了,网上说resize消耗很大, MutationObserver与ResizeObserver 更节省性能。

    2024年02月12日
    浏览(44)
  • vue动态绑定style样式之动态添加style样式的多种写法

    项目中会需要动态添加 style 行内样式,现指出常用的几种方式。 注意: 1、凡是有 - 的style属性名都要变成驼峰式,比如font-size要变成 fontSize。 2、除了绑定值,其他的属性名的值要用引号括起来,比如 fontSize:\\\'14px\\\' 而不是 fontSize :14px。 对象形式 data(){ return { baseStyles: { width:

    2024年04月17日
    浏览(60)
  • vue代码编辑器vue-codemirror的简单使用更改样式和切换主题等

    可以查看官网演示:vue-codemirror | Homepage 支持的语言mode:CodeMirror: Language Modes  支持的主题样式:CodeMirror: Theme Demo  开始安装和使用:  基础使用 注册全局组件 注册局部组件 使用组件 实现的效果: 编辑器默认高度是300px,如果想更改高度和字体大小:添加样式  更改主题的

    2024年02月13日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包