基于mint-ui的移动应用开发案例四(应用中心)
本节主要包括以下内容:
- 应用中心界面的布局
- mt-swipe,loadmore,mt-cell,mt-actionsheet等组件的使用
- echarts的使用
1.应用中心界面的布局
页面的大体结构是一个头标题,走马灯的图片展示区域,和下面的子应用的icon展示。
<template>
<div id="tool">
<!--头部-->
<mt-header fixed title="应用中心"></mt-header>
<!---内容区域-->
<div class="content">
<!--图片轮播展示-->
<div class="slider-img">
<mt-swipe :auto="4000">
<mt-swipe-item>
<img src="../assets/tool/swipe1.jpg" height="120" width="100%"/>
</mt-swipe-item>
<mt-swipe-item><img src="../assets/tool/swipe2.jpg" height="120" width="100%"/></mt-swipe-item>
<mt-swipe-item><img src="../assets/tool/swipe3.jpg" height="120" width="100%"/></mt-swipe-item>
</mt-swipe>
</div>
<div class="group-title">| - 常用应用</div>
<!--一条分割线-->
<div class="line"></div>
<!--应用展示-->
<div class="apps">
<div @click="go('chart')">
<img src="static/chart.png"/>
<span>业务统计</span>
</div>
<div @click="go('loadmore')">
<img src="static/data.png"/>
<span>测试数据</span>
</div>
<div @click="go('memolist')">
<img src="static/note.png"/>
<span>我的备忘</span>
</div>
</div>
</div>
</div>
</template>
<style scoped>
.mint-button {
display: flex;
flex-direction: column;
}
.content {
margin-top: 40px;
text-align: left;
}
.group-title {
margin-top: 10px;
font-size: 11px;
color: #0c60ee;
}
.line {
margin-top: 10px;
height: 1px;
background-color: #c4e3f3;
}
.apps {
display: flex;
flex-direction: row;
justify-content: space-around;
flex-wrap: wrap;
}
.apps div {
display: flex;
height: 70px;
width: 70px;
justify-content: center;
align-items: center;
}
.apps div {
display: flex;
flex-direction: column;
}
.apps div span {
margin-top: 5px;
font-size: 10px;
}
.apps img {
height: 40px;
width: 40px;
}
.slider-img {
height: 120px;
width: 100%;
}
</style>
<script>
export default {
methods: {
go(index){
this.$router.push('/tool/' + index);
}
},
created(){
let _footer = this.$store.state.footerVisible;
if (!_footer) {
this.$store.commit('TOGGLE_FOOTER');
}
this.$store.commit('SELECT_TAB', 'tool')
}
}
</script>
这里采用了flex布局。mt-swipe的使用很简单,就是在里面加上mt-swipe-item的slot,mt-swipe-item里面的slot就是展示内容,我这里是用几张图片代替了。在每个应用icon的div上添加了点击事件,点击后会跳入对应的界面。我们现在要新建三个子应用界面,并且要配置路由。
2.子应用1--业务统计---echarts,mt-actionsheet的使用
<template>
<div id="chart">
<mt-header fixed title="统计图表">
<router-link to="/tool" slot="left">
<mt-button icon="back">返回</mt-button>
</router-link>
<mt-button slot="right" @click="showSheet">切换</mt-button>
</mt-header>
<div id="chart-container">
<div id="myChart" :style="{ height: '300px'}"></div>
</div>
<mt-actionsheet
:actions="actions"
v-model="sheetVisible">
</mt-actionsheet>
</div>
</template>
<style>
.chart-container {
margin-top: 40px;
display: flex;
}
</style>
<script>
export default {
data(){
let that = this;
return {
sheetVisible: false,
actions: [{
name: '柱状图', method(){
//在切换图类型时重画表格
that.chartType = 'bar';
that.drawLine();
}
}, {
name: '折线图', method(){
//在切换图类型时重画表格
that.chartType = 'line';
that.drawLine();
}
}],
chartType: 'bar'
}
},
created(){
let _footer = this.$store.state.footerVisible;
if (_footer) {
this.$store.commit('TOGGLE_FOOTER');
}
},
mounted(){
this.drawLine();
},
methods: {
showSheet() {
this.sheetVisible = true
},
drawLine(){
// 基于准备好的dom,初始化echarts实例
//这里能用this.$echarts是因为在main.js里面添加了Vue.prototype.$echarts=echarts
let myChart = this.$echarts.init(document.getElementById('myChart'));
// 绘制图表
myChart.setOption({
color: ['#3398DB', '#ef1111'],
tooltip: {
trigger: 'axis',
axisPointer: { // 坐标轴指示器,坐标轴触发有效
type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
}
},
//提示块,可点击
legend: {
x: 'center',
data: ['第一季度', '第二季度'],
top: 50,
selectedMode: 'multiple',
},
//X轴
xAxis: {
data: ["衬衫", "羊毛衫", "雪纺衫", "裤子"]
},
grid: {
show: true,
top: 80,//grid 组件离容器上侧的距离,默认60;上同
},
yAxis: {},
//显示数据
series: [{
name: '第一季度',
type: this.chartType,
data: [5, 20, 9, 360]
}, {
name: '第二季度',
type: this.chartType,
data: [51, 2, 190, 26]
}]
});
}
}
}
</script>
1.actionsheet默认是隐藏的,点击右上角的切换按钮时会显示出来(改变了sheetVisible的可见属性),它接收一个action属性,action接收一个对象数组,每个对象包含一个name属性显示名称和一个method方法用于处理选中相应条目后的回调函数。2.echarts的显示分三部分,第一步是要使用一个div块初始化(init),第二步是设置属性(setOption),第三步是显示到界面上(drawLine)。具体的文档:http://echarts.baidu.com/examples.html#chart-type-bar
3.这里的created钩子里是将footerbar给隐藏掉了
4.注意在函数的回调里,this指代的已经不是当前vue对象了,使用this来调用vue中的方法时会报错。如果要在回调中操作vue中的数据或者方法,要在使用回调函数之前将vue本地化,即用一个变量保存this,然后在回调中使用这个变量操作vue的属性和方法。
5.头部标题栏的左侧是一个返回按钮,是利用路由来进行页面跳转的。
3.子应用2--加载数据--loadmore组件的使用
<template>
<div id="loadmore">
<mt-header fixed title="load more">
<router-link to="/tool" slot="left">
<mt-button icon="back">返回</mt-button>
</router-link>
</mt-header>
<div class="content">
<mt-loadmore :top-method="loadTop"
:bottom-all-loaded="bottomAllLoaded"
:auto-fill="false"
@top-status-change="handleTopChange"
:bottom-method="loadBottom" ref="loadmore">
<div slot="top" class="mint-loadmore-top">
<span v-show="topStatus === 'loading'" :class="{ 'rotate': topStatus === 'drop' }">↓</span>
<span v-show="topStatus === 'drop'">我在加载数据</span>
<span v-show="topStatus === 'pull'">下拉我就更新给你看</span>
</div>
<mt-cell v-for="(item,index) in list" :title="item+'s'" :key="index"></mt-cell>
</mt-loadmore>
</div>
</div>
</template>
<style scoped>
.content {
margin-top: 40px;
height: auto;
}
</style>
<script>
export default {
data(){
return {
bottomAllLoaded: false,
topStatus: '',
list: []
}
},
methods: {
loadTop(){
let that = this;
for (let i = 0; i < 10; i++) {
this.list.unshift('unshift' + i)
}
setTimeout(function () {
that.$refs.loadmore.onTopLoaded();
}, 1000)
},
loadBottom(){
for (let i = 0; i < 10; i++) {
this.list.push('push' + i)
}
if (this.list.length > 100) {
this.bottomAllLoaded = true;
}
this.$refs.loadmore.onBottomLoaded();
},
handleTopChange(status){
this.topStatus = status;
}
},
mounted(){
for (let i = 0; i < 40; i++) {
this.list.push(i)
}
}
}
</script>
1.loadmore的使用方法可以参考官方文档:http://mint-ui.github.io/docs/#/zh-cn2/loadmore。这里介绍几个相关的属性方法。topMethod和bottomMethod分别是下拉刷新和上拉加载更多的回调方法,这里的距离是默认70px。bottom-all-loaded属性是在数据完全记载完成时的一个标记,如果为true的话,则不会调用加载数据的方法,并且上拉也不会有任何反应。auto-fill属性是组件会计算初始的数据是否会占满整个屏幕,没有的话会自动调用bottomMethod来填充,我用的时候它是一直在加载的,然后浏览器都关不掉。所以我将其设置为false。另外top-status-change事件是用来监听顶部栏状态变化的,有三个值:pull,drop,loading对应三个状态,在自定义加载动画时可以使用。自定义加载动画是loadmore组件的一个名为top的slot插槽,可以在里面判断topStatus来进行不同内容的加载。
2.在调用topMethod加载完数据后一定要执行 this.$refs.loadmore.onTopLoaded();,bottomMethod也一样。
4.子应用3-我的备忘-mt-cell,mt-field,mt-datetime-picker组件使用
这些组件的使用比较简单,直接看代码和文档就可以了:
memolist.vue
<template>
<div id="memo-list">
<mt-header fixed title="我的备忘列表">
<router-link to="/tool" slot="left">
<mt-button icon="back">返回</mt-button>
</router-link>
<mt-button slot="right" @click="newMemo">-|-</mt-button>
</mt-header>
<div class="content">
<template v-for="(item,index) in memoList">
<mt-cell isLink @click.native="showDetail(item)">
<span slot="title">{{item.title}}</span>
<span>{{item.content}}</span>
</mt-cell>
</template>
</div>
</div>
</template>
<style scoped>
.content {
margin-top: 40px;
}
span {
font-size: 13px;
/**设置文字超出元素宽度后的省略号**/
width: 150px; /*必须设置宽度*/
overflow: hidden; /*溢出隐藏*/
text-overflow: ellipsis; /*以省略号...显示*/
white-space: nowrap; /*强制不换行*/
}
</style>
<script>
import {MessageBox} from 'mint-ui';
export default {
created(){
let _footer = this.$store.state.footerVisible;
if (_footer) {
this.$store.commit('TOGGLE_FOOTER');
}
},
methods: {
newMemo(){
this.$router.push('/tool/memonew');
},
showDetail(item){
MessageBox(item.title, item.content);
}
},
mounted(){
},
data(){
return {
memoList: [{
title: '周报',
content: '周五之前记得提交周报和周总结周五之前记得提交周报和周总结周五之前记得提交周报和周总结周五之前记得提交周报和周总结周五之前记得提交周报和周总结'
}, {title: '锻炼提醒', content: '晚上记得三俯卧撑'}]
}
}
}
</script>
memonew.vue:<template>
<div id="memo">
<mt-header fixed title="我的备忘">
<router-link to="/tool/memolist" slot="left">
<mt-button icon="back">返回</mt-button>
</router-link>
<mt-button slot="right" @click="saveMemo">保存</mt-button>
</mt-header>
<div class="content">
<mt-field label="标题" v-model="title"></mt-field>
<mt-field label="是否提醒">
<mt-switch v-model="isRemind"></mt-switch>
</mt-field>
<mt-cell title="提醒时间" v-show="isRemind">
<div @click="chooseDatetime">{{dateTimeText}}</div>
</mt-cell>
<mt-field class="memo-content" placeholder="备忘录" type="textarea" rows="8" v-model="content"></mt-field>
<mt-datetime-picker
@confirm="confirm"
ref="picker"
type="datetime"
v-model="datetime">
</mt-datetime-picker>
</div>
</div>
</template>
<style scoped>
.content {
margin-top: 40px;
}
.mint-cell {
min-height: 40px;
}
.memo-content {
border-bottom: 1px solid #b9def0;
}
</style>
<script>
import * as types from '../../store/index.js'
export default {
data(){
return {
title: '',
content: '',
datetime: '',
dateTimeText: '请选择提醒时间',
isRemind: false
}
},
created(){
let _footer = this.$store.state.footerVisible;
if (_footer) {
this.$store.commit('TOGGLE_FOOTER');
}
},
methods: {
chooseDatetime(){
this.$refs.picker.open();
},
confirm(val){
this.dateTimeText = val.toLocaleString()
},
saveMemo(){
localStorage.setItem('memo', JSON.stringify({
title: this.title,
content: this.content,
dateTime: this.dateTimeText
}));
console.info(localStorage.getItem('memo'))
}
}
}
</script>
1.列表界面的文字超出div区域后显示省略号的样式::
/**设置文字超出元素宽度后的省略号**/ width: 150px; /*必须设置宽度*/ overflow: hidden; /*溢出隐藏*/ text-overflow: ellipsis; /*以省略号...显示*/ white-space: nowrap; /*强制不换行*/ 2.备忘列表界面,备忘item的点击显示是用MessageBox来实现的,使用之前要记得引入:import {MessageBox} from 'mint-ui'
3.新建备忘界面,在选中一个日期后的confirm回调中,接收一个val的参数,可以用toLocaleString()将其转换成本地的字符串。
4.这里的saveMemo只是测试,不涉及具体的保存数据功能。
5.路由配置
import Vue from 'vue'
import Router from 'vue-router'
import Main from '../pages/main.vue'
import Tool from '../pages/tool.vue'
import My from '../pages/my.vue'
import MemoNew from '../pages/tool/memonew.vue'
import MemoList from '../pages/tool/memolist.vue'
import Chart from '../pages/tool/chart.vue'
import Loadmore from '../pages/tool/Loadmore.vue'
Vue.use(Router);
export default new Router({
routes: [
{
path: '/main', component: Main
}, {
path: '/tool', component: Tool
}, {
path: '/my', component: My
}, {
path: '/tool/memonew', component: MemoNew
}, {
path: '/tool/memolist', component: MemoList
}, {
path: '/tool/chart', component: Chart
},
{
path: '/tool/loadmore', component: Loadmore
}
]
})
当前完成的效果演示:
2018-07-12更新:由于后续增加和改进的东西比较多,强烈建议参考github上最新的项目:
https://github.com/JerryYuanJ/a-vue-app-template
如果你项目搭建中遇到问题,请提交issue或者及时与我联系,谢谢。