web前端教程:Vue项目开发流程

vue

web前端教程: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>

<div>

<header>头部</header>

<div>内容</div>

</div>

<footer>底部</footer>

</div>

</template>

<script>

export default {

name: \'App\'

}

</script>

<style>

@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>

<header>首页头部</header>

<div>首页内容</div>

</div>

</template>

<script>

export default {

}

</script>

<style>

</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>

<router-view></router-view>

<router-view name="footer"></router-view>

</div>

</template>

6、底部点击切换路由

components/Footer.vue,需要在App.vue中修改布局样式

<template>

<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>

<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>

.banner {

height: 150px;

}

</style>

prolist.vue

<template>

<ul>

<li>

肖生客的救赎

</li>

</ul>

</template>

<script>

export default {

}

</script>

home/index.vue中引用组件

<template>

<div>

<header>首页头部</header>

<div>

<Banner />

<Prolist />

</div>

</div>

</template>

<script>

import Banner from \'@/components/Banner\'

import Prolist from \'@/components/Prolist\'

export default {

components: {

Banner,

Prolist

}

}

</script>

<style>

.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>

<header>首页头部</header>

<div>

<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>

.banner {

height: 150px;

}

</style>

prolist.vue

<template>

<ul>

<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>

<header>首页头部</header>

<div>

<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>

.banner {

height: 150px;

}

</style>

使用mapActions的等价写法

<template>

<div>

<header>首页头部</header>

<div>

<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>

.banner {

height: 150px;

}

</style>

11、列表进入详情

编写详情页面 detail/index.vue,一定要记得修改App.vue中的样式

<template>

<div>

<div>

<header>详情头部</header>

<div>内容</div>

</div>

<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>

<transition name="slide">

<router-view></router-view>

</transition>

<router-view name="footer"></router-view>

</div>

</template>

<script>

export default {

name: \'App\'

}

</script>

<style>

@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>

<header>分类头部</header>

<div>

<mt-loadmore :top-method="loadTop" :bottom-method="loadBottom" :bottom-all-loaded="allLoaded" ref="loadmore">

<ul>

<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>

.kindlist {

li {

height: 40px;

border-bottom: 1px solid #ccc;

line-height: 40px;

}

}

</style>

如果想要结合vuex实现

kind/index.vue

<template>

<div>

<header>分类头部</header>

<div>

<mt-loadmore :top-method="loadTop" :bottom-method="loadBottom" :bottom-all-loaded="allLoaded" ref="loadmore">

<ul>

<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>

.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 @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>

<header>购物车头部</header>

<div>

<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>

</style>

16、注册功能 --- 计算属性

<template>

<div>

<header>注册</header>

<div>

<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>

</style>

登录

<template>

<div>

<header>登录</header>

<div>

<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>

</style>

以上是 web前端教程:Vue项目开发流程 的全部内容, 来源链接: utcz.com/z/379766.html

回到顶部