用Vue搭建项目--小博彩(详)
一:项目环境准备
- 项目目录结构准备
(1)搭建脚手架
npm install -g vue-cli
复制代码
(2)一定要在当前的目录结构下输入
vue init webpack 目录名
?Project name lottery
?Project description this is a niubility project
?Author xiaokaikai
?Vue build (选择一种构建的形式)
> Runtime + Compiler: recommended for most users
?Install vue-router?(Y/n) Y --这里说是否安装路由插件
?Use ESLint to lint your code? N-- 是否检查代码格式
?Pick an ESLint preset Standard -- 选择一种代码检查的规范
?Set up unit tests N 是否进行单元测试
?Setup e2e tests with Nightwatch N 是否使用e2e工具进行构建
?Should we run 'npm install' for you after the project has been created? npm --选择npm方式安装
输入完成之后,工具就开始构建我们的工程啦!
复制代码
(3)我们可以自定义目录出来,例如
pages : 所有的页面组件放在这里
pages/home: 页面所有的公用组件
pages/user:
utils : 放置工具类
store : 放置vuex数据仓库
复制代码
(4)整理包结构
<1>App.vue
<template>
<div id="app">
<router-view/>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style>
</style>
复制代码
<2>删除component目录
<3>删除assets/logo
- 安装JQuery和Bootstrap
(1)安装JQuery
由于bootstrap依赖Jquery,所以需要先安装jquery,这里版本使用1.12.4
npm install jquery@1.12.4 --save
复制代码
(2)验证
pages/home/HomePage
<template>
<!--
1.测试npm i jquery@1.12.4 --save之后能不能跑得动-->
<!--
2.在router目录下更改配置-->
<!---->
<div>
网站
</div>
</template>
<script>
$(function(){
alert(123);
}
export default {
name: "home-page"
}
</script>
<style scoped>
</style>
复制代码
(3)在router/index做配置
import Vue from 'vue'
import Router from 'vue-router'
//配置HomePage
import HomePage from '@/pages/home/HomePage'
Vue.use(Router)
export default new Router({
routes: [
//更改访问对象
{
path: '/',
name: 'HomePage',
component: HomePage
}
]
})
复制代码
(4)找到build/webpack.base.conf.js文件中:
在文件头部添加引用
const webpack = require('webpack');
复制代码
在文件配置对象的末尾增加如下配置
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"windows.jQuery": "jquery"
})
]
复制代码
(5)npm run dev再执行一次
3.安装Bootstrap
(1)安装bootstrap3.3.7
npm install bootstrap@3.3.7 --save
复制代码
(2)引入bootstrap
在src/main.js文件的顶部加入bootstrap的主要文件引用
import 'bootstrap/dist/css/bootstrap.min.css'
import 'bootstrap/dist/js/bootstrap.min.js'
复制代码
(3)导入我们之前案例中编写的lottery.css
-
将lottery.css复制粘贴进assets
-
在src/main.js文件的顶部'引入lottery文件 import"@/assets/lottery.css"
vue-devtool准备
不安装也可以...
vue-devtool是Vue官方提供的开发调试工具,能帮助我们查看Vue组件的数据,状态等属性。
二:博彩首页
(1)pages/common/TitleBar组件
做标题栏部分
<!--标题栏,可能有返回按钮-->
<template>
<div class="row title">
<div class="col-xs-12 title">
<router-link
tag="div"
v-if="needBack"
class="div_back"
to="/"
><返回
</router-link>
{{title}}
</div>
</div>
</template>
<script>
export default {
name: "title-bar",
props: {
title: String,
needBack: {
type:Boolean,
default:false
}
}
}
</script>
<style scoped>
.div_back{
position: absolute;
left: 15px;
}
</style>
复制代码
(2)home/HomePage.vue
<template>
<!--
1.测试npm i jquery@1.12.4 --save之后能不能跑得动-->
<!--
2.在router目录下更改配置-->
<!---->
<div>
<title-bar></title-bar>
</div>
</template>
<script>
// $(function(){
// alert(123);
// })
//HomePage要使用TitleBar里面的内容,要import.注意from里面的路径写法
import TitleBar from"@/pages/common/TitleBar"
//单文件也相当于是局部组件,那么就要注册或者说是绑定到下面的格式里面去
export default {
name: "home-page",
//绑定
components:{
TitleBar
}
}
</script>
<style scoped>
</style>
复制代码
(3)pages/common/TitleBar.vue完成标题栏部分的返回按钮和博彩首页的样式
<template>
<div class="row">
<div class = "col-xs-12 title" >
<!--网站标题-->
<!--指定返回的样式....控制返回的显示和隐藏-->
<div class="div-back" v-if="needback"><返回</div>
{{title}}
</div>
</div>
</template>
<script>
export default {
//vue将字母进行了拆分
name: "title-bar",
//接收外部传过来的数据
props:["title","needback"]
}
</script>
<style scoped>
.div-back{
position: absolute;
}
</style>
复制代码
(4)home/HomePage.vue
<div>
<!--在页面上调用的时候传值 显示返回按钮-->
<title-bar :title="title" needback="true"></title-bar>
</div>
</template>
<script>
//HomePage要使用TitleBar里面的内容,要import.注意from里面的路径写法
import TitleBar from"@/pages/common/TitleBar"
//单文件也相当于是局部组件,那么就要注册或者说是绑定到下面的格式里面去
export default {
name: "home-page",
//绑定
components:{
TitleBar
},
//取title这个变量
data(){
return{
title:"博彩首页"
}
}
}
</script>
<style scoped>
</style>
复制代码
三:Swiper轮播图组件
(1)在bootstrap插件中将轮播图部分代码复制过来
pages/common/Carousel.vue
<template>
<div id="carousel-example-generic" class="carousel slide row" 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/1.png" alt="...">
<div class="carousel-caption">
...
</div>
</div>
<div class="item">
<img src="@/assets/2.png" alt="...">
<div class="carousel-caption">
...
</div>
</div>
<div class="item">
<img src="@/assets/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: "carousel"
}
</script>
<style scoped>
</style>
复制代码
(2)将轮播图图片放在assets文件夹中
(3)在common/Carousel.vue中,导入Carousel和绑定Carsousel
<template>
<!--
1.测试npm i jquery@1.12.4 --save之后能不能跑得动-->
<!--
2.在router目录下更改配置-->
<!---->
<div>
<!--这是标题栏..... 在页面上调用的时候传值 显示返回按钮-->
<title-bar :title="title" needback="true"></title-bar>
<!--这是轮播图-->
<Carousel></Carousel>
</div>
</template>
<script>
// $(function(){
// alert(123);
// })
//HomePage要使用TitleBar里面的内容,要import.注意from里面的路径写法
import TitleBar from "@/pages/common/TitleBar"
//HomePage要使用Carousel里面的内容,要import.注意from里面的路径写法
import Carousel from "@/pages/common/Carousel"
//单文件也相当于是局部组件,那么就要注册或者说是绑定到下面的格式里面去
export default {
name: "home-page",
//绑定
components: {
//将TieleBar注册到home-page这里来
TitleBar,
//将Carousel注册到home-page这里来
Carousel
},
//取title这个变量
data() {
return {
title: "博彩首页"
}
}
}
</script>
<style scoped>
</style>
复制代码
四:彩票历史记录
(1)home/components/HistoryItem做彩票历史记录
<template>
<!--4.彩票历史记录-->
<!--删除掉onclick-->
<div class="row item">
<!--左边11个格子-->
<div class="col-xs-11">
<!--开奖日期-->
<div>
<span style="font-size: 18px;">第2018019期</span>
<span style="margin-left: 10px;">2018-02-13(二)</span>
</div>
<!--开奖号码-->
<div style="margin-top: 10px;">
<div class="ball-item ball-red">01</div>
<div class="ball-item ball-red">11</div>
<div class="ball-item ball-red">22</div>
<div class="ball-item ball-red">23</div>
<div class="ball-item ball-red">28</div>
<div class="ball-item ball-red">30</div>
<div class="ball-item ball-blue">15</div>
</div>
</div>
<!--右边1个格子-->
<div class="col-xs-1 div-right" >
<span class="glyphicon glyphicon-chevron-right"></span>
</div>
</div>
</template>
<script>
export default {
name: "history-item"
}
</script>
<style scoped>
/*把div里面的样式抽取出来*/
.item{
border: 1px solid gainsboro;height: 80px;padding-top: 5px;
}
/*把div里面的样式抽取出来*/
.div-right{
padding-left: 0px;padding-top: 30px;
}
</style>
复制代码
(2)home/components/HistoryList做彩票历史记录
<template>
<div>
<history-item v-for="i in 10" :key="i"></history-item></history-item>
</div>
</template>
<script>
// HistoryList这个组件要迭代这个HistoryItem,在这里导入
import HistoryItem from "./HistoryItem"
export default {
name: "history-list",
components:{
HistoryItem
}
}
</script>
<style scoped>
</style>
复制代码
五:将彩票历史记录写活
(1)在HomePage上添加mounted,在mounted里面发送请求
//取title这个变量
data() {
return {
title: "博彩首页"
}
},
mounted() {
// 发起请求,当数据请求回来的时候,将数据渲染到页面上
console.log("发送请求")
}
}
复制代码
(2)发送异步请求axios
参考文档: https://www.kancloud.cn/yunye/axios/234845
<1>安装
npm install axios
复制代码
<2>在HomePage里面导入axios
//HomePage要使用axios里面的内容,要import.注意from里面的路径写法
import axios from "axios"
复制代码
<3>在static新建一个file,文件名为index,里面写入数据
{
data:["1","2","3","4"]
}
复制代码
<4>在mouted()中用axios获取数据
mounted() {
// 发起请求,当数据请求回来的时候,将数据渲染到页面上
console.log("发送请求")
axios.get("/static/index").then(resp=>{
console.log(resp.data);
})
}
控制台能看到有static/index里面输出的结果.
复制代码
<5>将index里面的数据用数组的形式进行保存
//取title这个变量
data() {
return {
title: "博彩首页",
//将index里面的数据进行保存
historyList: []
}
},
mounted() {
// 发起请求,当数据请求回来的时候,将数据渲染到页面上
console.log("发送请求")
axios.get("/static/index").then(resp => {
this.historyList = resp.data.data;
})
}
复制代码
<6>将保存的数据扔到历史记录里面
<div>
<!--这是标题栏..... 在页面上调用的时候传值 显示返回按钮-->
<title-bar :title="title" needback="true"></title-bar>
<!--这是轮播图-->
<carousel></carousel>
<!--历史记录-->
<!--将历史记录的数据扔到这里来-->
<history-list :data="historyList"></history-list>
</div>
复制代码
<7>historyList接收data,用props
export default {
name: "history-list",
components:{
//将HistoryItem注册到home-page这里来
HistoryItem,
props:["data"]
}
}
复制代码
<8>循环
<template>
<div>
<history-item v-for="history in data" :key="history.code" :history1="history"></history-item>
</div>
</template>
复制代码
<9>将history的数据history1传给historyItem,为了展现index里面的所有数据
<script>
export default {
name: "history-item",
props:["history1"]
}
</script>
复制代码
<10>将historyItem的数据进行整改
<div>
<span style="font-size: 18px;">第{{history1.code}}期</span>
<span style="margin-left: 10px;">{{history1.data}}</span>
</div>
<!--开奖号码-->
<div style="margin-top: 10px;">
<div class="ball-item ball-red" v-for="red in history1.red.split(',')">{{red}}</div>
<div class="ball-item ball-blue">{{history1.blue}}</div>
</div>
</div>
script>
export default {
name: "history-item",
props:["history1"]
}
</script>
复制代码
-
使用
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); });
需求:当后台给了地址不断更换的时候的做法.
只要网址有改变,就修改一下target里面的网址就行了.
为了便于我们以后进行前后端联调,建议大家在代码中编写的时候,找到config/index.js修改proxyTable为如下的内容:
proxyTable: {
'/api':{
target:'http://localhost:8080',
//只要/以api开头的路径都重新改为static
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',
}
}
复制代码
六:底部菜单栏设置
(1)common/MenuBar
<template>
<div class="div-height">
<div class="menu" >
<div class="col-xs-4 menu-item menu-item-activied">
<span class="glyphicon glyphicon-home"></span>
<p>首页</p>
</div>
<div class="col-xs-4 menu-item">
<span class="glyphicon glyphicon-shopping-cart"></span>
<p>选号</p>
</div>
<div class="col-xs-4 menu-item">
<span class="glyphicon glyphicon-user"></span>
<p>我</p>
</div>
</div>
</div>
</template>
<script>
export default {
name: "menu-bar"
}
</script>
<style scoped>
.div-height{
height:50px;
}
</style>
复制代码
(2)各组件的步骤配置
<div>
<!--这是标题栏..... 在页面上调用的时候传值 显示返回按钮-->
<title-bar :title="title" needback="true"></title-bar>
<!--这是轮播图-->
<carousel></carousel>
<!--历史记录-->
<!--将历史记录的数据扔到这里来-->
<history-list :data="historyList"></history-list>
<!--底部菜单栏-->
<menu-bar></menu-bar>
</div>
//HomePage要使用MenuBar里面的内容,要import.注意from里面的路径写法
import MenuBar from "@/pages/common/MenuBar"
//将MenuBar注册到home-page这里来
MenuBar,
复制代码
(3)在MenuBar里面,传入:class
<template>
<div class="div-height">
<div class="menu">
<div class="col-xs-4 menu-item" :class="{'menu-item-activied':index=='1'}">
<span class="glyphicon glyphicon-home"></span>
<p>首页</p>
</div>
<div class="col-xs-4 menu-item">
<span class="glyphicon glyphicon-shopping-cart"></span>
<p>选号</p>
</div>
<div class="col-xs-4 menu-item" :class="{'menu-item-activied':index=='3'}">
<span class="glyphicon glyphicon-user"></span>
<p>我</p>
</div>
</div>
</div>
</template>
<script>
export default {
name: "menu-bar",
props:{
index:{
type:String,
default:"1"
}
}
}
</script>
复制代码
(4)在HomePage里面,传入一个index
<div>
<!--这是标题栏..... 在页面上调用的时候传值 显示返回按钮-->
<title-bar :title="title" needback="true"></title-bar>
<!--这是轮播图-->
<carousel></carousel>
<!--历史记录-->
<!--将历史记录的数据扔到这里来-->
<history-list :data="historyList"></history-list>
<!--底部菜单栏-->
<menu-bar index="3"></menu-bar>
</div>
复制代码
七:点击历史记录跳转到历史记录详情页面
(1)使用声明式跳转:router-link tag="div" to="url"
home/components/DetailPage
<template>
<div>博彩详情组件</div>
</template>
<script>
export default {
name: "detail-page"
}
</script>
<style scoped>
</style>
复制代码
router/index
import Vue from 'vue'
import Router from 'vue-router'
//配置HomePage
import HomePage from '@/pages/home/HomePage'
//配置DetailPage
import DetailPage from '@/pages/home/DetailPage'
Vue.use(Router)
export default new Router({
routes: [
//更改访问对象
{
path: '/',
name: 'HomePage',
component: HomePage
},
//跳转到博采详情页面
{
path: '/detail',
name: 'DetailPage',
component: DetailPage
}
]
})
复制代码
home/components/HistoryList
<template>
<div>
<router-link tag="div" to="/detail?code=123">点击跳转</router-link>
<history-item v-for="history in data" :key="history.code" :history1="history"></history-item>
</div>
</template>
复制代码
home/components/DetailPage传参data
<script>
export default {
name: "detail-page",
data(){
return{
code:this.$route.query.code
}
}
}
</script>
复制代码
(2)使用编程式跳转
//this.$router:代表当时全局的路由器 //this.$route:代表的是当前的路由信息 复制代码
(3)点击历史记录就跳转
- @click.native="toToDetail('/detail?code='+history.code)"
home/components/historyList
<history-item
v-for="history in data"
:key="history.code"
:history1="history"
@click.native="goToDetail('/detail?code='+history.code)">
</history-item>
复制代码
(4)优化返回按键
DetailPage
<template>
<div>
<!--<!–把传入的参数带过来–>-->
<!--博彩详情组件{{code}}-->
<title-bar title="博彩详情" :needback="true"></title-bar>
<!--导入轮播图-->
<carousel></carousel>
<!--导入底部菜单栏-->
<menu-bar></menu-bar>
</div>
</template>
<script>
//HomePage要使用TitleBar里面的内容,要import.注意from里面的路径写法
import TitleBar from "@/pages/common/TitleBar"
//HomePage要使用Carousel里面的内容,要import.注意from里面的路径写法
import Carousel from "@/pages/common/Carousel"
//HomePage要使用MenuBar里面的内容,要import.注意from里面的路径写法
import MenuBar from "@/pages/common/MenuBar"
export default {
name: "detail-page",
components:{
TitleBar,
MenuBar,
Carousel
},
//跳转到详情页面的时候传入参数
data() {
return {
code: this.$route.query.code
}
}
}
</script>
<style scoped>
</style>
复制代码
TitleBar
<template>
<div class="row">
<div class="col-xs-12 title">
<!--网站标题-->
<!--指定返回的样式....控制返回的显示和隐藏-->
<div class="div-back" v-if="needback"><返回</div>
{{title}}
</div>
</div>
</template>
<script>
export default {
//vue将字母进行了拆分
name: "title-bar",
//接收外部传过来的数据
// props: ["title", "needback"]
// }
props: {
title: {
type: String
},
needback: {
type: Boolean,
default:false
}
}
}
</script>
<style scoped>
.div-back {
position: absolute;
}
</style>
复制代码
(5)导入老师发的detail文件到static文件里面
DetailPage
<template>
<div>
<title-bar title="博彩详情" :needback="true"></title-bar>
<!--轮播图-->
<carousel></carousel>
<!--显示彩票信息-->
<!--3.开奖日期-->
<div style="margin-top: 8px;">
<div style="float: left;">第{{history.code}}期</div>
<div style="float: right;">{{history.date}}</div>
</div>
<!--清除浮动的div-->
<div class="clearfix"></div>
<!--4.中奖号码-->
<div class="row text-center" style="margin-top: 10px;" v-if="history.red != null">
<div class="ball-item ball-red" v-for="red in history.red.split(',')">{{red}}</div>
<div class="ball-item ball-blue">{{history.blue}}</div>
</div>
<!--5.奖池金额-->
<div style="margin-top: 14px;">
<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" style="color: red;">{{history.sales}}</td>
<td class="text-center" style="color: red;">{{history.poolmoney}}</td>
</tr>
</tbody>
</table>
</div>
<!--6.中奖信息-->
<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">
<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 Carousel from '@/pages/common/Carousel';
import MenuBar from '@/pages/common/MenuBar'
export default {
name: "detail-page",
components: {
TitleBar,
Carousel,
MenuBar
},
data() {
return {
code: this.$route.query.code,
history: {}
}
},
mounted() {
//发送请求获取 获取当前期的数据
axios.get('/api/detail?code=' + this.code).then(resp => {
console.log(resp.data)
this.history = resp.data.data;
});
}
}
</script>
<style scoped>
</style>
复制代码
组件之间的跳转
-
声明式跳转https://router.vuejs.org/zh/api/#router-link-props
Home
Home
Home
Home
User
Register
-
编程式跳转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
复制代码
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()
复制代码
选号组件
选号页面示例代码
<template>
<div>
<!--标题栏-->
<title-bar :needBack="needBack" title="博彩选号"></title-bar>
<!--信息声明-->
<lottery-info></lottery-info>
<div style="color:darkgray">请选择6个红球,1个蓝球</div>
<!--红球展示区域-->
<red-ball-picker :data="randomRed" @onRedSelected="handleRedSelected"></red-ball-picker>
<!--蓝球展示区域-->
<blue-ball-picker :data="randomBlue" @onBlueSelected="handleBlueSelected"></blue-ball-picker>
<button type="button" class="btn btn-default pull-right clearfix" @click="addOne()">添加</button>
<div class="clearfix"></div>
<!--机选按钮-->
<div class="rdm-div">
<button type="button" class="btn btn-default pull-right" @click="addRandom()">机选</button>
<select class="form-control select" v-model="num">
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
</select>
</div>
<!--5.底部菜单栏-->
<div class="menu">
<div class="menu-item" @click="goToCart">
<span class="glyphicon glyphicon-shopping-cart"></span>
<span class="badge" >{{cartSize}}</span>
<p>购物车</p>
</div>
<div class="menu-item" @click="goToCart">
<span class="glyphicon glyphicon-save"></span>
<p>立即投注</p>
</div>
</div>
</div>
</template>
<script>
import TitleBar from '@/pages/common/TitleBar'
import RedBallPicker from '@/pages/shopping/components/RedBallPicker'
import BallUtils from '@/utils/BallUtils'
import BlueBallPicker from "./components/BlueBallPicker";
import LotteryInfo from "./components/LotteryInfo";
import {mapActions,mapGetters} from 'vuex'
export default {
name: "select-page",
components:{
BlueBallPicker,
TitleBar,
RedBallPicker,
LotteryInfo
},
data (){
return{
needBack:true,
redBalls:[],
blueBall:null,
randomRed:null,
randomBlue:null,
num:1
}
},
computed:{
...mapGetters(['cartSize']),
},
methods:{
...mapActions(['addToCart']),
handleRedSelected(balls){
this.redBalls = balls;
},
handleBlueSelected(ball){
this.blueBall = ball;
},
addOne(){
//先判断红球=0,蓝球=0,一个没有选话就随机产生一组
if(this.redBalls!=null && this.redBalls.length==0 && this.blueBall == null){
//随机产生一注彩票
this.randomOne();
}else if(this.redBalls!=null && this.redBalls.length==6 && this.blueBall != null){
//判断选择的红球的数量是否=6,蓝球的数量=1,添加到购物车
this.addToCart({redBalls:this.redBalls,blue:this.blueBall,count:1})
}else{
//否则条件不成立,提示红球6个蓝球1个
alert("红球的数量须为6个,蓝球的数量为1个");
}
},
randomOne(){
this.randomRed = BallUtils.randomRed()
this.randomBlue = BallUtils.randomBlue()
},
addRandom(){
//根据用户机选的数量,随机产生
let self = this
for(let i=0; i < this.num; i++){
self.randomOne();
//将每次随机产生的号码,添加到购物车中
self.addToCart({redBalls:self.randomRed,blue:self.randomBlue,count:1})
}
},
goToCart(){
this.$router.push('/cart')
}
}
}
</script>
<style scoped>
.select{
float:right;
width:90px;
}
.badge {
background-color: red;
position: absolute;
top: -10px
}
.menu-item{
width: 50%;
}
.rdm-div{
margin-top: 15px;
}
</style>
复制代码
红球选号区域
我们首先来解决一下页面上球的显示问题,红球总共33个,如果我们直接写死的话,重复代码会很多,我们考虑来初始化这33个红球,示例代码如下
这里我们选用created这个生命周期钩子
created(){
//初始化页面中的球数据
for(let i = 1; i<=33; i++){
let red = i;
if(i < 10){
red ="0"+i;
}
//每一个被初始化出来的红球都是没有被选中的状态
this.balls.push({number:red.toString(),selected:false});
}
}
复制代码
某个红球被选中
- 先判断当前球是否已经被选中
- 若被选中,则取消选中状态
- 将当前红球,从所有已选中的球中删除掉
- 若未被选中,则先判断当前选中的红球是否小于6个
- 若小于6个
- 修改当前求的状态
- 将当前球保存到所有选中的球中
- 若已经等于6个红球了
- 提示用户最多只能选择6个红球
- 若小于6个
- 若被选中,则取消选中状态
- 通知父组件,红球选中的数据发生了改变
注意:我们这里只通知父组件选中球的信息,如["01","03","05","08","09","32"]
handleRedClick(ball){
//1.先判断当前球是否已经被选中
if(ball.selected){
//如果当前球已经被选中,则取消选中
ball.selected = false;
//将当前的球从被选中的数组中删除掉
let index = this.selectedRedBalls.indexOf(ball.number);
//删除元素
this.selectedRedBalls.splice(index,1);
}else{
//判断当前选中的球是否小于6个
if(this.selectedRedBalls.length < 6){
//选中当前球
ball.selected = true;
this.selectedRedBalls.push(ball.number);
}else{
alert('红球最多只能选择6个')
}
}
//通知父组件数据发生变化了
this.$emit('onRedSelected',this.selectedRedBalls);
}
<template>
<div class="clearfix">
<div v-for="ball in balls" :key="ball.number" class="col-xs-ball">
<div class="ball-item ball-red" @click="handleRedClick(ball)" :class="{'ball-red-selected':ball.selected}">
{{ball.number}}
</div>
</div>
</div>
</template>
<script>
export default {
name: "red-ball-picker",
props:{
data:{
type:Array,
default:null
}
},
data(){
return {
balls:[],
selectedRedBalls:[]
}
},
methods:{
handleRedClick(ball){
//1.先判断当前球是否已经被选中
if(ball.selected){
//如果当前球已经被选中,则取消选中
ball.selected = false;
//将当前的球从被选中的数组中删除掉
let index = this.selectedRedBalls.indexOf(ball.number);
//删除元素
this.selectedRedBalls.splice(index,1);
}else{
//判断当前选中的球是否小于6个
if(this.selectedRedBalls.length < 6){
//选中当前球
ball.selected = true;
this.selectedRedBalls.push(ball.number);
}else{
alert('红球最多只能选择6个')
}
}
//通知父组件数据发生变化了
this.$emit('onRedSelected',this.selectedRedBalls);
}
},
watch:{
data(newVal,OldVal){
//监听data数据的变化
if(newVal != null && newVal.length == 6){
//清空当前已经选择数组的状态
this.selectedRedBalls = [];
// 将新数据保存到当前选中的球数组中
this.selectedRedBalls.push(...newVal);
//修改页面上球的状态
let self = this;
this.balls.forEach(function(ball){
let index = self.selectedRedBalls.indexOf(ball.number);
ball.selected = index != -1;
});
//通知父组件数据发生变化了
this.$emit('onRedSelected',self.selectedRedBalls);
}
}
},
created(){
//初始化页面中的球数据
for(let i = 1; i<=33; i++){
let red = i;
if(i < 10){
red ="0"+i;
}
this.balls.push({number:red.toString(),selected:false});
}
}
}
</script>
<style scoped>
</style>
复制代码
蓝球选号区域
初始化16个蓝球
created(){
//初始化页面中的球数据
for(let i = 1; i<=16; i++){
let blue = i;
if(i < 10){
blue ="0"+i;
}
this.balls.push({number:blue.toString(),selected:false});
}
}
复制代码
某个蓝球被选中
-
先取消前一次选中的蓝球的状态
-
修改当前选中蓝球的状态
VueX存储购物车
这里我们定义购物车里面的内容为如下格式:
{red:"01,03,05,08,09,32",blue:"13",count:2}
复制代码
示例代码如下
//从浏览器内置的存储去获取数据
let jsonStr = localStorage.getItem("carts");
//将json字符串转成json数组
let defaultCarts = JSON.parse(jsonStr);
//定义保存数据的地方
const state={
carts:defaultCarts // {red:'01,02,03,04,05,06',blue:"16",count:1}
}
//对外提供访问数据的方法
const getters={
cartSize:(state)=>state.carts.length,
getCarts:(state)=>state.carts,
totalMoney:(state)=>{
let totalCount = 0;
state.carts.forEach((item)=>{
totalCount+=item.count;
});
return totalCount*2;
}
}
//对外提供获取数据的方法
const actions={
// {red:'01,02,03,04,05,06',blue:"16",count:1}
// 传递过来的数据是 {redBalls:this.redBalls,blueBall:this.blueBall,count:1};
addToCart(context,data){
console.log("actions中addToCart被调用");
console.log("action提交数据给mutations去修改")
let redBalls = data.redBalls;
let red = "";
redBalls.forEach((item)=>{
red +=","+item;
});
red = red.substr(1);
//console.log(red);
let cartItem = {red:red,blue:data.blueBall,count:data.count};
context.commit('mAddToCart',cartItem);
},
//清空购物车
clearCarts(context){
context.commit('mClearCarts');
},
//删除某一条记录
deleteItem(context,cartItem){
//action调用mutations去真的删除
context.commit('mDeleteItem',cartItem);
}
}
//跟踪数据变化的,vue需要的, 真正修改数据
const mutations = {
mAddToCart(state,cartItem){
console.log("mutations中修改数据:"+cartItem);
state.carts.push(cartItem);
//将内存中的数据保存到浏览器本地
localStorage.setItem("carts",JSON.stringify(state.carts))
},
//真正清空数组的地方
mClearCarts(state){
state.carts=[];
localStorage.clear();
},
mDeleteItem(state,cartItem){
let index = state.carts.indexOf(cartItem);
//删除记录
state.carts.splice(index,1);
localStorage.setItem("carts",JSON.stringify(state.carts))
}
}
//导出文件的所有内容
export default {
state,getters,actions,mutations
}
复制代码
购物车页面
购物车组件
<template>
<div>
<!--需要返回按钮的标题栏-->
<title-bar :needBack="true" title="购物车"></title-bar>
<!--需要轮播图-->
<swiper></swiper>
<!--需要彩票信息-->
<lottery-info></lottery-info>
<!--三个按钮组-->
<div class="row" style="margin-bottom: 10px;">
<div class="col-xs-4">
<button type="button" class="btn btn-default" @click="handleSelect">+手动选号</button>
</div>
<div class="col-xs-4">
<button type="button" class="btn btn-default" @click="handleRandom">+机选一注</button>
</div>
<div class="col-xs-4">
<button type="button" class="btn btn-default" @click="handleClear">清空列表</button>
</div>
</div>
<!--展示购物项条目-->
<div>
<shopping-item v-for="item in carts" :key="item.red" :data="item" @onDeleteItem="deleteItem" ></shopping-item>
</div>
<!--底部的菜单栏-->
<div style="height: 50px">
<div class="menu" >
<div class="menu-item" @click="submitOrder" >
<p>立即付款 {{totalMoney}}元</p>
</div>
</div>
</div>
</div>
</template>
<script>
import TitleBar from '@/pages/common/TitleBar';
import Swiper from '@/pages/common/Swiper';
import LotteryInfo from './components/LotteryInfo'
import ShoppingItem from './components/ShoppingItem'
import BallUtils from '@/utils/BallUtils'
import {mapActions,mapGetters} from 'vuex'
export default {
name: "cart-page",
components:{
Swiper,
TitleBar,
LotteryInfo,
ShoppingItem
},
methods:{
...mapActions({
addToCart:"addToCart",
clearCart:"clearCart",
deleteOne:'deleteOne'
}),
handleSelect(){
//跳转去选号页面
this.$router.go(-1);
},
handleRandom(){
let redBalls = BallUtils.randomRed();
let blue = BallUtils.randomBlue();
this.addToCart({redBalls:redBalls,blue:blue,count:1});
},
handleClear(){
//this.$store.dispatch('clearCart')
this.clearCart()
},
deleteItem(cart){
this.deleteOne(cart);
}
},
computed:{
...mapGetters({
carts:"carts",
totalMoney:"totalMoney"
})
}
}
</script>
<style scoped>
.menu{
height: 60px;
}
.menu-item{
width: 100%;
text-align: center;
height: 50px;
line-height: 50px;
}
</style>
复制代码
购物项组件
<template>
<div class="row shop-item" >
<div class="col-xs-1" @click="handleDelete(data)" style="padding-left: 10px;padding-top: 18px;">
<!--删除的图标-->
<span v-if="showDelete" class="glyphicon glyphicon-remove-circle"></span>
</div>
<div class="col-xs-10" style="padding-right: 0px;padding-left: 5px" >
<div>
<div class="ball-item ball-red" v-for="red in data.red.split(',')" :key="red">{{red}}</div>
<div class="ball-item ball-blue" >{{data.blue}}</div>
</div>
<div style="margin-top: 5px;">单式{{data.count}}注 {{data.count*2}}元</div>
</div>
<div class="col-xs-1" style="padding-left: 5px;padding-top: 18px;">
<!--小箭头-->
<span v-if="showRight" class="glyphicon glyphicon-chevron-right"></span>
</div>
</div>
</template>
<script>
export default {
name: "shopping-item",
props:{
showDelete:{
type:Boolean,
default:true
},
showRight:{
type:Boolean,
default:true
},
data:{
type:Object
}
},
methods:{
handleDelete(){
this.$emit('onDeleteItem',this.data)
}
}
}
</script>
<style scoped>
.shop-item{
padding-top: 10px;
padding-bottom: 10px;
border: 1px solid #E5E5E5;
}
</style>
复制代码
生产环境打包
项目中我们编写的vue文件并不能直接丢给服务器。
vue-cli为我们提供了一键打包的功能,并自动为我们进行了资源压缩,合并,小图进行base64,css编译等很多功能,只需要执行以下命令即可:
npm run build
复制代码
将打包出来的dist目录下的内容,丢给服务器人员即可。
回顾:
第一天: 基础语法
v-model
v-for
v-if
props
$emit 对外发消息
:class
:属性名=js代码
data:{}
computed:{}
watch:{}
methods:{}
mounted:{} 若有异步请求
created:{} 同步处理
单文件组件:局部组件
第二天:
网站首页 axios 发起异步请求
博彩详情页面: this.$router.push 组件之间的跳转
this.$router.go()
共享数据: Vuex
登录页面
用户页面
new Vuex.Store({
module:{
}
});
const state={} 存储数据
const getters={} 相当于是javabean中Get方法 获取数据方法
const actions={} 相当于是set方法, 对外提供修改数据的方法
const mutations={} 内部自己真正去修改数据的地方
第三天:
选中球
机选球
添加记录去vuex
购物车去展示数据
localStorage
链接:https://pan.baidu.com/s/1DzCJJtGVYThF4YxwqqxDmw 密码:8uan
链接:https://pan.baidu.com/s/1EBJjxH-OObV2r50tXg88DQ 密码:rj4n
网友评论