小小千想和您聊一聊

当前位置: 首页> 技术分享> Vue项目开发流程

Vue项目开发流程

  一、企业项目开发流程

  产品提需求

  交互设计出原型设计

  视觉设计出UI设计图

  前端开发出页面模板

  server端存取数据库

  验收测试

  二、为什么要使用vue: https://cn.vuejs.org/v2/guide/comparison.html

  5个前端,4个会vue,1个会react,那么你该如何选择

  客户要求使用vue

  ...

  三、如何选择脚手架

  自己搭建脚手架 webpack

  使用现成的脚手架 https://cli.vuejs.org/zh/

  vue-cli 基于webpack 3

  @vue/cli 基于webpack 4

  假设电脑中装的时@vue/cli脚手架,但是想用vue-cli的模板,可以如下安装指令

  cnpm install -g @vue/cli

  cnpm install -g @vue/cli-init

  四、创建项目

  @vue/cli

  第一种创建方式: vue create mynewapp

  第二种创建方式: vue ui

  第三种创建法师: vue init webpack myapp

  五、开始项目配置

  1、如果做的移动端,那么需要考虑300ms延时以及点击穿透的问题,甚至是部分android手机不支持promise的解决办法,在index.html中引入如下代码,如果做的是pc端,忽略此步骤

// 避免移动端真机运行双击屏幕会放大
<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=0">
<script src="https://as.alipayobjects.com/g/component/fastclick/1.0.6/fastclick.js"></script> <script> if ('addEventListener' in document) { document.addEventListener('DOMContentLoaded', function() { FastClick.attach(document.body); }, false); } if(!window.Promise) { document.writeln('<script src="https://as.alipayobjects.com/g/component/es6-promise/3.2.2/es6-promise.min.js"'+'>'+'<'+'/'+'script>'); } </script>
    2、修改目录结构
src
    api
    assets
    components
    lib
    router
    store
    views
    App.vue
    main.js
    3、修改App.vue结构
cnpm i node-sass sass-loader -D
<template>
<div class="container">
<div class="box">
<header class="header">头部</header>
<div class="content">内容</div>
</div>
<footer class="footer">底部</footer>
</div>
</template>


<script>
export default {
name: 'App'
}
</script>


