部署完成的模板github链接:https://github.com/pantt/mpvue2-typescript
1.在微信公众平台注册申请AppID
2.安装开发者工具:在微信公众平台安装开发者工具,用于小程序调试
mpvue 继承自 Vue.js,其技术规范和语法特点与 Vue.js 保持一致。
# 全局安装 vue-cli
$ npm install --global vue-cli
# 创建一个基于 mpvue-quickstart 模板的新项目
$ vue init mpvue/mpvue-quickstart my-project
# 安装依赖
$ cd my-project
$ npm install
# 启动构建
$ npm run dev
此时mpvue版本应为2.x,webpack 3.x
截止目前(2019/2/26):
*mpvue暂不支持webpack4,mpvue-entry暂不支持mpvue 2.x
接下来,只需启动微信开发者工具,引入项目目录dist中的wx文件夹即可预览到简单的 mpvue 小程序。
# 安装 vue 与装饰器,mpvue-loader目前支持用TypeScript来写,功能还在完善中(WIP)。需要搭 配vue-property-decorator来使用。
$ npm install --save vue vue-property-decorator
# 安装 typescript
$ npm install --save [email protected]
# 安装 typescript 所需loader(注意存在版本兼容问题,需下载指定版本ts-loader与awesome-typescript-loader最新版目前不兼容webpack4以下版本)
$ npm install --save [email protected] [email protected]
# 安装声明文件@types/node @types/weixin-app
$ npm install --save @types/node @types/weixin-app
安装官方微信小程序定义文件:[[https://github.com/wechat-miniprogram/api-typings#微信小程序定义文件]]
此为微信小程序 API 的 TypeScript 类型定义文件,请时刻关注官方最新版本
$ npm install miniprogram-api-typings
找到resolve属性,在extensions参数中增加’.ts’:
// webpack.conf.js
resolve:
extensions: ['.js', '.vue', '.json','.ts'],
alias: {
'vue': 'mpvue',
'@': resolve('src'),
},
//...
}
添加对应的loader:
// webpack.conf.js
module.exports = {
//...
module: {
rules: [
{
test: /\.vue$/,
loader: 'mpvue-loader',
options: {
//...
ts: [ //添加对应vue的loader
'babel-loader',
{
// loader: 'ts-loader',
loader: 'awesome-typescript-loader',
options: {
// errorsAsWarnings: true,
useCache: true,
}
}
]
}
},
// ts文件的loader
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: [
'babel-loader',
{
loader: 'mpvue-loader',
options:Object.assign({checkMPEntry: true}, vueLoaderConfig)//与同级的js中对应项值一致
},
{
// loader: 'ts-loader',
loader: 'awesome-typescript-loader',
options: {
// errorsAsWarnings: true,
useCache: true,
}
}
]
},
]
// ...
}
TypeScript识别不了后缀为vue的文件,需要加入一个声明文件,在项目的src目录下新建一个名为vue-shim.d.ts的文件,在其中增加代码:
declare module "*.vue" {
import Vue from "vue";
export default Vue;
}
为了使用TypeScript我们需要给它指定一个配置,在项目根目录下新建一个名为tsconfig.json的文件,增加内容(示例,完整配置请查看https://www.tslang.cn/docs/handbook/tsconfig-json.html):
{
"compilerOptions": {
// 与 Vue 的浏览器支持保持一致
"target": "es2015",
// 这可以对 `this` 上的数据属性进行更严格的推断
"strict": true,
// 如果使用 webpack 2+ 或 rollup,可以利用 tree-shake:
"module": "es2015",
"moduleResolution": "node",
"baseUrl": "./",
"outDir": "./dist/",
"paths": {
"vue": [
"node_modules/mpvue"
],
"@/*": [
"src/*"
]
},
"types": [
"@types/weixin-app",//声明文件
"@types/node"
],
"allowJs": true,
"allowSyntheticDefaultImports": true,
"noImplicitAny": false,
"skipLibCheck": true,
"strictPropertyInitialization": false,
"experimentalDecorators": true
},
"include": [
"./src/**/*"
],
"exclude": [
"node_modules"
],
"typeAcquisition": {
"enable": true
}
}
// main.ts
import { Component, Emit, Inject, Model, Prop, Provide, Vue, Watch } from 'vue-property-decorator';
import { VueConstructor } from "vue";
interface IMpVue extends VueConstructor {
mpType: string
}
// 添加小程序hooks http://mpvue.com/mpvue/#_4
Component.registerHooks([
// app
'onLaunch', // 初始化
'onShow', // 当小程序启动,或从后台进入前台显示
'onHide', // 当小程序从前台进入后台
// pages
'onLoad', // 监听页面加载
'onShow', // 监听页面显示
'onReady', // 监听页面初次渲染完成
'onHide', // 监听页面隐藏
'onUnload', // 监听页面卸载
'onPullDownRefresh', // 监听用户下拉动作
'onReachBottom', // 页面上拉触底事件的处理函数
'onShareAppMessage', // 用户点击右上角分享
'onPageScroll', // 页面滚动
'onTabItemTap', //当前是 tab 页时, 点击 tab 时触发 (mpvue 0.0.16 支持)
])
Vue.config.productionTip = false
// 在这个地方引入是为了registerHooks先执行
const MyApp = require('./App.vue').default as IMpVue
const app = new Vue(MyApp)
app.$mount()
//webpack.conf.js
//...
//配置多入口
function getEntry (rootSrc) {
var map = {};
glob.sync(rootSrc + '/pages/**/main.ts')
.forEach(file => {
var key = relative(rootSrc, file).replace('.ts', '');
map[key] = file;
})
return map;
}
const appEntry = { app: resolve('./src/main.ts') }
const pagesEntry = getEntry(resolve('./src'), 'pages/**/main.ts')
const entry = Object.assign({}, appEntry, pagesEntry)
//...
这种方式的自动识别
//app.ts
import { Vue, Component } from 'vue-property-decorator'
declare module "vue/types/vue" {
interface Vue {
$mp: any;
}
}
// 必须使用装饰器的方式来指定components
@Component({
mpType: 'app', // mpvue特定
}as any)
class App extends Vue {
// app hook
onLaunch() {
let opt = this.$root.$mp.appOptions
}
onShow() {
}
onHide() {
}
mounted() { // vue hook
}
}
export default App
// index.ts
import { Vue, Component } from 'vue-property-decorator'
import Card from '@/components/card.vue' // mpvue目前只支持的单文件组件
// 必须使用装饰器的方式来指定component
@Component({
components: {
Card,
},
})
class Index extends Vue {
ver: number = 123
onShow() { // 小程序 hook
}
mounted() { // vue hook
}
}
export default Index
//main.ts
import Vue from 'vue'
import App from './index.vue'
const app = new Vue(App)
app.$mount()
From Card {{text}} {{ver}}
// card.ts
import { Vue, Component, Prop } from 'vue-property-decorator'
// 必须使用装饰器的方式来指定component
@Component
class Card extends Vue {
@Prop({ default: '1' }) //注意用法!
text: string;
ver: number = 2;
onShow() {
}
onHide() {
}
mounted() { // vue hook
}
}
export default Card