初來乍到-Vue+Vant+Vuex+Vue-router+less實現公司需求(一):換膚

Created By JishuBao on 2019-03-11 12:38:22
Recently revised in 2019-03-13 12:38:22css

 

  歡迎你們來到技術寶的掘金世界,您的star是我寫文章最大的動力!GitHub地址     
  這是一篇使用vue+vant+vuex+vue-router實現公司需求的文章,會詳細的介紹每一個插件的做用等...   
   感受不錯的小夥伴,點贊star走一波;  
   感受文章有誤的小夥伴,評論區、QQ羣走一波;  
   虛心求教,不勝感激~html

開篇題外話:前端

 因爲技術寶剛到公司,人生地不熟,正式項目尚未啓動,暫時負責修改樣式,解決同事遇到的技術小bug...,可是今天我接到了個人直接領導給我安排的任務,心情異常激動,說是讓準備如下幾個功能:vue

開篇點題:   node

1.換膚react

2.動效webpack

3.div換位置(動態換)(手動換)git

 今天就來帶領你們來跟技術寶一塊兒來學習下這些內容!github

1、項目搭建

 首先開始頁面的開發,瞭解前端的人都知道,沒有項目怎麼開始寫頁面呢?因此咱們接下來的任務就是搭建項目!首先將上次咱們用webpack4搭建的Vue項目搭建起來,這裏我給你們準備了Github地址Webpack4OfVue,你們記得給我點個star哦,不勝感激!web

1.下載項目

 和使用Npm同樣,咱們首先確保本身電腦上安裝了node,肯定能夠執行git相關的命令,首先git clone項目到本地,以下圖:

2.跑起來

 和正常的vue/react項目同樣,在文件下執行 yarn install/npm install && yarn start/npm start 運行項目並打開http://localhost:10000便可看到

$ yarn install
yarn install v1.7.0
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
info fsevents@1.2.7: The platform "win32" is incompatible with this module.
info "fsevents@1.2.7" is an optional dependency and failed compatibility check. Excluding it from installation.
[3/4] Linking dependencies...
warning " > less-loader@4.1.0" has unmet peer dependency "less@^2.3.1 || ^3.0.0".
[4/4] Building fresh packages...
success Saved lockfile.
Done in 123.95s.
複製代碼
$ yarn start
yarn run v1.7.0
$ cross-env webpack-dev-server --config build/webpack.dev.conf.js
 98% after emitting DONE  Compiled successfully in 3639ms10:43:15

 I  You application is running here http://localhost:10000

 N  Some additionnal notes to be displayed unpon successful compilation
複製代碼

3.安裝demo所需依賴

 因爲這次demo的開發須要依賴於Vant+Vuex+Vue-router+less,因此咱們要安裝所需的依賴!

 執行命令:

yarn add vuex vue-router vant
複製代碼

 安裝所需依賴完畢!

yarn add v1.7.0
[1/4] Resolving packages...
[2/4] Fetching packages...
info fsevents@1.2.7: The platform "win32" is incompatible with this module.
info "fsevents@1.2.7" is an optional dependency and failed compatibility check. Excluding it from installation.
[3/4] Linking dependencies...
warning " > less-loader@4.1.0" has unmet peer dependency "less@^2.3.1 || ^3.0.0".
[4/4] Building fresh packages...

success Saved lockfile.
warning Your current version of Yarn is out of date. The latest version is "1.13.0", while you're on "1.7.0".
info To upgrade, run the following command:
$ curl --compressed -o- -L https://yarnpkg.com/install.sh | bash
success Saved 7 new dependencies.
info Direct dependencies
├─ vant@1.5.9
├─ vue-router@3.0.2
└─ vuex@3.1.0
info All dependencies
├─ @babel/runtime@7.3.4
├─ @vant/icons@1.0.8
├─ @vue/babel-helper-vue-jsx-merge-props@1.0.0-beta.2
├─ vant@1.5.9
├─ vue-lazyload@1.2.3
├─ vue-router@3.0.2
└─ vuex@3.1.0
Done in 24.50s.
複製代碼

