用白鷺開發H5小遊戲有一段時間了,也開發了幾款H5小遊戲,這篇文章主要整理下開發過程的一些經驗以及本身逐漸封裝出來的一個開發腳手架。vue
直接使用EgretLauncher建立一個項目 git
整個文件刪除掉,等會咱們再建立一個(至關於一個page,加載頁面)github
先在項目src目錄下建立一些文件夾,以下:web
┗src
┣━base
┃ ┗━存放一些基類
┣━common
┃ ┗━存放一些公共的類
┣━component
┃ ┗━存放一些組件
┣━data
┃ ┗━存放數據
┣━net
┃ ┗━api、網絡請求
┣━page
┃ ┗━頁面
┣━Main.ts----入口文件
┗━Platform.ts----一些變量等的聲明
複製代碼
項目大概就按上面的結構劃分,接下來就來寫一些基類、公共類等的實現vue-router
在base目錄下建立BaseView.ts文件,BaseView類繼承自egret.DisplayObjectContainer,能夠當成是一個view容器,主要是實現一些view(彈窗、頁面等)裏面常常須要用到的方法。typescript
class BaseView extends egret.DisplayObjectContainer {
/** * 加載框(可用於網絡請求前調用,或一些異步耗時操做前調用) */
private _loading: egret.DisplayObjectContainer
private _loadingIcon: egret.Bitmap
/** * 記錄是否彈出加載框 */
private isLoading: boolean = false
/** * 加載動畫 */
private loadingTween: egret.Tween
public constructor() {
super()
this.addEventListener(egret.Event.ADDED_TO_STAGE, this.onAddToStage, this)
}
/** * 被添加到舞臺 */
public onAddToStage(event: egret.Event) {
}
/** * 視圖銷燬 */
public onDestory() {
}
/** * 消息提示 */
protected toast(msg: string, duration = 2000, cb?: Function) {
// 後面會寫到如何封裝該Toast類
Toast.instance.show(msg, duration, cb)
}
/** * 顯示加載框 */
protected showLoading() {
if (this.isLoading) {
return
}
this.isLoading = true
if (!this._loading) {
this._loading = new egret.DisplayObjectContainer()
let bg = new egret.Shape()
bg.graphics.beginFill(0x000000, 1)
bg.graphics.drawRect(0, 0, this.width, this.height)
bg.graphics.endFill()
bg.alpha = 0.3
bg.touchEnabled = true
this._loading.addChild(bg)
}
if (!this._loadingIcon) {
this._loadingIcon = ResUtil.createBitmap('loading_icon') // 這是本身封裝的獲取bitmap的方法,後面會寫到
this._loadingIcon.width = 50
this._loadingIcon.height = 50
this._loadingIcon.anchorOffsetX = this._loadingIcon.width / 2
this._loadingIcon.anchorOffsetY = this._loadingIcon.height / 2
this._loadingIcon.x = this.width / 2
this._loadingIcon.y = this.height / 2
this._loading.addChild(this._loadingIcon)
}
egret.MainContext.instance.stage.addChild(this._loading)
this.loadingTween = egret.Tween
.get(this._loadingIcon, {loop: true})
.to({
rotation: 360
}, 500, egret.Ease.sineIn)
}
/** * 關閉加載框 */
protected closeLoading() {
if (!this.isLoading) {
return
}
if (this.loadingTween) {
this.loadingTween.setPaused(true)
}
this.loadingTween = null
egret.MainContext.instance.stage.removeChild(this._loading)
this.isLoading = false
}
}
複製代碼
在base目錄下建立BaseScene.ts文件,BaseScene類繼承自BaseView,遊戲通常以場景區分,好比開始場景、遊戲場景、結束場景等,這裏就理解爲頁面,因此建立一個場景基類,設置一些默認值,好比全屏寬高等,固然,可能部分場景不須要全屏,那能夠繼承BaseScene而後重寫寬高,或者使用BaseView。json
class BaseScene extends BaseView {
/**
* 場景名稱
*/
private _pageName: string = ''
public constructor(pageName: string = '') {
super()
this._pageName = pageName
// 設置場景寬高爲舞臺的寬高
this.width = GameUtil.getStageWidth()
this.height = GameUtil.getStageHeight()
// 防止頁面點擊穿透
this.touchEnabled = true
}
public get pageName() {
return this._pageName
}
/**
* 關於場景動畫部分,後面寫路由時會寫到
*/
/**
* 進入動畫執行結束
*/
public afterEnterAnimation() {
// console.log(this._pageName, 'afterEnterAnimation')
}
/**
* 離開動畫執行結束
*/
public afterLeaveAnimation() {
// console.log(this._pageName, 'afterLeaveAnimation')
}
}
複製代碼
咱們的場景基類就這麼簡單,之後若是還有通用的場景方法,能夠繼續添加到這個類中。 由於繼承自BaseView,因此場景中也能夠直接使用BaseView中封裝的public方法,好比:用 this.toast() 方法來彈出提示。axios
這是一個提示組件,在component目錄下建立Toast.ts文件,使用單例模式,統一管理提示。api
class ToastMsg { // 消息格式
public msg: string
public duration: number = 2000
public cb: Function
public constructor(msg, duration, cb) {
this.msg = msg
this.duration = duration
this.cb = cb
}
}
/** * 這是模仿Android中的Toast * 實現彈出消息提示,並自動關閉 */
class Toast {
/** * 消息列表 */
private _msgList: Array<ToastMsg> = new Array<ToastMsg>()
private _toasting: boolean = false
private _stage: egret.Stage // 舞臺
private _toastContainer: egret.DisplayObjectContainer
private _shapeBg: egret.Bitmap
public static toast: Toast
public constructor() {
// toast到舞臺上,保證消息顯示在最上層
this._stage = egret.MainContext.instance.stage
this._toastContainer = new egret.DisplayObjectContainer()
}
public static get instance() {
if (!this.toast) {
this.toast = new Toast()
}
return this.toast
}
public show(msg: string, duration = 2000, cb?: Function) {
// 將消息存進列表
this._msgList.push(new ToastMsg(msg, duration, cb))
// 若是當前在顯示消息,那麼不掉用顯示方法,裏面輪詢會調用到的
if (!this._toasting) {
this._toasting = true
this._show()
}
}
private _show() {
// 列表長度大於0,說明隊列中還有消息,繼續彈出
if(this._msgList.length > 0) {
// 獲取第一條消息
let msg = this._msgList.shift()
this._toastContainer.alpha = 0
// 建立文本
let textField: egret.TextField = new egret.TextField()
textField.text = msg.msg
textField.textAlign = 'center'
textField.textColor = 0xffffff
textField.size = 24
// 文本與黑色背景邊緣的寬度
let space = 40
// 若是文字寬度超過屏幕寬度的0.8倍,就設置一下(至關於設置外容器的最大寬度,暫時只想到這個辦法)
if (textField.textWidth >= GameUtil.getStageWidth() * 0.8) {
textField.width = GameUtil.getStageWidth() * 0.8 - space
}
// 設置裝文本的容器的寬高和錨點,文本的錨點
this._toastContainer.width = textField.width + space
this._toastContainer.height = textField.height + space
this._toastContainer.anchorOffsetX = this._toastContainer.width / 2
this._toastContainer.anchorOffsetY = this._toastContainer.height
textField.anchorOffsetX = textField.width / 2
textField.anchorOffsetY = textField.height / 2
textField.x = this._toastContainer.width / 2
textField.y = this._toastContainer.height / 2
// 容器的位置,在底部橫向居中
this._toastContainer.x = GameUtil.getStageWidth() / 2
this._toastContainer.y = GameUtil.getStageHeight() * 0.8
let shapeBg = new egret.Shape()
shapeBg.graphics.beginFill(0x000000, 1)
shapeBg.graphics.drawRoundRect(0, 0, this._toastContainer.width, this._toastContainer.height, 20, 20)
shapeBg.graphics.endFill()
this._toastContainer.addChild(shapeBg)
this._toastContainer.addChild(textField)
this._stage.addChild(this._toastContainer)
// 彈出和消失動畫
egret.Tween
.get(this._toastContainer)
.to({
alpha: 1
}, 200, egret.Ease.sineIn)
.wait(msg.duration) // 等待xxx毫秒後再消失
.to({
alpha: 0
}, 200, egret.Ease.sineIn)
.wait(100)
.call(()=> {
this._toastContainer.removeChild(shapeBg)
this._toastContainer.removeChild(textField)
this._stage.removeChild(this._toastContainer)
msg.cb && msg.cb()
this._show() // 繼續顯示下一條消息
}, this)
} else {
this._toasting = false
}
}
}
複製代碼
接下來建立一個工具類,方便用於獲取舞臺寬高等,在common中建立GameUtil.ts
/** * 工具類 */
/** * 工具類 */
class GameUtil {
public static isIos: boolean = /iphone|ipad|ipod/.test(navigator.userAgent.toLowerCase())
public static getTopStage(): egret.Stage {
return egret.MainContext.instance.stage
}
/** * 獲取舞臺高度 */
public static getStageHeight(): number {
return egret.MainContext.instance.stage.stageHeight
}
/* * 獲取舞臺寬度 */
public static getStageWidth(): number {
return egret.MainContext.instance.stage.stageWidth
}
// 是容器可點擊
public static tap(bitmap: egret.DisplayObject, callback, thisObject) {
bitmap.touchEnabled = true
bitmap.addEventListener(egret.TouchEvent.TOUCH_TAP, callback, thisObject)
}
// 建立圓角矩形
public static drawRoundRect(shape: egret.Shape, color: number, width: number, height: number, round: number, rArr: Array<number>) {
shape.graphics.clear()
shape.graphics.beginFill(color, 1)
shape.graphics.drawRoundRect(0, 0, width, height, round, round)
shape.graphics.endFill()
let roundArr: Array<number> = [0, 1, 2, 3].filter(item=> rArr.indexOf(item) === -1)
let rectData: Array<Array<number>> = [
[0, 0],
[1, 0],
[0, 1],
[1, 1]
]
for (let i = 0;i < roundArr.length;++i) {
let x = (width - round) * rectData[roundArr[i]][0]
let y = (height - round) * rectData[roundArr[i]][1]
shape.graphics.beginFill(color, 1)
shape.graphics.drawRect(x, y, round, round)
shape.graphics.endFill()
}
}
}
複製代碼
資源管理,用於獲取圖片等,在common中建立ResUtil.ts
class ResUtil {
private bitmapList: {[index: string]: egret.Texture} = {}
private movieClipList: {[index: string]: egret.MovieClip} = {}
private static resUtil: ResUtil
public static get instance() {
if (!this.resUtil) {
this.resUtil = new ResUtil()
}
return this.resUtil
}
/** * 加載網絡圖片 * item: { * url: 'xxxx' // 圖片地址 * xxxx // 本身附帶其餘參數 * } */
public static loadImageByUrl(item, callback) {
try {
RES.getResByUrl(item.url, (event)=> {
callback && callback({
status: 1,
event: event,
item: item
})
}, this, RES.ResourceItem.TYPE_IMAGE)
} catch (e) {
console.error(e)
callback && callback({
status: 0
})
}
}
/** * 建立圖片 * @param name * @param suffix */
public static createBitmap(name: string, suffix: string = 'png'): egret.Bitmap {
const key = `${name}_${suffix}`
let result = new egret.Bitmap()
if (!this.instance.bitmapList[key]) {
this.instance.bitmapList[key] = RES.getRes(key)
}
result.texture = this.instance.bitmapList[key]
return result
}
/** * 建立動圖 * @param name * @param suffix */
public static createMovieClip(name: string): egret.MovieClip {
let result = new egret.MovieClip()
if (!this.instance.movieClipList[name]) {
const data_stay: any = RES.getRes(name + '_json')
const texture_stay: egret.Texture = RES.getRes(name + '_png')
const mcFactory_stay: egret.MovieClipDataFactory = new egret.MovieClipDataFactory(data_stay, texture_stay)
this.instance.movieClipList[name] = new egret.MovieClip(mcFactory_stay.generateMovieClipData(name))
}
result.movieClipData = this.instance.movieClipList[name].movieClipData
return result
}
/** * 獲取動圖的最大寬高 * @param name * @param suffix */
public static getMoviceClipWH(name: string): {w: number, h: number} {
let mw = 0
let mh = 0
const movie = ResUtil.createMovieClip(name)
const tData = movie.movieClipData.textureData
for (let key in tData) {
mw = Math.max(tData[key].w, mw)
mh = Math.max(tData[key].h, mh)
}
return {
w: mw,
h: mh
}
}
}
複製代碼
有了以上一些基類,咱們還須要作一個頁面路由跳轉控制,這裏模仿vue-router的使用方法,本身實現一個簡單的Router,直接在src目錄下建立Router.ts文件。
class Router {
private static router: Router
private _stage: egret.DisplayObjectContainer // 場景容器
/** * 當前路由信息 */
private _route: {
name: string,
meta: any,
params: any,
scene: BaseScene
} = {name: '', meta: null, scene: null, params: null}
private _params: {
meta: any,
params: any,
} = {meta: null, params: null}
/** * 路由映射表 */
private _routeMap: SelfMap<{
className: any,
name: string,
meta: any,
params?: any
}> = new SelfMap<{
className: any,
name: string,
meta: any,
params?: any
}>()
/** * 頁面離開動畫 */
private _leaveAnimation: SelfAnimation
/** * 頁面進入動畫 */
private _enterAnimation: SelfAnimation
/** * */
private _beforeEach: Function = (to, from, next)=> {next()}
private constructor() {
}
public static get instance() {
if (!this.router) {
this.router = new Router()
}
return this.router
}
public static get params() {
return this.instance._params.params
}
public static get meta() {
return this.instance._params.meta
}
/** * 初始化,設置放置頁面的容器 */
public static init(main: egret.DisplayObjectContainer) {
if (this.instance._stage) {
console.log('已經建立過場景容器')
return
}
if (!main) {
console.log('主場景不能爲空')
return
}
// 建立一個新容器放在main上,專門用來存放頁面,這樣能保證toast一直在全部頁面上
this.instance._stage = new egret.DisplayObjectContainer()
main.addChild(this.instance._stage)
return this
}
/** * 註冊頁面 */
public static register(key: string, className: any, meta: any = null) {
this.instance._routeMap.put(key, {className: className, name: key, meta: meta})
return this
}
/** * 跳轉路由以前作的事 */
public static beforeEach(beforeEach: Function) {
this.instance._beforeEach = beforeEach
return this
}
/** * 設置頁面離開動畫 */
public static setLeaveAnimation(animation?: SelfAnimation) {
this.instance._leaveAnimation = animation
return this
}
/** * 設置頁面進入動畫 */
public static setEnterAnimation(animation?: SelfAnimation) {
this.instance._enterAnimation = animation
return this
}
/** * 退出頁面,有動畫就執行動畫 */
private leavePage(page: BaseScene, callback: Function, leaveAnimation: SelfAnimation) {
if (!page) {
callback && callback()
return
}
let animation = leaveAnimation || this._leaveAnimation
page.onDestory()
if (animation) {
animation.execute(page, ()=> {
callback && callback()
})
} else {
callback && callback()
}
}
/** * 加載頁面,有動畫就執行動畫 */
private enterPage(page: BaseScene, callback: Function, enterAnimation: SelfAnimation) {
let animation = enterAnimation || this._enterAnimation
if (animation) {
animation.beforeAnim(page)
}
this._stage.addChild(page)
if (animation) {
animation.execute(page, ()=> {
callback && callback()
})
} else {
callback && callback()
}
}
private _currentLeavePage: BaseScene = null
public static to(config: {
name: string,
params?: any,
leaveAnimation?: SelfAnimation,
enterAnimation?: SelfAnimation
}) {
let page = this.instance._routeMap.get(config.name)
if (page == undefined) {
console.error(`scene ${config.name} is not register`)
return
}
let currentRoute = this.instance._route
this.instance._beforeEach(page, currentRoute, (to: string = config.name)=> {
if (to != config.name) {
config.name = to
page = this.instance._routeMap.get(config.name)
if (page == undefined) {
console.error(`scene ${config.name} is not register`)
return
}
}
let currentLeavePage = this.instance._currentLeavePage
// 若是當前離開的頁面跟正要離開的頁面同樣,不執行
if (currentLeavePage && currentRoute.scene && currentLeavePage.pageName === currentRoute.scene.pageName) {
return
}
// 若是要進入的頁面跟當前頁面同樣,不執行
if (config.name === currentRoute.name) {
return
}
this.instance._currentLeavePage = currentRoute.scene
currentLeavePage = currentRoute.scene
this.instance.leavePage(currentRoute.scene, ()=> {
currentLeavePage && currentLeavePage.afterLeaveAnimation()
let newPage = new page.className(config.name)
this.instance._params.meta = page.meta
this.instance._params.params = config.params
this.instance.enterPage(newPage, ()=> {
currentLeavePage && this.instance._stage.removeChild(currentLeavePage)
currentLeavePage = this.instance._currentLeavePage = null
currentRoute.name = config.name
currentRoute.meta = page.meta
currentRoute.scene = newPage
currentRoute.params = config.params
newPage.afterEnterAnimation()
}, config.enterAnimation)
}, config.leaveAnimation)
})
}
}
複製代碼
其中用到了SelfMap和SelfAnimation都是本身實現的簡單的工具類,這裏就不介紹,能夠在源碼中查看。
在入口文件Main.ts的runGame方法中註冊路由
...
private async runGame() {
Router.init(this)
.setLeaveAnimation(new SelfAnimation().add({alpha: 0}, 300))// 設置頁面離開動畫
.setEnterAnimation(new Animation().init({alpha: 0}).add({alpha: 1}, 300)) // 設置頁面進入動畫
.register('loading', LoadingScene) // 註冊加載頁
.register('game', GameScene) // 註冊遊戲場景路由
.to({ // 跳轉到加載頁頁面
name: 'loading'
})
...
}
...
// 在其餘地方跳轉頁面能夠直接使用
// Router.to({name: xxxx})
複製代碼
主要用於顯示加載資源進度以及作一些初始化操做
class LoadingScene extends BaseScene {
private progressBar: egret.Shape
private progressText: egret.TextField
private barWidth: number = 0
private barHeight: number = 0
private startTime: number = 0
private preload: number = 2 // preload資源組的數量
private main: number = 100 - this.preload
public async onAddToStage() {
this.drawBg();
this.initProgress();
try {
this.startTime = new Date().getTime()
await RES.loadConfig(`resource/default.res.json?v=${Math.random()}`, "resource/")
await RES.loadGroup("preload", 0, {
onProgress: (current: number, total: number)=> {
let progress = current / total * this.preload
let width = this.barWidth * progress / 100
this.drawProgress(width, Math.floor(progress))
}
})
// 由於logo是圖片,須要等資源加載回來才能夠繪製
this.drawLogo();
this.load()
} catch(e) {
console.error(e)
}
}
private async load() {
await RES.loadGroup("main", 0, {
onProgress: (current: number, total: number)=> {
let progress = current / total * this.main + this.preload
let width = this.barWidth * progress / 100
this.drawProgress(width, Math.floor(progress))
}
})
}
private initProgress() {
this.barWidth = this.width * 0.6
this.barHeight = 20
this.progressBar = new egret.Shape()
this.progressBar.width = this.barWidth
this.progressBar.height = this.barHeight
this.progressBar.x = (this.width - this.barWidth) / 2
this.progressBar.y = (this.height - this.barHeight) / 2
this.addChild(this.progressBar)
this.progressText = new egret.TextField()
this.progressText.textColor = 0x005660
this.progressText.size = 28
this.progressText.strokeColor = 0xFFFFFF
this.progressText.stroke = 3
this.progressText.width = this.width
this.progressText.textAlign = 'center'
this.progressText.text = '0%'
this.progressText.y = this.progressBar.y - this.progressText.height - 20
this.addChild(this.progressText)
}
private drawProgress(width, progress) {
this.progressBar.graphics.clear()
this.progressBar.graphics.beginFill(0xFFFFFF, 1)
this.progressBar.graphics.drawRoundRect(0, 0, width, this.barHeight, this.barHeight, this.barHeight)
this.progressBar.graphics.endFill()
this.progressText.text = `${progress}%`
if (progress == 100) {
let diff = new Date().getTime() - this.startTime
diff = diff < 1000 ? (1000 - diff) : 300
egret.setTimeout(()=> {
// 加載完成跳轉到遊戲頁面
Router.to({name: 'game'})
}, this, diff)
}
}
private drawBg() {
let bg: egret.Shape = new egret.Shape();
bg.graphics.beginFill(0x56A1D2);
bg.graphics.drawRect(0, 0, this.width, this.height);
bg.graphics.endFill();
this.addChild(bg);
}
private drawLogo() {
let logo: egret.Bitmap = ResUtil.createBitmap('egret_icon');
logo.x = (this.width - logo.width) / 2
this.addChild(logo);
}
}
複製代碼
class GameScene extends BaseScene {
public async onAddToStage() {
let bg: egret.Bitmap = ResUtil.createBitmap('bg', 'jpg');
bg.width = this.width;
bg.height = this.height;
this.addChild(bg);
let btn: egret.Shape = new egret.Shape();
GameUtil.drawRoundRect(btn, 0xFFFFFF, 300, 100, 10, [0, 1, 2, 3]);
btn.x = (this.width - btn.width) / 2;
btn.y = (this.height - btn.height) / 2;
this.addChild(btn);
let btnText: egret.TextField = new egret.TextField();
btnText.text = '點擊';
btnText.textColor = 0x000000;
btnText.x = (this.width - btnText.width) / 2;
btnText.y = (this.height - btnText.height) / 2;
this.addChild(btnText);
GameUtil.tap(btn, ()=> {
this.toast('點擊按鈕');
}, this)
}
}
複製代碼
這裏使用的是egret.HttpRequest來封裝的,固然也能夠本身引入axios等框架。
在net目錄下建立Http.ts,對egret.HttpRequest封裝,支持promise
class Http {
private baseUrl: string = ''
public static http: Http
public static get instance() {
if (!this.http) {
this.http = new Http()
}
return this.http
}
private constructor() {
}
private request({method = egret.HttpMethod.GET, url, params = {}, headers = {}}): Promise<any> {
if (!(/http(|s):\/\//.test(url))) {
url = this.baseUrl + url
}
let _params: any = ''
let _headers = {}
_headers['Content-Type'] = 'application/x-www-form-urlencoded'
// 若是有傳入,則覆蓋掉
for (let key in headers) {
_headers[key] = headers[key]
}
if (_headers['Content-Type'] === 'application/json') {
_params = JSON.stringify(params)
_params = _params.replace(/\+/g, "%2B").replace(/\&/g, "%26")
// console.log(_params)
} else {
for (let key in params) {
_params += `${key}=${('' + params[key]).replace(/\&/g, "%26")}&`
}
_params = _params.replace(/\+/g, "%2B")
// console.log(_params)
if (_params.length > 0) {
_params = _params.substring(0, _params.length - 1)
}
if (method === egret.HttpMethod.GET) {
url += `?${_params}`
}
}
return new Promise((resolve, reject)=> {
let request = new egret.HttpRequest()
request.responseType = egret.HttpResponseType.TEXT
request.open(url, method)
for (let key in _headers) {
request.setRequestHeader(key, _headers[key])
}
if (method === egret.HttpMethod.GET) {
request.send()
} else {
request.send(_params)
}
request.addEventListener(egret.Event.COMPLETE, (event)=> {
dealResult(event)
}, this)
request.addEventListener(egret.IOErrorEvent.IO_ERROR, (event)=> {
dealResult(event, false)
}, this)
function dealResult(event, success = true) {
let response
try {
response = JSON.parse(request.response)
} catch(e) {
response = request.response
}
if (success) {
resolve(response)
} else {
reject(response)
}
}
})
}
public setBaseUrl(baseUrl: string) {
this.baseUrl = baseUrl
}
public get(url: string, params = {}, headers = {}): Promise<any> {
return this.request({
url: url,
params: params,
headers: headers
})
}
public post(url: string, params = {}, headers = {}): Promise<any> {
return this.request({
method: egret.HttpMethod.POST,
url: url,
params: params,
headers: headers
})
}
}
複製代碼
一樣在net目錄下建立Api.ts文件,用於管理本身的api接口
class Api {
private static api: Api
private constructor() {
let baseUrl: string = 'http://xxx.com'
if (DEBUG) {
baseUrl = 'http://localhost:3000'
}
Http.instance.setBaseUrl(baseUrl)
}
public static get instance() {
if (!this.api) {
this.api = new Api()
}
return this.api
}
/** * 統一處理結果 */
private predeal(http: Promise<any>): Promise<any> {
return http.then(response=> {
if (response.code == '0') {
// 這個結構根據本身的數據肯定
return Promise.resolve(response.payload.data || response.payload || response)
} else {
return Promise.reject(response)
}
})
.catch(response=> {
return Promise.reject(response.msg || '請求出錯')
})
}
/** * get */
private get(url: string, params = {}, headers = {}): Promise<any> {
return this.predeal(Http.instance.get(url, params, headers))
}
/** * post */
private post(url: string, params = {}, headers = {}): Promise<any> {
return this.predeal(Http.instance.post(url, params, headers))
}
/** * get例子 */
public getInfo(): Promise<any> {
return this.get('/info')
}
/** * post例子 */
public postInfo(params): Promise<any> {
return this.post('/info', params)
}
}
複製代碼
如今H5基本都離不開bgm等音樂的播放,所以,腳手架也封裝了一個音頻管理類,方便使用,這個寫得比較粗糙,還須要優化。具體代碼在項目中可查看。
封裝了CacheStorge類,用於管理localstorage存儲數據,可直接保存獲取對象等數據,詳見common/CacheStorge.ts文件
引入外部js庫,須要特殊處理,這裏處理過,能夠參照項目,在添加lib目錄裏的wxjssdk,而且在egretProperties.json的modules裏面配置路徑
{
"engineVersion": "5.2.17",
"compilerVersion": "5.2.17",
"template": {},
"target": {
"current": "web"
},
"modules": [
{
"name": "egret"
},
{
"name": "game"
},
{
"name": "tween"
},
{
"name": "assetsmanager"
},
{
"name": "promise"
},
{
"name": "wxjssdk",
"path": "./libs/wxjssdk"
}
]
}
複製代碼
封裝了獲取簽名信息,已經分享接口,先調用getWxSignPackage獲取簽名配置,該方法裏的數據處理須要根據本身的接口數據作處理。
class WxSdk {
private signPackage: BodyConfig = new BodyConfig()
public static wxsdk: WxSdk
public static get instance() {
if (!this.wxsdk) {
this.wxsdk = new WxSdk()
}
return this.wxsdk
}
private constructor() {
}
/** * 配置微信簽名 */
public configWx(): Promise<any> {
// 這裏有個坑。用//api.24haowan.com時,nonceStr是大寫。用平臺時是:noncestr。切換時記得切換
if (!this.signPackage.appId || !this.signPackage.timestamp ||
!this.signPackage.nonceStr || !this.signPackage.signature) {
return Promise.reject('微信簽名參數錯誤')
}
this.signPackage.debug = false
this.signPackage.jsApiList = [
// 全部要調用的 API 都要加到這個列表中
'onMenuShareTimeline', 'onMenuShareAppMessage', 'hideMenuItems',
// 錄音相關
'startRecord', 'stopRecord', 'onVoiceRecordEnd', 'playVoice', 'onVoicePlayEnd', 'pauseVoice', 'stopVoice', 'uploadVoice', 'downloadVoice',
]
/* 微信接口 */
wx.config(this.signPackage)
wx.error(err=> {
console.error('error: configWx of wxsdk.ts', err)
})
return Promise.resolve('微信簽名配置完成')
}
/** * 獲取微信簽名信息 */
public getWxSignPackage(): Promise<any> {
let params = {
url: encodeURIComponent(window.location.href.split('#')[0])
}
// 獲取微信簽名
return Http.instance.get('xxxxx', params)
.then(response=> {
let data = response.payload
if (!data.appId) {
return Promise.reject(response.msg || response)
}
this.signPackage.appId = data.appId
this.signPackage.timestamp = data.timestamp
this.signPackage.nonceStr = data.nonceStr
this.signPackage.signature = data.signature
return Promise.resolve(this.configWx())
})
.catch(error=> {
console.error('error: getWxSignPackage of wxsdk.js', JSON.stringify(error))
return Promise.reject(error)
})
}
public share(shareInfo: ShareBody) {
if (!shareInfo.title) {
shareInfo.title = '分享標題'
}
if (!shareInfo.link) {
shareInfo.link = window.location.href.split('#')[0]
}
if (!shareInfo.desc) {
shareInfo.desc = '分享描述'
}
wx.ready(()=> {
console.log('wx ready', shareInfo)
wx.onMenuShareAppMessage(shareInfo)
wx.onMenuShareTimeline(shareInfo)
wx.onMenuShareQQ(shareInfo)
wx.onMenuShareWeibo(shareInfo)
})
}
}
複製代碼
至此,一個簡單的框架就基本完成了,可能還不太完善,但已經能夠知足一些簡單的需求了,本人已經使用這個結構開發了三四個遊戲並都順利上線。
最後再附上github地址: github.com/CB-ysx/egre…