下面是全部代码
<svg ref="svgref" style="width: 17vw; height: 42vh" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 330 400">
<path
ref="svgref1"
:d="`M ${p12}C ${cp12} ${cp22} ${p22}`"
fill="none"
vector-effect="non-scaling-stroke"
/>
<foreignObject width="100%" height="100%">
<div id="allmenu">
<div
v-for="(item, index) in menulist.slice(0, 8)"
:key="index"
class="menuitem"
@click="changeindex((item.name || item.deptName), item.path)"
>
<span
:type="'left'+(index+1)"
class="itemname"
:class="[activeindex === (item.name || item.deptName) ? 'fontcolor' : '']"
@click="onSetName(item.name || item.deptName)"
v-tooltip.text.ellipsis
>
{{ item.name || item.deptName }}
span>
div>
div>
foreignObject>
svg>
<script>
import { _throttle } from './throttle'
export default {
name: 'leftFrom',
components: {},
props: {
// 组件宽高
width: {
type: Number,
default: 300
},
height: {
type: Number,
default: 400
},
towMenuname: {
type: String,
default: ''
},
// 组件菜单栏
menulist: {
type: Array,
default () {
return [
// 菜单项
{ name: '菜单一菜单一菜单一' },
{ name: '菜单二菜单二菜单二' },
{ name: '菜单三菜单三菜单三' },
{ name: '菜单四菜单四菜单四' },
{ name: '菜单五菜单五菜单五' },
{ name: '菜单六菜单六菜单六' },
{ name: '菜单七菜单七菜单七' },
{ name: '菜单八菜单八菜单八' },
{ name: '菜单九菜单九菜单九' },
{ name: '菜单十一' },
{ name: '菜单十二' },
{ name: '菜单十三' }
]
}
}
},
data () {
return {
// 菜单每个选项的t,t用来求三层次贝塞尔曲线对应的点,缓慢的增加或减少t可以实现动画效果
menuitemt: [],
// 菜单选中状态
activeindex: '',
// 计数器,根据每次动画帧数缓慢增加减少t实现动画
counter: 0,
bottom: 4,
top: 4
}
},
computed: {
// 右到左 300 - 70 = 230
// 起始点
p12: function name () {
return [150, -10] // 从左到右 , 从上到下
},
p22: function name () {
return [170, 400] // 下面的尾巴 从左到右 , 从上到下
},
// 控制点
cp12: function name () {
return [30, 60] // 中间点 负数往左 正数往右, 从上至下
},
cp22: function name () {
return [70, 400]
}
},
watch: {
menulist: {
handler (newName, oldName) {
this.init()
}
},
towMenuname: {
handler (newName, oldName) {
this.activeindex = newName
this.top = 0
this.bottom = this.menulist.length - 8
console.log(this.bottom)
}
}
},
created () {},
async mounted () {
// 添加滚轮事件
var menu = document.getElementById('menu')
// 为menu绑定一个鼠标滚动的事件
menu.onmousewheel = (event) => {
// 判断鼠标滚轮滚动的方向
event = event || window.event
// alert(event.wheelDelta);向上120,向下-120
if (event.wheelDelta > 0 || event.detail < 0) {
// 火狐event.detail 向上滚动-3 向下滚动+3
// 向上滚,改变menulist数组
this.up()
} else {
// 向下滚,改变menulist数组
this.down()
}
return false
}
this.init()
},
methods: {
onSetName (name) {
this.$emit('onDataItemName', name)
},
// 初始化
init () {
this.$nextTick(function () {
this.elem = document.getElementsByClassName('menuitem')
let i
// 每个菜单项的在贝塞尔曲线的间隔
const menuinterval = 1 / 10
for (i = 0; i < this.menulist.length; i++) {
// 这里写死了t,t取值在0-1之间,这里不算0的话t有9个,显示的菜单也有九个(菜单小于9个有多少显示多少)
this.menuitemt[i] = (i + 1) * menuinterval
if (!this.elem[i]) return
// 操作dom移动到合适的位置
this.elem[i].style.left =
-44 +
this.threeOrderBezier(
this.menuitemt[i],
this.p12,
this.cp12,
this.cp22,
this.p22
)[0] +
'px'
this.elem[i].style.top =
-20 +
this.threeOrderBezier(
this.menuitemt[i],
this.p12,
this.cp12,
this.cp22,
this.p22
)[1] +
'px'
}
})
},
// 获取三次贝塞尔曲线的位置
threeOrderBezier (t, p1, cp1, cp2, p2) {
// 参数分别为t,起始点,两个控制点和终点
var [x1, y1] = p1
var [cx1, cy1] = cp1
var [cx2, cy2] = cp2
var [x2, y2] = p2
var x =
x1 * (1 - t) * (1 - t) * (1 - t) +
3 * cx1 * t * (1 - t) * (1 - t) +
3 * cx2 * t * t * (1 - t) +
x2 * t * t * t
var y =
y1 * (1 - t) * (1 - t) * (1 - t) +
3 * cy1 * t * (1 - t) * (1 - t) +
3 * cy2 * t * t * (1 - t) +
y2 * t * t * t
return [x, y]
},
// 改变menu数组使用防抖节流
down: _throttle(function (val) {
if (this?.menulist.length > 8 && this?.top > 0) {
this.animation({}, 0)
console.log('bbb')
this.bottom = this.bottom + 1
this.top = this.top - 1
}
}),
up: _throttle(function (val) {
if (this?.menulist.length > 8 && this?.bottom > 0) {
this.animation({}, 1)
console.log('aaaa')
this.bottom = this.bottom - 1
this.top = this.top + 1
}
}),
// up() {
// this.animation({}, 1)
// },
// 改变选中
changeindex (name, route) {
this.activeindex = name
this.$router.push(route)
},
// 每次鼠标滚轮触发该方法
animation (args, flag) {
function animate (draw, duration, callback) {
var start = 0
requestAnimationFrame(function animate (time) {
start = start + 1
var timePassed = start
if (timePassed > 10) {
timePassed = duration
}
draw(timePassed)
if (timePassed < 10) {
requestAnimationFrame(animate)
} else callback()
})
}
animate(
(timePassed) => {
// 调用需要执行的方法
this.counter = this.counter + 1
var i
// 根据帧数将每个间隔再分成26份
const menuinterval = 1 / 10 / 10
var elem = document.getElementsByClassName('menuitem')
// if (!elem[i]) return
if (flag) {
for (i = 0; i < 8; i++) {
elem[i].style.left =
-44 +
this.threeOrderBezier(
this.menuitemt[i] - menuinterval * this.counter,
this.p12,
this.cp12,
this.cp22,
this.p22
)[0] +
'px'
elem[i].style.top =
-20 +
this.threeOrderBezier(
this.menuitemt[i] - menuinterval * this.counter,
this.p12,
this.cp12,
this.cp22,
this.p22
)[1] +
'px'
}
} else {
for (i = 0; i < 8; i++) {
elem[i].style.left =
-44 +
this.threeOrderBezier(
this.menuitemt[i] + menuinterval * this.counter,
this.p12,
this.cp12,
this.cp22,
this.p22
)[0] +
'px'
elem[i].style.top =
-20 +
this.threeOrderBezier(
this.menuitemt[i] + menuinterval * this.counter,
this.p12,
this.cp12,
this.cp22,
this.p22
)[1] +
'px'
}
}
// console.log(elem[1].style.left, elem[1].style.top)
},
300,
function changeItems () {
if (flag) {
this.menulist.push(this.menulist.shift())
} else {
var last = this.menulist.pop() // 取数组最后一项
this.menulist.unshift(last) // 插入数组第一位
}
this.init()
this.counter = 0
}.bind(this)
)
}
}
}
</script>