2、項目頁面編寫

 在上一節中咱們搭建好了基本的開發環境,接下來就帶你們編寫基本的頁面,因爲樣式不在此篇文章的考慮範圍以內,因此咱們直接採用vant的ui框架進行頁面的搭建!

1.新建模糊頁面login、home、secord

 本文是移動端的一個編寫,因此咱們採用有讚的vant來編寫項目,在src文件夾下新建一個views文件夾,再在views文件夾下新建幾個基本頁面內容以下:

<template>
    <div class="container">login</div>
</template>

<script>
export default{
    
}
</script>

<style>
.container{
    background-color:skyblue;
    font-size:20px;
}
</style>
//login.vue文件內容
複製代碼
<template>
    <div class="container">home</div>
</template>

<script>
export default{
    
}
</script>

<style>
.container{
    background-color:skyblue;
    font-size:20px;
}
</style>
//home.vue文件內容
複製代碼
<template>
    <div class="container">secord</div>
</template>

<script>
export default{
    
}
</script>

<style>
.container{
    background-color:skyblue;
    font-size:20px;
}
</style>
//secord.vue內容
複製代碼

項目骨架以下圖

2.新建路由配置文件

 在src文件夾下新建router文件夾,文件夾下新建index.js文件看成路由配置文件

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

import Home from './../views/home';
import Secord from './../views/secord';
import UserLogin from './../views/login';

import globalStore from './../store/global';

Vue.use(VueRouter);

const router=new VueRouter({
    routes:[
        {
            path:'/',
            redirect:to=>{
                if(localStorage.getItem('token') && globalStore.state.isAuthentication){
                    return {path:'/home'}
                }else{
                    return {path:'/user/login'}
                }
            }// /路徑下若是持久化存儲localStorage下有token而且global.js下的Authentication(是否登錄)爲true/false,若是登錄跳轉到Home頁面,沒有的話,就跳轉到用戶登錄頁面。
        },
        {
            path:'/user/login',
            name:'userlogin',
            component:UserLogin
        },
        {
            path:'/effects',
            name:'effects',
            component:Effects,
        },
        {
            path:'/home',
            name:'home',
            component:Home,
        },
        {
            path:'/secord',
            name:'secord',
            component:Secord
        }
    ]
});

export default router;
//index.js文件內容如上!
複製代碼

3.小試牛刀

import Vue from 'vue';//在import Vue的過程當中,Vue主要是在原型上完成方法的掛載,而且初始化了全局的API。
import App from './App.vue';//引入主VUE頁面
import router from './router/index';

import './styles/reset.css' /**引入樣式重置 */

Vue.config.productionTip = false;//阻止啓動生產消息,經常使用做指令

new Vue({
    el:"#root",//將渲染結果掛在這id爲root的html上
    router,
    render:h=>h(App),//render函數是渲染一個視圖,而後提供給el掛載,若是沒有render那頁面什麼都不會出來
});
//index.js文件內容如上!
複製代碼

在src文件夾下的index.js下引入路由配置文件,如上代碼所示

同時修改app.vue(根vue頁面)的template標籤

<template>
    <div id="app"> <router-view /> </div> </template>
複製代碼

運行項目你會發現經過對應路徑已經有頁面展現出來

4.rem實現手機端自適應

 由於本文是基於手機端的小demo,因此須要實現手機端屏幕大小自適應!

rem佈局的本質是等比縮放,rem是根據根font-size的大小設置的

 在src文件夾下新建utils,用來存放工具類函數等...

 在utils文件夾下新建Rem.js

const baseSize=32;

function setRem(){
    const htmlWidth=document.documentElement.clientWidth || document.body.clientWidth;
    const htmlDom=document.getElementsByTagName('html')[0];
    //設置頁面根節點字體大小
    htmlDom.style.fontSize=htmlWidth/10+'px';
}

