第一章:基于@vue/cli4.x+vue2.x原生封裝的tabbar高可用組件示例

引言

如今前端框架也越來(lái)越豐富,學(xué)習(xí)成本也在逐漸加深,我作為純后端Java開發(fā)人員,也學(xué)習(xí)了一下目前前端比較火的vue,并將學(xué)習(xí)的第一階段成果以一個(gè)高可用,可自定義內(nèi)容的,自己手動(dòng)擼的一個(gè)封裝好的一個(gè)tabbar組件。本章關(guān)于里面用到的知識(shí)點(diǎn)的原理不會(huì)過(guò)多的去講解,主要作為一次初級(jí)入門的實(shí)踐示例來(lái)分享。

封裝好的tabbar作用

這是我第一個(gè)小實(shí)踐示例。主要用到 @vue/cli4.x+vue2.x+vue-router(路由)來(lái)實(shí)現(xiàn)。實(shí)現(xiàn)好的效果如下圖展示:

示例演示

封裝好下面的tabbar,跳轉(zhuǎn)不同的路徑顯示不同的vue頁(yè)面,下面的按鈕個(gè)數(shù)可以自定義,點(diǎn)擊的效果顏色也可以自定義,以及圖標(biāo)跟文字都是可以實(shí)現(xiàn)類似參數(shù)傳遞的功能來(lái)高度自定義tabbar的內(nèi)容。

  • @vue/cli4.x: 這是vue原生的官方腳手架。具體的詳細(xì)的介紹我不多說(shuō)了,你可以理解為用它可以創(chuàng)建一個(gè)vue的項(xiàng)目的架子,相當(dāng)于建房子的一個(gè)框架,把一些最基本的東西給你生成好了,你只需要去具體實(shí)現(xiàn)你自己的業(yè)務(wù)代碼。你也可以查看官網(wǎng)的介紹點(diǎn)這里
  • vue2.x: Vue (讀音 /vju?/,類似于 view) 是一套用于構(gòu)建用戶界面的漸進(jìn)式框架。摘抄自官網(wǎng),曾今我有很長(zhǎng)時(shí)間都讀錯(cuò)了它。
  • vue-router: 是vue.js官方的路由管理器。它和vue.js的核心深度集成。

應(yīng)用

開發(fā)正式開始之前,需要準(zhǔn)備的工作

  • WebStorm 2019.3.2 x64開發(fā)工具的安裝
  • node.js的安裝

1、在webstorm的命令行窗口或者cmd窗口安裝官網(wǎng)提供的最新腳手架@vue/cli。我這里直接在webstorm命令行窗口進(jìn)行安裝演示,如圖:

安裝@vue/cli腳手架

點(diǎn)擊Terminal是打開命令行的操作。npm install -g @vue/cli安裝命令中-g表示全局安裝。其實(shí)我之前已經(jīng)在我電腦上安裝過(guò)了,這里為了演示。
2、使用腳手架創(chuàng)建tabbar項(xiàng)目。執(zhí)行vue create tabbar命令后會(huì)彈出如下選擇界面:
創(chuàng)建項(xiàng)目

default表示它給你推薦的默認(rèn)配置

  • babel:

babel是一個(gè)JavaScript編譯器;
babel是一個(gè)工具鏈,主要用于將ECMAScript2015+版本的代碼轉(zhuǎn)換為向后兼容的JavaScript語(yǔ)法,以便能夠在當(dāng)前和舊版本的瀏覽器或其它環(huán)境中運(yùn)行

  • eslint: 可以理解為質(zhì)量檢查工具,讓你可以對(duì)自己有個(gè)相對(duì)規(guī)范的開發(fā)
    如果我們選擇 manually select features,那么腳手架會(huì)提供更多個(gè)性化的配置讓我們選擇如何初始化項(xiàng)目。


    腳手架提供的更多個(gè)性化的配置選擇

    上下鍵選擇,空格鍵確認(rèn)選擇。這里我簡(jiǎn)單描述下每個(gè)配置選項(xiàng)

  • typescript: 使用下一代Javascript的typescript語(yǔ)法,可以理解為更新的腳本語(yǔ)言,如果不熟練的話不推薦使用。
  • Progressive Web App (PWA) Support: 我在知乎上找到這樣一段描述

Progressive Web App其實(shí)嚴(yán)格說(shuō)來(lái)不是一個(gè)產(chǎn)品,而是一種理念,或者叫打包產(chǎn)品,因?yàn)樗前驯姸嗄茏學(xué)EB產(chǎn)品APP化的能力的一個(gè)集合。
從Google官方網(wǎng)站介紹內(nèi)容提煉一下,PWA的三大基本能力分別是:1、 類APP交互 2、消息推送 3、離線緩存

我的理解是將我們的應(yīng)用可以整的類似app的交互體驗(yàn),即webapp。

  • Router: 是否安裝路由
  • Vuex: 是否安裝全局狀態(tài)管理器
  • CSS Pre-processors: 選擇CSS 預(yù)處理類型
  • Linter / Formatter :一種規(guī)范類型
  • Unit Testing:選擇Unit測(cè)試方式
  • E2E Testing: 端到端的測(cè)試,E2E是end to end 的簡(jiǎn)寫

