实现给滚动元素添加多个锚点。并实现滚动过程对锚点样式实现反作用
给元素添加锚点,点击锚点可滚动到对应的元素
锚点的取得是通过滚动元素的数组tabList中获取,动态生成锚点,通过a标签的href 指定对应的ID来实现。
leftDiv包裹的元素是动态生成的锚点;需要锚点的滚动元素在rightDiv中,有动态id的元素;通过动态的ID数组获取动态的锚点。点击锚点可直接到相应的ID。
<el-tabs v-model="activeName" @tab-click="handleClick" >
<el-tab-pane v-for="(once,index) in tabList" :key="index" :label="once.label" :name="once.name">
<div class="coverDiv">
<ul class="leftDiv" ref="leftDiv">
<li v-for="twice in navLis" :key="twice.id">
<a :href="twice.href" :class="{ 'active': twice.isActive }"
@click="clickFirst(twice.id)">{{ twice.h2 }}</a>
</li>
</ul>
<div class="rightDiv">
<div v-for="item in once.list" :key="item.num" >
<div v-if="item.id" :id="item.id" :ref="item.id"></div>
<h2 v-if="item.h2">{{ item.h2 }}</h2>
<div v-if="item.html1" v-html="item.html1"></div>
<h3 v-if="item.h3">{{ item.h3 }}</h3>
<div v-if="item.code" style="position:relative" @mouseover="hover($event)" @mouseleave="leave($event)">
<prism-editor class="my-editor height-300 speWidth " v-model="item.code" :highlight="highlighter"
readonly line-numbers></prism-editor>
<div style="position:absolute;right:15px;top:15px;border-radius:2px;background-color:#eee;display:none;cursor: pointer; padding:2px 8px;"
@click="copyFn(item.num)">复制</div>
</div>
</div>
</div>
</div>
</el-tab-pane>
</el-tabs>
实现滚动元素对锚点反作用,即滚动到相应的位置,需要对应的锚点样式进行修改
mounted给滚动元素绑定滚动事件。
动态获取各个ID的位置,通过id在窗口中的显示位置,来判断当前需要有样式的锚点是哪个。
mounted() {
this.addScroll()
},
methods: {
addScroll(){
const myDiv = document.getElementById('myDiv');
let that = this
// const leftDiv = document.getElementById('leftDiv');
myDiv.addEventListener('scroll', function() {
const scrollTop = myDiv.scrollTop; // 获取滚动条距离顶部的距离
// const scrollHeight = myDiv.scrollHeight; // 获取可滚动区域的高度
const clientHeight = myDiv.clientHeight; // 获取 div 元素的高度
let middleLeftDiv = ""
// let middleA = ''
if(that.activeName === "firstTab"){
middleLeftDiv = that.$refs.leftDiv[0]
// middleA = "first"
}
if(that.activeName === "secondTab"){
middleLeftDiv = that.$refs.leftDiv[1]
// middleA = "pythonFirst"
}
if(that.activeName === "thirdTab"){
middleLeftDiv = that.$refs.leftDiv[2]
// middleA = "phpFirst"
}
if(scrollTop >= 272){
let finalHeight = scrollTop - clientHeight + middleLeftDiv.clientHeight + 'px'
middleLeftDiv.style.top = finalHeight
}else{
middleLeftDiv.style.top = '0px'
// that.rightA = middleA
}
that.idList.forEach(item=>{
const second = that.$refs[item][0].getBoundingClientRect().top; //获取元素距离顶部的距离
// 滚动元素反作用于锚点元素
if(second >0 && second<clientHeight){
that.rightA = item
}
})
})
},
clickFirst(which) {
this.rightA = which
},
handleClick() {
if (this.activeName === 'firstTab') {
this.rightA = "first"
}
if (this.activeName === 'secondTab') {
this.rightA = "pythonFirst"
}
if (this.activeName === 'thirdTab') {
this.rightA = "phpFirst"
}
},
highlighter(code) {
return highlight(code, languages.js)
},
hover(el) {
el.currentTarget.lastElementChild.style.display = "block"
},
leave(el) {
el.currentTarget.lastElementChild.style.display = "none"
},
copyFn(num) {
const textToCopy = this[num];
// 使用Clipboard API将文本复制到剪贴板
window.navigator.clipboard
.writeText(textToCopy)
.then(() => {
this.$message.success("复制成功")
})
.catch((error) => {
this.$message.error(`复制文本到剪贴板时出错:${error}`)
});
},},
<template>
<div >
<el-dialog title="示例代码SDK" id="myDiv" :visible.sync="codeExamples" :close-on-click-modal="false" :close-on-press-escape="false">
<el-tabs v-model="activeName" @tab-click="handleClick" >
<el-tab-pane v-for="(once,index) in tabList" :key="index" :label="once.label" :name="once.name">
<div class="coverDiv">
<ul class="leftDiv" ref="leftDiv">
<li v-for="twice in navLis" :key="twice.id">
<a :href="twice.href" :class="{ 'active': twice.isActive }"
@click="clickFirst(twice.id)">{{ twice.h2 }}</a>
</li>
</ul>
<div class="rightDiv">
<div v-for="item in once.list" :key="item.num" >
<div v-if="item.id" :id="item.id" :ref="item.id"></div>
<h2 v-if="item.h2">{{ item.h2 }}</h2>
<div v-if="item.html1" v-html="item.html1"></div>
<h3 v-if="item.h3">{{ item.h3 }}</h3>
<div v-if="item.code" style="position:relative" @mouseover="hover($event)" @mouseleave="leave($event)">
<prism-editor class="my-editor height-300 speWidth " v-model="item.code" :highlight="highlighter"
readonly line-numbers></prism-editor>
<div style="position:absolute;right:15px;top:15px;border-radius:2px;background-color:#eee;display:none;cursor: pointer; padding:2px 8px;"
@click="copyFn(item.num)">复制</div>
</div>
</div>
</div>
</div>
</el-tab-pane>
</el-tabs>
</el-dialog>
</div>
</template>
<script>
import ApiList from "@/components/TabPages/ApiList";
import ResponseCode from "@/components/TabPages/ResponseCode";
import PublicPrivateGeneration from "@/components/TabPages/PublicPrivateGeneration";
// import Prism Editor
import { PrismEditor } from 'vue-prism-editor'
import 'vue-prism-editor/dist/prismeditor.min.css'
// import highlighting library
import { highlight, languages } from 'prismjs/components/prism-core'
import 'prismjs/components/prism-clike'
import 'prismjs/components/prism-javascript'
import 'prismjs/themes/prism-tomorrow.css'
import {
javaCode1,
javaCode2,
javaCode3,
javaCode4,
javaCode5,
javaCode6,
javaCode7,
javaCode8,
javaCode9,
javaCode10,
javaCode11,
javaCode12,
javaCode13,
javaCode14,
javaCode15,
javaCode16,
phpCode1,
phpCode2,
phpCode3,
phpCode4,
phpCode5,
pythonCode1,
pythonCode2,
pythonCode3,
pythonCode4,
pythonCode5,
pythonCode6,
} from "@/utils/markdown"
export default {
created() {},
mounted() {
this.addScroll()
},
data() {
return {
rightA: "first",
activeName: "firstTab",
javaCode1,
javaCode2,
javaCode3,
javaCode4,
javaCode5,
javaCode6,
javaCode7,
javaCode8,
javaCode9,
javaCode10,
javaCode11,
javaCode12,
javaCode13,
javaCode14,
javaCode15,
javaCode16,
phpCode1,
phpCode2,
phpCode3,
phpCode4,
phpCode5,
pythonCode1,
pythonCode2,
pythonCode3,
pythonCode4,
pythonCode5,
pythonCode6,
tabList: [{
name: "firstTab",
label: "JAVA",
list: [
{
id: "first",
h2: "RSA2签名",
h3: "报文签名算法",
h4: "",
html1: `此方法在请求类接口交易中,报文头signMethod取值为“RSA2”时使用,
对“待签字符串”进行RSA签名,为了保证双方的身份可靠性和数据完整性。</br>主要步骤如下:</br>
1.代签字符串用SHA-256算法生成摘要</br>
2.使用接入方RSA秘钥对的私钥对摘要做签名,生成签名值</br>
3.对签名值做Base64编码,放到http消息头的sign字段中</br>
4.签名算法,填写在http消息头的signMethod字段中`,
code: javaCode1,
num: "javaCode1"
},
{
h3: "SHA256签名算法",
code: javaCode2,
num: "javaCode2"
},
{
h3: "RSA签名算法",
code: javaCode3,
num: "javaCode3"
},
{
html1: `*注1 privateKey(私钥):可于开放平台用工具生成公私钥对,将生成的公钥通过开放平台-个人中心-相应的API认证账号-RSA2验签公钥进行设置;对应生成的私钥请保存好`,
num: "1004"
},
{
id: "second",
h2: "RSA2验签",
h3: "通知报文验签样例代码",
h4: "",
html1: `此方法在通知类接口交易中,用“待签字符串”和验签公钥,对通知报文的
签名做验签,为了保证请求来源的身份可靠性和报文完整性。</br>
主要步骤如下:</br>
1.从http消息头中获取signMethod;</br>
2.对待签名串使用SHA-256算法生成摘要;</br>
3.从http消息头中获取sign,对sign做base64解码;</br>
4.从开放平台API认证账号处获取接收方通知验签公钥;</br>
5.对第3步解码后的sign值,用第4步获取的公钥进行验签`,
num: "1005"
},
{
h3: "RSA2验签样例代码:SHA-256算法生成摘要",
code: javaCode11,
num: "javaCode11"
},
{
h3: "RAS验签算法",
code: javaCode12,
num: "javaCode12"
},
{
id: "third",
h2: "SM2签名",
h3: "引用jar包",
h4: "",
html1: `
此方法在请求类接口交易中,报文头signMethod取值为“SM2”时使用,对“待签字符串”进行SM2签名
,为了保证双方的身份可靠性和数据完整性。</br>主要步骤如下:</br>
1.代签字符串用SM3算法生成摘要</br>
2.使用接入方SM2秘钥对的私钥对摘要做签名,生成签名值</br>
3.对签名值做Base64编码,放到http消息头的sign字段中</br>
4.签名算法,填写在http消息头的signMethod字段中`,
code: javaCode4,
num: "javaCode4"
}, {
h3: "实体类结构",
code: javaCode5,
num: "javaCode5"
}, {
h3: "获得公私钥对",
code: javaCode6,
num: "javaCode6"
}
, {
h3: "SM3摘要算法",
code: javaCode7,
num: "javaCode7"
}
, {
h3: "SM2签名算法",
code: javaCode8,
num: "javaCode8"
}
, {
h3: "对SM2Signature 对象进行加密,获得sign值",
code: javaCode9,
num: "javaCode9"
}, {
h3: "获得转换后的公钥加密串,为了验签用",
html1: `将生成的公钥通过开放平台-个人中心-相应的API认证账号-SM2验签公钥进行设置;
对应生成的私钥请保存好`,
code: javaCode10,
num: "javaCode10"
}, {
id: "fourth",
h2: "SM2验签",
h3: "SM2验签样例代码:BC工具生成待签字符串摘要",
code: javaCode13,
num: "javaCode13"
}, {
h3: "SM2验签算法",
code: javaCode14,
num: "javaCode14"
}, {
id: "fifth",
h2: "SM4加密",
code: javaCode15,
num: "javaCode15"
}, {
id: "sixth",
h2: "接口调用",
code: javaCode16,
num: "javaCode16"
}
]
},
{
name: "secondTab",
label: "python",
list: [
{
id: "pythonFirst",
h2: "RSA2签名",
code: pythonCode1,
num: "pythonCode1"
},
{
id: "pythonSecond",
h2: "RSA2验签",
code: pythonCode2,
num: "pythonCode2"
},
{
id: "pythonThird",
h2: "SM2签名",
code: pythonCode3,
num: "pythonCode3"
},
{
id: "pythonFourth",
h2: "SM2验签",
code: pythonCode4,
num: "pythonCode4"
},
{
h3: "SM3",
code: pythonCode5,
num: "pythonCode5"
},
{
id: "pythonFifth",
h2: "SM4加密",
code: pythonCode6,
num: "pythonCode6"
}
]
},
{
name: "thirdTab",
label: "PHP",
list: [
{
id: "phpFirst",
h2: "RSA2签名",
code: phpCode1,
num: "phpCode1"
},
{
id: "phpSecond",
h2: "RSA2验签",
code: phpCode2,
num: "phpCode2"
},
{
id: "phpThird",
h2: "SM2签名",
code: phpCode3,
num: "phpCode3"
}, {
id: "phpFourth",
h2: "SM2验签",
code: phpCode4,
num: "phpCode4"
},
{
id: "phpFifth",
h2: "SM4加密",
code: phpCode5,
num: "phpCode5"
},
{
id: "phpSixth",
h2: "接口调用",
}
]
},
],
};
},
components: {
PrismEditor
},
computed: {
// 获取a标签
navLis(){
let middleArr = []
if(this.activeName === "firstTab"){
middleArr = this.tabList[0]["list"].filter(item=>{return !!item.id})
}
if(this.activeName === "secondTab"){
middleArr = this.tabList[1]["list"].filter(item=>{return !!item.id})
}
if(this.activeName === "thirdTab"){
middleArr = this.tabList[2]["list"].filter(item=>{return !!item.id})
}
return middleArr.map(twice=>{
twice["href"] = `#${twice.id}`
twice["isActive"] = this.rightA === twice.id
return twice
})
},
idList(){
let middleArr = []
if(this.activeName === "firstTab"){
middleArr = this.tabList[0]["list"].filter(item=>{return !!item.id})
}
if(this.activeName === "secondTab"){
middleArr = this.tabList[1]["list"].filter(item=>{return !!item.id})
}
if(this.activeName === "thirdTab"){
middleArr = this.tabList[2]["list"].filter(item=>{return !!item.id})
}
return middleArr.map(third=>third["id"])
}
},
methods: {
addScroll(){
const myDiv = document.getElementById('myDiv');
let that = this
// const leftDiv = document.getElementById('leftDiv');
myDiv.addEventListener('scroll', function() {
const scrollTop = myDiv.scrollTop; // 获取滚动条距离顶部的距离
// const scrollHeight = myDiv.scrollHeight; // 获取可滚动区域的高度
const clientHeight = myDiv.clientHeight; // 获取 div 元素的高度
let middleLeftDiv = ""
// let middleA = ''
if(that.activeName === "firstTab"){
middleLeftDiv = that.$refs.leftDiv[0]
// middleA = "first"
}
if(that.activeName === "secondTab"){
middleLeftDiv = that.$refs.leftDiv[1]
// middleA = "pythonFirst"
}
if(that.activeName === "thirdTab"){
middleLeftDiv = that.$refs.leftDiv[2]
// middleA = "phpFirst"
}
if(scrollTop >= 272){
let finalHeight = scrollTop - clientHeight + middleLeftDiv.clientHeight + 'px'
middleLeftDiv.style.top = finalHeight
}else{
middleLeftDiv.style.top = '0px'
// that.rightA = middleA
}
that.idList.forEach(item=>{
const second = that.$refs[item][0].getBoundingClientRect().top; //获取元素距离顶部的距离
// 滚动元素反作用于锚点元素
if(second >0 && second<clientHeight){
that.rightA = item
}
})
})
},
clickFirst(which) {
this.rightA = which
},
handleClick() {
if (this.activeName === 'firstTab') {
this.rightA = "first"
}
if (this.activeName === 'secondTab') {
this.rightA = "pythonFirst"
}
if (this.activeName === 'thirdTab') {
this.rightA = "phpFirst"
}
},
highlighter(code) {
return highlight(code, languages.js)
},
hover(el) {
el.currentTarget.lastElementChild.style.display = "block"
},
leave(el) {
el.currentTarget.lastElementChild.style.display = "none"
},
copyFn(num) {
const textToCopy = this[num];
// 使用Clipboard API将文本复制到剪贴板
window.navigator.clipboard
.writeText(textToCopy)
.then(() => {
this.$message.success("复制成功")
})
.catch((error) => {
this.$message.error(`复制文本到剪贴板时出错:${error}`)
});
},},
};
</script>
<style lang="less" scoped>
/deep/ .el-tabs__nav-wrap::after {
background-color: transparent !important;
}
.el-dropdown-link {
cursor: pointer;
color: black;
}
.el-icon-arrow-down {
font-size: 12px;
}
.versionIntroduction{
display:flex;
padding: 0 15px;
strong{
width:78px;
}
p{
margin:0;
flex:1;
}
}
.rightDiv {
width: calc(100%-65px);
padding-left: 65px;
}
.coverDiv {
position: relative;
}
.leftDiv {
width: 65px;
padding-left:0;
margin-top:0;
position: absolute;
left:0;
top:0;
a {
text-decoration: none;
color:#606266;
}
.active {
color: #409EFF;
}
}
.speWidth {
width: calc(~"100% - 15px");
}
/* required class */
.my-editor {
/* we dont use `language-` classes anymore so thats why we need to add background and text color manually */
background: #2d2d2d;
color: #ccc;
/* you must provide font-family font-size line-height. Example: */
font-family: Fira code, Fira Mono, Consolas, Menlo, Courier, monospace;
font-size: 14px;
line-height: 1.5;
padding: 5px;
}
/* optional class for removing the outline */
.prism-editor__textarea:focus {
outline: none;
}
/* not required: */
.height-300 {
max-height: 300px;
}
p {
text-align: left;
}
h2,
h3,
h4,
div {
text-align: left;
}
</style>