setRem();
//Rem.js內容如上
複製代碼

而後在src文件夾的index.js文件中新增rem設置,即引入

import './styles/reset.css' /**引入樣式重置 */
複製代碼

由於暫時沒有在less中發現和scss中相似的寫法,故在scss定義一個px轉化爲rem的方法,在styles文件夾新建common.scss,須要時引入就行

@function pxToRem($px){
    @return $px/20px*1rem;
}
//common.scss內容以下
複製代碼

5.在項目中引入vuex

 雖然我們只有幾個頁面,徹底不必引入vuex,使項目看起來變得很複雜,可是這不是爲了讓你們熟悉vuex嘛,知道如何在項目中使用,首先在src選新建store文件夾,暫且定義三個文件,global.js存放與全局相關的狀態,home.js存放home頁面相關的狀態,secord.js存放secord頁面相關的狀態。

import Vue from 'vue';
import Vuex from 'vuex';

import home from './home';
import secord from './secord';

Vue.use(Vuex);

export default new Vuex.Store({
    namespaced:true,

    modules:{
        home,
        secord
    },

    state:{
        isAuthentication:false,//是否有權限,是否登錄
    },
    getters:{

    },
    actions:{

    },
    mutations:{
        updateState(state,payload){
            Object.assign(state,payload);
        }
    }
});
//global.js文件內容如上
複製代碼
export default {

    namespaced:true,

    state:{

    },
    getters:{

    },
    actions:{

    },
    mutations:{
        updateState(state,paylaod){
            Object.assign(state,payload);
        }
    }

}
//home.js內容如上
複製代碼
export default {

    namespaced:true,

    state:{

    },
    getters:{

    },
    actions:{

    },
    mutations:{
        updateState(state,paylaod){
            Object.assign(state,payload);
        }
    }

}
//secord.js內容如上
複製代碼

文件寫好後能夠在index.js裏面引入相關的文件使之初始化

import store from './store/global';

new Vue({
    el:"#root",//將渲染結果掛在這id爲root的html上
    router,
    store,//加載vuex
    render:h=>h(App),//render函數是渲染一個視圖,而後提供給el掛載,若是沒有render那頁面什麼都不會出來
});
複製代碼

vuex核心概念

1.namespaced:也就是標識符,指明在哪一個模塊以後,vuex中的store分模塊管理,須要在store的index.js中引入各個模塊,爲了解決不一樣模塊命名衝突的問題,將不一樣模塊的namespaced:true,以後在不一樣頁面中引入getter、actions、mutations時,須要加上所屬的模塊名。

2.modules:Modules:將store分割成不一樣的模塊。

3.state:包含全部應用級別狀態的對象。

4.getters: vuex 中的getters 想當於vue中的computed ,getters是vuex 中的計算屬性 ,計算屬性寫起來是方法,但它是個屬性。

5.actions:包含異步操做、提交mutaions改變狀態。

6.mutations:惟一修改狀態的事件的回調函數。

由於咱們暫時沒有進行業務模塊的開發,因此暫時沒有定義不少狀態等...

6.登錄頁面login.vue的佈局樣式編寫

 在閱讀了Vant的官網後,咱們須要如今public文件夾下的index.html文件的head標籤內部引入vant樣式!

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vant@1.6/lib/index.css">
複製代碼

 在項目中引入babel-plugin-import

PS E:\MyProject\Webpack4OfVueStage> yarn add babel-plugin-import -D
yarn add v1.7.0
[1/4] Resolving packages...
[2/4] Fetching packages...
info fsevents@1.2.7: The platform "win32" is incompatible with this module.
info "fsevents@1.2.7" is an optional dependency and failed compatibility check. Excluding it from installation.
[3/4] Linking dependencies...
warning " > less-loader@4.1.0" has unmet peer dependency "less@^2.3.1 || ^3.0.0".
[4/4] Building fresh packages...
success Saved lockfile.
success Saved 1 new dependency.
info Direct dependencies
└─ babel-plugin-import@1.11.0
info All dependencies
└─ babel-plugin-import@1.11.0
Done in 7.72s.
複製代碼

