yuffie-browser

vue3 版阿拉丁 h5 基础库 主要有容器、客户端、配置平台的通信及模拟,前端路由导航(活动入口)功能
2,888
Install
npm install yuffie-browser
Latest Version:0.4.6
Vue:3
Last Updated:May 16, 2022
Links: npm
Maintainer: levan.zz

Yuffie Browser

vue3 版阿拉丁 h5 基础库 主要有容器、客户端、配置平台的通信及模拟,前端路由导航(活动入口)功能

0.4.0版本以后,layout组件支持新配置平台,不再对group_id进行判断过滤

[[TOC]]

项目初始化方式

项目建议使用 vite 提供的 vue 模板初始化,可参考文档。

h5 库安装方法

yarn add yuffie-browser

全局注册

createYuffie 创建一个 vue 插件,并且在 main.ts 中注册,使用方法如下:

--- yuffie.ts
import { createYuffie, YuffieConfig } from 'yuffie-browser'

// 活动树,用于声明活动顺序
const routeTree = [
  // 层级1
  {
    type: '10001',
  },
  {
    type: '10002',
    children: [
      {
        type: '10002-1',
      },
      {
        type: '10002-2',
      },
    ],
  },
  {
    type: '10003',
    children: [
      {
        type: '10003-1',
      },
      {
        type: '10003-2',
      },
    ],
  },
  {
    type: '10004',
    children: [
      {
        type: '10004-1',
      },
      {
        type: '10004-2',
      },
    ],
  },
]

// 活动目录扫描
const activities = import.meta.glob('/src/activities/**/activity.vue')
const apiMockFiles = import.meta.globEager('/src/activities/**/api_mock.*')
const clientMocksFiles = import.meta.globEager('/src/activities/**/client_mock.*')
const configMocksFiles = import.meta.globEager('/src/activities/**/config_mock.*')

// 根据活动树结构生成路由
const createRoute = (rt: typeof routeTree, p = '/src/activities') => {
  const routes: YuffieConfig['routes'] = []
  rt.forEach((r, i) => {
    const path = `${p}/${r.type}`
    routes[i] = {
      type: r.type,
      component: activities[`${path}/activity.vue`],
      apiMock: apiMockFiles[Object.keys(apiMockFiles).find(file => RegExp(`${path}/api_mock.*`).test(file))!]?.default,
      clientMock:
        clientMocksFiles[Object.keys(clientMocksFiles).find(file => RegExp(`${path}/client_mock.*`).test(file))!]
          ?.default,
      configMock:
        configMocksFiles[Object.keys(configMocksFiles).find(file => RegExp(`${path}/config_mock.*`).test(file))!]
          ?.default,
    }
    if (r.children) {
      routes[i].children = createRoute(r.children, path)
    }
  })
  return routes
}
const config: YuffieConfig = {
  url: 'ws://121.4.214.235:1945',
  useMock: true,
  // 也支持手写yuffie-routes
  routes: createRoute(routeTree),
}

export default createYuffie(config)



--- main.ts
createApp(root).use(Yuffie).mount('#app')

YuffieConfig 是注册配置的类型文件,包括:

字段 说明 是否必填 示例
url 后台地址(websocket) 是 ws://10.12.28.63:1945
routes 路由 是 类型为YuffieRouteList,包含所有需展示的活动配置,支持自定义,也可以扫描路由自动生成
useMock 是否使用 mock 是 true
token 用户登录的 token,用于联调阶段模拟。 否
gameId gameId,用于 session 模拟。 否
groupId 游戏组号,用于 session 模拟。 否
roleId 角色 Id,用于 session 模拟。 否
userId 用户 Id, 用于 session 模拟。 否
channalId 渠道 ID, 用于 session 模拟。 否
useMock 是否使用 mock 是 true
mockLoadingTime 请求 loading 时间,单位:毫秒 number 否
onReceive 发送 websocket 消息后的回调,可以用于消息的展示。 否 onReceive(res) {console.log(res)}

use(Yuffie)后根节点会注册一些全局状态,提供给活动页面。同时该插件也能自动判断运行时的活动 id,如果是 mock 启动,则会自动替换 mock 响应。

活动中使用

在活动代码中,使用useYuffie方法获取 h5 库的 context,示例如下:

import { useYuffie } from 'yuffie-browser'
const { onCreate, send, getActivityConfig, client } = useYuffie()

此方法等同于

import { yuffieInjectToken } from 'yuffie-browser'
inject(yuffieInjectToken)

上下文中注入的方法

包含路由,通信,事件监听等。详见下表

  • yuffieNotice
  • yuffieRuntimeConfig
  • yuffieSession
  • activityConfigs
  • send
  • getActivityConfig
  • client
  • onCreate
