Skip to content

微信小程序与 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.requestVue axios
请求方法wx.requestaxios.create
拦截器手动封装逻辑(请求前加 token,响应后判定)内置 interceptors
token 存储wx.setStorageSync / wx.getStorageSynclocalStorage / 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,通常有三种方法:

  1. 全局变量
js
// app.js
App({
  globalData: { userInfo: null },
});
js
// 页面中
const app = getApp();
this.setData({ user: app.globalData.userInfo });
  1. 事件总线(自己写个 pub/sub)
  2. 第三方库 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.navigateTothis.$router.push
事件通信eventChannel.emit('event', data)$emit / EventBus / props
接收方getOpenerEventChannel().on$on / props / route.query
本质“页面跳转时临时开一条通道传数据”Vue 要么路由传参,要么用全局事件总线

核心思想:

  • Vue 的 $emit 只能父子组件通信;
  • 小程序的 eventChannel 是“页面级 emit”,专门解决“跳转页面传递复杂数据”的问题;
  • 如果你用 Vue 来类比,就是 $emit + 路由跳转 + EventBus 三合一