实现光标跟随效果

直接上代码

本次采用 vue3.3.8 markdown-it:13.0.1 highlight.js:11.8.0 版本

 npm i markdown-it highlight.js
 // markdown-it 内置了一些字符转译,但是需要注意一些比较少字符转译方法是没有接入,使用的时候需要注意下,具体根据官方网站进行查看

markdown-it 中文文档_语法拓展

 <!-- Marked.vue -->
 <!--
 showCursor:是否现象光标
 content: 传输内容
 -->
 <chatContent :showCursor="showCursor" :content="content"></chatContent>
 <!-- chatContent .vue -->
<script setup>
import MarkdownIt  from 'markdown-it'
import hljs from 'highlight.js'
import 'highlight.js/styles/androidstudio.css'
const props = defineProps({
    content:{
        type:String,
        required:true
    },
    showCursor:{
        type:Boolean,
        default:false
    }
})
const md = new MarkdownIt({
    highlight: function (code, lang) {
   if(lang && hljs.getLanguage(lang)){
    return hljs.highlight(code,{language:lang}).value
   }
   return hljs.highlightAuto(code).value
  }
});

const markdownContent = computed(()=>{
    return md.render(props.content)
})
const pos = reactive({x:0,y:0})
const constentRef = ref(null)


function getLastTextNode(dom){
    const children = dom.childNodes
    for(let i = children.length-1; i >= 0;i--){
        const node = children[i];
        if(node.nodeType === Node.TEXT_NODE && /\S/.test(node.nodeValue)){
            node.nodeValue = node.nodeValue.replace(/\s+$/,'')
            return node
        }else if(node.nodeType === Node.ELEMENT_NODE){
            const last = getLastTextNode(node)
            if(last){
                return last
            }
        }
    }
    return null
}

function updateCursor(){
    const contentDom = constentRef.value
    const lastText = getLastTextNode(contentDom)
    const txtNode = document.createTextNode('\u200b')
    if(lastText){
        lastText.parentElement.appendChild(txtNode)
    }else{
        contentDom.appendChild(txtNode)
    }
    const domRect = contentDom.getBoundingClientRect()
    const range = document.createRange()
    range.setStart(txtNode,0)
    range.setEnd(txtNode,0)
    const rect = range.getBoundingClientRect()
    pos.x = rect.left - domRect.left
    pos.y = rect.top - domRect.top
    txtNode.remove()
}

onMounted(updateCursor)
onUpdated(updateCursor)
</script>

<template>
    <div class="container">
        <div class="markdown-body" ref="constentRef" v-html="markdownContent"></div>
        <div v-show="showCursor" class="cursor"></div>
    </div>
</template>

 
<style lang="scss" scoped>
 .markdown-body{
    background: inherit;
    line-height: 2;
}
.container{
    position: relative;
    .cursor{
        content:'';
        position: absolute;
        width: 8px;
        height: 20px;
        background: #3d3d3d;
        animation: toggle .6s infinite;
        opacity: 0;
        transform: translateY(3px);
        left: calc( v-bind('pos.x') * 1px );
        top: calc( v-bind('pos.y') * 1px );
    }
}
@keyframes toggle {
    30%{
        opacity: 1;
    }
}
</style>

本次代码参考于 bilibili 视频

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值