<style lang="scss">
@import '~@/lib/reset.scss';
html, body, .container, .detailContent {
@include rect(100%, 100%); // width: 100%; height: 100%;
}
.container, .detailContent {
@include flexbox(); // display: flex
@include flex-direction(column); // flex-direction:column
.box {
@include flex();
@include rect(100%, auto);
@include flexbox();
@include flex-direction(column);
.header {
@include rect(100%, 0.44rem);
@include background-color(#f66);
}
.content {
@include flex(); // flex: 1;
@include rect(100%, auto);
@include overflow(auto);
}
}
.footer {
@include rect(100%, 0.5rem);
@include background-color(#efefef);
@include flexbox();
a {
@include flex();
@include rect(auto, 100%);
@include flexbox();
@include justify-content(); // justify-content: center;
@include align-items(); // align-items: center;
@include text-color(#333);
&.active {
@include text-color(#f66);
}
}
}
}
</style>
 4、依据结构设计页面
    views/home/index.vue
    views/kind/index.vue
    views/cart/index.vue
    views/user/index.vue
以home为例
<template>
<div class="box">
<header class="header">首页头部</header>
<div class="content">首页内容</div>
</div>
</template>


<script>
export default {
}
</script>


<style lang="scss">
</style>

    5、配置路由
router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import routes from './routes'

Vue.use(Router)

export default new Router({
routes
})
router/routes.js ----- 命名视图+命令路由+路由的懒加载+路由重定向
// 如果一个页面不需要底部,那么就不要传footer,比如kind无需底部
const routes = [
{
path: '/',
redirect: '/home'
},
{
path: '/home',
name: 'home',
components: {
default: () => import('@/views/home'),
footer: () => import('@/components/Footer')
}
},
{
path: '/kind',
name: 'kind',
components: {
default: () => import('@/views/kind'),
footer: () => import('@/components/Footer')
}
},
{
path: '/cart',
name: 'cart',
components: {
default: () => import('@/views/cart'),
footer: () => import('@/components/Footer')
}
},
{
path: '/user',
name: 'user',
components: {
default: () => import('@/views/user'),
footer: () => import('@/components/Footer')
}
}
]


export default routes


修改App.vue ---- 命名视图(多视图路由)default   footer
<template>
<div class="container">
<router-view></router-view>
<router-view name="footer"></router-view>
</div>
</template>
6、底部点击切换路由
    components/Footer.vue,需要在App.vue中修改布局样式
<template>
<footer class="footer">
<ul>
<router-link tag="li" to="/home">
<span></span>
<p>首页</p>
</router-link>
<router-link tag="li" to="/kind">
<span></span>
<p>分类</p>
</router-link>
<router-link tag="li" to="/cart">
<span></span>
<p>购物车</p>
</router-link>
<router-link tag="li" to="/user">
<span></span>
<p>我的</p>
</router-link>
</ul>
</footer>
</template>


<script>
export default {
}
</script>


7、编写页面
    PC: element-ui  https://element.eleme.io/
       iview   https://www.iviewui.com/
    移动端: mint-ui   http://mint-ui.github.io/
         vant   https://youzan.github.io/vant/
    mint-ui 为例
cnpm i mint-ui -S
cnpm install babel-plugin-component -D
修改.babelrc文件
{
"presets": [
["env", {
"modules": false,
"targets": {
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
}
}],
"stage-2"
],
"plugins": ["transform-vue-jsx", "transform-runtime",["component", [
{
"libraryName": "mint-ui",
"style": true
}
]]],
"env": {
"test": {
"presets": ["env", "stage-2"],
"plugins": ["transform-vue-jsx", "transform-es2015-modules-commonjs", "dynamic-import-node"]
}
}
}
7.1 main.js入口文件处引入mintui
import Vue from 'vue'
import App from './App'
import router from './router'
import MintUI from 'mint-ui'
Vue.config.productionTip = false
Vue.use(MintUI)
7.2 封装了banner.vue和prolist.vue组件
banner.vue组件中使用了UI库 ---- 轮播图默认占据整个高度,提前设置好一个父容器
<template>
<div class="banner">
<mt-swipe :auto="4000">
<mt-swipe-item>11</mt-swipe-item>
<mt-swipe-item>22</mt-swipe-item>
<mt-swipe-item>33</mt-swipe-item>
</mt-swipe>
</div>
</template>


<script>
import Vue from 'vue'
import { Swipe, SwipeItem } from 'mint-ui'
Vue.use(Swipe, SwipeItem)
export default {
}
</script>


<style lang="scss">
.banner {
height: 150px;
}
</style>
prolist.vue
<template>
<ul class="prolist">
<li>
肖生客的救赎
</li>
</ul>
</template>


<script>
export default {
}
</script>
home/index.vue中引用组件
<template>
<div class="box">
<header class="header">首页头部</header>
<div class="content">
<Banner />
<Prolist />
</div>
</div>
</template>


<script>
import Banner from '@/components/Banner'
import Prolist from '@/components/Prolist'
export default {
components: {
Banner,
Prolist
}
}
</script>


<style lang="scss">
.banner {
height: 150px;
}
</style>

8、数据请求
cnpm i axios -S
8.1 添加mock数据功能 ----- 开发前期 ---- 后端没有接口时这样用
cnpm i mockjs -D
api/mock.js
// 引入mockjs
const Mock = require('mockjs')
const Random = Mock.Random
const doubandata = function () {
let articles = []
for (let i = 0; i < 10; i++) {
let newArticleObject = {
title: Random.csentence(5, 30),
thumbnail_pic_s: Random.dataImage('300x250', 'mock的图片'),
author_name: Random.cname(),
date: Random.date() + ' ' + Random.time()
}
articles.push(newArticleObject)
}
return articles
}
// Mock.mock( url, post/get , 返回的数据);
Mock.mock('/douban', 'get', doubandata)
api/index.js
import axios from 'axios'
import { Indicator } from 'mint-ui'
const baseUrl = process.env.NODE_ENV === 'development' ? '' : 'https://www.daxunxun.com'
console.log(baseUrl)
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
Indicator.open()
return config
}, function (error) {
// 对请求错误做些什么
Indicator.close()
return Promise.reject(error)
})


// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 对响应数据做点什么
Indicator.close()
return response
}, function (error) {
// 对响应错误做点什么
Indicator.close()
return Promise.reject(error)
})


