基于Taro4打造的一款最新版微信小程序、H5的多端開發簡單模板

基于Taro4、Vue3、TypeScript、Webpack5打造的一款最新版微信小程序、H5的多端開發簡單模板

1

特色

  • 🛠? Taro4, Vue 3, Webpack5, pnpm10

  • 💪 TypeScript 全新類型系統支持

  • 🍍 使用 Pinia 的狀態管理

  • 🎨 Tailwindcss4 - 目前流行的原子化 CSS 框架,用于快速UI開發

  • 🔥 使用 新的 <script setup> 語法

  • 🚀 NutUI-Vue - 無需引入直接使用高質量組件,覆蓋移動端主流場景

  • 🌍 API 采用模塊化導入方式 根據demo.js文件設置接口,以API_xxx_method的方式命名,在請求時無需導入 直接使用useRequest()函數返回參數以解構的方式獲取,拿到即為寫入的接口

準備

本項目搭建采用環境如下

vscode v1.103.2
node v22.14.0
taro v4.1.5
pnpm v10.11.0

步入正題

創建項目基本結構

  1. 打開vscode編輯器終端進行操作

  2. 安裝taro腳手架

    pnpm install -g @tarojs/cli
    
  3. 創建基礎模版

    taro init my-taro-project
    

    根據相應提示進行如下選擇
    請添加圖片描述

  4. 進入創建的 my-taro-project終端目錄下
    為了可以同時并且實時的預覽小程序和h5,更改下config/index.ts文件中的部分內容

    outputRoot: `dist/${process.env.TARO_ENV}`
    
  5. 直接運行微信小程序自動安裝依賴

    pnpm dev:weapp
    
  6. 打開微信開發者工具

    如未安裝點擊下面鏈接下載安裝即可👇
    https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html

    打開編譯過后的微信小程序代碼在:`dist》weapp`目錄
    

    請添加圖片描述

項目結構介紹

https://docs.taro.zone/docs/folder

接入Pinia

安裝
pnpm install pinia taro-plugin-pinia
修改配置

修改config/index.ts內容

