首頁>技術>

前言

最近得空一直在搗鼓Vue3開發,想要快速上手,還是得寫一些自定義元件。之前就有基於vue2.x寫過一些自定義Navbar+Tabbar及彈窗元件。於是就擼起袖子開整。

今天主要是給大家分享一些如何快速上手Vue3開發。

目前Vue3的最新版本是V3.0.4,star高達19.7K+。而且更新還很頻繁。

# vue3官網https://v3.vuejs.org/# vue3中文網https://v3.cn.vuejs.org/# vue3倉庫地址https://github.com/vuejs/vue-next# Vite構建工具https://vite-design.surge.sh/

透過如下2種方法快速建立Vue3專案。

1、Vite構建工具

$ npm init vite-app <project-name>$ cd <project-name>$ npm install$ npm run dev

如果安裝了Vite腳手架 create-vite-app,也可以透過下面方法快速建立。

$ create-vite-app <project-name>

2、@vue/cli腳手架

透過CLI建立需要版本是V4.5以上。升級CLI,npm i @vue/cli -g

$ vue create <project-name># 選擇 Vue3選項 即可$ npm run serve

下面進入今天的主題,Vue3實現自定義導航欄+底部Tab+彈窗元件。

在components目錄下新建headerBar.vue和tabBar.vue兩個頁面。

並新建一個components.js頁面用於引入公共元件。

然後在main.js中註冊即可。

1、自定義headerBar.vue

其實這個元件和vue2.x建立沒啥區別。

