vue实战项目-ego商城

时间:2024-10-04 11:58:52

vue实战项目-ego商城

搭建项目

在这里插入图片描述

提前cmd查一下vue -V查看vuecli的版本,我本来的版本太高跟这个教程完全对不上,所以重新下载了低版本的vuecli
从5.0.4降到3.11.0,因为elementUI只能支持到vuecli3的版本
低版本vuecli安装教程
VScode里面直接输入vue create ego_cz即可,后面的ego_cz是项目名
在这里插入图片描述

但是一开始报错Error: command failed: npm install --loglevel error --legacy-peer-deps
后来发现需要用管理员身份打开IDEA才可以。
搭建项目过程就不讲了,有router和vuex就可以了。
创建好项目之后,cd ego_cz,进入自己的项目目录。
接下来去安装依赖
//npm install --save axios
2.element //vue add element 选择部份依赖即可
安装完依赖,直接去element官网,快速上手部分找到全部组件,用这些替换plugins目录下的内容
在这里插入图片描述
在这里插入图片描述
里面全是vue2的写法,所以想用这个必须降低vuecli的版本号。唉,搞这个也搞半天。
之后执行npm run serve,查看能否正常进入vue展示页面,并且在中间有个el-button的按钮。这代表依赖都装好了。

页面搭建

views目录下是我们的页面文件,把里面的aboutview删掉以及component目录下的helloword都删掉。
注意:文件name设置不能使用简单的一个词,不然会报错,类似下图:
在这里插入图片描述
所以我把每个view文件后面都添加了View让其变得复杂。
首先在views目录下建立文件,作为整体的布局。
里面包含首页、产品管理、规格参数、广告分类四大子模块
因此我们为这四个模块建立了一个目录交main,首页就是不用动,另外要在目录里创建三个文件
分别是:,,
为了解决报错问题,我们要将与之前删掉的aboutbiew和helloword相关的文件内容都删掉,并且要改变router设置。

//
<template>
  <div id="app">
    <router-view></router-view>
  </div>
</template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
//
<template>
    <div>
        <!-- 登录界面 -->
        <router-view></router-view>
    </div>
</template>

<script>
export default {
    name:'LayoutView',
}
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
//
<template>
    <div>
        商品管理
    </div>
</template>
<script>
export default {
name:'ProductView',
}
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

其他两个同理,先简单写出来,测试路由是否可行
接下来去解决路由问题,打开router里面的,首先从文件中引入LayoutView,把本来的homeview改成我们的LayoutView,在给这个路径下面添加子模块路由。

//  src/router/
import Vue from 'vue'
import VueRouter from 'vue-router'
import HomeView from '../views/main/'
import LayoutView from '../views/'
Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'LayoutView',
    component: LayoutView,
    children: [
    //以下都是layout子元素
      {
        //path啥也不加进来的就是home这个页面
        path: '',
        name: 'Home',
        component:HomeView
      },
      {
        // 加上product就进入了产品页面
        path: 'product',
        name: 'ProductView',
        component:() => import('../views/main/')
      },
      {
        path: 'params',
        name: 'ParamsView',
        component:() => import('../views/main/')
      },
      {
        path: 'ad',
        name: 'ADCategory',
        component:() => import('../views/main/')
      },
    ]
  },
]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

路由设置完成,运行路由加上path部分查看页面跳转。
在这里插入图片描述
为了实现基本的css
我们在assets下面新建css目录,在里面新建文件

