项目环境准备

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="/"
          >&lt;返回
          </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的使用

https://vuex.vuejs.org/zh/

演示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>&nbsp;|&nbsp;<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()