<template>    <div class="tab-bar" :class="{'fixed': fixed}">        <div class="tab-bar__wrap flexbox flex-alignc" :style="{'background': bgcolor}">            <div v-for="(item, index) in tabs" :key="index" class="navigator" :class="currentTabIndex == index ? 'on' : ''" @click="switchTabs(index, item)">                <div class="ico" :class="{'dock': item.dock}">                    <i v-if="item.dock" class="dock-bg" :style="{'background': item.dockBg ? item.dockBg : activeColor}"></i>                    <i v-if="item.icon" class="iconfont" :class="item.icon" :style="{'color': (currentTabIndex == index && !item.dock ? activeColor : color), 'font-size': item.iconSize}"></i>                    <img v-if="item.img" class="iconimg" :src="currentTabIndex == index && !item.dock ? item.activeImg : item.img" :style="{'font-size': item.iconSize}" />                    <em v-if="item.badge" class="nuxt__badge">{{item.badge}}</em>                    <em v-if="item.dot" class="nuxt__badge-dot"></em>                </div>                <div class="txt" :style="{'color': (currentTabIndex == index ? activeColor: color)}">{{item.title}}</div>            </div>        </div>    </div></template><script>import { ref } from 'vue'import { useRouter, useRoute } from 'vue-router'    export default {        props: {            current: { type: [Number, String], default: 0 },            // 背景色            bgcolor: { type: String, default: '#fff' },            // 顏色            color: { type: String, default: '#999' },            // 啟用顏色            activeColor: { type: String, default: '#22d59c' },            // 是否固定            fixed: { type: [Boolean, String], default: false },            // tab選項            tabs: {                type: Array,                default: () => null            },        },        emits: {            click: null        },        setup(props, context) {            const currentTabIndex = ref(props.current)            const router = useRouter()            const route = useRoute()            // 匹配當前路由頁面            const _curPath = route.path            props.tabs.map((item, index) => {                if(item.path == _curPath) {                    currentTabIndex.value = index                }            })            const switchTabs = (index, item) => {                currentTabIndex.value = index                context.emit('click', index)                if(item.path) {                    router.push(item.path)                }            }            return {                currentTabIndex,                switchTabs,            }        }    }</script>

支援自定義背景色、文字顏色|選中顏色、是否固定、點選選項(返回索引值)。

另外還支援dock效果,圖示支援iconfont及圖片。

<tab-bar bgcolor="#f9f9f9" color="#f00" @click="tabbarClicked" :tabs="[  {    icon: 'icon-home', title: '首頁', path: '/index',  },  {    icon: 'icon-guanli', title: '管理', path: '/manage'    badge: 1  },  {    icon: 'icon-fabu', title: '釋出',    dock: true, dockBg: '#f60',    iconSize: '20px',  },  {    icon: 'icon-guanli', title: '聯絡人',    img: 'http://www.xxx.com/contact.jpg',    activeImg: 'http://www.xxx.com/contact_on.jpg',  },  {    icon: 'icon-me', title: '我的',    dot: true  }]"/>// 點選事件tabbarClicked(index) {  console.log('tabbar索引值:' + index)}
3、自定義V3Popup元件

V3Popup 基於Vue3開發的一款集合Alert、Dialog、ActionSheet、Toast等功能的移動端Vue3.0彈出框元件。

支援標籤式+函式式兩種呼叫方式。

// 標籤式呼叫<v3-popup  v-model="showAlert"  title="標題"   content="彈窗內容資訊"  type="ios"  shadeClose="false"  xclose  z-index="2021"  :btns="[    {...},    {...},  ]"/>
// 函式式呼叫let $el = this.$v3popup({  title: '標題',  content: '彈窗內容資訊',  type: 'ios',  shadeClose: false,  xclose: true,  zIndex: 2021,  btns: [    {text: '關閉'},    {      text: '確定',      style: 'color:#09f;',      click: () => {        $el.close()      }    },  ]});

template模板寫法和vue2.x沒什麼區別,主要是邏輯處理部分,既可以使用vue2.x的寫法,也可以使用vue3的Composition API寫法。

下面主要是使用Vue3寫法實現邏輯。

<script>    import { ref, reactive, watch, toRefs, nextTick, onMounted } from 'vue'    /**     * Vue3.0寫法     */    let $index = 0, $locknum = 0, $timer = {}    export default {        props: {            // 接收父元件v-model值,如果v-model:xxx,則這裡需寫xxx: {...}            modelValue: { type: Boolean, default: false },            // 彈框識別符號,相同ID共享一個例項            id: {                type: String, default: ''            },            title: String,            content: String,            type: String,            popupStyle: String,            icon: String,            shade: { type: [Boolean, String], default: true },            shadeClose: { type: [Boolean, String], default: true },            opacity: { type: [Number, String], default: '' },            round: Boolean,            xclose: Boolean,            xposition: { type: String, default: 'right' },            xcolor: { type: String, default: '#333' },            anim: { type: String, default: 'scaleIn' },            position: String,            follow: { type: Array, default: null },            time: { type: [Number, String], default: 0 },            zIndex: { type: [Number, String], default: '8080' },            teleport: [String, Object],            btns: {                type: Array, default: null            },            onSuccess: { type: Function, default: null },            onEnd: { type: Function, default: null },            // 接收函式式移除指令            remove: Function,        },        emits: [            'update:modelValue',        ],        setup(props, context) {            const elRef = ref(null)            const data = reactive({                opened: false,                closeCls: '',                toastIcon: {                    //...                }            })            watch(() => props.modelValue, (val) => {                if(val) {                    open()                } else {                    close()                }            })            onMounted(() => {                if(props.modelValue) {                    open()                }            })            // 開啟彈框            const open = () => {                if(data.opened) return                data.opened = true                typeof props.onSuccess === 'function' && props.onSuccess()                const dom = elRef.value                dom.style.zIndex = getZIndex() + 1                if(JSON.parse(props.shade)) {                    if(!document.body.classList.contains('vui__body-hidden')) {                        document.body.classList.add('vui__body-hidden')                    }                    $locknum++                }                // 倒計時關閉                if(props.time) {                    $index++                    // 避免重複點選                    if($timer[$index] !== null) clearTimeout($timer[$index])                    $timer[$index] = setTimeout(() => {                        close()                    }, parseInt(props.time) * 1000)                }                //...            }            // 關閉彈框            const close = () => {                data.closeCls = true                setTimeout(() => {                    data.opened = false                    data.closeCls = false                    if(JSON.parse(props.shade)) {                        $locknum--                        if(!$locknum) {                            document.body.classList.remove('vui__body-hidden')                        }                    }                    if(props.time) {                        $index--                    }                    context.emit('update:modelValue', false)                    typeof props.onEnd === 'function' && props.onEnd()                }, 200)            }            // 點選遮罩層            const shadeClicked = () => {                if(JSON.parse(props.shadeClose)) {                    close()                }            }            // 按鈕事件            const btnClicked = (e, index) => {                //...            }            // 獲取彈窗層級            const getZIndex = () => {                //...            }            // 獲取彈窗座標點            const getPos = (x, y, ow, oh, winW, winH) => {                let l = (x + ow) > winW ? x - ow : x;                let t = (y + oh) > winH ? y - oh : y;                return [l, t];            }            return {                ...toRefs(data),                shadeClicked,                btnClicked,                close,                elRef,            }        }    }</script>

vue3中watch監聽事件,可以監聽一個、多個值(物件/陣列)。

<script>    import { ref, computed, reactive, toRefs, watch, nextTick } from 'vue'    export default {        setup() {            const count = ref(0)            const data = reactive({                num: 0,                total: computed(() => data.num * 2),                handlePlus: () => {                    data.num++                }            })            // 監聽器watch使用            // 1、監聽ref一個值count            // watch(count, () => {})            watch(count, (newVal, oldVal) => {                console.log('count updated:' + count.value)                console.log(newVal, oldVal, "--新舊值");            })            // 監聽reactive中某一項            watch(() => data.num, (newVal, oldVal) => {                console.log('+++count updated:' + data.num)                console.log(newVal, oldVal, "==新舊值");            })            // 2、監聽整個reactive中data物件            watch(data, () => {                console.log('==count updated:' + data.num)            })            // 3、監聽多個值            // watch([count, data], () => {})            watch([count, () => data.num], () => {                console.log('某一項updated:' + count.value + '---' + data.num)            })            return {                //...            }        }    }</script>

注意:Vue3不支援div的slot插槽。

16
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 【Python】幾招個數據分析大招送給準備轉崗的你