body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, form, fieldset, legend, input, textarea, button, p, blockquote, th, td
{margin: 0;padding: 0;}
body{text-align: center;}
li{ list-style: none;}
a{text-decoration: none;}
input,button,img{border: none}
.active{
    color:#409EFF
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

并且记得在里面导入这个css文件
在这里插入图片描述

登录UI实现

路由限制(没有登陆时不得进入主页)

在router目录下建立

import router from "./index";   //引入路由对象  在文件里面export default router
//用户未登录时,无法进入这个首页,所以要设置路由权限
router.beforeEach((to, from, next) => {
    if (to.meta.isLogin) {
        let token = false;
        if (token) {
            // 已经登陆直接进入
            next();
        } else {
            next({
                // 没有登陆就改变路由进入登录界面
                name:'LoginView'
            })
        }
    } else {
        next();
    }
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

在里面添加引用

import './router/permission'
  • 1

登录注册页面(写到同一个页面上)

在最外层写一层div确定登陆注册框大概位置,在里面写一层elementUI里面的card,并确定好其大小。
lang='less’会报错,npm安装依赖即可

//html部分
<template>
    <!-- 登录注册界面,与Layout级别一样 -->
    <div class="login">
        <el-card class="box-card">
            <!-- slot插槽,可以往里面填写想要的内容 -->
        <div slot="header" class="clearfix">
            <span>Ego商城</span>
        </div>
        内容部分
    </el-card>
    </div>
</template>
//css样式
<style scoped lang='less'>
// lang=“less” 可以敲层级关系的样式
// scoped 使style内的样式只作用于当前的界面
.login{
    width: 1200px;
    margin:0 auto;
    .box-card{
        width: 500px;
        margin: 100px auto;
    }
}
</style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

在这里插入图片描述

希望能够展现出使用tab键更改登陆注册页面的功能,所以找到tabs标签页组件,将其写入内容部分。
因为tabs标签绑定了currentIndex代表当前页面对应内容,所以我们要在data里添加currentIndex,currentIndex是与name值绑定的,我们设其默认值为login,默认进入登录界面。

<template>
    <!-- 登录注册界面,与Layout级别一样 -->
    <div class="login">
        <el-card class="box-card">
            <!-- slot插槽,可以往里面填写想要的内容 -->
        <div slot="header" class="clearfix">
            <span>Ego商城</span>
        </div>
        <el-tabs v-model="currentIndex" :stretch='true'>
            <!-- 与name相对应,v-model双向绑定 -->
            <el-tab-pane label="登录" name="login">
                登录
            </el-tab-pane>
            <el-tab-pane label="注册" name="register">
                注册
            </el-tab-pane>
        </el-tabs>
    </el-card>
    </div>
</template>

data(){
	return{
	currentIndex:'login',
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

在这里插入图片描述
往登录内容里面写入表单,从elementUI里面找表单即可。
把登陆内容改成如下内容
解释下表单的属性,model双向绑定LoginForm表单对象内容,rules代表对每个输入值的判定规则
status icon是表单后面的小叉号,不满足条件执行回调函数
ref是指的获取这个dom元素,点击提交时绑定的方法参数就是ref设定的值
prop设置的需要被校验的字段名

<el-form :model="LoginForm" :rules="rules" status-icon ref="LoginForm">
                    <!-- ref与model绑定对象要是相同的 -->
                    <el-form-item label="用户名"  label-width="80px" prop="username">
                        <!-- prop代表的是验证规则 -->
                        <el-input type="text" v-model=""></el-input>
                    </el-form-item>
                    <el-form-item label="密码"  label-width="80px" prop="password">
                        <el-input type="password" v-model=""></el-input>
                    </el-form-item>
                    <el-form-item >
                        <!-- 此处点击事件传的时ref的对象 -->
                        <el-button type="primary" @click="submitForm('LoginForm')">提交</el-button>
                    </el-form-item>
                </el-form>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

这其中不仅绑定了数据,也绑定了方法
具体用法如下
首先把LoginForm对象写入data内部

LoginForm:{
                password:'',
                username:'',
            },
  • 1
  • 2
  • 3
  • 4

写字段校验的方法:

// 用户名验证规则
        var validateUserName=(rule,value,callback)=>{
            if(value===''){
                callback(new Error('请输入用户名'));
            }else if(value.length<6){
                callback(new Error('用户名太短'))
            }
            else{
                callback();
            }
        }
    // 密码验证规则
        var validatePassWord=(rule,value,callback)=>{
            if(value===''){
                callback(new Error('请输入密码'));
            }else{
                callback();
            }
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
'
运行

将rules写入data,使得字段名对应自己的校验方法

rules:{
                //验证规则对应表示
                username:[
                    {
                        validator: validateUserName,trigger: 'blur'
                    }
                ],
                password:[
                    {
                        validator: validatePassWord,trigger: 'blur'
                    }
                ]
            }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

最后在方法里面写入绑定的点击事件submitForm函数

submitForm(formName){
            this.$refs[formName].validate((valid)=>{
                if(valid){
                    console.log(this.LoginForm);
                }else{
                    return;
                }
            })
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

不满足校验条件时
成功提交
注册UI实现与登陆相似
表单内容添加一个确认密码输入框,并为其添加确认密码验证规则

<el-form-item label="确认密码"  label-width="80px" prop="checkPassword">
                        <el-input type="password" v-model=""></el-input>
                    </el-form-item>
  • 1
  • 2
  • 3
//确认密码验证规则
        var checkPass=(rule,value,callback)=>{
            if(value===''){
                callback(new Error('请输入密码'));
            }else if(value !=this.RegisterForm.password){
                callback(new Error('两次输入密码不一致'))
            }
            else{
                callback();
            }
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
'
运行

rules部分添加确认密码的校验规则

rules:{
                //验证规则对应表示
                username:[
                    {
                        validator: validateUserName,trigger: 'blur'
                    }
                ],
                password:[
                    {
                        validator: validatePassWord,trigger: 'blur'
                    }
                ],
                checkPassword:[
                    {
                        validator: checkPass,trigger: 'blur'
                    }
                ]
            }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

此时出现的问题是我们之前提交之后输出的都是登陆的信息,想要根据不同标签输出不同的对象值,需要在tabs标签上添加点击事件

<el-tabs v-model="currentIndex" :stretch='true' @tab-click="handleTabsClick">
  • 1

用来获取当前处于哪个标签上
首先在data上添加一个activetabs变量,默认值设置为login,点击标签改变当前的标签值

handleTabsClick(tab){
            this.activeTab=tab.name
        }
  • 1
  • 2
  • 3

对应的标签输出对应的对象值内容

submitForm(formName){
            this.$refs[formName].validate((valid)=>{
                if(valid){
                    if(this.activeTab==='login'){
                        console.log(this.LoginForm);
                    }
                    if(this.activeTab==='register'){
                        console.log(this.RegisterForm)
                    }
                }else{
                    return;
                }
            })
        },
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

目前为止,登陆注册的前端页面已经基本实现

登录注册后台接口

小细节很多,注意不要出错
首先在ego目录下建立server目录,用来存放后台信息,与前端的src文件是独立开来的
里面建立三个文件,index(建立express对象,处理跨域及端口)、router(不同路由,调用不同方法)和config(连接数据库以及设置数据库操作方法)
事先需要安装好express、mysql、jsonwebtoken、cors、body-parse
直接使用npm install --save 依赖名
在这里插入图片描述
1.连接数据库(数据库里的表是直接导入进mysql的,所以不需要自己手写表格)

//
//调用mysql
const mysql = require('mysql');
//连接数据
const client = mysql.createConnection({
    host: 'localhost',
    user: 'root',  //数据库用户名
    password: '1234',  //数据库密码
    database:'ego'   //数据库的名字
})

// 传一个sql语句、arr数组参数以及回调函数
const sqlClient = (sql, arr, callback) => {
    client.query(sql, arr, (error, result) => {
        if (error) {
            console.log(error);
            return;
        } else {
            callback(result);
            // 没错就直接返回result值
        }
    })
    
    
}
module.exports = sqlClient```
2.定义注册登录前后端交互方法

```javascript
//
const express = require('express');
const router = express.Router();
//引入数据库方法
const sqlClient = require('./config')
// 前端响应
const jwt=require('jsonwebtoken')

// 注册
router.post('/register', (req, res) => {
    const { username, password, email } = req.body;
    const sql = 'insert into user values(null,?,?,?)';
    const arr = [username, password, email]
    sqlClient(sql, arr, result => {
        // 影响行数大于0则代表插入成功了
        if (result.affectedRows > 0) {
            res.send({
                status: 200,
                msg:'注册成功'
            })
        } else {
            res.send({
                status: 401,
                msg:'注册失败'
            })
        }
    })
})

// 登录
router.post('/login', (req, res) => {
    const { username, password } = req.body;
    const sql = 'select * from user where username=? and password=?'
    const arr = [username, password];
    sqlClient(sql, arr, result => {
        if (result.length > 0) {
        //登陆成功获得token
            let token = jwt.sign({
                username,
                id:result[0].id
            }, 'somekeys')
            
            res.send({
                status: 200,
                token,
                username
            })
        } else {
            res.send({
                status: 401,
                msg:'登陆失败'
            })
        }
    })
})
module.exports = router
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85

3.调用express对象,应用路由、设置端口以及跨域处理

//
// 引入express和app
const express = require('express');
const app = express();
// 引入跨域处理
const cors = require('cors');
// express获取post传参数据
const bodyParser = require('body-parser')
// 路由对象
const router = require('./router')


app.use(cors());
app.use(bodyParser.urlencoded({
    extended:true
}))
// 前面添加/api就可以加载router,进行跨域了
app.use('/api', router);
//后端响应端口
app.listen(9090, () => {
    console.log(9090);
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

后端基本完成,为了使前后端可以同时运行
打开,再scripts里面添加一句

"dev": "concurrently \"npm run serve\" \"nodemon server/\""
  • 1

这样我们在终端运行npm run dev就会同时运行前后端服务
后台接口基本完成

前后端交互

打开src,新建目录utils里面存放工具模块,新建request.js
直接复制来即可,使用axios发送请求

//
// 网络请求
import axios from "axios"
import qs from "qs"
import router from "../router"
// import store from "../store"

const toLogin = () =>{
    router.push("/login")
}

const errorHandle = (status,info) =>{
    switch(status){
        case 400:
            console.log("服务器收到客户端通过PUT或者POST请求提交的表示,表示的格式正确,但服务器不懂它什么意思");
            toLogin();
            break;
        case 401:
            console.log("客户端试图对一个受保护的资源进行操作,却又没有提供正确的认证证书");
            toLogin();
            break;
        case 403:
            console.log("客户端请求的结构正确,但是服务器不想处理它");
            toLogin();
            break;
        case 404:
            console.log("资源被围定义(网络请求地址错误)");
            break;
        case 500:
            console.log("执行请求处理代码时遇到了异常,它们就发送此响应代码");
            break;
        case 503:
            console.log("最可能的原因是资源不足:服务器突然收到太多请求,以至于无法全部处理");
            break;
        default:
            console.log(info);
            break;
    }
}

const instance = axios.create({
    timeout:5000
})

instance.all = axios.all;
instance.spread = axios.spread
instance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

instance.interceptors.request.use(
    config =>{
        if(config.method === 'post'){
            config.data = qs.stringify(config.data);
        }
        // 判断token是否存在,存在就添加到请求头上
        // const token = ;
        // if(token){
        //      = ;
        // }
        return config;
    },
    error => Promise.reject(error)
)

instance.interceptors.response.use(
    response => response.status === 200 ? Promise.resolve(response) : Promise.reject(response) ,
    error =>{
        const { response } = error;
        if(response){
            errorHandle(response.status,response.data);
            return Promise.reject(response);
        }else{
            console.log("请求被中断");
        }
    }
)

export function get(url,params){
    return new Promise((resolve,reject) =>{
        instance.get(url,{
            params
        }).then(res =>{
            resolve(res.data);
        }).catch(err =>{
            reject(err.data);
        })
    })
}

export function post(url,params){
    return new Promise((resolve,reject) =>{
        instance.post(url,params).then(res =>{
            resolve(res.data)
        }).catch(err =>{
            reject(err.data)
        })
    })
}

export default instance
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99

打开登录注册页面,LoginView页面,引入api以及vuex
建立了vuex,在store下面建立modules目录,新建
在这里插入图片描述

//
// 写vuex结构
export default {
    namespaced: true,
    state: {
        user: {
            username: "",
            token:"",
        }
    },
    mutations: {
        setUser(state, user) {
            state.user=user
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

外面的index引入login

import Vue from 'vue'
import Vuex from 'vuex'
import login from './modules/login'

Vue.use(Vuex)

export default new Vuex.Store({
  
  modules: {
    login
  }
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

在LoginView界面引入api和vuex

import api from '../api'
import { mapMutations } from 'vuex'
  • 1
  • 2
methods: {
        ...mapMutations('login',['setUser']),
        submitForm(formName){
            this.$refs[formName].validate((valid)=>{
                if(valid){
                    if(this.activeTab==='login'){
                        // 登录
                        api.login(this.LoginForm).then(res => {
                            if(res.data.status===200){
                                this.setUser(res.data);
                                localStorage.setItem('ego',JSON.stringify(res.data));
                                // 登陆成功后跳转首页
                                this.$router.push('/')
                            }else{
                                const h = this.$createElement;
                                this.$notify({
                                    title:"登陆失败",
                                    message: h('i','用户名密码错误'),
        });
                            }
                        })
                    }
                    if(this.activeTab==='register'){
                        // 注册
                        api.register(this.RegisterForm).then(res =>{
                            if(res.data.status ===200){
                                const h = this.$createElement;
                                this.$notify({
                                    title:'注册成功',
                                    message: h('i','请前往登陆页面登录'),
                                });
                            }else{
                                const h = this.$createElement;
                                this.$notify({
                                    title:'注册失败',
                                    message: h('i','请重新注册'),
                                });
                            }
                            })
                    }
                }else{
                    return;
                }
            })
        },
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

解决强制刷新问题,登陆后再进入该界面需要直接跳转到主页,首先再utils里面新建文件

// 解决强制刷新的问题,登陆后再进入页面直接跳转到主页面
import store from "@/store";

if (localStorage.getItem('ego')) {
    store.commit('login/setUser',JSON.parse(localStorage.getItem('ego')))
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在main里面引用这个init

import './utils/init'
  • 1

router的permission里面改变token内容

import router from "./index";   //引入路由对象  在文件里面export default router
//用户未登录时,无法进入这个首页,所以要设置路由权限
import store from '../store'

router.beforeEach((to, from, next) => {
    if (to.meta.isLogin) {
        let token = store.state.login.user.token;
        if (token) {
            // 已经登陆直接进入
            next();
        } else {
            next({
                // 没有登陆就改变路由进入登录界面
                name:'LoginView'
            })
        }
    } else {
        next();
    }
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

到此为止登陆注册页面已经完成