由於項目中使用的是babel7,因此新建babel.config.js

//在編譯過程當中將import的寫法自動轉換爲按需引入的方式
module.exports={
    plugins:[
        [
            'import',{
                libraryName:'vant',
                libraryDirectory:'es',
                style:true
            },'vant'
        ]
    ]
}
複製代碼

在index.js文件裏面引入所需的大部分組件

import {Dialog,Row,Col,Picker,Field,Cell,CellGroup,Button,Toast,NavBar,Tabbar,TabbarItem,List,Panel,NoticeBar,Tag,Popup} from 'vant';

Vue.use(Row).use(Col);
Vue.use(Field);
Vue.use(Cell).use(CellGroup);
Vue.use(Button);
Vue.use(Toast);
Vue.use(NavBar);
Vue.use(Tabbar).use(TabbarItem);
Vue.use(Panel);
Vue.use(List);
Vue.use(NoticeBar);
Vue.use(Tag);
Vue.use(CircleButton);
Vue.use(Popup);
Vue.use(Picker);
Vue.use(Dialog);
複製代碼
<template>
    <div class="change" >
        <div style="width:100%;height:150px;"></div>
        <div style="margin-top:20px">
        <van-row type="flex" justify="center">
            <van-col span="20">
                <van-cell-group style="border-radius:10px;">
                    <van-field 
                        v-model="username"
                        required 
                        clearable
                        label="用戶名"
                        icon="question"
                        placeholder="請輸入用戶名"
                        
                    />

                    <van-field 
                        v-model="password"
                        type="password"
                        label="密碼"
                        placeholder="請輸入密碼"
                        required 
                        v-on:keyup.13="handleLogin"
                    />    
                </van-cell-group>
            </van-col>
        </van-row>
        </div>
        <div style="margin-top:180px">
        <van-row type="flex" justify="center">
            <van-col span="18">
                <van-button type="primary" size="large" @click="handleLogin">肯定</van-button>
            </van-col>
        </van-row>
        </div>
         
    </div>
</template>

<script>
    
    import { mapState } from 'vuex';
    export default{
        data(){
            return{
                password:'',
                username:'',
            }
        },
        computed:{
            ...mapState({
                isAuthentication:state=>state.isAuthentication,
            })
        },
        methods:{
            handleLogin(){
                if(!this.username || !this.password){
                    this.$toast({
                        message:'請將信息填寫完整'
                    });
                }else{
                    this.$store.dispatch('login',{
                        password:this.password,
                        username:this.username,
                    });
                    this.$router.push({name:'home'})
                }   
            }
        },
    }
</script>

<style lang="less" scoped>
    @import "./../styles/color.less";
    .change{
        width:100%;
        height:100%;
        z-index:2;
        position:absolute;
        top:0;
        bottom:0;
    }
    
</style>
//以上爲login.vue的內容(只關注樣式部分,邏輯部分能夠暫時忽略)
複製代碼

效果圖以下(很醜,粗略設計):

 接下來我就經過login.vue文件帶領你們領略vuex的用法

<van-col span="18">
    <van-button type="primary" size="large" @click="handleLogin">肯定</van-button> </van-col> 複製代碼

 經過vue的**@click綁定一個點擊事件handleLogin**,在methods裏面定義一個方法handleLogin

handleLogin(){
                if(!this.username || !this.password){
                    this.$toast({
                        message:'請將信息填寫完整'
                    });
                }else{
                    this.$store.dispatch('login',{
                        password:this.password,
                        username:this.username,
                    });
                    this.$router.push({name:'home'})
                }   
}
複製代碼

 輸入框輸入帳號密碼,經過v-model指令將輸入框的內容與data裏面定義的usernamepassword綁定,當帳號爲空或者密碼爲空時,調用vanttoast(彈出框:將信息填寫完整),當帳號密碼都不爲空時,經過this.$store.dispatch請求login方法,值得注意的是dispatch觸發的是vuex模塊的actions(經常使用於異步操做),讓咱們看看globalactions中的login方法,localStorage是一種瀏覽器存儲數據的方式。