const api = {
requestGet (url) {
return new Promise((resolve, reject) => {
axios.get(baseUrl + url)
.then(data => resolve(data.data))
.catch(err => reject(err))
})
},
requestPost (url, params) {
return new Promise((resolve, reject) => {
axios.post(baseUrl + url, params)
.then(data => resolve(data.data))
.catch(err => reject(err))
})
}
}


export default api
main.js处引入mock,项目上线以及由接口时则删掉即可
import Vue from 'vue'
import App from './App'
import router from './router'
import MintUI from 'mint-ui'
import '@/api/mock'
8.2 假设后端已经有了接口,但是可能会存在跨域问题,如果有跨域问题,开发时需要使用到反向代理
删掉main.js出的mock
config/index.js处配置反向代理
proxyTable: {
'/daxun': {
target: 'https://www.daxunxun.com/',
changeOrigin: true,
pathRewrite: {
'^/daxun': ''
}
},
},
修改api/index.js的 baseUrl地址
const baseUrl = process.env.NODE_ENV === 'development' ? '/daxun' : 'https://www.daxunxun.com'
重启服务器,查看效果,预期一致
9、数据处理
    本组件内部处理 data
    状态管理器处理
    data处理方式
    home/index.vue
<template>
<div class="box">
<header class="header">首页头部</header>
<div class="content">
<Banner />
<Prolist :prolist = "prolist"/>
</div>
</div>
</template>


<script>
import Banner from '@/components/Banner'
import Prolist from '@/components/Prolist'
import api from '@/api'
export default {
data () {
return {
bannerdata: [],
prolist: []
}
},
components: {
Banner,
Prolist
},
mounted () {
api.requestGet('/douban').then(data => {
console.log(data)
this.prolist = data
})
}
}
</script>


<style lang="scss">
.banner {
height: 150px;
}
</style>


prolist.vue
<template>
<ul class="prolist">
<li v-for="(item, index) of prolist" :key="index">
{{ item.title }}
</li>
</ul>
</template>


<script>
export default {
props: {
prolist: Array
}
}
</script>


mock.js修改了模拟地址,以后切换更加简单

Mock.mock('/daxun/douban', 'get', doubandata)
以后切换mock和开发服务器只需要添加和删除main.js中的mock字段即可
10、状态管理器
cnpm i vuex -S
创建store/index.js,store/home.js,store/kind.js
index.js
import Vue from 'vue'
import VueX from 'vuex'
import home from './home'
import kind from './kind'
Vue.use(VueX)


const store = new VueX.Store({
modules: {
home,
kind
}
})


export default store

kind.js
export default {
state: {},
getters: {},
actions: {},
mutations: {}
}


home.js
import api from '@/api'
const store = {
state: {
    bannerdata: [1, 2, 3],
    prolist: []
},
getters: {
    prolistLength (state) {
        return state.prolist.length
    }
},
actions: {
    getprolist ({ commit }) { // 参数的解构赋值 context
        api.requestGet('/douban')
        .then(data => {
            console.log(data)
            commit('changeprolist', data) // context.commit('changeprolist', data)
        }).catch(err => console.log(err))
    }
},
mutations: {
changebannerdata (state, data) {
    state.bannerdata = data
},
changeprolist (state, data) {
    state.prolist = data
}
}
}