當(dāng)你選擇完這個(gè)個(gè)性化的配置后,他會(huì)提示你是否保存這個(gè)默認(rèn)配置,方便下次使用。我的項(xiàng)目是選擇了默認(rèn)的配置
生成后的項(xiàng)目如圖:

項(xiàng)目結(jié)構(gòu)化展示

我們主要是在src目錄下進(jìn)行開發(fā)。
3、安裝vuerouter路由
安裝vue-router

然后我們?cè)趘ue中安裝vuer-outer,配置我們的頁(yè)面
路由的配置

import Vue from 'vue'
import VueRouter from 'vue-router'
import routes from "./routes"

//1、先在vue中安裝router路由
Vue.use(VueRouter);

//2、創(chuàng)建router實(shí)例,然后傳入‘routers’配置
const router = new VueRouter({
  routes,   //傳入寫好的路由頁(yè)面配置
  mode: 'history'  //可以使得頁(yè)面跳轉(zhuǎn)時(shí)不帶#號(hào)
})

//3、導(dǎo)出路由對(duì)象
export default router;

代碼中有詳細(xì)的注釋、關(guān)于為什么用import、export這種概念性的不做過(guò)多描述
其中路由的頁(yè)面配置

//定義路由
const routes = [
  {
    path: '',
    redirect: '/home'
  },
  {
    path: '/home',
    meta: {
      title: '首頁(yè)'
    },
    component: ()=>import("views/home/Home")
  },
  {
    path: '/category',
    meta: {
      title: '分類'
    },
    component: ()=>import("views/category/Category")
  },
  {
    path: '/cart',
    meta: {
      title: '購(gòu)物車',
    },
    component: ()=>import("views/cart/Cart")
  },
  {
    path: '/profile',
    meta: {
      title: '我的'
    },
    component: ()=>import("views/profile/Profile")
  }
]

export default routes;

將配置好的路由放入vue實(shí)例中去

vue示例添加路由

views文件夾下創(chuàng)建我們的業(yè)務(wù)所需頁(yè)面
創(chuàng)建業(yè)務(wù)頁(yè)面

腳手架的文件夾命名是有規(guī)范的,頁(yè)面文件一般建立在views下面,router即路由的文件所在位置
樣式和圖片所在位置

里面的資源可以在我的gitee代碼倉(cāng)庫(kù)中進(jìn)行下載。
4、敲黑板,重點(diǎn)來(lái)了,組件的創(chuàng)建
tabbar組件部分

我們將tabbar看作一個(gè)整體,封裝第一層組件
TabBar.vue

<template>
    <div id = "tab-bar">
        <!--定義一個(gè)插槽,里面的內(nèi)容由外部來(lái)定義-->
        <slot></slot>
    </div>
</template>

<script>
  export default {
    name: "TabBar"
  }
</script>

<style scoped>
    #tab-bar {
        display: flex;
        background-color: #f6f6f6;
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        box-shadow: 0 -3px 1px rgba(100,100,100,.2);
    }
</style>

TabBar.vue頁(yè)面中我只定義了一個(gè)插槽,這個(gè)插槽可以放任何我們業(yè)務(wù)需要的東西進(jìn)去,首先將tabbar的大筐筐的樣式和布局來(lái)定義好

將大筐筐定義好

slot插槽的內(nèi)容外部來(lái)定義。
TabBarItem.vue:針對(duì)每個(gè)按鈕的封裝實(shí)現(xiàn)

<template>
    <div class="tab-bar-item" @click="tabBarItemClick">
        <!--圖片區(qū)域-->
        <!--未點(diǎn)擊圖片顯示狀態(tài)-->
        <div v-if = "!isActive">
            <slot name="item-icon"></slot>
        </div>
        <!--點(diǎn)擊圖片顯示狀態(tài)-->
        <div v-else>
            <!--創(chuàng)建一個(gè)具名插槽-->
            <slot name="item-icon-active"></slot>
        </div>
        <!--文字區(qū)域-->
        <div :style = "isActiveColor">
            <slot name="item-text"></slot>
        </div>
    </div>
</template>

<script>
  export default {
    name: "TabBarItem",
    //接收來(lái)自父組件的參數(shù)
    props: {
      path: String,   //第一種寫法   參數(shù):類型
      activeColor: {  //第二種寫法,用對(duì)象來(lái)接收??梢圆还舛x接收的參數(shù)類型,還可以定義默認(rèn)值
        type: String,
        default: 'red'
      }
    },
    data() {
      return {

      }
    },
    //定義我們需要的計(jì)算屬性
    computed: {
      isActive() {
        //判斷當(dāng)前點(diǎn)擊的是否與路由的路徑一致
        return this.$route.path == this.path;
      },
      isActiveColor() {
        return this.isActive ? {color: this.activeColor} : {}
      }
    },
    methods: {
      tabBarItemClick() {
        console.log('path===' + this.path);
        //進(jìn)行切換路由頁(yè)面
        this.$router.replace(this.path);
      }
    }
  }