async login({commit},payload){
            if(payload.password && payload.username){
                localStorage.setItem('token','AUTHENTION');
                commit('updateState',{
                    isAuthentication:true
                })
            }else{

            }
}
複製代碼

 當帳號密碼存在時,commit觸發updateState方法,值得注意的是commit提交觸發的是mutations方法:

updateState(state,payload){
            Object.assign(state,payload);
}
複製代碼

Object.assign()方法用於將多個對象合併爲一個對象,上面的updateState方法能夠將isAuthentication設置爲true。

import Vue from 'vue';
import Vuex from 'vuex';

import home from './home';
import secord from './secord';

Vue.use(Vuex);

export default new Vuex.Store({
    namespaced:true,

    modules:{
        home,
        secord
    },

    state:{
        isAuthentication:false,
    },
    getters:{

    },
    actions:{
        async login({commit},payload){
            if(payload.password && payload.username){
                localStorage.setItem('token','AUTHENTION');
                commit('updateState',{
                    isAuthentication:true
                })
            }else{

            }
        }
    },
    mutations:{
        updateState(state,payload){
            Object.assign(state,payload);
        }
    }
});
//global.js完整代碼
複製代碼

7.home頁面(換膚)的編寫

 由上面的login.vue所寫,當填寫帳號密碼後:

this.$router.push({name:'home'})
複製代碼

 這是vue-router的方法,目的是跳轉到home頁面,此時url爲home

 話很少說,先把代碼展現出來,再展現邏輯部分。

<template>
    <div class="home">
        <van-nav-bar
            title="測試換膚功能"
            left-text="返回"
            left-arrow
            right-text="換膚"
            class="change"
            @click-right="changeSkin"
        ></van-nav-bar>

        <van-card
            num="2"
            price="2.00"
            desc="描述信息"  
            title="商品標題"
            :thumb="imageUrl"
        />
        <van-card
            num="2"
            price="2.00"
            desc="描述信息"  
            title="商品標題"
            :thumb="imageUrl"
        />
        <van-card
            num="2"
            price="2.00"
            desc="描述信息"  
            title="商品標題"
            :thumb="imageUrl"
        />
        <van-card
            num="2"
            price="2.00"
            desc="描述信息"  
            title="商品標題"
            :thumb="imageUrl"
        />
        <van-card
            num="2"
            price="2.00"
            desc="描述信息"  
            title="商品標題"
            :thumb="imageUrl"
        />

        <van-popup v-model="formVisible" position="bottom">
            <van-picker 
                show-toolbar
                title="請選擇皮膚"
                @cancel="handleCancelSelect"
                @confirm="handleSubmitSelect"
                :columns="columns"  
            />
        </van-popup>

        <common-tabbar 
            :activeIndex="activeIndex"
            v-on:onChange="handleChangeTabBar" 
        />
    </div>
</template>

<script>

import CommonTabbar from './../components/common/Tabbar.vue';
import SkinTypeEnum from './../enum/SkinTypeEnum';
import { mapState } from 'vuex';

