项目环境准备
1. 项目目录结构准备
我们可以自定义目录出来,例如
pages : 所有的页面组件放在这里
pages/common: 页面所有的公用组件
utils : 放置工具类
store : 放置vuex数据仓库
2. 安装JQuery和Bootstrap
安装JQuery
由于bootstrap依赖Jquery,所以需要先安装jquery,这里版本使用1.11.3
npm install jquery@1.11.3 --save
找到build/webpack.base.conf.js文件中
在文件头部添加引用
const webpack = require('webpack');
在文件所有配置对象的末尾增加如下配置
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"windows.jQuery": "jquery"
})
]
安装Bootstrap
npm install bootstrap@3.3.7 --save
引入bootstrap
在src/main.js文件的顶部加入bootstrap的主要文件引用
import 'bootstrap/dist/css/bootstrap.min.css'
import 'bootstrap/dist/js/bootstrap.min.js'
导入我们之前案例中编写的lottery.css
3. vue-devtool准备
vue-devtool是Vue官方提供的开发调试工具,能帮助我们查看Vue组件的数据,状态等属性。
链接地址:https://github.com/vuejs/vue-devtools
博彩首页
TitleBar组件
<!--标题栏,可能有返回按钮-->
<template>
<div class="row title">
<div class="col-xs-12">
<router-link
tag="div"
v-if="needBack"
class="div_back"
to="/"
><返回
</router-link>
{{title}}
</div>
</div>
</template>
<script>
export default {
name: "TitleBar",
props: {
title: String,
needBack: {
type:Boolean,
default:false
}
}
}
</script>
<style scoped>
.div_back{
position: absolute;
left: 15px;
}
</style>
Swiper轮播图组件
<template>
<div id="carousel-example-generic" class="row carousel slide" data-ride="carousel">
<!-- Indicators -->
<ol class="carousel-indicators">
<li data-target="#carousel-example-generic" data-slide-to="0" class="active"></li>
<li data-target="#carousel-example-generic" data-slide-to="1"></li>
<li data-target="#carousel-example-generic" data-slide-to="2"></li>
</ol>
<!-- Wrapper for slides -->
<div class="carousel-inner" role="listbox">
<div class="item active">
<img src="@/assets/img/1.png" alt="...">
<div class="carousel-caption">
</div>
</div>
<div class="item">
<img src="@/assets/img/2.png" alt="...">
<div class="carousel-caption">
</div>
</div>
<div class="item">
<img src="@/assets/img/3.png" alt="...">
<div class="carousel-caption">
</div>
</div>
</div>
<!-- Controls -->
<a class="left carousel-control" href="#carousel-example-generic" role="button" data-slide="prev">
<span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="right carousel-control" href="#carousel-example-generic" role="button" data-slide="next">
<span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div>
</template>
<script>
export default {
name: "swiper"
}
</script>
<style scoped>
</style>
HistoryList准备
组件之间的跳转
- 声明式跳转https://router.vuejs.org/zh/api/#router-link-props
<!-- 字符串 -->
<router-link to="home">Home</router-link>
<!-- 渲染结果 -->
<a href="home">Home</a>
<!-- 使用 v-bind 的 JS 表达式 -->
<router-link v-bind:to="'home'">Home</router-link>
<!-- 不写 v-bind 也可以,就像绑定别的属性一样 -->
<router-link :to="'home'">Home</router-link>
<!-- 同上 -->
<router-link :to="{ path: 'home' }">Home</router-link>
<!-- 命名的路由 -->
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
<!-- 带查询参数,下面的结果为 /register?plan=private -->
<router-link :to="{ path: 'register', query: { plan: 'private' }}">Register</router-link>
- 编程式跳转https://router.vuejs.org/zh/guide/essentials/navigation.html
// 字符串
router.push('home')
// 对象
router.push({ path: 'home' })
// 命名的路由
router.push({ name: 'user', params: { userId: 123 }})
// 带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
注意:如果提供了 path,params 会被忽略,上述例子中的 query 并不属于这种情况。取而代之的是下面例子的做法,你需要提供路由的 name 或手写完整的带有参数的 path:
const userId = 123
router.push({ name: 'user', params: { userId }}) // -> /user/123
router.push({ path: `/user/${userId}` }) // -> /user/123
// 这里的 params 不生效
router.push({ path: '/user', params: { userId }}) // -> /user
发送异步请求axios
参考文档: https://www.kancloud.cn/yunye/axios/234845
- 安装
npm install axios
- 使用
axios.get(url[, config])
axios.delete(url[, config])
axios.post(url[, data[, config]])
axios.put(url[, data[, config]])
//发生get请求
axios.get('/user?ID=12345')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
// 可选地,上面的请求可以这样做
axios.get('/user', {
params: {
ID: 12345
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
发送post请求
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
为了便于我们以后进行前后端联调,建议大家在代码中编写的时候,找到config/index.js修改proxyTable为如下的内容:
proxyTable: {
'/api':{
target:'http://localhost:8080',
pathRewrite:{'^/api':'/static'}
}
}
这段代码的意思是我将当前项目所有/api的内容,映射到http://localhost:8080这个路径里面,并且我需要将所有以/api开头的路径,修改为/static,实际的目标就是将如下路径进行一个修改
axios.get('/api/index') --- 修改为 axios.get('/static/index')
当我们项目进行联调的时候,我们就不需要修改vue中的代码,只需将proxyTable修改为:
proxyTable: {
'/api':{
target:'目标服务器路径,例如http://localhost:3000',
}
}
HistoryList示例
<template>
<div class="wraper">
<div v-for="history in list" :key="history.code" @click="handleItemClick(history.code)">
<history-item :history="history"></history-item>
</div>
</div>
</template>
<script>
import HistoryItem from './HistoryItem'
export default {
name: "history-list",
props: ['list'],
components: {
HistoryItem
},
methods:{
handleItemClick(history){
this.$router.push({
name:'LotteryDetail',
params:{
code:history
}
})
}
}
}
</script>
<style scoped>
</style>
HistoryItem组件
<template>
<div class="row item">
<!--左边11个格子-->
<div class="col-xs-11">
<!--开奖日期-->
<div class="row">
<span style="font-size: 18px;">第{{history.code}}期</span>
<span style="margin-left: 10px;">{{history.date}}</span>
</div>
<!--开奖号码-->
<div class="row" style="margin-top: 10px;">
<div class="ball-item ball-red" v-for="redBall in history.red.split(',')">{{redBall}}</div>
<div class="ball-item ball-blue">{{history.blue}}</div>
</div>
</div>
<!--右边1个格子-->
<div class="col-xs-1 item-arrow">
<span class="glyphicon glyphicon-chevron-right"></span>
</div>
</div>
</template>
<script>
export default {
name: "history-item",
props:["history"]
}
</script>
<style scoped>
.item{
border: 1px solid gainsboro;
height: 80px;
padding-top: 5px;
padding-left: 15px;
}
.item-arrow{
padding-left: 0px;
padding-top: 30px;
}
</style>
LotteryDetail组件
路由的配置
{
path: '/detail/:code',
name: 'LotteryDetail',
component: LotteryDetail,
props:true
}
编程的方式跳转
this.$router.push({
name:'LotteryDetail',
params:{
code:history
}
});
LotteryDetail的示例代码
注意: vue的组件中对table标签要求比较严格,我们需要按如下方式来定义table
<table>
<thead>
<tr><td></td></tr>
</thead>
<tbody>
<tr><td></td></tr>
</tbody>
</table>
LotteryDetail的示例代码
<template>
<div v-if="history != null">
<!--标题栏-->
<title-bar :needBack="needBack" :title="title"></title-bar>
<!--广告轮播图-->
<swiper></swiper>
<!--彩票条目-->
<div class="clearfix">
<div class="pull-left">第{{code}}期</div>
<div class="pull-right">{{history.date}}</div>
</div>
<!--显示本期中奖的球-->
<div class="row text-center" style="margin-top: 10px;margin-bottom: 10px
">
<div class="ball-item ball-red" v-for="redBall in history.red.split(',')">{{redBall}}</div>
<div class="ball-item ball-blue">{{history.blue}}</div>
</div>
<!--显示中奖的信息-->
<div>
<table class="table table-bordered">
<thead>
<tr style="background-color: gainsboro">
<td class="text-center">本期销量</td>
<td class="text-center">奖池奖金</td>
</tr>
</thead>
<tbody>
<tr>
<td class="text-center">{{history.sales}}</td>
<td class="text-center">{{history.poolmoney}}</td>
</tr>
</tbody>
</table>
</div>
<!--显示中奖的结果数据-->
<div>
<table class="table table-bordered">
<thead>
<tr style="background-color: gainsboro">
<td class="text-center">奖项</td>
<td class="text-center">中奖注数</td>
<td class="text-center">奖金</td>
</tr>
</thead>
<tbody>
<!--中奖结果数据循环生成-->
<tr v-for="prizegrade in history.prizegrades" :key="prizegrade.type">
<td class="text-center">{{prizegrade.type}}</td>
<td class="text-center">{{prizegrade.typenum}}</td>
<td class="text-center">{{prizegrade.typemoney}}</td>
</tr>
</tbody>
</table>
</div>
<menu-bar></menu-bar>
</div>
</template>
<script>
import TitleBar from '@/pages/common/TitleBar'
import Swiper from '@/pages/common/Swiper'
import axios from 'axios'
import MenuBar from '@/pages/common/MenuBar'
export default {
name: "lottery-detail",
props:['code'],
components: {
TitleBar,
Swiper,
MenuBar
},
data (){
return {
needBack : true,
title : "博彩详情",
history:null
}
},
mounted (){
axios.get("/api/detail?code="+this.code).then((res)=>{
this.history = res.data.data;
});
}
}
</script>
<style scoped>
</style>
用户页面
Vuex的使用
演示demo
import Vuex from 'vuex'
import Vue from 'vue'
Vue.use(Vuex);
export default new Vuex.Store({
state:{
all:['aa','bb','cc']
},
actions:{ //action中可执行异步操作
action1(context,msg){
console.log('action..'+msg);
context.commit('mutations1',msg);
}
},
mutations:{ //mutations中不能执行异步操作
mutations1(state){
state.all=['dd','ee']
}
}
});
注意:根Vue实例中需要引入store
在组件中,我们就可以这样来修改这里面的数据:
this.$store.dispatch("action1",'hahaha');
定义Store
import Vue from 'vue';
import VueX from 'vuex';
import User from './user'
//使用插件
Vue.use(VueX);
export default new VueX.Store({
modules:{
User
}
});
定义UserStore
const key = "user";
const state = {
user:null
}
const getters = {
isLogin:(state)=>state.user != null,
user:(state)=>state.user
}
const actions = {
loadLocalUser:(context)=>{
let user = localStorage.getItem(key);
context.commit('setUser',user);
},
setUser:(context,user)=>{
context.commit('setUser',user);
},
logout:(context)=>{
localStorage.removeItem(key);
context.commit('setUser',null);
}
}
const mutations = {
setUser:(state,user)=>{
state.user = user;
//保存
localStorage.setItem(key,user);
}
}
export default {
state,actions,mutations,getters
}
常用的辅助函数:
import {mapActions,mapGetters} from 'vuex'
在computed中使用
...mapGetters(['对应getters中的属性'])
在methods中使用
...mapActions(['对应action的名字'])
登录页面
<template>
<div>
<!--标题栏-->
<title-bar title="登录页面"></title-bar>
<!--登录的标蓝-->
<div class="row" style="margin-top: 32px;">
<!--空列-->
<div class="col-xs-1"></div>
<!--内容部分-->
<div class="col-xs-10">
<!--2.登录注册的标题-->
<div class="row">
<div class="col-xs-6 text-center" style="color: green;">登录</div>
<div class="col-xs-6 text-center" onclick="location.href='03-注册页面.html'" >注册</div>
</div>
<!--3.水平分割线-->
<hr style="border: 2px solid gainsboro;" />
<!--4.表单输入项-->
<div class="form-group">
<input type="text" v-model="email" class="form-control" placeholder="请输入您的邮箱...">
</div>
<!--5.密码-->
<div class="form-group">
<input type="password" v-model="password" class="form-control" placeholder="请输入您的密码...">
</div>
<!--9.注册-->
<div class="form-group">
<input type="button" @click="handleLogin()" class="form-control btn btn-success" value="登录" >
</div>
<!--跳转去登录-->
<div style="margin-top: 15px;">
<a href="#" style="color: green;">忘记密码</a> | <a href="03-注册页面.html" style="color: green;">去注册</a>
</div>
</div>
<!--空列-->
<div class="col-xs-1"></div>
</div>
</div>
</template>
<script>
import TitleBar from '@/pages/common/TitleBar'
import {mapGetters,mapActions} from 'vuex'
import axios from 'axios'
export default {
name: "login-page",
components:{
TitleBar
},
data(){
return {
email:'',
password:''
}
},
methods:{
...mapActions(['setUser']),
handleLogin(){
//this.$store.dispatch('changeAction','李四');
//this.$store.state.username = '王五'
//this.changeAction('赵六')
//发送异步请求去获取用户信息
axios.get('/api/login',{params:{email:this.email,password:this.password}}).then(resp=>{
console.log(resp.data.data);
this.setUser(resp.data.data);
this.$router.push('/user');
});
}
}
}
</script>
<style scoped>
</style>
我的页面
<template>
<div>
<title-bar title="用户信息"></title-bar>
<!--用户信息栏-->
<div class="row">
<div class="col-xs-4">
<img src="img/icon.jpg" alt="" class="img-circle img-thumbnail" style="width:80px;height:80px" />
</div>
<div class="col-xs-8" style="padding-top: 22px;padding-left: 5px;">
<p style="font-size: 16px;">{{user.username}}</p>
<p style="font-size: 14px;">手机号:{{user.mobile}}</p>
</div>
</div>
<!--水平分割线-->
<hr />
<!--今日幸运中奖号码-->
<div class="row">
<div class="col-xs-12" style="color: red;margin-bottom: 9px;">
您今日幸运中奖号码为:
</div>
<div class="col-xs-12 text-center" style="height:49px;">
<div class="ball-item ball-red">01</div>
<div class="ball-item ball-red">03</div>
<div class="ball-item ball-red">08</div>
<div class="ball-item ball-red">12</div>
<div class="ball-item ball-red">23</div>
<div class="ball-item ball-red">29</div>
<div class="ball-item ball-blue">15</div>
</div>
<div class="col-xs-offset-7 col-xs-2">
<button class="btn btn-default">购买立中大奖</button>
</div>
</div>
<!--水平分割线-->
<hr />
<!--累计中奖次数-->
<div class="row">
<div class="col-xs-6">
累计中奖次数:<span style="color:red;font-size: 14px;">1024</span>
</div>
<div class="col-xs-6">
累计中奖金额:<span style="color:red">512万</span>
</div>
</div>
<!--水平分割线-->
<hr />
<!--账户余额-->
<div class="row">
<div class="col-xs-12">
账户余额:<span style="color:red;font-size: 14px;">{{user.money}}元</span>
</div>
</div>
<!--水平分割线-->
<hr />
<!--我的订单-->
<div class="row">
<div class="col-xs-12">
我的订单
</div>
</div>
<!--水平分割线-->
<hr />
<!--基本信息-->
<div class="row">
<div class="col-xs-12">
基本信息
</div>
</div>
<!--水平分割线-->
<hr />
<!--设置信息-->
<div class="row">
<div class="col-xs-12">
设置
</div>
</div>
<!--水平分割线-->
<hr />
<!--底部菜单栏-->
<menu-bar index="3"></menu-bar>
</div>
</template>
<script>
import TitleBar from '@/pages/common/TitleBar'
import MenuBar from '@/pages/common/MenuBar'
import {mapGetters} from 'vuex'
export default {
name: "user-page",
components:{
TitleBar,
MenuBar
},
data(){
return {
name:this.$store.state.username
}
},
computed:{
...mapGetters(['user'])
}
}
</script>
<style scoped>
</style>
localStorage的使用
localStorage.getItem(key,value);
localStorage.setItem(key,value);
localStorage.removeItem(key)
localStorage.clear()