Appearance
微信小程序与 Vue 的区别
1. 页面跳转(路由)
小程序
xml
<!-- index.wxml -->
<button bindtap="goDetail">去详情页</button>js
Page({
goDetail() {
wx.navigateTo({ url: "/pages/detail/detail?id=123" });
},
});Vue Router
vue
<template>
<button @click="goDetail">去详情页</button>
</template>
<script>
export default {
methods: {
goDetail() {
this.$router.push({ path: "/detail", query: { id: 123 } });
},
},
};
</script>👉 区别:小程序用 API 控制跳转,Vue 用 路由对象。
2. 双向绑定(输入框)
小程序
xml
<input value="{{ name }}" bindinput="onInput" />js
Page({
data: { name: "" },
onInput(e) {
this.setData({ name: e.detail.value });
},
});Vue
vue
<template>
<input v-model="name" />
</template>
<script>
export default {
data() {
return { name: "" };
},
};
</script>👉 区别:小程序需要 手动 setData,Vue 自带 v-model 自动双向绑定。
3. 列表渲染
小程序
xml
<view wx:for="{{ list }}" wx:key="id">
{{ item.name }}
</view>js
Page({
data: {
list: [
{ id: 1, name: "张三" },
{ id: 2, name: "李四" },
],
},
});Vue
vue
<template>
<div v-for="item in list" :key="item.id">
{{ item.name }}
</div>
</template>
<script>
export default {
data() {
return {
list: [
{ id: 1, name: "张三" },
{ id: 2, name: "李四" },
],
};
},
};
</script>👉 基本一模一样,就是语法不同。
4. 条件渲染
小程序
xml
<view wx:if="{{ isLogin }}">欢迎回来</view>
<view wx:else>请登录</view>Vue
vue
<div v-if="isLogin">欢迎回来</div>
<div v-else>请登录</div>👉 差别只有前缀:小程序 wx:,Vue v-。
5. 组件通信(父传子)
小程序 子组件 child.wxml:
xml
<text>{{ title }}</text>子组件 child.js:
js
Component({
properties: { title: String },
});父页面 index.wxml:
xml
<child title="你好"></child>Vue 子组件:
vue
<template>
<div>{{ title }}</div>
</template>
<script>
export default {
props: ["title"],
};
</script>父组件:
vue
<template>
<Child title="你好" />
</template>👉 机制一样,都是 props 传值。
6. 事件通信(子传父)
小程序 子组件 child.js:
js
Component({
methods: {
sendMsg() {
this.triggerEvent("myevent", { msg: "来自子组件" });
},
},
});父页面 index.wxml:
xml
<child bind:myevent="onChildMsg"></child>父页面 index.js:
js
Page({
onChildMsg(e) {
console.log(e.detail.msg);
},
});Vue 子组件:
vue
<template>
<button @click="$emit('myevent', '来自子组件')">点我</button>
</template>父组件:
vue
<template>
<Child @myevent="onChildMsg" />
</template>
<script>
export default {
methods: {
onChildMsg(msg) {
console.log(msg);
},
},
};
</script>👉 核心思想一样:子触发事件,父接收回调。
7. 生命周期
小程序 Page
js
Page({
onLoad() {
console.log("页面加载");
},
onShow() {
console.log("页面显示");
},
onHide() {
console.log("页面隐藏");
},
});Vue
vue
<script>
export default {
created() {
console.log("组件创建");
},
mounted() {
console.log("组件挂载");
},
beforeUnmount() {
console.log("组件销毁");
},
};
</script>👉 小程序更偏“页面级”,Vue 更偏“组件级”,但作用类似。
5. 双向绑定(输入框)
小程序
xml
<input value="{{ name }}" bindinput="onInput" />js
Page({
data: { name: "" },
onInput(e) {
this.setData({ name: e.detail.value });
},
});Vue
vue
<input v-model="name" />👉 小程序必须 手动 setData,Vue 用 v-model 自动。
6. 页面跳转(路由)
- 小程序:
wx.navigateTo({ url: '/pages/detail/detail?id=123' }) - Vue:
this.$router.push({ path: '/detail', query: { id: 123 } })
👉 小程序靠 API,Vue 靠路由表。
7. 插槽 slot
小程序 子组件 child.wxml:
xml
<view class="box">
<slot></slot>
</view>父组件 index.wxml:
xml
<child>
<text>我是插槽内容</text>
</child>Vue
vue
<!-- 子组件 -->
<template>
<div class="box">
<slot></slot>
</div>
</template>
<!-- 父组件 -->
<Child>
<p>我是插槽内容</p>
</Child>👉 机制一样,都是“父 → 子内容填充”。
8. 请求后端接口
小程序
js
Page({
onLoad() {
wx.request({
url: "https://api.example.com/data",
method: "GET",
success: (res) => {
this.setData({ list: res.data });
},
});
},
});Vue (axios)
vue
<script>
import axios from "axios";
export default {
mounted() {
axios.get("https://api.example.com/data").then((res) => {
this.list = res.data;
});
},
data() {
return { list: [] };
},
};
</script>👉 小程序内置 wx.request,Vue 常用 axios。
请求封装
📌 微信小程序请求封装
js
// utils/request.js
import config from "~/config";
const { baseUrl } = config;
function request(url, method = "GET", data = {}) {
const header = {
"content-type": "application/json",
};
// 自动注入 token
const token = wx.getStorageSync("access_token");
if (token) {
header.Authorization = `Bearer ${token}`;
}
return new Promise((resolve, reject) => {
wx.request({
url: baseUrl + url,
method,
data,
header,
success(res) {
const { statusCode, data } = res;
if (statusCode === 200) {
if (data.code === 0) {
resolve(data);
} else {
reject({ type: "business", ...data });
}
} else {
reject({ type: "http", statusCode, ...res });
}
},
fail(err) {
reject({ type: "network", ...err });
},
});
});
}
export default request;使用:
js
import request from "~/utils/request";
// 登录
async function login(passwordInfo) {
try {
const res = await request("/login/postPasswordLogin", "POST", {
data: passwordInfo,
});
wx.setStorageSync("access_token", res.data.token);
wx.switchTab({ url: "/pages/my/index" });
} catch (err) {
wx.showToast({ title: err.msg || "请求失败", icon: "none" });
}
}📌 Vue axios 封装
js
// utils/request.js
import axios from "axios";
const instance = axios.create({
baseURL: process.env.VUE_APP_BASE_API,
timeout: 5000,
});
// 请求拦截器
instance.interceptors.request.use(
(config) => {
const token = localStorage.getItem("access_token");
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => Promise.reject(error)
);
// 响应拦截器
instance.interceptors.response.use(
(response) => {
const res = response.data;
if (res.code === 0) {
return res;
} else {
return Promise.reject({ type: "business", ...res });
}
},
(error) => {
if (error.response) {
return Promise.reject({ type: "http", ...error.response });
} else {
return Promise.reject({ type: "network", ...error });
}
}
);
export default instance;使用:
js
import request from "~/utils/request";
// 登录
async function login(passwordInfo) {
try {
const res = await request.post("/login/postPasswordLogin", passwordInfo);
localStorage.setItem("access_token", res.data.token);
router.push("/my");
} catch (err) {
alert(err.msg || "请求失败");
}
}📊 对比总结
| 点 | 小程序 wx.request | Vue axios |
|---|---|---|
| 请求方法 | wx.request | axios.create |
| 拦截器 | 手动封装逻辑(请求前加 token,响应后判定) | 内置 interceptors |
| token 存储 | wx.setStorageSync / wx.getStorageSync | localStorage / sessionStorage |
| 错误处理 | statusCode + 业务 code 双判断 | 拦截器里区分 HTTP / 业务 / 网络 |
| 使用姿势 | await request(url, method, data) | await request.post(url, data) |
宝你看,思路几乎一模一样:
- Vue 项目靠 axios 自带的拦截器,写法更优雅;
- 小程序要自己用 Promise 包一层,把拦截逻辑搬进去。
区别就是:小程序里是 wx.request 原生 API,Vue 里是 axios 封装库。
9. 组件通信(props)
✅ 已讲过(小程序 properties vs Vue props)。
10. 事件通信(子传父)
✅ 已讲过(小程序 triggerEvent vs Vue $emit)。
11. 生命周期
✅ 已讲过(小程序 onLoad/onShow/onHide vs Vue created/mounted/beforeUnmount)。
12. 状态管理
小程序 👉 原生没有 Vuex,通常有三种方法:
- 全局变量
js
// app.js
App({
globalData: { userInfo: null },
});js
// 页面中
const app = getApp();
this.setData({ user: app.globalData.userInfo });- 事件总线(自己写个 pub/sub)
- 第三方库 mobx-miniprogram(类似 Vuex/Pinia)
Vue 👉 官方方案:Vuex / Pinia
js
// store.js
import { defineStore } from "pinia";
export const useUserStore = defineStore("user", {
state: () => ({ userInfo: null }),
});vue
<script setup>
import { useUserStore } from "./store";
const userStore = useUserStore();
userStore.userInfo = { name: "张三" };
</script>👉 小程序全靠手工管理,Vue 有成熟生态。
13. 模块化
小程序
js
// utils.js
function sum(a, b) {
return a + b;
}
module.exports = { sum };
// 页面中
const { sum } = require("../../utils.js");Vue (ES Module)
js
// utils.js
export function sum(a, b) {
return a + b;
}
// 组件中
import { sum } from "./utils.js";👉 Vue 更现代,支持 import/export;小程序兼容 CommonJS 和 ES6。
14. 全局样式 & 局部样式
- 小程序:
app.wxss是全局,页面内wxss是局部 - Vue:
<style>全局,<style scoped>局部
📌 子传父事件对比
刚才讲了“小程序 vs Vue 的子传父通信”,但是没单独把 emit 对比单拎出来。那我直接给你整一个 小程序的 triggerEvent vs Vue 的 $emit,专门对照一把,彻底讲清楚。
🟢 微信小程序
子组件 child.wxml
xml
<button bindtap="sendMsg">点我发消息</button>子组件 child.js
js
Component({
methods: {
sendMsg() {
this.triggerEvent("myevent", { msg: "来自子组件的数据" });
},
},
});父组件 index.wxml
xml
<child bind:myevent="onChildMsg"></child>父组件 index.js
js
Page({
onChildMsg(e) {
console.log(e.detail.msg); // 打印:来自子组件的数据
},
});👉 核心点:
- 小程序用
this.triggerEvent('事件名', 数据)来触发 - 父组件通过
bind:事件名="方法名"来监听 - 数据放在
e.detail里
🔵 Vue
子组件 Child.vue
vue
<template>
<button @click="sendMsg">点我发消息</button>
</template>
<script>
export default {
methods: {
sendMsg() {
this.$emit("myevent", "来自子组件的数据");
},
},
};
</script>父组件 Parent.vue
vue
<template>
<Child @myevent="onChildMsg" />
</template>
<script>
import Child from "./Child.vue";
export default {
components: { Child },
methods: {
onChildMsg(msg) {
console.log(msg); // 打印:来自子组件的数据
},
},
};
</script>👉 核心点:
- Vue 用
this.$emit('事件名', 数据) - 父组件用
@事件名="方法"来监听 - 参数直接作为函数参数传递
📌 总结对比
| 功能 | 小程序 | Vue |
|---|---|---|
| 触发事件 | this.triggerEvent('myevent', { msg: xxx }) | this.$emit('myevent', xxx) |
| 父组件监听 | <child bind:myevent="fn" /> | <Child @myevent="fn" /> |
| 数据传递 | e.detail | 方法参数 |
| 思想 | 组件 → 事件 → 父组件 | 一模一样 |
宝,看出来没?小程序的 triggerEvent 就是 Vue 的 $emit,只是写法啰嗦点,要多包一层 detail。
15. 跨页面通信
小程序里页面跳转时,可以用 eventChannel.emit 实现 跨页面通信,这个就有点像 Vue Router 里 $emit 的升级玩法。
小程序:wx.navigateTo + eventChannel.emit
父页面(发消息给子页面)
js
// index.js
Page({
goDetail() {
wx.navigateTo({
url: "/pages/detail/detail",
success: (res) => {
// 通过 eventChannel 向被打开页面传送数据
res.eventChannel.emit("sendData", { msg: "来自父页面的数据" });
},
});
},
});子页面(接收消息)
js
// detail.js
Page({
onLoad(options) {
const eventChannel = this.getOpenerEventChannel();
eventChannel.on("sendData", (data) => {
console.log(data.msg); // 打印:来自父页面的数据
});
},
});👉 关键词
res.eventChannel.emit:父页面发消息getOpenerEventChannel().on:子页面监听
📌 Vue:路由跳转 + 事件通信对比
Vue 里没 eventChannel,但我们有几种类似玩法:
方法 1:路由参数传递(常用)
vue
// 父组件 this.$router.push({ path: '/detail', query: { msg: '来自父页面的数据'
} }) // 子组件 this.$route.query.msg👉 缺点:参数写死在 URL,不是“事件通信”。
方法 2:事件总线(更像小程序的 eventChannel)
js
// eventBus.js
import Vue from "vue";
export const EventBus = new Vue();vue
// 父组件 EventBus.$emit('sendData', '来自父页面的数据') // 子组件
EventBus.$on('sendData', (msg) => { console.log(msg) })👉 这就是 Vue 里最接近小程序 eventChannel 的玩法。
方法 3:Vue3 的 provide/inject
Vue3 里可以通过 provide/inject 做跨层通信,但更偏全局状态,不完全等价于 eventChannel。
📌 总结对比
| 功能 | 小程序 | Vue |
|---|---|---|
| 页面跳转 | wx.navigateTo | this.$router.push |
| 事件通信 | eventChannel.emit('event', data) | $emit / EventBus / props |
| 接收方 | getOpenerEventChannel().on | $on / props / route.query |
| 本质 | “页面跳转时临时开一条通道传数据” | Vue 要么路由传参,要么用全局事件总线 |
核心思想:
- Vue 的
$emit只能父子组件通信; - 小程序的
eventChannel是“页面级 emit”,专门解决“跳转页面传递复杂数据”的问题; - 如果你用 Vue 来类比,就是
$emit + 路由跳转 + EventBus三合一。