export default{
    data(){
        return{
            show:true,
            activeIndex:0,
            imageUrl:'http://img5.mtime.cn/CMS/News/2019/03/11/091140.35777532_620X620.jpg',
            columns: [`少女粉`,
                    `天空藍`, 
                    `茄子紫`, 
                    `清新綠`,
                    `警告色`,
                    `危險紅`
            ]
        }
    },
    components:{
        CommonTabbar
    },
    computed:mapState({
        formVisible:state=>state.home.formVisible,
    }),
    methods:{
        handleChangeTabBar(e){
            console.log(e);
            if(e===2){
                this.$router.push({name:'secord'})
            }else if(e===1){
                this.$router.push({name:'effects'})
            }
        },
        changeSkin(){//點擊換膚彈出皮膚選擇框
            this.$store.commit('home/updateState',{
                formVisible:true
            })
        },
        handleCancelSelect(){//點擊取消
            this.$store.commit('home/updateState',{
                formVisible:false,
            })
        },
        handleSubmitSelect(value,index){//點擊肯定
            let colorValue=SkinTypeEnum.getThemeValue(value);
            document.getElementById('app').className=`${colorValue}Theme`;
            this.$store.commit('home/updateState',{
                formVisible:false,
            });
            localStorage.setItem('app_theme',document.getElementById('app').className)
        }
    }
}
</script>

<style scoped lang="less">
@import "./../styles/color.less";
.change{
     /deep/.van-icon .van-icon-arrow-left .van-nav-bar__arrow{
         color:white;
     }
     /deep/.van-nav-bar__text{
         color:white;
     }
     /deep/.van-nav-bar__title{
         color:white;
     }
}
</style>
//home.vue的內容
複製代碼

其中咱們自定義了一個組件tabbar,由於組件中每一個頁面都用到了這個組件,因此咱們把它抽象成一個組件,這樣咱們就不須要重複寫代碼了,每一個頁面直接引用就能夠了,固然頁面也不是不少,咱們徹底能夠每一個頁面都寫一個,可是這不是爲了讓你們都瞭解組件的用法嘛!!!

 新建components文件夾,在components文件夾下新建common文件夾,在common文件夾下新建Tabbar.vue文件。

<template>
    <van-tabbar v-model="activeIndexData" class="change" @change="handleChangeTabBar">
        <van-tabbar-item>
                <span>換膚</span>
                <i slot="icon" class="iconfont iconhuanfu" style="{fontSize:'20px',color:'white'}"></i>
        </van-tabbar-item>
        <van-tabbar-item>
                <span>動效</span>
                <i slot="icon" class="iconfont iconxiaoguo" style="{fontSize:'20px'}"></i>
        </van-tabbar-item>
        <van-tabbar-item>
                <span>切換</span>
                <i slot="icon" class="iconfont iconqiehuan" style="{fontSize:'20px'}"></i>
        </van-tabbar-item>
    </van-tabbar>
</template>

<script>
export default{
    data(){
        let me=this;
        return{
            activeIndexData:me.activeIndex,
        }
    },
    methods:{
        handleChangeTabBar(e){
            this.$emit('onChange',e)
        }
    },
    props:{
        activeIndex:{
            type:Number,
            default:0,
        },
    },
}
</script>

<style lang="less">
@import "./../../styles/color.less";
.change{
    /deep/.van-tabbar-item{
        color:white;
    }
    /deep/.van-tabbar-item--active{
        color:#1989fa;
    }
}

</style>
//tabbar.vue的內容
複製代碼

 其中props定義的是父組件傳來的值,類型是number,默認值是0。

引入組件並註冊組件

components:{
        CommonTabbar
},
複製代碼

computed中能夠獲取vuex home模塊定義的state

computed:mapState({
        formVisible:state=>state.home.formVisible,
}),
複製代碼

 當點擊換膚的時候,觸發changeSkin方法:

changeSkin(){//點擊換膚彈出皮膚選擇框
            this.$store.commit('home/updateState',{
                formVisible:true
            })
},
複製代碼

 觸發commit,即home模塊裏面的mutations裏面的updateState方法,使formVisible設置爲true,formVisible與v-model綁定,經過true/false來控制popup顯示/隱藏。

 點擊換膚讓popup彈窗顯示出來,popup裏面有picker的column綁定了columns,即各類皮膚顏色。

