这次给大家带来搭建简单的游戏管理系统,搭建简单游戏管理系统的注意事项有哪些,下面就是实战案例,一起来看一下。
当前我们项目的界面是这样的:
简单来说,看不出一点管理系统的样子,到Axure中文网找了一下,管理类网站的原型应该是下面这个样子的:
照着撸一个呗,管理系统界面一般由顶部导航&状态栏、左侧导航栏、右侧内容区域三个部分组成,也就是这样的:
我们网站内容较少所以顶部无需导航栏,也就是顶部只需保留左侧标题和右侧状态部分,接着再填充一下界面,顶部左侧加入系统名称和logo,顶部右侧加入用户名,左侧导航栏填充入导航项,右侧内容栏根据左侧选中的导航项显示对应的内容:
填充完布局之后好像变得能看了一些,那我们就根据效果图来完成这个界面。
借助框架能够快速实现整体样式,选用最通用的样式框架Bootstrap3来协助完成界面,但是如果想要引入Bootstrap3控件的话需要引入jQuery,这是我们不想要的。
这时候我们可以考虑使用和Angular项目的相性最佳的angular-ui-bootstrap来取代Bootstrap3的控件,angular-ui-bootstrap是AngularUI团队在Bootstrap基础上用AngularJS实现的一组UI控件,在达到和Bootstrap控件相同效果的情况下还无需引入jQuery简直棒。
于是我们简单选定了Bootstrap + angular-ui-bootstrap组合来加速界面开发。
参考angular-ui-bootstrap文档-Dependencies,了解到其版本的选择与Angular的版本有对应关系,不过我们用的是AngularJS1.6.10版本所以可以直接安装最新的angular-ui-bootstrap:
yarn add angular-ui-bootstrap --save
由于上面的文档还提到angular-ui-bootstrap需要Angular-animate、Angular-touch、Bootstrap CSS,直接安装yarn安装顺便更新一下angular到1.7.0:
yarn add angular --save yarn add angular-animate --save yarn add angular-touch --save yarn add bootstrap@3 --save
在app.js中加入引用并为'pokemon-app'模块加入依赖(暂时不加入Bootstrap3样式):
import ngAnimate from 'angular-animate'; import ngTouch from 'angular-touch'; import uibootstrap from 'angular-ui-bootstrap'; ... angular.module('pokemon-app', [ ... ngAnimate, ngTouch, ngUIBootstrap ... ])
在index.tpl.html中加入一段文档中的测试代码:
<h4>Single toggle</h4> <pre class="brush:php;toolbar:false">{{singleModel}}
接着在app.js中的AppController中加入:
$scope.singleModel = 1;
结果如下:
中间多出了一个button并且可以通过点击修改数字,这表示angular-ui-bootstrap已经安装成功了~
接下来我们为项目加入Bootstrap.css,CSS可以通过Webpack打包然后在项目入口文件app.js中加载,这里我们要用到css-loader、style-loader、file-loader(加载字体,如果没有这个loader字体会加载失败):
yarn add css-loader style-loader file-loader --save-dev
修改webpack.config.js的module如下:
module: { rules: [{ test: /\.html$/, loader: 'raw-loader' }, { // 负责css模块加载 test: /\.css$/, use: ['style-loader', 'css-loader'] }, { test: /\.(woff|woff2|eot|ttf|svg)$/, use: ['file-loader'] }] },
app.js中引入
import 'bootstrap/dist/css/bootstrap.min.css';
现在查看自动重载之后的页面,你会发现熟悉的Bootstrap页面样式终于出现了:
首先去掉上面添加的angular-ui-bootstrap测试代码,然后开始界面开发:
顶部栏使用navbar样式编写,去掉原来的h1标签然后左边填充icon和系统名右边填充用户名,编写代码如下(图源来自神奇宝贝百科,承诺不用于商业用途):
<nav class="navbar navbar-inverse navbar-fixed-top"> <p class="container-fluid"> <p class="navbar-header"> <a href="#" class="navbar-brand"> <img width="20" height="20" src="http://s1.52poke.wiki/wiki/5/5e/Bag_%E7%B2%BE%E7%81%B5%E7%90%83_Sprite.png"> </a> <a href="#" class="navbar-brand">口袋妖怪管理系统v0.0.1</a> </p> <p id="navbar" class="navbar-collapse collapse"> <ul class="nav navbar-nav navbar-right"> <li><a href="#">Nodreame</a></li> </ul> </p> </p> </nav>
效果如下:
为了防止链接丢失导致图片加载失败,把图片下载下来放在本地assert/img文件夹下,命名为spriteball-common.png。按照Webpack模块化规则,图片也应该作为一个模块来加载,于是参考文档url-loader,在webpack.config.js文件的module中加入:
{ test: /\.(png|svg|jpg|gif)$/, use: [ { loader: 'url-loader', options: { limit: 8192, fallback: 'file-loader' } } ] }
用url-loader作为小于8192byte图片的加载器,如果符合条件图片链接将会转为一个DataURL,如果超过改限制,将会默认使用file-loader作为图片的加载器,修改后重新编译通过.
现在继续修改index.tpl.html中图片位置的a标签,加入id="icon"并屏蔽原来图片:
<a href="#" class="navbar-brand" id="icon"> <!-- <img width="20" height="20" src="http://s1.52poke.wiki/wiki/5/5e/Bag_%E7%B2%BE%E7%81%B5%E7%90%83_Sprite.png" alt=""> --> <!-- <img src="../assert/img/spriteball-common.png" alt=""> --> </a>
在app.js中引入图片,并通过DOM操作把图片插入页面:
import icon from '../assert/img/spriteball-common.png' ... function AppController ($scope) { // $scope.singleModel = 1; var sysIcon = new Image(); sysIcon.src = icon; sysIcon.width = 20; sysIcon.height = 20; document.getElementById('icon').appendChild(sysIcon); }
重新编译,在浏览器元素检测中看到图片已成功插入页面并以DataURL形式被引用:
顶部栏基本编写完成~
顶部栏完成之后,左右将分成两部分,这里的页面布局划分Bootstrap3似乎没有提供响应的样式,不过在Bootstrap的官网样例中我们找到了类似的Dashboard,他提供了一个现成的dashboard.css我们可以直接用起来,将dashboard.css放到assert/css文件夹下,并在app.js中引用:
import '../assert/css/dashboard.css'
然后开始跟随Demo简单布局:
<p class="container-fluid"> <p class="row"> <p class="col-sm-3 col-md-2 sidebar">sidebar</p> <p class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">main</p> </p> </p>
很简单就完成了页面布局划分(这里左侧导航栏在小于768px时将自动隐藏):
然后继续编写左侧导航栏:
<p class="col-sm-3 col-md-2 sidebar"> <ul class="nav nav-sidebar"> <li><a href="/#!/pokemons">图鉴</a></li> <li><a href="/#!/skills">技能</a></li> <li><a href="/#!/hagberrys">树果</a></li> <li><a href="/#!/props">道具</a></li> <li><a href="/#!/games">游戏</a></li> </ul> </p>
简单的左侧导航栏已经基本完成,并且点击能够看到内容切换,现在我们将被部分遮蔽的内容移动到右侧内容区域:
<p class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> <p ng-view></p> </p>
简单移动完成页面:
基础页面完成之后,看看内容样式还是比较丑,跟随dashboard例子和Bootstrap修改其样式,对图鉴页(原来的口袋妖怪详情页)进行修改:
<h1 class="page-header">图鉴</h1> <p class="table-responsive"> <table class="table table-striped"> <thead> <tr> <th>NO.</th> <th>名称</th> <th>数量</th> <th>重量</th> <th>总计</th> <th>操作</th> </tr> </thead> <tbody> <tr ng-repeat="pokemon in pokemons"> <td>{{pokemon.no}}</td> <td><a href="/#!/pokemon/{{pokemon.no}}">{{pokemon.name}}</a></td> <td><input type="text" ng-model="pokemon.count"></td> <td>{{pokemon.weight}}</td> <td>{{pokemon.weight * pokemon.count}}</td> <td><button class="btn btn-xs btn-primary" ng-click="remove($index)">删除</button></td> </tr> </tbody> </table> </p>
<p> <a href="/#!/pokemons"> <span class="glyphicon glyphicon-arrow-left"></span>返回图鉴列表 </a> </p> <h2 class="sub-header"><b>{{pokemon.name}}</b></h2> <img ng-src="{{pokemon.img}}" width="200" height="200"> <p><b>编号: </b>No.{{pokemon.no}}</p> <p><b>体重: </b>{{pokemon.weight}}</p> <p><b>属性: </b>{{pokemon.property}}</p> <p><b>种类: </b>{{pokemon.type}}</p> <p> <b>特性: </b> <ul> <li><b>普通特性: </b>{{pokemon.character.common}}</li> <li><b>隐藏特性: </b>{{pokemon.character.conceal}}</li> </ul> </p> <p ng-show="pokemon.forms"> <b style="float: left;">其他形象:</b><br/> <p ng-repeat="form in pokemon.forms" style="float: left;"> <img ng-src="{{form.src}}"> <p style="text-align: center;">{{form.name}}</p> </p> <p style="clear: both;"></p> </p>
上面代码中,pm-list修改了标题和表格样式,pm-detail修改了返回样式并稍微修缮了布局,修改结果如下:
其他界面也进行类似的修改,结果如下:
至此基本网站布局已完成。
现在网站布局和样式得到了优化,但是一些细节暂时还没处理好,列出一些比较直观能看到的不足:
左侧导航栏交互缺乏选中感
删除按钮没有二次确认容易导致误删
现在我们就来完善这些细节。
dashboard.css已经帮我们写好了选中左侧导航栏某项之后变蓝底白字的样式,只需要简单在选中项的
.run(['$rootScope', '$location', function ($rootScope, $location) { $rootScope.$on('$locationChangeSuccess', function () { $rootScope.nowUrl = $location.url(); console.log('nowUrl:', $rootScope.nowUrl); // console.log('$route,routes.null.redirectTo:', $route.routes.null.redirectTo); }); }])
监听页面切换的日志结果如下:
ke'yi看到获取到的nowUrl都是http://localhost:8080/#!
后面的部分,那么了解到这点之后我们就可以尝试在index.tpl.html中借助ng-class指令来完成"根据当前url选中对应导航项"的操作了,修改index.tpl.html中
<ul class="nav nav-sidebar"> <li ng-class="{'/pokemons': 'active'}[nowUrl]"><a href="/#!/pokemons">图鉴</a></li> <li ng-class="{'/skills': 'active'}[nowUrl]"><a href="/#!/skills">技能</a></li> <li ng-class="{'/hagberrys': 'active'}[nowUrl]"><a href="/#!/hagberrys">树果</a></li> <li ng-class="{'/props': 'active'}[nowUrl]"><a href="/#!/props">道具</a></li> <li ng-class="{'/games': 'active'}[nowUrl]"><a href="/#!/games">游戏</a></li> </ul>
为了达到二次确认删除的效果,我们可以使用angular-ui-bootstrap提供的模态框Modal,参考Modal.
首先我们在src目录下新建文件夹common来存放通用的html模板,新建文件deleteDialog.tpl.html作为模态框的模板文件:
<p class="modal-header"> <h3 class="modal-title" id="modal-title">{{modalTitle}}</h3> </p> <p class="modal-body" id="modal-body"> {{modalBody}} </p> <p class="modal-footer"> <button class="btn btn-danger" type="button" ng-click="ok()">删除</button> <button class="btn btn-default" type="button" ng-click="cancel()">取消</button> </p>
接下来就可以编写触发模态框的逻辑了,模仿文档修改pokemon.js中PMListController如下:
PMListController.$inject = ['$scope', '$uibModal']; function PMListController ($scope, $uibModal) { $scope.pokemons = pokemons; console.log($scope.pokemons); $scope.remove = function (index) { console.log('index:', index); var modalInstance = $uibModal.open({ animation: true, ariaLabelledBy: 'modal-title', ariaDescribedBy: 'modal-body', template: delDiage, controller: 'DeleteInstanceController', resolve: { pokemon: function () { return $scope.pokemons[index]; } } }); modalInstance.result.then(function (content) { console.log('Delete!', content); $scope.pokemons.splice(index, 1); }, function (content) { console.log('Cancel!', content); }); }; }
上面我们做了两处修改:
1. 为PMListController加入了依赖$uibModal,用以调用模态框; 2. 修改remove方法,使用$uibModal.open()创建模态框实例,并用实例编写模态框关闭的promise,关闭时选择close或cancel将触发不同事件。
完成了模态框触发逻辑编写之后,我们开始编写模态框的逻辑:
DeleteInstanceController.$inject = ['$scope', '$uibModalInstance', 'pokemon']; function DeleteInstanceController ($scope, $uibModalInstance, pokemon) { // console.log('thisIndex:', thisIndex); console.log('pokemon:', pokemon); $scope.modalTitle = '删除'; $scope.modalBody = '是否删除' + pokemon.name + '的数据'; $scope.ok = function () { console.log('delete!'); $uibModalInstance.close(pokemon); }; $scope.cancel = function () { console.log('cancel!'); $uibModalInstance.dismiss('cancel'); }; }
这里加入了$uibModalInstance和pokemon依赖,$uibModalInstance代表当前模态框对象,pokemon是$uibModal.open()配置中resolve传递过来的数据。在该controller中完成模态框的内容编写以及两个button触发的事件。接下来我们把这个controller加入module:
export default angular.module('pokemon-app.pokemon', [ngRoute]) .config(['$routeProvider', function ($routeProvider) { $routeProvider .when('/pokemons', { template: pmlist, controller: 'PMListController' }) .when ('/pokemon/:no', { template: pmdetail, controller: 'PMDetailController' }) }]) .controller('PMListController', PMListController) .controller('PMDetailController', PMDetailController) .controller('DeleteInstanceController', DeleteInstanceController) .name;
倒数第二行就是新加入module的controller,pm-list.html不用作任何修改,保存等待自动编译重载。
至此,系统的操作体验升级已经基本完成,为了系统体验同步,我们需要把模态框的效果也应用到其他的界面上。
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
以上是搭建简单的游戏管理系统的详细内容。更多信息请关注PHP中文网其他相关文章!