🧩 当 <swiper>
不听话的时候:我与 getCurrentInstance()
的灵魂对话
有时候,写代码就像在养宠物。你以为你在控制它,其实是它在戏弄你 🐶。 ------ 一个被
uni.createVideoContext()
玩坏的前端开发者。
🎬 起因:我的视频不听话
最近在用 uni-app + Vue3 做一个"仿抖音短视频"页面。 你知道的,就是那种上滑切换,下滑返回,播放、暂停全自动的效果。
我写了一个漂亮的 swiper
组件,每个 swiper-item
里面放一个 video
。 切换的时候,我希望上一个视频暂停、下一个视频自动播放。听起来很合理,对吧?🤔
于是我写下了几行理所当然的伪代码:
当滑动到下一个视频时:
找到上一个视频
暂停它
找到当前视频
播放它
理论上完美 ✅。 实际效果?❌ 上一个视频愣是还在"热情洋溢"地播放! 我滑了半天,页面成了个"多重奏"现场 🎶。
🧠 第一次怀疑人生:我的 createVideoContext
坏了吗?
我当时心想: "奇怪,我的查找视频上下文不是写对了吗?createVideoContext('video-123')
,这不就行了吗?"
于是我疯狂输出日志、打印对象、console.log 全开火力 🔥。 结果发现: 👉 它根本没找到那个视频对象。
我怀疑是不是我写错了 id。 我仔细数了下:video-1
、video-2
、video-3
......全都对的。 但 createVideoContext()
死活就是"找不到视频"。
我盯着控制台发呆 5 分钟,开始怀疑自己是不是生活在另一个维度 🌀。
💡 灵光一闪:难道是作用域问题?
突然我想起来一个古早的 Vue 概念------ "组件作用域"。
于是我做了个实验。 我加了个播放按钮,直接点某个视频播放。 结果------按钮点了也没反应 😭。 不是逻辑问题,而是找不到视频节点!
我这才意识到:
哦豁,这不是单纯的 Vue 页面。 我现在在玩的是 "Vue + 原生小程序 + 组件沙盒" 的三合一组合拳!🥊
🕵️ 第二次调查:swiper 的"真面目"
接着我翻了一下官方文档(是的,没事多看文档救命 🧾)。
我发现一个惊天秘密:
<swiper>
和<swiper-item>
在 uni-app 里不是普通的 Vue 标签, 它们其实是原生平台组件,比如微信小程序原生的 swiper。
这就像你以为你在 Vue 世界里写代码, 但其实你的一部分 DOM 已经被"托运"到底层平台去渲染了 🚛。
换句话说:
css
页面(Page)
└── 我的Vue组件
└── swiper(其实是原生层的组件)
├── swiper-item 1(一个独立作用域)
│ └── video 1
├── swiper-item 2(另一个作用域)
│ └── video 2
看到没? 这些 swiper-item
其实被"装箱"发到原生层展示去了。 你以为它们还在你的组件内部, 但实际上它们早已经搬出去单独生活 🏠。
🚨 真相浮出水面:我在错的地方找对象!
于是我终于懂了:
我在当前组件里喊:
bash
找一下 id 为 video-1 的视频!
系统听到了,但它去错地方找了------ 它只会在"当前页面"作用域里翻找, 结果那个视频其实藏在 <swiper-item>
的"子作用域"里。 你说它能找到才怪 🤷♂️。
🧩 解决方案:召唤 getCurrentInstance()
这时候,我遇到了一个神秘的法术: getCurrentInstance()
🪄。
它的意思是:"获取我当前组件的实例对象"。 在 Vue3 里没有 this
,所以想拿到组件上下文,就得靠它。
于是我试着这样想象:
嘿 uni-app,
我知道你平时只在全局页面里找视频,
但我现在这个视频是在我的小组件里,
麻烦你到我的小仓库(instance)里找一下。
uni-app 很懂事地回答:"收到,老大。" 然后啪的一下,就能控制视频播放和暂停了 🎉。
🧠 延伸理解:getCurrentInstance()
就像一张"定位卡"
如果把 uni-app 比喻成一个仓库系统:
- 整个页面是总仓库;
- 每个 Vue 组件是一个分仓库;
- 而 swiper-item 就像是一个"外包的临时仓库", 它不和主仓共享目录。
当我只写 createVideoContext('video-1')
, 系统就只在"总仓库"翻找。
而我真正的货(video)在"分仓库"里。 于是------找不到。
只有当我加上 getCurrentInstance()
这张"仓库定位卡", 系统才知道该去哪儿取货 🏷️。
🧩 再理解一层:为什么 <swiper>
看起来在同一个文件,却不是同一个世界?
这部分真相更玄学 😂。
虽然我写在同一个 .vue
文件里, 但是------ uni-app 的编译器会把 <swiper-item>
的内容拆成独立的小块交给原生引擎。
所以从 Vue 的角度来看,它像这样:
makefile
Vue: 我渲染了个 swiper 组件
原生层: 好的,我接管它,帮你展示 UI
于是你的 <video>
不再属于 Vue 自己渲染的虚拟DOM, 而是交给原生层去展示。
那 createVideoContext()
默认在哪找? 👉 它默认只在 Vue 页面自己能看到的那一层找。 自然找不到被"托管"的视频。
🧩 你可能会问:"那为什么不是全局实例?"
因为 Vue 设计哲学就是 ------ "各扫门前雪,不扰他人霜" ❄️。
getCurrentInstance()
只返回当前组件实例, 不会给你"所有实例"的集合。
如果 Vue 让你随便跨组件访问,那组件隔离就全废了。 这对性能、维护、安全,都是灾难级的设计。
所以,Vue 不提供"全局通行证", 而是要求你在谁家拿钥匙就只能开谁家的门 🗝️。
🔍 最终总结
我们这一场"视频播放风波"的真相其实就一句话:
不是你的代码写错了,而是你找错了层级。
<swiper>
和 <swiper-item>
虽然在同一个 .vue
文件里, 但它们运行在不同的渲染作用域。 video
节点藏在更深的一层"原生作用域"里。 只有加上 getCurrentInstance()
, uni-app 才知道要到你这个组件的世界里去找那个视频 🎯。
🎁 如果 getCurrentInstance()
会说话
👨💻 你:我明明在这个 Vue 文件里,为什么视频不听话?!
🤖
getCurrentInstance()
:兄弟,你找错门了,那视频住在 swiper-item 的楼下。👨💻 你:啊?那我该怎么办?
🤖
getCurrentInstance()
:给我一张通行证,我带你进去 😎。
🧘 最后的感悟
那一刻我突然有点感动(或者说释怀😅)。
原来 getCurrentInstance()
不只是一个API, 它其实是一种"沟通的桥梁" 🌉------ 让 Vue 世界和原生世界能互相理解。
它告诉我一个道理:
写代码也像谈恋爱------ 你以为只是一个简单的"找对象", 但其实要先确定"找的范围对不对"。💔💖