这篇内容是在有道云旧笔记基础上重新整理的 Vue/Vite 工程实践 笔记。原始记录偏碎片化,这里补充了使用场景、阅读顺序和落地时需要注意的边界,方便以后在项目里快速复用。

适用场景 ​

  • Vue/Vite 项目中遇到配置、组件封装、构建或运行时问题时,作为排查入口。
  • 需要把一次性调试经验沉淀成团队内可复用的前端工程实践。
  • 迁移旧项目或升级依赖时,用来对照检查环境变量、插件和组件行为差异。

核心要点 ​

  • 正文以代码或命令片段为主,阅读时建议先确认目标问题,再挑选对应片段验证。
  • 保留了 1 段可直接参考的代码或命令,复制前需要按当前项目路径、版本和变量名做调整。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
 // vue js
methods: {
handleOnChoneSwipe(index) {
const { swipeList } = this
const swipeItem = swipeList[index]
const lanName = 'lancemach-video--s'

if (swipeList?.length && swipeItem?.videoUrl) {
const [swipeVideo] = document.getElementsByClassName(`${lanName}${index}`)
const [coverImg] = swipeVideo.parentNode.getElementsByClassName('img-cover')
const [lanPlay] = coverImg.parentNode.getElementsByClassName('lancemach-play-start')
const playing = 'playing'

if (swipeItem?.pause) {
this.handlePlayVideoPauseAll(`${lanName}${index}`)

coverImg && coverImg.classList.add(playing)
lanPlay && lanPlay.classList.add(playing)
// this.autoplay = false
swipeItem.pause = false
swipeVideo.play()
this.palyVideo = swipeVideo
} else {
coverImg && coverImg.classList.remove(playing)
lanPlay && lanPlay.classList.remove(playing)
// this.autoplay = true
swipeItem.pause = true
swipeVideo.pause()
// swipeVideo.load()
this.palyVideo = {}
}
}
},
handleInitVideoAll() {
const videos = document.getElementsByTagName('video')
let k = 0
for (const video of videos) {
if (video.className.indexOf('lancemach-video') === -1) {
video.className += `lancemach-video lancemach-video--vi${k}`
k++
// const [coverImg] = video.previousSibling.getElementsByClassName('img-cover')
if (!Object.values(video.classList).includes('lancemach-video-box')) {
const vBox = document.createElement('div')
const pBox = document.createElement('div')
video.parentNode.insertBefore(vBox, video.nextSibling)
vBox.classList.add('lancemach-video-box')
pBox.className += 'lancemach-play-start lancemach-play-shade'
vBox.appendChild(pBox)
vBox.appendChild(video)
}
} else {
if (video.parentNode.getElementsByClassName('lancemach-play-start').length < 1) {
const iBox = document.createElement('img')
iBox.classList.add('lancemach-play-start')
iBox.src = this.videoPlaying
video.parentNode.insertBefore(iBox, video.previousSibling)
}
}
}
this.handlesTargetEleViewport()
},
handlePlayVideo(e) {
const { target } = e

const targetVideo = (Object.values(target.classList).includes('lancemach-play-start') && !Object.values(target.classList).includes('lancemach-play-shade')) ? target.nextElementSibling.nextElementSibling : target.nextElementSibling
// target.nodeName === 'IMG' && target.className === 'img' && target.parentNode.className === 'lancemach-video-box' && targetVideo.nodeName === 'VIDEO'
if ((Object.values(target.classList).includes('img-cover') || Object.values(target.classList).includes('lancemach-play-start')) && Object.values(target.parentNode.classList).includes('lancemach-video-box') && targetVideo.nodeName === 'VIDEO') {
const string = 'lancemach-video--v'
const [className] = targetVideo.className.split(' ').filter((i) => i.indexOf(string) !== -1)

this.handlePlayVideoPauseAll(className)

target.classList.add('playing')
target[Object.values(target.classList).includes('lancemach-play-start') ? 'nextElementSibling' : 'previousSibling'].classList.add('playing')
targetVideo.play()
}
},
handlePlayVideoPauseAll(className = '') {
const videos = document.getElementsByTagName('video')
for (const video of videos) {
video.addEventListener('play', () => {
if (!video.className.includes(className)) {
this.handlePlayVideoPause(className)
}
})
}
},
handlePlayVideoPause(className = '', playing = 'playing') {
const lanName = 'lancemach-video--s'
if (className.indexOf(lanName) !== -1) {
const [lastName] = className.split(' ').filter((i) => i.indexOf(lanName) !== -1)
const index = lastName.replace(new RegExp(lanName, 'g'), '')
if (index > -1) {
this.swipeList[index].pause = true
}
}
const [playVideo] = document.getElementsByClassName(className)
const [coverImg] = playVideo.parentNode.getElementsByClassName('img-cover')
const [lanPlay] = playVideo.parentNode.getElementsByClassName('lancemach-play-start')

coverImg && coverImg.classList.remove(playing)
lanPlay && lanPlay.classList.remove(playing)
playVideo.pause()
// playVideo.load()
},
handlesTargetEleViewport() {
const scrollListener = document.querySelector('.container')
if (scrollListener) {
const videos = document.getElementsByTagName('video')
scrollListener.addEventListener('scroll', throttle(() => {
// scrollListener.scrollTop
const headerHeight = 44 // 页面布局header 高度
for (const video of videos) {
const videoClientRect = video.getBoundingClientRect()
if ((videoClientRect.bottom - (headerHeight || 0)) <= 0) {
// 当前视频是否正在播放
if (video.currentTime > 0 && !video.paused && !video.ended && video.readyState > 2) {
const playVideoClassName = video.className.split(' ').find((i) => i.indexOf('lancemach-video--') !== -1)
playVideoClassName && this.handlePlayVideoPause(playVideoClassName)
}
}
}
}, 500))
}
}
},
beforeDestroy() {
this.handlePlayVideoPauseAll()
}

实践检查清单 &#8203;

  • 先确认 Vue、Vite、Node、包管理器版本,再判断示例是否需要按当前工程结构调整。
  • 涉及构建或插件配置时,建议同时验证开发环境和生产构建结果。
  • 涉及 UI 或浏览器行为时,至少在桌面端和移动端各验证一次关键路径。
  • 涉及接口、服务端或权限逻辑时,补充失败分支和权限边界测试。

复盘小结 &#8203;

这篇笔记更适合作为问题排查或方案落地前的速查材料。后续如果在真实项目中再次遇到同类问题,可以继续把具体版本、报错信息、最终取舍和验证结果补到对应小节里,让它从代码片段逐步沉淀成完整方案。