字段 说明 类型 是否为响应式(Ref)
yuffieNotice websocket 中主动推送事件的总线,包含 on,off 方法。用于订阅和取消订阅。其中 NotifyEnum.ConnectNotify 方法为 ws 链接建立后触发,需要在根节点监听此方法,并实现登录鉴权等方法,可以参照示例中的登录方法 {on: (type: NotifyEnum, callback: NoticeHandler) = > void, off: (type: NotifyEnum, callback: NoticeHandler) => {} } 否
yuffieRuntimeConfig 运行时参数,包含 id 和 token,token 为登录时('/'路由时),读取 route.query.token 参数,并自动保存到此参数中;id 为活动路由时 route.query.id 参数 Ref<Partial<YuffieRuntimeConfig>> 是
yuffieSession 用于保存登录接口返回的身份信息 Ref<Partial<YuffieSessionConfig>> 是
yuffieTime 登录前为本地时间,登录后为服务器时间。毫秒级时间戳 Ref<number> 是
yuffieLoading 是否正在发送请求,可以用作全局的 loading 判断 Ref<boolean> 是
useMock 是否开启 mock(和全局注册的 useMock 值一致,无响应式) boolean 否
activityConfigs 活动静态配置,会从通知中自动读取, yuffieNotice 中订阅,并 unzip 获取。如果传递此列表则说明连接后台,且后台无配置推送。如果此配置有值,则下方 getActivityConfig 方法不会读取 config_mock 文件,而是读取此配置。 Ref<Array<YuffieActivityConfig>> 是
getActivityConfig 根据活动类型获取活动静态配置,如果是 mock 环境,则会读取同文件夹下的 config_mock.js 中数据。 function<T = any>(id?) { return T } 否
send promise 包装的 websocket 请求,method 和 payload 为请求后台参数,id 如果不传,则默认为当前活动 id,指定后则根据 id 参数发送。 function<T = any>(method: string, payload: object, id?: string) { return Promise<YuffieResponse<T>> } 否
onCreate 组件初始化方法,模拟生命周期,在浏览器隐藏到打开时自动触发传入的函数。 onCreate(func: function) 否
client 游戏端注入浏览器的方法调用,下文会详细说明 否

方法如果需要推导类型,则可传入方法泛型参数,如:

const res = send<string>(...payload)

示例中会自动推断请求返回的 res 类型为 string

client 对象为浏览器注入的 js 方法,包含以下内容:

方法 类型
isOnline () => Promise<boolean>
showEntry () => void
hideEntry () => void
showMark () => void
hideMark () => void
showBrowser () => void
hideBrowser () => void
getItemsCount (payload: Array<{type: number;id: number;}>) =>Promise<Array<number>>
canPutInBag (payload: Array<{type: number;id: number;}>) =>Promise<boolean>
event {on: (type: ClientNotifyEnum, callback: function) = > void,off: (type: ClientNotifyEnum, callback: function) => {}}

方法对应的作用见阿拉丁接入文档。

event 对象和 yuffieNotice 使用方法大致相同,包含 on,和 off 两个方法。用于订阅游戏主动通知的事件,事件包含on-bag-change, on-browser-show两种。

如果是 mock 模式启动,调用 client 的方法,会自动读取当前活动目录下的 client_mock.js 读取 mock 的返回值。

Layout 组件

根据代码(自动路由中为文件路径),和配置平台的条件,自动生成带红点的导航栏,和 router-view 的组件。

如果全局注册时传递 useMock 为 true,导航栏会根据全局注册 routes,不判断条件直接展示路径下的全部活动。 否则则会判断配置中的组号(group_id)时间(activity_time)显示标题(show_title)等条件,过滤出对应的活动。

可以多层级嵌套使用,用于展示树形系列活动布局。

<script lang="ts">
  import { YuffieLayout } from 'yuffie-browser'

  export default {
    name: 'App',
    components: {
      YuffieLayout,
    },
  }
</script>
<template>
  <YuffieLayout>
    <!-- 导航 -->
    <template #menu="{ activity, showMark }">
      <div class="menu">
        <div>{{ activity.name }}</div>
      </div>
    </template>
    <!-- 自定义菜单 -->
    <template #custom>
      <div>自定义内容</div>
    </template>
    <!-- 关闭 -->
    <template #close>
      <div class="close" />
    </template>
  </YuffieLayout>
</template>

其中有 slot menu 需要自行编写,用于活动的导航定义。 建议在根组件编写一下两个 slot:

  • custom
  • close

custom 用于右上角的自定义按钮,目前在天龙怀旧中为刷新和问号按钮。close 用于右上角的关闭按钮。 menu 和 close 都已经绑定好了点击的事件(切换路由,点击关闭游戏窗口)

slot menu 提供的上下文参数包括

  • activity: 单个活动的配置
  • showMark: 是否显示红点
  • filterResult: 是否被配置过滤, 即根据条件此 activity 是否应该显示(needFilter 为 true 时默认会过滤显示的配置,此值会为 true;当组件中使用 needFilter 为 false,活动配置不被过滤时,则 filterResult 的值为根据配置中活动是否显示计算的结果)
  • clientEvent: 跳转事件,当点击阻止冒泡时,可以使用此字段

layout 组件的 props:

