從零構建vue2 + vue-router + vuex 開發環境到入門,實現基本的登入退出功能(二)

狼族小狽發表於2016-12-03

前言

國慶在回家的路上,得知了vue2釋出了正式版,
國慶回來後,在公司內兩個專案便直接應用上了vue2,
一個是PC端的商戶後臺,一個是微信端商城,
都是基於Vue2、vue-router、vuex ......
在開發的過程中,遇到了一系列的問題,
比如頁面後退資料還原,滾動條還原,
登入超時,獲取列表資料,表單提交,
多臺伺服器自動化部署,最終後一個個解決了,
能夠平穩的從react切換到vue2開發,vue的文件功不可沒。複製程式碼

github:github.com/lzxb/vue2-d…

原始碼說明

專案目錄說明

.
|-- config                           // 專案開發環境配置
|   |-- index.js                     // 專案打包部署配置
|-- src                              // 原始碼目錄
|   |-- components                   // 公共元件
|       |-- header.vue               // 頁面頭部公共元件
|       |-- index.js                 // 載入各種公共元件
|   |-- config                       // 路由配置和程式的基本資訊配置
|       |-- routes.js                // 配置頁面路由
|   |-- css                          // 各種css檔案
|       |-- common.css               // 全域性通用css檔案
|   |-- iconfont                     // 各種字型圖示
|   |-- images                       // 公共圖片
|   |-- less                         // 各種less檔案
|       |-- common.less              // 全域性通用less檔案
|   |-- pages                        // 頁面元件
|       |-- home                     // 個人中心
|       |-- index                    // 網站首頁
|       |-- login                    // 登入
|       |-- signout                  // 退出
|   |-- store                        // vuex的狀態管理
|       |-- index.js                 // 載入各種store模組
|       |-- user.js                  // 使用者store
|   |-- template                     // 各種html檔案
|       |-- index.html               // 程式入口html檔案
|   |-- util                         // 公共的js方法,vue的mixin混合
|   |-- app.vue                      // 頁面入口檔案
|   |-- main.js                      // 程式入口檔案,載入各種公共元件
|-- .babelrc                         // ES6語法編譯配置
|-- gulpfile.js                      // 啟動,打包,部署,自動化構建
|-- webpack.config.js                // 程式打包配置
|-- server.js                        // 代理伺服器配置
|-- README.md                        // 專案說明
|-- package.json                     // 配置專案相關資訊,通過執行 npm init 命令建立
.複製程式碼

1.html入口檔案,原始檔路徑:src/template/index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no,minimal-ui">
    <title>vue2-demo</title>
</head>

<body>
    <div id="app">
        <router-view></router-view>
    </div>
</body>

</html>複製程式碼

2.js入口檔案,原始檔路徑:src/main.js

import Vue from 'vue'
import VueRouter from 'vue-router'

import routes from './config/routes'
import store from './store/'
import components from './components/' //載入公共元件

import './css/common.css'
import './less/common.less'

Object.keys(components).forEach((key) => {
    var name = key.replace(/(\w)/, (v) => v.toUpperCase()) //首字母大寫
    Vue.component(`v${name}`, components[key])
})

Vue.use(VueRouter)

const router = new VueRouter({
    routes
})
router.beforeEach(({meta, path}, from, next) => {
    var { auth = true } = meta
    var isLogin = Boolean(store.state.user.id) //true使用者已登入, false使用者未登入

    if (auth && !isLogin && path !== '/login') {
        return next({ path: '/login' })
    }
    next()
})

new Vue({ store, router }).$mount('#app')複製程式碼

3.頁面路由,許可權配置,原始檔路徑:src/config/routes.js

import App from '../app'

export default [
    {
        path: '/',
        component: App,
        children: [
            {
                path: '/login', //登入
                meta: { auth: false },
                component: resolve => require(['../pages/login/'], resolve)
            },
            {
                path: '/signout', //退出
                component: resolve => require(['../pages/signout/'], resolve)
            },
            {
                path: '/home', //個人主頁
                component: resolve => require(['../pages/home/'], resolve)
            },
            {
                path: '/', //首頁
                meta: { auth: false },
                component: resolve => require(['../pages/index/'], resolve)
            },
            {
                path: '*', //其他頁面,強制跳轉到登入頁面
                redirect: '/login'
            }
        ]
    }
]複製程式碼

4.頁面入口元件,原始檔路徑:src/app.vue

<style lang="less" scoped>

</style>
<template>
    <router-view></router-view>
</template>
<script>
    export default {

    }
</script>複製程式碼

5.store例項化,匯入各種modules,原始檔路徑:src/store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import user from './user'

Vue.use(Vuex)

export default new Vuex.Store({
    strict: process.env.NODE_ENV !== 'production', //在非生產環境下,使用嚴格模式
    modules: {
        user
    }
})複製程式碼

6.定義store user 模組,原始檔路徑:src/store/user.js

import Vue from 'vue'

export const USER_SIGNIN = 'USER_SIGNIN' //登入成功
export const USER_SIGNOUT = 'USER_SIGNOUT' //退出登入

export default {
    state: JSON.parse(sessionStorage.getItem('user')) || {},
    mutations: {
        [USER_SIGNIN](state, user) {
            sessionStorage.setItem('user', JSON.stringify(user))
            Object.assign(state, user)
        },
        [USER_SIGNOUT](state) {
            sessionStorage.removeItem('user')
            Object.keys(state).forEach(k => Vue.delete(state, k))
        }
    },
    actions: {
        [USER_SIGNIN]({commit}, user) {
            commit(USER_SIGNIN, user)
        },
        [USER_SIGNOUT]({commit}) {
            commit(USER_SIGNOUT)
        }
    }
}複製程式碼