</script>

<style scoped>
    .tab-bar-item {
        flex: 1;
        text-align: center;
        height: 49px;
        font-size: 14px;
    }

    .tab-bar-item img {
        width: 24px;
        height: 24px;
        margin-top: 3px;
        vertical-align: middle;
        margin-bottom: 2px;
    }
</style>

props: props用來(lái)接收父級(jí)傳過(guò)來(lái)的參數(shù)來(lái)定義父級(jí)傳過(guò)來(lái)的參數(shù),

  • path: 父級(jí)定義好的跳轉(zhuǎn)路徑

  • activeColor: 定義父級(jí)傳過(guò)來(lái)的點(diǎn)擊的切換顏色
    此頁(yè)面定義了三個(gè) 具名插槽slot:

  • <slot name="item-icon"></slot> :沒有被點(diǎn)擊的圖片插槽,這里的插槽使得圖片的定義由父級(jí)來(lái)定義

  • <slot name="item-icon-active"></slot>:被點(diǎn)擊的圖片插槽,這里的插槽使得圖片的定義由父級(jí)來(lái)定義

  • <slot name="item-text"></slot>:文字區(qū)域插槽

    image.png

    MainTabBar.vue:父級(jí)頁(yè)面,傳入業(yè)務(wù)需要的圖標(biāo)參數(shù)與文字到子頁(yè)面的插槽中

<template>
    <tab-bar>
        <!--path和activeColor相當(dāng)于父組件向子組件傳遞的參數(shù),子組件用props來(lái)接收-->
        <tab-bar-item path="/home" activeColor="deepPink">
            <img slot="item-icon" src="~assets/img/tabbar/home.svg" alt="">
            <img slot="item-icon-active" src="~assets/img/tabbar/home_active.svg" alt="">
            <div slot="item-text">首頁(yè)</div>
        </tab-bar-item>
        <tab-bar-item path="/category" activeColor="deepPink">
            <img slot="item-icon" src="~assets/img/tabbar/category.svg" alt="">
            <img slot="item-icon-active" src="~assets/img/tabbar/category_active.svg" alt="">
            <div slot="item-text">分類</div>
        </tab-bar-item>
        <tab-bar-item path="/cart" activeColor="deepPink">
            <img slot="item-icon" src="~assets/img/tabbar/shopcart.svg" alt="">
            <img slot="item-icon-active" src="~assets/img/tabbar/shopcart_active.svg" alt="">
            <div slot="item-text">購(gòu)物車</div>
        </tab-bar-item>
        <tab-bar-item path="/profile" activeColor="deepPink">
            <img slot="item-icon" src="~assets/img/tabbar/profile.svg" alt="">
            <img slot="item-icon-active" src="~assets/img/tabbar/profile_active.svg" alt="">
            <div slot="item-text">我的</div>
        </tab-bar-item>
    </tab-bar>
</template>

<script>
    import TabBar from "components/tabbar/TabBar";
    import TabBarItem from "components/tabbar/TabBarItem";
  export default {
    name: "MainTabBar",
    components: {
      TabBar,
      TabBarItem
    }
  }
</script>

<style scoped>

</style>

封裝好這個(gè)組建后,vue主頁(yè)面進(jìn)行引用


image.png
<template>
  <div id="app">
    <router-view/>
    <MainTabBar></MainTabBar>
  </div>
</template>

<script>
import MainTabBar from "components/tabbar/MainTabBar";
export default {
  name: 'App',
  components: {
    MainTabBar
  }
}
</script>

<style>
@import "assets/css/base.css";
</style>

<router-view/>放入我們配置好的路由頁(yè)面。
最后我們輸入 npm run serve

啟動(dòng)應(yīng)用

我們輸入npm run serve命令是由package.json頁(yè)面配置決定的
image.png

注意:頁(yè)面中的路徑在 vue.config.js進(jìn)行了別名配置,項(xiàng)目用到的資源和導(dǎo)入頁(yè)面組件時(shí)所以才可以不用寫絕對(duì)路徑。
image.png

module.exports = {
  configureWebpack: {
    resolve: {
      alias: {
        'assets': '@/assets',
        'components': '@/components',
        'views': '@/views'
      }
    }
  }
}

這里的 @表示項(xiàng)目的src目錄,vue以及幫我們定義好了,這里定義好目錄別名后。項(xiàng)目?jī)?nèi)部用到圖片路徑就可以直接用我們配置好的別名路徑代替全局路徑了

配置好的路徑實(shí)際使用截圖

  • 1、import導(dǎo)入頁(yè)面的時(shí)候可以直接用配置好的別名
  • 2、html標(biāo)簽,vue頁(yè)面模板用到的時(shí)候需要在配置好的別名路徑前加~

作者:金哲一(jinzheyi)【筆名】
本文代碼地址:https://gitee.com/jinzheyi/vue
本文鏈接:http://m.itdecent.cn/p/b2ae3e903300

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容