export default store
home/index.vue 通过mapState辅助函数可以直接获取状态管理器中的值,通过dispatch 触发异步的actions
<template>
<div class="box">
<header class="header">首页头部</header>
<div class="content">
<Banner />
<Prolist :prolist = "prolist"/>
{{ bannerdata }}
</div>
</div>
</template>


<script>
import Banner from '@/components/Banner'
import Prolist from '@/components/Prolist'
import { mapState } from 'vuex'


export default {
computed: {
...mapState({
bannerdata: (state) => state.home.bannerdata,
prolist: (state) => state.home.prolist
})
},
components: {
Banner,
Prolist
},
mounted () {
this.$store.dispatch('getprolist') // dispatch 一个action(异步操作)
}
}
</script>


<style lang="scss">
.banner {
height: 150px;
}
</style>


使用mapActions的等价写法
<template>
<div class="box">
<header class="header">首页头部</header>
<div class="content">
<Banner />
<Prolist :prolist = "prolist"/>
{{ bannerdata }}
</div>
</div>
</template>


<script>
import Banner from '@/components/Banner'
import Prolist from '@/components/Prolist'
import { mapState, mapActions } from 'vuex'


export default {
computed: {
...mapState({
bannerdata: (state) => state.home.bannerdata,
prolist: (state) => state.home.prolist
})
},
components: {
Banner,
Prolist
},
methods: {
...mapActions(['getprolist']) // 生成一个同名的函数 function getprolsit () {this.$store.dispatch('getprolist')}
},
mounted () {
this.getprolist()
}
}
</script>


<style lang="scss">
.banner {
height: 150px;
}
</style>



11、列表进入详情
编写详情页面 detail/index.vue,一定要记得修改App.vue中的样式
<template>
<div class="detailContent">
<div class="box">
<header class="header">详情头部</header>
<div class="content">内容</div>
</div>
<footer class="footer">详情底部</footer>
</div>
</template>


<script>
export default {
}
</script>


    修改routes.js
{
path: '/detail/:id',
name: 'detail',
components: {
default: () => import('@/views/detail')
}
}
声明式跳转
    prolist.vue
<router-link tag="li" :to="{name: 'detail', params: {id: item.id}}" v-for="(item, index) of prolist" :key="index">
{{ item.title }}
</router-link>
编程时跳转
<li v-for="(item, index) of prolist" :key="index" @click="goDetail(item)">
{{ item.title }}
</li>

methods: {
goDetail (item) {
    // this.$router.push('/detail/' + item.id)
    this.$router.push({
        name: 'detail',
        params: {id: item.id}
    })
}
}
    详情页面可以通过  this.$route.params.id 拿到传递过来的数据

12、页面切换效果
App.vue使用transition包裹router-view
<template>
<div class="container">
<transition name="slide">
<router-view></router-view>
</transition>
<router-view name="footer"></router-view>
</div>
</template>


<script>
export default {
name: 'App'
}
</script>