<van-popup v-model="formVisible" position="bottom">
            <van-picker show-toolbar title="請選擇皮膚" @cancel="handleCancelSelect" @confirm="handleSubmitSelect" :columns="columns" /> </van-popup> 複製代碼

 當點擊取消時設置formVisible爲false時,彈框即消失。

 當點擊肯定選擇顏色時,觸發handleSubmitSelect方法,此時我再此介紹一個枚舉類形式的函數,此函數的目的是經過一個英文值含義或者中文值含義來返回對應的值。

function getThemeValue(value){

    console.log('a');

    if(!value){
        return '';
    }

    if(value === "少女粉"){
        return 'girl';
    }

    if(value === "天空藍"){
        return 'blue';
    }

    if(value === "茄子紫"){
        return 'purple';
    }

    if(value === '清新綠'){
        return 'green';
    }

    if(value === '警告色'){
        return 'warning';
    }

    if(value === '危險紅'){
        return 'danger';
    }

}

export default {
    getThemeValue,
}
//SkinTypeEnum.js定義
複製代碼

 直接引入調用,把中文值轉化爲對應的英文。

handleSubmitSelect(value,index){//點擊肯定
            let colorValue=SkinTypeEnum.getThemeValue(value);
            document.getElementById('app').className=`${colorValue}Theme`;
            this.$store.commit('home/updateState',{
                formVisible:false,
            });
            localStorage.setItem('app_theme',document.getElementById('app').className)
}
//改變膚色的重要方法
複製代碼

接下來就是整個功能的重中之重了!!請祥聽

8.編寫less文件實現換膚

1.在styles文件夾下新建theme.less

.theme(@background){
    .change{
        background-color:@background;
    }
}
//theme.less內容
複製代碼

2.在styles文件夾下新建color.less

@import "./theme.less";

@girlPink:#FC9F9F;//少女粉
@skyBlue:#1890FF;//天空藍
@eggplantPurple:purple;//茄子紫
@freshGreen:#09C160;//清新綠
@warningColor:#FF976A;
@dangerRed:#FF4D4F;//危險紅


.girlTheme{
    .theme(@girlPink);
}
.blueTheme{
    .theme(@skyBlue);
}
.purpleTheme{
    .theme(@eggplantPurple);
}
.greenTheme{
    .theme(@freshGreen);
}
.warningTheme{
    .theme(@warningColor);
}
.dangerTheme{
    .theme(@dangerRed);
}
//color.less內容
複製代碼

熟悉Less的小夥伴們應該看到之後就大體明白了,經過color.less引入theme.less,可使change類名下的背景顏色改成相對應類目不同的顏色

3.在須要改變膚色的頁面引入color.less,並將須要修改的div類目設置爲change

 由於咱們的項目是單頁(SPA)應用,全部的vue頁面都是在根div下,因此設置根目錄下的class類名就能夠改變vue頁面class類名change的div背景色。因此咱們把想要更換div背景色套上change類名就好了!其實咱們以前寫的頁面都已經套上change了哦!不知道你們有沒有發現!

4.持久化改變膚色

 其實這裏仍是有一個Bug的,就是每當重啓服務瀏覽器的時候,全部的類名初始化,以前的顏色將會消失,因此咱們這裏將皮膚主題保存進localStorage(若是不手動清楚瀏覽器緩存,它就始終不會消失!)

localStorage.setItem('app_theme',document.getElementById('app').className)
複製代碼

在根vue app.vue裏面的生命週期函數中設置存下來的膚色,一切萬事OK!

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

<script>
export default {
    data(){
        return{
            msg:'webpack4搭建react環境基本完成,是否是很簡單呢'
        }
    },
    mounted:function(){
        let theme=localStorage.getItem('app_theme');
        document.getElementById('app').className=theme;
    }
}
</script>
複製代碼

大體效果就以下圖所示,下一個需求是動態更改div位置,但願你們能夠期待哦!

若是你以爲個人文章還不錯的話,能夠給個star哦~,GitHub地址

相關文章
相關標籤/搜索