plugins: ["taro-plugin-pinia",
],
compiler: {type: "webpack5",prebundle: {enable: false, // 開啟后導致pinia丟失響應式},
},
引入使用

創建以下文件夾以及文件
請添加圖片描述

寫入以下代碼
index.ts

import { createPinia } from "pinia";
import type { App } from "vue";export const piniaStore = createPinia();
export function setupStore(app: App) {app.use(piniaStore);
}

demo.ts

import { defineStore } from 'pinia'
import { piniaStore } from '@/stores'const useCounterStore = defineStore('counter', {state: () => {return { count: 0 }},actions: {increment() {this.count++},},
})export function useCounterOutsideStore() {return useCounterStore(piniaStore)
}

使用pinia
app.ts

import { createApp } from "vue";
import { setupStore } from "./stores"; // +
import "./app.css";const App = createApp({onShow(options) {console.log("App onShow.");},
});
setupStore(App); // +export default App;

src/pages/index/index.ts

<template><view>{{ msg }}</view><view class="text-red-500" @tap="testPinia">點我測試pinia{{ count }}</view>
</template><script setup lang="ts">
import { ref, computed } from 'vue'
import './index.css'
import { useCounterOutsideStore } from '@/stores/modules/demo'const msg = ref('Hello world')
const count = computed(() => counterStore.count)
const counterStore = useCounterOutsideStore()
const testPinia = () => {counterStore.increment()console.log(counterStore.count)
}
</script>

運行結果
請添加圖片描述

接入Tailwind

安裝
pnpm install -D tailwindcss @tailwindcss/postcss postcss weapp-tailwindcss autoprefixer

https://github.com/sonofmagic/weapp-tailwindcss

創建寫入

創建 postcss.config.js 并注冊 tailwindcss

export default {plugins: {"@tailwindcss/postcss": {},autoprefixer: {},},
}

tailwind.config.ts

/** @type {import('tailwindcss').Config} */
module.exports = {// 這里給出了一份 taro 通用示例,具體要根據你自己項目的目錄結構進行配置// 比如你使用 vue3 項目,你就需要把 vue 這個格式也包括進來// 不在 content glob 表達式中包括的文件,在里面編寫 tailwindcss class,是不會生成對應的 css 工具類的content: ['./public/index.html', './src/**/*.{html,js,ts,jsx,tsx}'],// 其他配置項 ...corePlugins: {// 小程序不需要 preflight,因為這主要是給 h5 的,如果你要同時開發多端,你應該使用 process.env.TARO_ENV 環境變量來控制它preflight: false,},
}

package.json

"scripts": {
+ "postinstall": "weapp-tw patch"
}

添加這段腳本的用途是,每次安裝包后,都會自動執行一遍 weapp-tw patch 這個腳本,給本地的 tailwindcss 打上小程序支持補丁。

config/index.js

mini: {webpackChain(chain) {chain.resolve.plugin("tsconfig-paths").use(TsconfigPathsPlugin);chain.merge({plugin: {install: {plugin: UnifiedWebpackPluginV5,args: [{// 這里可以傳參數rem2rpx: true,tailwindcss: {v4: {cssEntries: [// 你 @import "weapp-tailwindcss"; 那個文件絕對路徑path.resolve(__dirname, "../src/app.css"),],},},// https://github.com/sonofmagic/weapp-tailwindcss/issues/155injectAdditionalCssVarScope: true, // 解決nutui對tailwindcss的影響},],},},});}
},

src/app.css

@import "weapp-tailwindcss";

使用tailwind

src/pages/index/index.ts

<template><view>{{ msg }}</view><view class="text-red-500" @tap="testPinia">點我測試pinia{{ count }}</view><view className="text-[#acc855] text-[100px]">Hello world!</view><view class="outer"><view class="inner">嵌套樣式測試</view><view class="w-[50%] h-5 bg-amber-400"></view></view>
</template><script setup lang="ts">
import { ref, computed } from 'vue'
import './index.css'
import { useCounterOutsideStore } from '@/stores/modules/demo'const msg = ref('Hello world')
const count = computed(() => counterStore.count)
const counterStore = useCounterOutsideStore()
const testPinia = () => {counterStore.increment()console.log(counterStore.count)
}
</script>

src/pages/index/index.css

.outer{.inner{color: blue;font-size: xx-large;}
}

在tailwind4版本中已經實現了 樣式嵌套功能所以不用sass、less這些 也可以嵌套樣式編寫

運行結果

請添加圖片描述

接入NutUI

安裝
pnpm add @nutui/nutui-taro @nutui/icons-vue-taro @tarojs/plugin-html

@tarojs/plugin-html 使用 HTML 標簽,nutui需要用到

自動按需引入nutui組件

pnpm add @nutui/auto-import-resolver unplugin-vue-components -D
寫入使用

在config/index.js添加以下相應配置

import ComponentsPlugin from 'unplugin-vue-components/webpack'
import NutUIResolver from '@nutui/auto-import-resolver'config = {// 開啟 HTML 插件plugins: ['@tarojs/plugin-html'],designWidth (input) {// 配置 NutUI 375 尺寸if (input?.file?.replace(/\\+/g, '/').indexOf('@nutui') > -1) {return 375}// 全局使用 Taro 默認的 750 尺寸return 750},deviceRatio: {640: 2.34 / 2,750: 1,828: 1.81 / 2,375: 2 / 1},// 小程序開發mini: {webpackChain(chain) {chain.plugin('unplugin-vue-components').use(ComponentsPlugin({resolvers: [NutUIResolver({taro: true})]}))},},// Taro-H5 開發h5: {webpackChain(chain) {chain.plugin('unplugin-vue-components').use(ComponentsPlugin({resolvers: [NutUIResolver({taro: true})]}))},}
}

src/app.ts

import { createApp } from "vue";
import { setupStore } from "./stores";
import "@nutui/nutui-taro/dist/style.css"; // +
import "./app.css";const App = createApp({onShow(options) {console.log("App onShow.");},
});
setupStore(App);export default App;

配置完成后,可以直接在模板中使用 NutUI 組件,unplugin-vue-components 插件會自動注冊對應的組件,并按需引入組件樣式。

使用NutUI

src/pages/index/index.ts

<template><view>{{ msg }}</view><view class="text-red-500" @tap="testPinia">點我測試pinia{{ count }}</view><view className="text-[#acc855] text-[100px]">Hello world!</view><view class="outer"><view class="inner">嵌套樣式測試</view><view class="w-[50%] h-5 bg-amber-400"></view></view><nut-button type="info">測試nutui</nut-button>
</template><script setup lang="ts">
import { ref, computed } from 'vue'
import './index.css'
import { useCounterOutsideStore } from '@/stores/modules/demo'const msg = ref('Hello world')
const count = computed(() => counterStore.count)
const counterStore = useCounterOutsideStore()
const testPinia = () => {counterStore.increment()console.log(counterStore.count)
}
</script>

運行結果

請添加圖片描述

接入自定義Tabbar

創建所需的目錄結構

請添加圖片描述

寫入代碼

src/stores/modules/system.ts

import { defineStore } from "pinia";
import { piniaStore } from "@/stores";type SystemState = {tabbar: {active: string;};
};const useSystemStore = defineStore("system", {state: (): SystemState => {return { tabbar: { active: "home" } };},actions: {setActiveTab(tab: string) {if (tab === this.tabbar.active) return;this.tabbar.active = tab;},},
});export function useSystemOutsideStore() {return useSystemStore(piniaStore);
}

將nut-tabbar的切換狀態存入store為了解決頁面重復渲染tabbar引起的問題 https://github.com/jd-opensource/nutui/issues/2368

router/index.ts

import Taro from "@tarojs/taro";type Params = Record<string, string | number | boolean | undefined | null>;interface Router {push(url: string, params?: Params): void;replace(url: string, params?: Params): void;switchTab(url: string, params?: Params): void;reLaunch(url: string, params?: Params): void;
}function buildQuery(params: Params): string {return Object.keys(params).map((key) =>`${encodeURIComponent(key)}=${encodeURIComponent(params[key] ?? "")}`).join("&");
}/*** Taro 應用的路由工具類。** 提供頁面跳轉、重定向、切換 Tab、重啟應用等方法,并支持可選的查詢參數。** @property navigateTo - 跳轉到指定頁面,可攜帶查詢參數。* @property redirectTo - 重定向到指定頁面,可攜帶查詢參數。* @property switchTab - 切換到指定 Tab 頁面,可攜帶查詢參數。* @property reLaunch - 重啟應用到指定頁面,可攜帶查詢參數。** @example* router.navigateTo('/pages/home', { userId: 123 });*/
const router: Router = {push(url, params) {if (params) {const query = buildQuery(params);Taro.navigateTo({ url: `${url}?${query}` });} else {Taro.navigateTo({ url });}},replace(url, params) {if (params) {const query = buildQuery(params);Taro.redirectTo({ url: `${url}?${query}` });} else {Taro.redirectTo({ url });}},switchTab(url, params) {if (params) {const query = buildQuery(params);Taro.switchTab({ url: `${url}?${query}` });} else {Taro.switchTab({ url });}},reLaunch(url, params) {if (params) {const query = buildQuery(params);Taro.reLaunch({ url: `${url}?${query}` });} else {Taro.reLaunch({ url });}},
};export { router };

Footer.vue

<template><view class="footer"><nut-tabbarv-model="activeName"@tab-switch="tabSwitch":safe-area-inset-bottom="true"><nut-tabbar-itemv-for="item in list":key="item.name":name="item.name":tab-title="item.title":icon="item.icon"></nut-tabbar-item></nut-tabbar></view>
</template><script setup lang="ts">
import { Home, Category, My } from "@nutui/icons-vue-taro";
import { ref, h, computed } from "vue";
import { router } from "@/router";
import { useSystemOutsideStore } from "@/stores/modules/system";const useSystemStore = useSystemOutsideStore();
type TabItem = {name: string;path: string;title: string;icon: unknown;
};const list = ref<TabItem[]>([{ name: "home", path: "/pages/index/index", title: "首頁", icon: h(Home) },{ name: "test", path: "/pages/test/test", title: "測試", icon: h(Category) },{ name: "my", path: "/pages/my/my", title: "我的", icon: h(My) },
]);const activeName = computed({get: () => useSystemStore.tabbar.active,set: (value) => useSystemStore.setActiveTab(value),
});const tabSwitch = (item: TabItem, index: number) => {const path = list.value.filter((tab) => tab.name === item.name)[0].path;console.log(path, index);router.switchTab(path);
};
</script>

Header.vue

<template><view class="header">header</view>
</template>

layout/index.vue

<template><nut-config-provider class="h-full" :theme-vars="themeVars"><view class="layout h-full flex flex-col"><view class="header" v-show="isShowHeader"><Header :title="title" /></view><view class="content flex-1"><slot /></view><view class="footer" v-show="isShowFooter"><Footer :activeName="footerActive" /></view></view></nut-config-provider>
</template><script setup lang="ts">
import Header from "@/components/Header.vue";
import Footer from "@/components/Footer.vue";
import { onMounted, ref } from "vue";type Props = {title: string;isShowHeader?: boolean;isShowFooter?: boolean;footerActive: string;
};
withDefaults(defineProps<Props>(), {title: "標題",isShowHeader: false,isShowFooter: true,footerActive: "home"
});// 修改nutui主題樣式 https://nutui.jd.com/taro/vue/4x/#/zh-CN/component/configprovider
const themeVars = ref({primaryColor: "#008000",primaryColorEnd: "#008000",
});onMounted(() => {console.log("頁面顯示");
});
</script>

index/index.vue

<template><Layout title="首頁" footerActive="home"><view>{{ msg }}</view><view class="text-red-500" @tap="testPinia">點我測試pinia{{ count }}</view><view className="text-[#acc855] text-[100px]">Hello world!</view><view class="outer"><view class="inner">嵌套樣式測試</view><view class="w-[50%] h-5 bg-amber-400"></view></view><nut-button type="info">測試nutui</nut-button></Layout>
</template><script setup lang="ts">
import { ref, computed } from 'vue'
import './index.css'
import Layout from '@/layout/index.vue' // +
import { useCounterOutsideStore } from '@/stores/modules/demo'const msg = ref('Hello world')
const count = computed(() => counterStore.count)
const counterStore = useCounterOutsideStore()
const testPinia = () => {counterStore.increment()console.log(counterStore.count)
}
</script>

my/index.vue test/index.vue 和下面一樣

<template><Layout title="我的" footerActive="my"><view class="my-page"><view class="my-header">我的</view><view class="my-content">歡迎來到我的頁面</view></view></Layout>
</template><script setup lang="ts">
import "./my.css";
import Layout from "@/layout/index.vue";
</script>

src/app.config.ts

// https://docs.taro.zone/docs/app-config
export default defineAppConfig({pages: ['pages/index/index', 'pages/my/my','pages/test/test',],tabBar: {custom: true,list: [{ pagePath: 'pages/index/index', text: '首頁' },{ pagePath: 'pages/test/test', text: '測試' },{ pagePath: 'pages/my/my', text: '我的' },]},window: {backgroundTextStyle: 'light',navigationBarBackgroundColor: '#fff',navigationBarTitleText: 'WeChat',navigationBarTextStyle: 'black'}
})

src/app.css

page{@apply h-full;
}

最終實現結果

請添加圖片描述

項目地址

https://github.com/template-space/taro-template-vue

后續功能接入

🔳taro-axiosAPI 采用模塊化導入方式
🔳上拉刷新、下拉加載
🔳子頁面分包,跳轉、攔截
🔳圖片、視頻、canvas、圖表echarts
🔳地圖
🔳…

敬請期待💥






到這里就結束了,后續還會更新 Taro、Vue 系列相關,還請持續關注!
感謝閱讀,若有錯誤可以在下方評論區留言哦!!!

111



推薦文章👇

uniapp-vue3-vite 搭建小程序、H5 項目模板

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/95702.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/95702.shtml
英文地址,請注明出處:http://en.pswp.cn/web/95702.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

ITU-R P.372 無線電噪聲預測庫調用方法

代碼功能概述&#xff08;ITURNoise.c&#xff09;該代碼是一個 ITU-R P.372 無線電噪聲預測 的計算程序&#xff0c;能夠基于 月份、時間、頻率、地理位置、人為噪聲水平 計算特定地點的 大氣噪聲、銀河噪聲、人為噪聲及其總和&#xff0c;并以 CSV 或標準輸出 方式提供結果。…

《從報錯到運行:STM32G4 工程在 Keil 中的頭文件配置與調試實戰》

《從報錯到運行&#xff1a;STM32G4 工程在 Keil 中的頭文件配置與調試實戰》文章提綱一、引言? 闡述 STM32G4 在嵌入式領域的應用價值&#xff0c;說明 Keil 是開發 STM32G4 工程的常用工具? 指出頭文件配置是 STM32G4 工程在 Keil 中開發的關鍵基礎環節&#xff0c;且…

Spring 事務提交成功后執行額外邏輯

1. 場景與要解決的問題在業務代碼里&#xff0c;常見訴求是&#xff1a;只有當數據庫事務真正提交成功后&#xff0c;才去執行某些“后置動作”&#xff0c;例如&#xff1a;發送 MQ、推送消息、寫審計/埋點日志、刷新緩存、通知外部系統等。如果這些動作在事務提交前就執行&am…

Clickhouse MCP@Mac+Cherry Studio部署與調試

一、需求背景 已經部署測試了Mysql、Drois的MCP Server,想進一步測試Clickhouse MCP的表現。 二、環境 1)操作系統 MacOS+Apple芯片 2)Clickhouse v25.7.6.21-stable、Clickhouse MCP 0.1.11 3)工具Cherry Studio 1.5.7、Docker Desktop 4.43.2(199162) 4)Python 3.1…

Java Serializable 接口:明明就一個空的接口嘛

對于 Java 的序列化,我之前一直停留在最淺層次的認知上——把那個要序列化的類實現 Serializbale 接口就可以了嘛。 我似乎不愿意做更深入的研究,因為會用就行了嘛。 但隨著時間的推移,見到 Serializbale 的次數越來越多,我便對它產生了濃厚的興趣。是時候花點時間研究研…

野火STM32Modbus主機讀取寄存器/線圈失敗(三)-嘗試將存貯事件的地方改成數組(非必要解決方案)(附源碼)

背景 盡管crc校驗正確了&#xff0c;也成功發送了EV_MASTER_EXECUTE事件&#xff0c;但是eMBMasterPoll( void )中總是接收的事件是EV_MASTER_FRAME_RECEIVED或者EV_MASTER_FRAME_SENT&#xff0c;一次都沒有執行EV_MASTER_EXECUTE。EV_MASTER_EXECUTE事件被別的事件給覆蓋了&…

微信小程序校園助手程序(源碼+文檔)

源碼題目&#xff1a;微信小程序校園助手程序&#xff08;源碼文檔&#xff09;?? 文末聯系獲取&#xff08;含源碼、技術文檔&#xff09;博主簡介&#xff1a;10年高級軟件工程師、JAVA技術指導員、Python講師、文章撰寫修改專家、Springboot高級&#xff0c;歡迎高校老師、…

59-python中的類和對象、構造方法

1. 認識一下對象 世間萬物皆是"對象" student_1{ "姓名":"小樸", "愛好":"唱、跳、主持" ......... }白紙填寫太落伍了 設計表格填寫先進一些些 終極目標是程序使用對象去組織數據程序中設計表格&#xff0c;我們稱為 設計類…

向成電子驚艷亮相2025物聯網展,攜工控主板等系列產品引領智造新風向

2025年8月27-29日&#xff0c;IOTE 2025 第二十四屆國際物聯網展深圳站在深圳國際會展中心&#xff08;寶安&#xff09;盛大啟幕&#xff01;作為全球規模領先的物聯網盛會之一&#xff0c;本屆展會以“生態智能&#xff0c;物聯全球”為核心&#xff0c;匯聚超1000家全球頭部…

陣列信號處理之均勻面陣波束合成方向圖的繪制與特點解讀

陣列信號處理之均勻面陣波束合成方向圖的繪制與特點解讀 文章目錄前言一、方向圖函數二、方向圖繪制三、副瓣電平四、陣元個數對主瓣寬度的影響五、陣元間距對主瓣寬度的影響六、MATLAB源代碼總結前言 \;\;\;\;\;均勻面陣&#xff08;Uniform Planar Array&#xff0c;UPA&…

算法在前端框架中的集成

引言 算法是前端開發中提升性能和用戶體驗的重要工具。隨著 Web 應用復雜性的增加&#xff0c;現代前端框架如 React、Vue 和 Angular 提供了強大的工具集&#xff0c;使得將算法與框架特性&#xff08;如狀態管理、虛擬 DOM 和組件化&#xff09;無縫集成成為可能。從排序算法…

網絡爬蟲是自動從互聯網上采集數據的程序

網絡爬蟲是自動從互聯網上采集數據的程序網絡爬蟲是自動從互聯網上采集數據的程序&#xff0c;Python憑借其豐富的庫生態系統和簡潔語法&#xff0c;成為了爬蟲開發的首選語言。本文將全面介紹如何使用Python構建高效、合規的網絡爬蟲。一、爬蟲基礎與工作原理 網絡爬蟲本質上是…

Qt Model/View/Delegate 架構詳解

Qt Model/View/Delegate 架構詳解 Qt的Model/View/Delegate架構是Qt框架中一個重要的設計模式&#xff0c;它實現了數據存儲、數據顯示和數據編輯的分離。這種架構不僅提高了代碼的可維護性和可重用性&#xff0c;還提供了極大的靈活性。 1. 架構概述 Model/View/Delegate架構將…

光譜相機在手機行業的應用

在手機行業&#xff0c;光譜相機技術通過提升拍照色彩表現和擴展健康監測等功能&#xff0c;正推動攝像頭產業鏈升級&#xff0c;并有望在AR/VR、生物醫療等領域實現更廣泛應用。以下為具體應用場景及技術突破的詳細說明&#xff1a;?一、光譜相機在手機行業的應用場景??拍照…

FASTMCP中的Resources和Templates

Resources 給 MCP 客戶端/LLM 讀取的數據端點&#xff08;只讀、按 URI 索引、像“虛擬文件系統”或“HTTP GET”&#xff09;&#xff1b; Templates 可帶參數的資源路由&#xff08;URI 里占位符 → 運行函數動態生成內容&#xff09;。 快速要點 ? 用途&#xff1a;把文件…

OpenBMC之編譯加速篇

加快 OpenBMC 的編譯速度是一個非常重要的話題,因為完整的構建通常非常耗時(在高性能機器上也需要數十分鐘,普通電腦上可能長達數小時)。以下是從不同層面優化編譯速度的詳細策略,您可以根據自身情況組合使用。 一、核心方法:利用 BitBake 的緩存和共享機制(效果最顯著…

Kafka面試精講 Day 8:日志清理與數據保留策略

【Kafka面試精講 Day 8】日志清理與數據保留策略 在Kafka的高吞吐、持久化消息系統中&#xff0c;日志清理與數據保留策略是決定系統資源利用效率、數據可用性與合規性的關鍵機制。作為“Kafka面試精講”系列的第8天&#xff0c;本文聚焦于日志清理機制&#xff08;Log Cleani…

基于Hadoop的網約車公司數據分析系統設計(代碼+數據庫+LW)

摘 要 本系統基于Hadoop平臺&#xff0c;旨在為網約車公司提供一個高效的數據分析解決方案。隨著網約車行業的快速發展&#xff0c;平臺上產生的數據量日益增加&#xff0c;傳統的數據處理方式已無法滿足需求。因此&#xff0c;設計了一種基于Hadoop的大規模數據處理和分析方…

Python反向迭代完全指南:從基礎到高性能系統設計

引言&#xff1a;反向迭代的核心價值在數據處理和算法實現中&#xff0c;反向迭代是解決復雜問題的關鍵技術。根據2024年Python開發者調查報告&#xff1a;85%的鏈表操作需要反向迭代78%的時間序列分析依賴反向處理92%的樹結構遍歷需要后序/逆序訪問65%的加密算法使用反向計算P…

ClickHouse使用Docker部署

OLTP和OLAP介紹基本業務量到達分庫分表量級&#xff0c;則離不開數據大屏、推薦系統、畫像系統等搭建&#xff0c;需要搭建以上系統&#xff0c;則離不開海量數據進行存儲-分析-統計。 而海量數據下 TB、PB級別數據存儲&#xff0c;靠Mysql進行存儲-分析-統計無疑是災難。所以就…