做小程序的人,多半碰到过这种尴尬:页面上放了个外部链接,用户一点,要么毫无反应,要么直接被甩出小程序、丢进浏览器里。流程一断,原来的页面上下文全丢了,用户还回不回来,全看运气。可偏偏很多场景又离不开外链——活动详情放在自家 H5 上,海报、短信、社群里到处铺,理想情况是用户点进去之后仍留在小程序里,看完内容还能顺手逛逛别的地方。链接能不能在程序内部打开?能,web-view 组件就是干这个的。
web-view 是小程序官方提供的网页容器,作用很直接:把一个 web 页面嵌进小程序页面里渲染,外部内容就能留在程序内部展示,不用再把用户踢出去。不过它也不是拿来就能用的——要加载的域名,得先在小程序后台配好业务域名白名单;个人主体的小程序,通常还不支持这个组件。动手前先把这两件事确认清楚,免得代码写完了才发现跑不通。

具体实现分三块。先准备页面:在 app.json 里把承接链接的页面注册进来,再给它挂一个自定义 tabBar 入口,配置大致长这样:
{
"pages": [
"pages/index/index",
"pages/webview/webview"
],
"tabBar": {
"list": [
{
"pagePath": "pages/index/index",
"text": "首页"
},
{
"pagePath": "pages/webview/webview",
"text": "链接",
"iconPath": "icon/webview.png",
"selectedIconPath": "icon/webview_selected.png"
}
]
}
}
pages 数组里除了首页,多了 pages/webview/webview;tabBar 里也给它留了个“链接”位,配上普通和选中两套图标。这样一来,这个页面就不是只被动等跳转进来,平时也能从底部导航直接点进去。
页面建好,接下来让它真能装下网页。在 pages/webview/webview 路径下新建页面,wxml 里只需要一行:
<web-view src="{{url}}"></web-view>

src 绑定的是页面 data 里的 url 字段,也就是外部传进来、要展示的那个网址。要接住这个参数,页面的 js 里还得在 onLoad 中取一下 query,塞进 data:
Page({
onLoad: function (options) {
if (options.url) {
this.setData({
url: decodeURIComponent(options.url)
})
}
}
})
链接是编码过再传来的,取值时记得用 decodeURIComponent 还原,不然带中文或特殊字符的地址容易出问题。

最后一块在 app.js。用户从外部跳进小程序时,启动参数会挂在 options.query 上,要做的是把它拿到,转给 webview 页面:
App({
onLaunch: function (options) {
if (options.query.url) {
wx.reLaunch({
url: '/pages/webview/webview?url=' + encodeURIComponent(options.query.url)
})
}
}
})

onLaunch 触发时先判断有没有 url 参数,有的话用 wx.reLaunch 关掉所有已打开的页面、切到 webview 页,并把链接编码后以 query 形式带过去。这里有个细节值得留意:onLaunch 只在冷启动时执行。如果小程序已经在后台运行,用户又从外链进来,走的是 onShow——需要的话,可以在那里补一道同样的判断,否则热启动的场景就漏掉了。
到这里,整条链路就通了:用户从外部点开链接,小程序启动,onLaunch 接住参数,reLaunch 把人带到 webview 页面,web-view 把目标网页渲染出来。全程没有跳出小程序,看完内容,抬手就能点回 tabBar 逛别的页面,体验是连贯的。
实际落地时,还有几件小事可以顺手做好:tabBar 图标路径按自己的目录改;传参统一用 encodeURIComponent 和 decodeURIComponent 这一对;域名白名单提前配;热启动的处理别漏。这些细节都不复杂,却决定着线上跑起来顺不顺。整套配置加代码,量很小,却能把“点开链接就被甩出去”变成“留在程序里看链接”——对要做活动承接、内容分发的小程序来说,花十分钟搭一次,很值。
지금 로그인