最近寫一個微信小程序的項(xiàng)目乙帮,由于是協(xié)同開發(fā),前期的搭建工作由另一個妹子完成极景,現(xiàn)在項(xiàng)目階段一完成了察净,為了備忘回顧,做一個階段性小結(jié)盼樟。
在寫小程序之前經(jīng)過對比最后采用了京東凹凸實(shí)驗(yàn)室開發(fā)的類react
框架Taro
氢卡,用框架的好處就不多說了,比直接寫原生小程序方便太多晨缴。數(shù)據(jù)管理采用的是封裝了redux
的dva
框架译秦,如果沒有學(xué)過的同學(xué)可以去看看文檔。先聲明篇幅比較長击碗,如果你需要筑悴,還請看完,相信一定有幫助延都,不想看的同學(xué)文末放了GitHub地址雷猪,自己去下睛竣。
附上文檔鏈接:
taro文檔:https://nervjs.github.io/taro/docs/README.html
dva文檔:https://dvajs.com/guide/
1.基礎(chǔ)步驟
// 全局安裝taro (cnpm為淘寶鏡像)
cnpm install -g @tarojs/cli
// 創(chuàng)建項(xiàng)目
taro init taro-demo
如下配置(推薦為項(xiàng)目配上ts
):
安裝與 react-redux API 幾乎一致的包 @tarojs/redux
cnpm install --save redux @tarojs/redux @tarojs/redux-h5 redux-thunk redux-logger
安裝dva
cnpm install --save dva-core dva-loading
-
dva-core
:封裝了 redux 和 redux-saga的一個插件 -
dva-loading
:管理頁面的loading狀態(tài)
2.整理項(xiàng)目文件
刪除
- 刪除
./src/page
文件夾下的index
文件夾
添加
- 在
./src
文件夾下添加如下文件夾(根據(jù)自己實(shí)際情況和項(xiàng)目需求進(jìn)行配置晰房,只羅列一些必要的):
assets
:靜態(tài)資源,如images射沟、scss殊者、iconfont...
components
:編寫共用組件
config
:項(xiàng)目配置文件
models
:dva插件model
函數(shù)引用或者共用的js
types
:公共typescript類型申明
utils
:封裝的插件
3.編寫插件(主要且常用的)
1.在./src/config
下創(chuàng)建index.ts
,添加項(xiàng)目配置信息验夯,例如:
/**
* 線上環(huán)境
* 為了方便測試猖吴,使用的是聚合數(shù)據(jù)免費(fèi)接口
* 網(wǎng)址:https://www.juhe.cn/
*/
export const ONLINEHOST = 'http://api.juheapi.com'
/**
* 測試環(huán)境
*/
export const QAHOST = 'http://xxx.cn'
/**
* 線上mock
*/
export const MOCKHOST = 'http://xxx/mock'
/**
* 是否mock
*/
export const ISMOCK = false
/**
* 當(dāng)前的host ONLINEHOST | QAHOST | MOCKHOST
*/
export const MAINHOST = ONLINEHOST
/**
* 全局的分享信息 不用每一個都去寫
*/
export const SHAREINFO = {
'title': '分享標(biāo)題',
'path': '路徑',
'imageUrl': '圖片'
}
2.在./src/utils
下創(chuàng)建dva.ts
,配置dva挥转,內(nèi)容如下:
import { create } from 'dva-core';
import { createLogger } from 'redux-logger';
import createLoading from 'dva-loading';
let app
let store
let dispatch
let registered
function createApp(opt) {
// redux日志
opt.onAction = [createLogger()]
app = create(opt)
app.use(createLoading({}))
if (!registered) opt.models.forEach(model => app.model(model))
registered = true
app.start()
store = app._store
app.getStore = () => store
app.use({
onError(err) {
console.log(err)
},
})
dispatch = store.dispatch
app.dispatch = dispatch
return app
}
export default {
createApp,
getDispatch() {
return app.dispatch
}
}
3.在./src/config
下創(chuàng)建requestConfig.ts
海蔽,統(tǒng)一配置請求接口共屈,內(nèi)容如下:
/**
* 請求的公共參數(shù)
*/
export const commonParame = {}
/**
* 請求映射文件
*/
export const requestConfig = {
loginUrl: '/api/user/wechat-auth', // 微信登錄接口
}
5.在./src/utils
下創(chuàng)建tips.ts
,整合封裝微信原生彈窗党窜,內(nèi)容如下:
import Taro from '@tarojs/taro'
/**
* 提示與加載工具類
*/
export default class Tips {
static isLoading = false
/**
* 信息提示
*/
static toast(title: string, onHide?: () => void) {
Taro.showToast({
title: title,
icon: 'none',
mask: true,
duration: 1500
});
// 隱藏結(jié)束回調(diào)
if (onHide) {
setTimeout(() => {
onHide();
}, 500);
}
}
/**
* 彈出加載提示
*/
static loading(title = '加載中', force = false) {
if (this.isLoading && !force) {
return
}
this.isLoading = true
if (Taro.showLoading) {
Taro.showLoading({
title: title,
mask: true
})
} else {
Taro.showNavigationBarLoading()
}
}
/**
* 加載完畢
*/
static loaded() {
let duration = 0
if (this.isLoading) {
this.isLoading = false
if (Taro.hideLoading) {
Taro.hideLoading()
} else {
Taro.hideNavigationBarLoading()
}
duration = 500
}
// 隱藏動畫大約500ms拗引,避免后面直接toast時的顯示bug
return new Promise(resolve => setTimeout(resolve, duration))
}
/**
* 彈出提示框
*/
static success(title, duration = 1500) {
Taro.showToast({
title: title,
icon: 'success',
mask: true,
duration: duration
});
if (duration > 0) {
return new Promise(resolve => setTimeout(resolve, duration));
}
}
}
5.在./src/utils
下創(chuàng)建common.ts
,共用函數(shù)幌衣,內(nèi)容如下:
/** 時間格式的轉(zhuǎn)換 */
export const formatTime = time => {
`${pad(time.getHours())}:${pad(time.getMinutes())}:${pad(time.getSeconds())}.${pad(time.getMilliseconds(), 3)}`
}
export var globalData: any = {} // 全局公共變量
6.在./src/utils
下創(chuàng)建logger.ts
矾削,封裝log函數(shù),內(nèi)容如下:
import {
formatTime
} from './common'
const defaults = {
level: 'log',
logger: console,
logErrors: true,
colors: {
title: 'inherit',
req: '#9E9E9E',
res: '#4CAF50',
error: '#F20404',
}
}
function printBuffer(logEntry, options) {
const {
logger,
colors
} = options;
let {
title,
started,
req,
res
} = logEntry
// Message
const headerCSS = ['color: gray; font-weight: lighter;']
const styles = s => `color: ${s}; font-weight: bold`
// render
logger.group(`%c ${title} @${formatTime(started)}`, ...headerCSS)
logger.log('%c req', styles(colors.req), req)
logger.log('%c res', styles(colors.res), res)
logger.groupEnd()
}
interface LogEntry {
started?: object // 觸發(fā)時間
}
function createLogger(options: LogEntry = {}) {
const loggerOptions = Object.assign({}, defaults, options)
const logEntry = options
logEntry.started = new Date()
printBuffer(logEntry, Object.assign({}, loggerOptions))
}
export {
defaults,
createLogger,
}
7.在./src/utils
下創(chuàng)建request.ts
豁护,封裝http請求哼凯,內(nèi)容如下:
import Taro, { Component } from '@tarojs/taro'
import {
ISMOCK,
MAINHOST
} from '../config'
import {
commonParame,
requestConfig
} from '../config/requestConfig'
import Tips from './tips'
// import { createLogger } from './logger'
declare type Methods = "GET" | "OPTIONS" | "HEAD" | "POST" | "PUT" | "DELETE" | "TRACE" | "CONNECT";
declare type Headers = { [key: string]: string };
declare type Datas = { method: Methods;[key: string]: any; };
interface Options {
url: string;
host?: string;
method?: Methods;
data?: Datas;
header?: Headers;
}
export class Request {
//登陸的promise
static loginReadyPromise: Promise<any> = Promise.resolve()
// 正在登陸
static isLogining: boolean = false
// 導(dǎo)出的api對象
static apiLists: { [key: string]: () => any; } = {}
// token
static token: string = ''
// constructor(setting) {
// }
/**
* @static 處理options
* @param {Options | string} opts
* @param {Datas} data
* @returns {Options}
* @memberof Request
*/
static conbineOptions(opts, data: Datas, method: Methods): Options {
typeof opts === 'string' && (opts = { url: opts })
return {
data: { ...conmomPrams, ...opts.data, ...data },
method: opts.method || data.method || method || 'GET',
url: `${opts.host || MAINHOST}${opts.url}`
}
}
static getToken() {
!this.token && (this.token = Taro.getStorageSync('token'))
return this.token
}
/**
*
* @static request請求 基于 Taro.request
* @param {Options} opts
*/
static async request(opts: Options) {
// token不存在
// if (!this.getToken()) { await this.login() }
// token存在
// let options = Object.assign(opts, { header: { 'token': this.getToken() } })
// Taro.request 請求
const res = await Taro.request(opts)
// 是否mock
if (ISMOCK) { return res.data }
// 登陸失效
if (res.data.code === 99999) { await this.login(); return this.request(opts) }
// 請求成功
// if (res.data && res.data.code === 0 || res.data.succ === 0) { return res.data }
if (res.data) { return res.data }
// 請求錯誤
const d = { ...res.data, err: (res.data && res.data.msg) || `網(wǎng)絡(luò)錯誤~` }
Tips.toast(d.err);
throw new Error(d.err)
}
/**
*
* @static 登陸
* @returns promise
* @memberof Request
*/
static login() {
if (!this.isLogining) { this.loginReadyPromise = this.onLogining() }
return this.loginReadyPromise
}
/**
*
* @static 登陸的具體方法
* @returns
* @memberof Request
*/
static onLogining() {
this.isLogining = true
return new Promise(async (resolve, reject) => {
// 獲取code
const { code } = await Taro.login()
// 請求登錄
const { data } = await Taro.request({
url: `${MAINHOST}${requestConfig.loginUrl}`,
data: { code: code }
})
if (data.code !== 0 || !data.data || !data.data.token) {
reject()
return
}
Taro.setStorageSync('token', data.data.token)
this.isLogining = false
resolve()
})
}
/**
*
* @static 創(chuàng)建請求函數(shù)
* @param {(Options | string)} opts
* @returns
* @memberof Request
*/
static creatRequests(opts: Options | string): () => {} {
return async (data = {}, method: Methods = "GET") => {
const _opts = this.conbineOptions(opts, data, method)
const res = await this.request(_opts)
// createLogger({ title: 'request', req: _opts, res: res })
return res
}
}
/**
*
* @static 拋出整個項(xiàng)目的api方法
* @returns
* @memberof Request
*/
static getApiList(requestConfig) {
if (!Object.keys(requestConfig).length) return {}
Object.keys(requestConfig).forEach((key) => {
this.apiLists[key] = this.creatRequests(requestConfig[key])
})
return this.apiLists
}
}
// 導(dǎo)出
const Api = Request.getApiList(requestConfig)
Component.prototype.$api = Api
export default Api as any
Tip
:這時候tslint會報這樣的錯:類型“Component<any, any>”上不存在屬性“$api”。
楚里,因?yàn)槲覀儧]有添加聲明断部,我們可以這樣解決,在./src
目錄下創(chuàng)建app-shim.d.ts
腻豌,內(nèi)容如下:
/**
*
* @static 添加taro等自定義類型
* @interface Component
*/
import Taro, { Component } from '@tarojs/taro'
// 在Component上定義自定義方法類型
declare module '@tarojs/taro' {
interface Component {
$api: any
}
}
//聲明
declare var require: any
declare var dispach: any
這時候應(yīng)該不報錯了家坎。
8.在./src/config
下創(chuàng)建taroConfig.ts
,封裝taro小程序的一些方法吝梅,內(nèi)容如下:
/**
* 進(jìn)行taro的處理
* 1.方法的改寫
* 2.utils的掛載
*
*/
import Taro, { Component } from "@tarojs/taro";
import { SHAREINFO } from '../config/index'
/**
* navigateTo 超過8次之后 強(qiáng)行進(jìn)行redirectTo 否則會造成頁面卡死
*
*/
const nav = Taro.navigateTo
Taro.navigateTo = (data) => {
if (Taro.getCurrentPages().length > 8) {
return Taro.redirectTo(data)
}
return nav(data)
}
/**
* Component掛載分享方法
*/
Component.prototype.onShareAppMessage = function () {
return SHAREINFO
}
4.編寫node命令快速創(chuàng)建page
和component
先來看一張圖虱疏,就明白為什么需要編寫這樣一個命令了
當(dāng)你每次需要創(chuàng)建一個頁面的時候需要不斷的創(chuàng)建,這樣太麻煩了苏携,而且容易出錯做瞪,所以寫個node命令快速生成如圖中index文件夾下的5個文件,一條命令的事情右冻,下面上代碼:
首先在
根目錄
下創(chuàng)建scripts
文件夾装蓬,在該文件夾下添加如下文件:
- 添加
./scripts/template.js
,內(nèi)容如下:
/**
* pages頁面快速生成腳本
* 用法:npm run tep `文件名`
*/
const fs = require('fs');
const dirName = process.argv[2];
const capPirName = dirName.substring(0, 1).toUpperCase() + dirName.substring(1);
if (!dirName) {
console.log('文件夾名稱不能為空纱扭!');
console.log('示例:npm run tep test');
process.exit(0);
}
//頁面模板
const indexTep = `
import Taro, { Component, Config } from '@tarojs/taro'
import { View } from '@tarojs/components'
// import { connect } from '@tarojs/redux'
// import Api from '../../utils/request'
// import Tips from '../../utils/tips'
import { ${capPirName}Props, ${capPirName}State } from './${dirName}.interface'
import './${dirName}.scss'
// import { } from '../../components'
// @connect(({ ${dirName} }) => ({
// ...${dirName},
// }))
class ${capPirName} extends Component<${capPirName}Props,${capPirName}State > {
config:Config = {
navigationBarTitleText: '標(biāo)題'
}
constructor(props: ${capPirName}Props) {
super(props)
this.state = {}
}
componentDidMount() {
}
render() {
return (
<View className='${dirName}-wrap'>
</View>
)
}
}
export default ${capPirName}
`
// scss文件模版
const scssTep = `
${dirName}-wrap {
width: 100%;
min-height: 100vh;
}
`
// config 接口地址配置模板
const configTep = `
export default {
test: '/wechat/perfect-info', //xxx接口
}
`
// 接口請求模板
const serviceTep = `
import Api from '../../utils/request'
export const testApi = data => Api.test(
data
)
`
//model模板
const modelTep = `
// import Taro from '@tarojs/taro';
import * as ${dirName}Api from './service';
export default {
namespace: '${dirName}',
state: {
},
effects: {},
reducers: {}
}
`
const interfaceTep = `
/**
* ${dirName}.state 參數(shù)類型
*
* @export
* @interface ${capPirName}State
*/
export interface ${capPirName}State {}
/**
* ${dirName}.props 參數(shù)類型
*
* @export
* @interface ${capPirName}Props
*/
export interface ${capPirName}Props {}
`
fs.mkdirSync(`./src/pages/${dirName}`); // mkdir $1
process.chdir(`./src/pages/${dirName}`); // cd $1
fs.writeFileSync(`${dirName}.tsx`, indexTep); //tsx
fs.writeFileSync(`${dirName}.scss`, scssTep); // scss
fs.writeFileSync('config.ts', configTep); // config
fs.writeFileSync('service.ts', serviceTep); // service
fs.writeFileSync('model.ts', modelTep); // model
fs.writeFileSync(`${dirName}.interface.ts`, interfaceTep); // interface
process.exit(0);
- 添加
./scripts/component.js
牍帚,內(nèi)容如下:
/**
* pages頁面快速生成腳本
* 用法:npm run com `文件名`
*/
const fs = require('fs');
const dirName = process.argv[2];
const capPirName = dirName.substring(0,1).toUpperCase() + dirName.substring(1);
if (!dirName) {
console.log('文件夾名稱不能為空!');
console.log('示例:npm run com test');
process.exit(0);
}
//頁面模板
const indexTep = `import Taro, { Component } from '@tarojs/taro'
import { View } from '@tarojs/components'
import { ${capPirName}Props, ${capPirName}State } from './${dirName}.interface'
import './${dirName}.scss'
class ${capPirName} extends Component<${capPirName}Props,${capPirName}State > {
constructor(props: ${capPirName}Props) {
super(props)
this.state = {}
}
static options = {
addGlobalClass: true
}
static defaultProps:${capPirName}Props = {}
render() {
return (
<View className='fx-${dirName}-wrap'>
</View>
)
}
}
export default ${capPirName}
`
// scss文件模版
const scssTep = `
${dirName}-wrap {
width: 100%;
}
`
const interfaceTep = `
/**
* ${dirName}.state 參數(shù)類型
*
* @export
* @interface ${capPirName}State
*/
export interface ${capPirName}State {}
/**
* ${dirName}.props 參數(shù)類型
*
* @export
* @interface ${capPirName}Props
*/
export interface ${capPirName}Props {}
`
fs.mkdirSync(`./src/components/${dirName}`); // mkdir $1
process.chdir(`./src/components/${dirName}`); // cd $1
fs.writeFileSync(`${dirName}.tsx`, indexTep); //tsx
fs.writeFileSync(`${dirName}.scss`, scssTep); // scss
fs.writeFileSync(`${dirName}.interface.ts`, interfaceTep); // interface
Tip
:最后也是重點(diǎn)乳蛾,記得在根目錄的package.json
的scripts
里加上如下內(nèi)容:
"scripts": {
...
"tep": "node scripts/template",
"com": "node scripts/component"
}
5.編寫業(yè)務(wù)代碼
上面4個步驟基本已經(jīng)配置完了暗赶,接下去進(jìn)入正題,可以愉快的擼代碼了肃叶。
運(yùn)行我們上面寫的快速生成腳本蹂随,在命令行里輸入:
cnpm run tep index
ok,這時候tslint應(yīng)該不報找不到index的錯了因惭,可以看到我們page
文件夾下生成了一個index
的文件夾岳锁,里面包含config.ts
、index.interface.ts
蹦魔、index.scss
激率、index.tsx
咳燕、model.ts
、service.ts
1.改寫./src/app.tsx
首先先下載taro的@tarojs/async-await
乒躺,在命令行輸入如下:
cnpm i --save @tarojs/async-await
下載完了之后迟郎,按照如下改寫app.tsx
import Taro, { Component, Config } from "@tarojs/taro";
import "@tarojs/async-await";
import { Provider } from "@tarojs/redux";
import "./utils/request";
import Index from "./pages/index";
import dva from './utils/dva'
import models from './models'
import './app.scss'
import { globalData } from "./utils/common";
const dvaApp = dva.createApp({
initialState: {},
models: models,
});
const store = dvaApp.getStore();
class App extends Component {
config: Config = {
pages: [
'pages/index/index'
],
window: {
backgroundTextStyle: 'light',
navigationBarBackgroundColor: '#fff',
navigationBarTitleText: 'WeChat',
navigationBarTextStyle: 'black'
}
}
/**
*
* 1.小程序打開的參數(shù) globalData.extraData.xx
* 2.從二維碼進(jìn)入的參數(shù) globalData.extraData.xx
* 3.獲取小程序的設(shè)備信息 globalData.systemInfo
* @memberof App
*/
async componentDidMount() {
// 獲取參數(shù)
const referrerInfo = this.$router.params.referrerInfo;
const query = this.$router.params.query;
!globalData.extraData && (globalData.extraData = {});
if (referrerInfo && referrerInfo.extraData) {
globalData.extraData = referrerInfo.extraData;
}
if (query) {
globalData.extraData = {
...globalData.extraData,
...query
};
}
// 獲取設(shè)備信息
const sys = await Taro.getSystemInfo();
sys && (globalData.systemInfo = sys);
}
componentDidShow() { }
componentDidHide() { }
componentDidCatchError() { }
// 在 App 類中的 render() 函數(shù)沒有實(shí)際作用
// 請勿修改此函數(shù)
render() {
return (
<Provider store={store}>
<Index />
</Provider>
)
}
}
Taro.render(<App />, document.getElementById('app'))
發(fā)現(xiàn)tslint
報找不到模塊“./models”。
這樣的錯聪蘸,不要急宪肖,我們在./models
文件夾下創(chuàng)建index.ts
這樣一個文件夾,內(nèi)容如下:
import index from '../pages/index/model';// index 頁面的model
// 這里記得export的是數(shù)組健爬,不是對象
export default [
index
]
可以發(fā)現(xiàn)控乾,tslint
已經(jīng)不報錯了。
2.改寫./src/pages/index/config.ts
export default {
getLists: '/japi/toh', // 獲取歷史上的今天接口
}
3.在./src/config/requestConfig.ts
引入上面配置的接口娜遵,如下修改:
import index from '../pages/index/config' // index接口
/**
* 請求的公共參數(shù)
*/
export const commonParame = {}
/**
* 請求映射文件
*/
export const requestConfig = {
loginUrl: '/api/user/wechat-auth', // 微信登錄接口
...index
}
4.改寫./src/pages/index/service.ts
蜕衡,如下:
import Api from '../../utils/request'
export const getLists = (data) => {
return Api.getLists(data)
}
5.改寫./src/pages/index/index.interface.ts
,如下:
/**
* index.state 參數(shù)類型
*
* @export
* @interface IndexState
*/
export interface IndexState {
month: number
day: number
}
/**
* index.props 參數(shù)類型
*
* @export
* @interface IndexProps
*/
export interface IndexProps {
dispatch?: any,
data?: Array<DataInterface>
}
export interface DataInterface {
day: number
des: string
lunar: string
month: number
pic: string
title: string
year: number
_id: string
}
6.改寫./src/pages/index/model.ts
设拟,如下:
// import Taro from '@tarojs/taro';
import * as indexApi from './service';
export default {
namespace: 'index',
state: {
data: [],
key: '72eed010c976e448971655b56fc2324e',
v: '1.0'
},
effects: {
* getLists({ payload }, { select, call, put }) {
const { key, v } = yield select(state => state.index)
const { error, result } = yield call(indexApi.getLists, {
key,
v,
...payload
})
if (!error) {
yield put({
type: 'updateState',
payload: {
data: result
}
})
}
}
},
reducers: {
updateState(state, { payload: data }) {
return { ...state, ...data }
}
}
}
7.改寫./src/pages/index/index.tsx
慨仿,如下:
import Taro, { Component, Config } from '@tarojs/taro'
import { View, Text } from '@tarojs/components'
import { connect } from '@tarojs/redux'
// import Api from '../../utils/request'
// import Tips from '../../utils/tips'
import { IndexProps, IndexState } from './index.interface'
import './index.scss'
// import { } from '../../components'
@connect(({ index }) => ({
...index,
}))
class Index extends Component<IndexProps, IndexState> {
config: Config = {
navigationBarTitleText: 'Taro + dva demo'
}
constructor(props: IndexProps) {
super(props)
this.state = {
month: 0,
day: 0
}
}
// 獲取今日數(shù)據(jù)
async getData(month: number, day: number) {
await this.props.dispatch({
type: 'index/getLists',
payload: {
month: month,
day: day
}
})
}
// 獲取系統(tǒng)當(dāng)前時間并請求參數(shù)
getDate() {
const myDate = new Date()
const m = myDate.getMonth() + 1
const d = myDate.getDate()
this.setState({
month: m,
day: d
})
this.getData(m, d)
}
componentDidMount() {
this.getDate()
}
render() {
const { month, day } = this.state
const { data } = this.props
return (
<View className='fx-index-wrap'>
<View className='index-topbar'>
<Text>{`${month}月${day}日`}</Text>
<View>歷史上的今天都發(fā)生了這些大事</View>
</View>
<View className='index-list'>
{
data && data.map((item, index) => {
return <View className='index-li' key={index}>
<View className='index-bg' style={`background-image: url(${item.pic})`}></View>
<View className='index-info'>
<View className='index-title'>{item.title}</View>
<View className='index-des'>{item.des}</View>
</View>
</View>
})
}
</View>
</View>
)
}
}
export default Index
5.接下來寫樣式./src/pages/index/index.scss
,如下:
.index {
&-wrap {
width: 100%;
min-height: 100vh;
}
&-topbar {
padding: 10rpx 50rpx;
text-align: center;
font-weight: bold;
Text {
color: rgb(248, 122, 3);
font-size: 40rpx;
}
View {
color: #333;
font-size: 30rpx;
}
}
&-list {
padding: 50rpx;
}
&-li {
box-shadow: 0 4rpx 20rpx rgba($color: #000000, $alpha: 0.1);
margin-bottom: 50rpx;
border-radius: 8rpx;
overflow: hidden;
}
&-bg {
width: 100%;
height: 300rpx;
background-repeat: no-repeat;
background-size: contain;
background-position: center center;
background-color: #f5f5f5;
}
&-info {
padding: 15rpx;
}
&-title {
font-size: 30rpx;
font-weight: bold;
margin-bottom: 10rpx;
}
&-des {
font-size: 26rpx;
color: #666;
}
}
這時候基本結(jié)束了纳胧,在命令行運(yùn)行:
cnpm run dev:weapp
如下顯示镰吆,說明編譯成功(tip
:以后記得先編譯,我是之前寫好了的跑慕,不然很有可能一堆報錯万皿,那時候估計(jì)你會絕望的)
最后的最后,打開微信開發(fā)者工具核行,選擇微信小程序牢硅,選擇taro-demo文件夾下編譯成功的
dist
,appid就用微信提供給你測試的芝雪,名字隨便輸入一個减余,點(diǎn)擊確定,之前步驟都沒問題的話惩系,最后顯示的結(jié)果如下圖:最后位岔,恭喜你,配置完了蛆挫,可以滿足基本開發(fā)和需求了赃承,如果有什么錯誤還望指出
妙黍。