props 字段 类型 说明
groupId string 组号:传递则根据此字段筛选活动展示,如果不传,则会根据登录返回的 session 中读取
useTheme boolean 是否使用主题
theme string 主题,即 assets/themes 下的 css 文件,此字段会读取此 prop 的同名 css,或 websocket 推送配置的 theme 字段,无配置则读取 default.css
autoFirstView boolean 进入活动布局后,是否自动进入需展示的第一个活动,默认为 false
showView boolean 是否显示 router-view, 默认为 true
showTitle boolean 是否显示导航栏, 默认为 true
titleStyle StyleValue 导航栏容器样式
viewStyle StyleValue router-view 容器样式
rootStyle StyleValue 组件根节点样式
path string 组件的当前路径,如果不传,则会自动读取 route.path 的值。用于查找当前路径的子活动。如果有多层级导航同时显示的情况,需要手动指定导此字段。 根节点必须设置为'/',用于入口和入口红点的展示
needFilter boolean 活动导航是否根据配置过滤,默认为 true。为 false 用于某些活动没有活动配置,或者层级导航需要展示不开启的活动情况。

layout 组件的暴露属性(使用 definExpose 声明,通过组件的 ref 调用):

props 字段 类型 说明
filterActivities ComputedRes<Array<YuffieActivityConfig>> 根据过滤条件筛选出来,导航要显示的活动列表
onClickRoute (activity: YuffieActivityConfig) => void 点击活动触发的路由跳转方法

以下是默认样式,可以覆盖,实现布局的自定义

// layout
.layout-main-container {
  display: flex;
  position: relative;
  box-sizing: border-box;
  overflow: auto;
  .layout-menu {
    overflow-y: auto;
  }
  .layout-view {
    flex: 1;
  }
  .layout-tools {
    position: absolute;
    top: 0;
    right: 0;
    display: flex;
  }
}

注意:使用主题时,会等待后台配置推送后后,再加载主题 css。 使用树形布局时,每层 v-deep 的覆盖都会影响子节点,因此建议使用行内样式,来控制布局的结构。如果必须使用外部样式,在子层级可能需要手动清除样式的影响。

树形布局如果父级节点没有活动 id,即进入层级后只有导航情况,则需要在子活动中配置 parent_type, parent_title 两个字段,用于找到父级组件,并展示标题。自动生成的父级配置会自动计算子活动的红点和展示时间。

建议的活动代码组织方式

活动需要以下四种文件:

  • activity.vue
  • api_mock.js
  • client_mock.js
  • config_mock.js

activity.vue 为单文件组件,包含一种活动类型的前端代码逻辑。

api_mock.js 为对后端接口的数据模拟,需要 export 一个 js object, key 为调用后台的 method, value 为需要模拟的响应,示例如下:

export default {
  main: [
    {
      levelId: 1,
      limit: 1,
    },
    {
      levelId: 2,
      limit: 1,
    },
    {
      levelId: 3,
      limit: 0,
    },
  ],
  get_items: {
    code: 0,
    msg: '领取成功',
  },
}

client_mock.js 为对注入到浏览器环境的 js 事件模拟,需要 export 一个 js object, key 为注入 window 中的方法名称, value 为需要模拟的结果,示例如下:

export default {
  showEntry: true,
  hideEntry: true,
  isOnline: true,
  showMark: true,
  hideMark: true,
  showBrowser: true,
  hideBrowser: true,
  getItemsCount: 1000,
  canPutInBag: true,
}

config_mock.js 为对活动静态配置的模拟,具体结构需要参照活动的具体需求来定义,示例如下:

export default {
  id: '2021070199',
  title: '标题',
}

Mock

库中提供了虚拟数据生成的工具,使用方法如下:

import { faker } from 'yuffie-browser'
const guid4 = faker.guid4()
const num = faker.digitOnes()
const url = faker.imgUrl()

faker 基于 mockjs 库的 random 模块封装,补充提供了以下方法:

方法 方法说明
imgUrl 获取一个随机图片
digitOnes 获取一个 0-9 范围内的数字
digitTens 获取一个 10-9999 范围内的数字
digitOnesStr 获取一个 0-9 范围内的数字转字符串
digitTensStr 获取一个 10-9999 范围内的数字转字符串
guid4 四位 guid
guid4Hex 16 进制的四位 guid
guid8Hex 16 进制的八位 guid
name 名字
title 标题

字符串转换

库中提供了驼峰和下划线字符串互转的方法

方法 方法说明
toHump 字符串 下划线转驼峰
toLine 字符串 驼峰转下划线
record2Line 对象 key 从下划线转化为驼峰(非递归)
record2Hump 对象 key 从驼峰转化为下划线(非递归)

使用方法如下:

import { toHump, toLine, record2Line } from 'yuffie-browser'
console.log(toHump('group_id')) // 'groupId'
console.log(toLine('groupId')) // 'group_id'
console.log(record2Line({ roleId: '1', groupId: '2' })) // {role_id: '1', group_id: '2'}
console.log(record2Line({ role_id: '1', group_id: '2' })) // { roleId: '1', groupId: '2' }

框架如何发布

编译后上传 npm 发布即可。

yarn build && yarn publish

Version History

Version Released Vue License
0.4.6 ^3.2.20
0.4.5 ^3.2.20
0.4.4 ^3.2.20
0.4.3 ^3.2.20
0.4.2 ^3.2.20