7.載入各種公共元件,原始檔路徑:src/components/index.js

import header from './header'
export default { header }複製程式碼

8.封裝頁面公共頭部元件,原始檔路徑:src/components/header.js

<style lang="less" scoped>
    .header {
        position: relative;
        line-height: 38px;
        color: #fff;
        text-align: center;
        background: #222;
        .item {
            position: absolute;
            top: 0;
            bottom: 0;
            z-index: 1;
            a {
                color: #fff;
            }
        }
        .left {
            left: 10px;
        }
        .right {
            right: 10px;
        }
    }
</style>
<template>
    <header class="header">
        <div class="item left">
            <slot name="left"></slot>
        </div>
        <div class="title">{{title}}</div>
        <div class="item right">
            <slot name="right"></slot>
        </div>
    </header>
</template>
<script>
    export default {
        props: {
            title: {
                type: String,
                default: ''
            }
        }
    }
</script>複製程式碼

9.引入全域性公共css,原始檔路徑:src/css/common.css

input::-webkit-outer-spin-button,  
input::-webkit-inner-spin-button{  
    -webkit-appearance: none !important;  
    margin: 0;  
}複製程式碼

10.引入全域性公共less,原始檔路徑:src/less/common.less

* {
    padding: 0;
    margin: 0;
}複製程式碼

11.建立首頁,,原始檔路徑:src/pages/index.vue

<style lang="less" scoped>
    .login-msg {
        padding: 50px;
        text-align: center;
    }
    .msg {
        padding: 50px;
        text-align: center;
        font-size: 20px;
        color: red;
    }
</style>
<template>
    <div>
        <v-header title="首頁">
            <router-link slot="right" v-if="user.id" to="/home">{{user.name}}</router-link>
        </v-header>
        <div class="login-msg" v-if="!user.id">
            <router-link to="/login">你還未登入,請先登入</router-link>
        </div>
        <div class="msg" v-if="user.id">
            <img width="50" :src="logo" alt=""> <br>
            哈哈,恭喜你已經入坑Vue2
        </div>
    </div>
</template>
<script>
    import { mapState } from 'vuex'
    import logo from './logo.png'
    export default {
        data() {
            return {
                logo
            }
        },
        computed: mapState({ user: state => state.user }),
    }
</script>複製程式碼

12.建立登入頁,,原始檔路徑:src/pages/login.vue

<style lang="less" scoped>
    .login {
        padding: 50px;
        text-align: center;
        .line {
            padding: 5px;
            input {
                padding: 0 10px;
                line-height: 28px;
            }
        }
        button {
            padding: 0 20px;
            margin-top: 20px;
            line-height: 28px;
        }
    }
</style>
<template>
    <div>
        <v-header title="登入">
            <router-link slot="left" to="/">返回</router-link>
        </v-header>
        <form class="login" v-on:submit.prevent="submit">
            <div class="line">    
                <div v-show="btn && !form.id">id不能為空</div>
                <input type="number" placeholder="輸入你的id" v-model="form.id">
            </div>
            <div class="line">
                <div v-show="btn && !form.name">使用者名稱不能為空</div>
                <input type="text" placeholder="輸入你的使用者名稱" v-model="form.name">
            </div>
            <button>登入</button>
        </form>
    </div>
</template>
<script>
    import { mapActions } from 'vuex'
    import { USER_SIGNIN } from 'store/user'

    export default {
        data() {
            return {
                btn: false, //true 已經提交過, false沒有提交過
                form: {
                    id: '',
                    name: ''
                }
            }
        },
        methods: {
            ...mapActions([USER_SIGNIN]),
            submit() {
                this.btn = true
                if(!this.form.id || !this.form.name) return
                this.USER_SIGNIN(this.form)
                this.$router.replace({ path: '/home' })
            }
        }
    }
</script>複製程式碼

13.建立個人主頁,,原始檔路徑:src/pages/home.vue

<style lang="less" scoped>

</style>
<template>
    <div>
        <v-header title="首頁">
            <router-link slot="left" to="/">首頁</router-link>
            <router-link slot="right" to="/signout">退出</router-link>
        </v-header>
        <div style="padding: 50px;">{{user.name}}歡迎回家</div>
    </div>
</template>
<script>
    import { mapState } from 'vuex'
    export default {
        computed: mapState({ user: state => state.user }),
    }
</script>複製程式碼

14.建立退出頁,,原始檔路徑:src/pages/signout.vue

<style lang="less" scoped>
    .btn {
        padding: 50px;
        text-align: center;
        button {
            padding: 5px 10px;
        }
    }
</style>
<template>
    <div>
        <v-header title="退出">
            <router-link slot="left" to="/home">返回</router-link>
        </v-header>
        <div class="btn">
            <button v-on:click="submit">確認退出</button>
        </div>
    </div>
</template>
<script>
    import { mapActions } from 'vuex'
    import { USER_SIGNOUT } from 'store/user'
    export default {
        methods: {
            ...mapActions([USER_SIGNOUT]),
            submit() {
                this.USER_SIGNOUT()
                this.$router.replace({ path: '/login' })
            }
        }
    }
</script>複製程式碼

進擊vue2

vue2重構cnode社群,將會近日完成,
一個從0構建的vue2的完整專案,
可以使用最簡單的方式實現頁面後退時狀態還原,
區域性滾動條還原等。複製程式碼

相關文章