<style lang="scss">
@import '~@/lib/reset.scss';
html, body, .container {
@include rect(100%, 100%); // width: 100%; height: 100%;
}
.container {
max-width: 640px;
margin: 0 auto;
box-shadow: 0 0 2px #ccc;
@include flexbox(); // display: flex
@include flex-direction(column); // flex-direction:column
.box {
@include flex();
@include rect(100%, auto);
@include flexbox();
@include flex-direction(column);
.header {
@include rect(100%, 0.44rem);
@include background-color(#f66);
}
.content {
@include flex(); // flex: 1;
@include rect(100%, auto);
@include overflow(auto);
}
}
.footer {
@include rect(100%, 0.5rem);
@include background-color(#efefef);
ul {
@include rect(100%, 100%);
@include flexbox();
li {
@include flex();
@include rect(auto, 100%);
@include flexbox();
@include justify-content(); // justify-content: center;
@include align-items(); // align-items: center;
@include text-color(#333);
&.router-link-exact-active,.router-link-active{
@include text-color(#f66);
}
}
}
}
}
.slide-enter {
transform: translateX(100%);
}
.slide-enter-active {
transition: all .3s;
}
.slide-enter-to {
transform: translateX(0%);
}
.slide-leave {
transform: translateX(0%);
}
.slide-leave-active {
transition: all 0s;
}
.slide-leave-to {
transform: translateX(-100%);
}
</style>



13、下拉刷新以及上拉加载功能
以分类为例
<template>
  <div class="box">
    <header class="header">分类头部</header>
    <div class="content">
      <mt-loadmore :top-method="loadTop" :bottom-method="loadBottom" :bottom-all-loaded="allLoaded" ref="loadmore">
        <ul class="kindlist">
          <li v-for="(item, index) of kindlist" :key="item.id">{{ item.title }} --- {{ index }}</li>
        </ul>
      </mt-loadmore>
    </div>
  </div>
</template>


<script>
import Vue from 'vue'
import { Loadmore } from 'mint-ui'
import api from '@/api'
Vue.use(Loadmore)


export default {
  data () {
    return {
      kindlist: [],
      allLoaded: false, // 所有的数据是否已经加载完毕
      pageCode: 1 // 页码
    }
  },
  mounted () { // 请求一次数据
    api.requestGet('/douban')
      .then(data => {
        this.kindlist = data
      })
  },
  methods: {
    loadTop () { // 下啦刷新函数 --- 请求了第一页的数据
      api.requestGet('/douban')
        .then(data => {
          this.kindlist = data // 替换数据
          this.pageCode = 1 // 刷新完毕,页码归1
          this.allLoaded = false // 刷新完毕,表示可以继续加载下一页
          this.$refs.loadmore.onTopLoaded() // 更新列表
        })
    },
    loadBottom () {
      api.requestGet('/douban?count=20&start=' + this.pageCode * 20)
        .then(data => {
          if (data.length === 0) { // 没有数据的条件
            this.allLoaded = true// 若数据已全部获取完毕
          }
          this.pageCode += 1 // 页码加一,下一次请求数据时用
          this.kindlist = [...this.kindlist, ...data] //组合数据
          this.$refs.loadmore.onBottomLoaded() // 更新列表
        })
    }
  }
}
</script>


<style lang="scss">
.kindlist {
  li {
    height: 40px;
    border-bottom: 1px solid #ccc;
    line-height: 40px;
  }
}
</style>



如果想要结合vuex实现
kind/index.vue
<template>
  <div class="box">
    <header class="header">分类头部</header>
    <div class="content">
      <mt-loadmore :top-method="loadTop" :bottom-method="loadBottom" :bottom-all-loaded="allLoaded" ref="loadmore">
        <ul class="kindlist">
          <li v-for="(item, index) of kindlist" :key="item.id">{{ item.title }} --- {{ index }}</li>
        </ul>
      </mt-loadmore>
    </div>
  </div>
</template>


<script>
import Vue from 'vue'
import { Loadmore } from 'mint-ui'
import { mapState } from 'vuex'
Vue.use(Loadmore)


export default {
  data () {
    return {
      allLoaded: false,
      pageCode: 1
    }
  },
  computed: {
    ...mapState({
      kindlist: (state) => state.kind.kindlist
    })
  },
  mounted () {
    this.$store.dispatch('getkindlist')
  },
  methods: {
    loadTop () {
      this.$store.dispatch('loadTop').then(() => {
        this.pageCode = 1
        this.allLoaded = false
        this.$refs.loadmore.onTopLoaded()
      })
    },
    loadBottom () {
      this.$store.dispatch('loadBottom', { pageCode: this.pageCode }).then(data => {
        if (data.length === 0) {
          this.allLoaded = true
        } else {
          this.pageCode += 1
        }
        this.$refs.loadmore.onBottomLoaded()
      })
    }
  }
}
</script>


<style lang="scss">
.kindlist {
  li {
    height: 40px;
    border-bottom: 1px solid #ccc;
    line-height: 40px;
  }
}
</style>



store/kind.js
import api from '@/api'
export default {
  state: {
    kindlist: []
  },
  getters: {},
  actions: {
    getkindlist ({ commit }) {
      api.requestGet('/douban')
        .then(data => {
          commit('changekindlist', data)
        })
    },
    loadTop ({ commit }) {
      return new Promise((resolve, reject) => {
        api.requestGet('/douban')
          .then(data => {
            commit('changekindlist', data)
            resolve()
          })
      })
    },
    loadBottom ({ commit, state }, params) {
      console.log(params)
      return new Promise((resolve, reject) => {
        api.requestGet('/douban?count=20&start=' + params.pageCode * 20)
          .then(data => {
            console.log('bottom', data)
            const arr = [...state.kindlist, ...data]
            console.log('arr', arr)
            commit('changekindlist', arr)
            resolve(data)
          })
      })
    }
  },
  mutations: {
    changekindlist (state, data) {
      state.kindlist = data
    }
  }
}



14、回到顶部
components/BackTop.vue
<template>
<span class="backtop" @click="backtop">返回顶部</span>
</template>


<script>
export default {
methods: {
backtop () {
console.log('1')
document.getElementById('content').scrollIntoView()
}
}
}
</script>


<style>
.backtop {
position:fixed;
right:10px;bottom:60px;
}
</style>


使用时可以给需要的地方添加一个
<div id="content"></div>
15、购物车业务逻辑
<template>
<div class="box">
<header class="header">购物车头部</header>
<div class="content">
<input type="checkbox" v-model="allChecked" @change="test">
<ul>
<li v-for="(item, index) of cartlist" :key="index">
<input type="checkbox" v-model="item.flag" @change="fn(item)"/>
{{ item.name }}
<button @click="item.num-=1">-</button> {{ item.num }} <button @click="item.num+=1">+</button>¥{{ item.price }} 小计: {{ item.num * item.price}}
</li>
</ul>
<h1>总数为:{{ totalNum }}</h1>
<h1>总价为:{{ totalprice }}</h1>
</div>
</div>
</template>


<script>
export default {
data () {
return {
allChecked: false,
cartlist: [
{
id: 1,
name: '苹果',
price: 4.8,
num: 2,
flag: false
},
{
id: 2,
name: '香蕉',
price: 3,
num: 5,
flag: false
},
{
id: 3,
name: '榴莲',
price: 29.8,
num: 1,
flag: false
}
]
}
},
methods: {
test () {
if (this.allChecked) {
this.cartlist.map(item => {
item.flag = true
})
} else {
this.cartlist.map(item => {
item.flag = false
})
}
},
fn (item) {
if (!item.flag) {
this.allChecked = false
} else {
let bool = true
this.cartlist.map(item => {
if (!item.flag) {
bool = false
}
})
this.allChecked = bool
}
}
},
computed: {
totalNum () {
let num = 0
this.cartlist.map(item => {
item.flag ? num += item.num : num += 0
})
return num
},
totalprice () {
let price = 0
this.cartlist.map(item => {
item.flag ? price += item.num * item.price : price += 0
})
return price.toFixed(2)
}
},
watch: {
allChecked (newVal) {


}
}
}
</script>


<style lang="scss">
</style>



16、注册功能 --- 计算属性
<template>
<div class="box">
<header class="header">注册</header>
<div class="content">
<mt-field placeholder="请输入用户名" :state="usernameState" v-model="username"></mt-field>
<mt-field placeholder="请输入密码" type="password" v-model="password" :state="passwordState"></mt-field>
<mt-field placeholder="验证码" v-model="code" :state="codeState">
<mt-button @click="sendCode" :disabled="sendState">{{msg}}</mt-button>
</mt-field>
<mt-button :disabled="disabledtype" @click="register" :type="type" size="large">注册</mt-button>
</div>
</div>
</template>


<script>
import Vue from 'vue'
import { Field, Button } from 'mint-ui'
import api from '@/api'
Vue.use(Field, Button)
export default {
data () {
return {
username: '17733203950',
password: '123456',
msg: '发送验证码',
time: 10,
sendState: false,
code: '',
adminCode: ''
}
},
computed: {
usernameState () {
if (this.username === '') {
return ''
} else if (/^[1][3,4,5,6,7,8,9][0-9]{9}$/.test(this.username)) {
return 'success'
} else {
return 'error'
}
},
passwordState () {
if (this.password === '') {
return ''
} else if (this.password.length > 5) {
return 'success'
} else {
return 'error'
}
},
codeState () {
if (this.code === '') {
return ''
} else if (this.code === this.adminCode) {
return 'success'
} else {
return 'error'
}
},
disabledtype () {
if (this.usernameState === 'success' && this.passwordState === 'success' && this.codeState === 'success') {
return false
}
},
type () {
if (this.usernameState === 'success' && this.passwordState === 'success' && this.codeState === 'success') {
return 'primary'
} else {
return 'default'
}
}
},
methods: {
getCode () {
api.requestGet('/users/sendCode?tel=' + this.username)
.then(data => {
if (data === 0) {
console.log('验证码发送失败')
} else if (data === 1) {
console.log('手机号已经注册过')
} else {
console.log(data)
this.adminCode = data.code
}
})
},
sendCode () {
console.log('发送短信验证码')
this.sendState = true
this.getCode()
var timer = setInterval(() => {
this.msg = this.time + '后重新发送'
this.time--
if (this.time === -1) {
this.msg = '发送验证码'
this.sendState = false
this.time = 10
clearInterval(timer)
}
}, 1000)
},
register () {
api.requestPost('/users/register', {
username: this.username,
password: this.password
}).then(data => {
if (data === 0) {
console.log('注册失败')
} else if (data === 1) {
console.log('注册成功')
} else {
console.log('用户名已注册')
}
})
}
}
}
</script>


<style lang="scss">
</style>


登录
<template>
<div class="box">
<header class="header">登录</header>
<div class="content">
<mt-field placeholder="请输入用户名" :state="usernameState" v-model="username"></mt-field>
<mt-field placeholder="请输入密码" type="password" v-model="password" :state="passwordState"></mt-field>
<mt-button :disabled="disabledtype" @click="login" :type="type" size="large">登录</mt-button>
</div>
</div>
</template>


<script>
import Vue from 'vue'
import { Field, Button } from 'mint-ui'
import api from '@/api'
Vue.use(Field, Button)
export default {
data () {
return {
username: '17733203950',
password: '123456'
}
},
computed: {
usernameState () {
if (this.username === '') {
return ''
} else if (/^[1][3,4,5,6,7,8,9][0-9]{9}$/.test(this.username)) {
return 'success'
} else {
return 'error'
}
},
passwordState () {
if (this.password === '') {
return ''
} else if (this.password.length > 5) {
return 'success'
} else {
return 'error'
}
},
disabledtype () {
if (this.usernameState === 'success' && this.passwordState === 'success') {
return false
}
},
type () {
if (this.usernameState === 'success' && this.passwordState === 'success') {
return 'primary'
} else {
return 'default'
}
}
},
methods: {
login () {
api.requestPost('/users/login', {
username: this.username,
password: this.password
}).then(data => {
if (data === 0) {
console.log('登录失败')
} else if (data === 1) {
console.log('登录成功')
// 登录成功,还可以返回token信息,把它保存到本地
// 以后请求数据时,把token携带过去
localStorage.setItem('isLogin', 'ok')
} else if (data === 2) {
console.log('用户未注册')
} else {
console.log('密码错误')
}
})
}
}
}
</script>


<style lang="scss">
</style>

上一篇:HTML5工具初识之网页编辑器

下一篇:项目搭建以及注册用户信息功能

QQ技术交流群

千锋HTML5官方①群
791201477

加入群聊