vue初始化

158 阅读3分钟

1. 初始化项目

npm create vite@latest my-vue-app -- --template vue

2. 安装依赖

npm install less less-loader -S
npm install vue-router -S
npm install pinia -D
npm install element-plus -S
npm install @element-plus/icons-vue -S

3.配置@根标记

vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vite.dev/config/
export default defineConfig({
  plugins: [vue()],
  resolve:{
    alias:[
      {
        find:"@",replacement:"/src"
      }
    ]
  }
})

4.常用的reset.less

juejin.cn/post/688522…

blog.csdn.net/fungleo/art…

cssreset.com/

D:\vueProject\vue3\my-vue-app\src\assets\less\index.less

D:\vueProject\vue3\my-vue-app\src\assets\less\reset.less

引入

import { createApp } from 'vue'

import App from './App.vue'
import "@/assets/less/index.less"
createApp(App).mount('#app')

5. 配置路由

route/index.js

import {createRouter,createWebHashHistory} from 'vue-router';
// import Main from '@/views/Main.vue'
// 制定路由规则
const routes=[
    {
        path:'/',
        name:'main',
        component:()=>import('@/views/Main.vue'),
        redirect:'/home',
        children:[
            {
                path:'/home',
                name:'home',
                component:()=>import('@/views/Home.vue'),
            },
            {
                path:'/user',
                name:'user',
                component:()=>import('@/views/User.vue'),
            },  
            {
                path:'/mall',
                name:'mall',
                component:()=>import('@/views/Mall.vue'),
            },
        ]
    }
]

const router=createRouter({
    history:createWebHashHistory(),
    routes
})

export default router;

同时修改main.js ,app.vue

import { createApp } from 'vue';
import App from './App.vue';

import "@/assets/less/index.less";
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css';
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import router from './router';
import { createPinia } from 'pinia';
const pinin = createPinia();
const app = createApp(App);
app.use(router);
app.use(pinin);
app.use(ElementPlus);
// https://element-plus.sxtxhy.com/
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
    app.component(key, component)
  }
app.mount('#app')
<script setup>

</script>

<template>
  <router-view></router-view>
</template>

<style scoped>
#app{
  width: 100%;
  height: 100%;
  overflow: hidden;
}
</style>

6.配置pinia

stores/index.js


import {defineStore} from 'pinia';
import {ref} from 'vue';
function initState(){
    return{
        isCollapse:false,
        tags:[
            {
                path:'/home',
                name:'home',
                label:'首页',
                icon:''
            }
        ],
        currentMenu:null
    }
}

export const useAllDataStore = defineStore('allData', () => {
    const state = ref(initState())
    function selectMenu(val){
        if(val.name === 'home'){
            state.value.currentMenu=null;
        }else{
            state.value.currentMenu=val;
           let index= state.value.tags.findIndex(item=>
            item.name === val.name)
           index === -1 ? state.value.tags.push(val):'';
        }
    }
    function undateTags(tag){
        let index= state.value.tags.findIndex(item=>item.name === tag.name)
        state.value.tags.splice(index,1)
    }
    return { state,selectMenu,undateTags }
  })

7.配置组件

CommonAside.vue

<template>
    <el-aside :width="width">
        <el-menu 
         background-color="#545c64"
         text-color="#fff"
         :collapse="isCollapse"

        >
            <h3 v-show="!isCollapse">管理平台</h3>
            <h3 v-show="isCollapse">平台</h3>
            <el-menu-item v-for="item in noChildren" :index="item.path" :key="item.path"
                @click="handleMenu(item)"
                >
                <component class="icons" :is="item.icon"></component>
                <span>{{ item.label }}</span>
            </el-menu-item>
            <el-sub-menu v-for="item in hasChildren" :index="item.path" :key="item.path" >
                <template #title>
                    <component class="icons" :is="item.icon"></component>
                    <span>{{ item.label }}</span>
                </template>
                <el-menu-item-group>
                    <el-menu-item v-for="(subItem, subIndex) in item.children" :index="subItem.path" :key="subItem.path" @click="handleMenu(subItem)">
                        <component class="icons" :is="subItem.icon"></component>
                        <span>{{ subItem.label }}</span>
                    </el-menu-item>
                </el-menu-item-group>
            </el-sub-menu>

        </el-menu>

    </el-aside>
</template>

<script setup>
import { ref, computed } from 'vue';
import {useAllDataStore} from '@/stores';
import { useRouter,useRoute } from 'vue-router';
const store = useAllDataStore()
const isCollapse=computed(()=>store.state.isCollapse);
const width = computed(()=>store.state.isCollapse ?'64px':'180px');
const router = useRouter();
const route = useRoute();
const handleMenu=(item)=>{
    router.push(item.path)
    store.selectMenu(item)
}
const list = ref([
    {
        path: '/home',
        name: 'home',
        label: '首页',
        icon: 'house',
        url: 'Home'
    },
     {
        path: '/mall',
        name: 'mall',
        label: '商品管理',
        icon: 'video-paly',
        url: 'Mall'
    }, 
    {
        path: '/user',
        name: 'user',
        label: '用户管理',
        icon: 'user',
        url: 'User'
    }, 
    // {
    //     path: 'other',
    //     label: '其他',
    //     icon: 'location',
    //     children: [
    //         {
    //             path: '/page1',
    //             name: 'page1',
    //             label: '页面1',
    //             icon: 'setting',
    //             url: 'Page1'
    //         }, {
    //             path: '/page2',
    //             name: 'page2',
    //             label: '页面2',
    //             icon: 'setting',
    //             url: 'Page2'
    //         },
    //     ]
    // }
])
const noChildren = computed(() => list.value.filter(item => !item.children))
const hasChildren = computed(() => list.value.filter(item => item.children))
const clickMenu = () => {
    router.push(item.path)
}
</script>

<style lang="less" scoped>
.icons{
    width:18px;
    height:18px;
    margin-right:5px;
}
.el-menu{
    border-right: none;
    h3{
        line-height: 48px;
        color:#fff;
        text-align: center;
    }
}
.el-aside{
    height: 100%;
    background: #545c64;
}
</style>

CommonHeader.vue

<template>
    <div class="header">
        <div class="l-content">
            <el-button size="small" @click="handleCollapse">
                <component class="icons" is="menu" ></component>
            </el-button>
            <el-breadcrumb separator="/" class="bread">
                <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
                <el-breadcrumb-item v-if="current" :to="current.path">{{ current.label }}</el-breadcrumb-item>
            </el-breadcrumb>
        </div>
        <div class="r-content">
            <el-dropdown>
                <span class="el-dropdown-link">
                    <img :src="getImageUrl('user')" class="user">
                </span>
                <template #dropdown>
                    <el-dropdown-menu>
                        <el-dropdown-item>个人中心</el-dropdown-item>
                        <el-dropdown-item>退出</el-dropdown-item>
                    </el-dropdown-menu>
                </template>
            </el-dropdown>

        </div>
    </div>
</template>

<script setup>
import { ref, computed } from 'vue';
import {useAllDataStore} from '@/stores';
const getImageUrl = (user) => new URL(`../assets/images/${user}.png`, import.meta.url).href;
const store = useAllDataStore()
const handleCollapse=()=>{
    store.state.isCollapse=!store.state.isCollapse
}
const current = computed(()=>store.state.currentMenu)
console.log('xxxxxxxxxxx current:',current)
</script>

<style lang="less" scoped>
.header{
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: 100%;
    height: 100%;
    background: #333;
}
.icons{
    width: 20px;
    height: 20px;

}
.l-content{
    display: flex;
    align-items: center;
    .el-button{
        margin-right: 20px;
    }
}
.r-content{
    .user{
        width: 40px;
        height: 40px;
        border-radius: 50%;
    }
}
:deep(.bread span){
    color:#fff !important;
    cursor: pointer !important;
}
</style>

CommonTab.vue

<template>
    <div class="tags">
        <el-tag v-for="(tag, index) in tags" 
        :key="tag.name" 
        :closable="tag.name !== 'home'"
        :effect="route.name === tag.name ? 'dark' : 'plain'"
        @click="handleMenu(tag)"
        @close="handleClose(tag,index)"
        >
            {{ tag.label }}

        </el-tag>
    </div>
</template>

<script setup>
import { ref, computed, transformVNodeArgs } from 'vue';
import { useAllDataStore } from '@/stores';
import { useRouter, useRoute } from 'vue-router';
const store = useAllDataStore()
const tags = computed(() => store.state.tags)
const router = useRouter()
const route = useRoute()
const handleMenu=(tag)=>{
    router.push(tag.name)
    store.selectMenu(tag)
}
const handleClose=(tag,index)=>{
    store.undateTags(tag)
    // 如果点击的关闭的tag不是当前页面
    if(tag.name !== route.name)
    return
    if(index === store.state.tags.length){
        store.selectMenu(tags.value[index-1])
        router.push(tags.value[index-1].name)
    }else{
        store.selectMenu(tags.value[index])
        router.push(tags.value[index].name)
    }
}

</script>

<style lang="less" scoped>
.tags {
    margin: 20px 0 0 20px;
}
.el-tag{
    margin-right: 10px;
}
</style>

8. 配置页面

views/Home.vue

<template>
  home
</template>

<script>
export default {

}
</script>

<style>

</style>

views/Main.vue

<template>
    <div class="common-layout">
        <el-container class="lay-container">
            <!-- 左侧组件 -->
            <common-aside />
            <el-container>
                <el-header class="el-header">
                    <!-- header组件 -->
                    <common-header />
                </el-header>
                <common-tab></common-tab>
                <el-main class="right-main">
                    <!-- 路由出口 -->
                    <router-view></router-view>
                </el-main>
            </el-container>
        </el-container>
    </div>
</template>

<script setup>
import CommonAside from'@/components/CommonAside.vue';
import CommonHeader from'@/components/CommonHeader.vue';
import CommonTab from'@/components/CommonTab.vue';
</script>

<style lang="less" scoped>
.common-layout,
.lay-container {
    height: 100%;
}
.el-header{
    background: #333;
}
</style>

views/Mall.vue

<template>
   mall
</template>

<script>
export default {

}
</script>

<style>

</style>

views/User.vue

<template>
  user
</template>

<script>
export default {

}
</script>

<style>

</style>

APP.vue

<script setup>

</script>

<template>
  <router-view></router-view>
</template>

<style scoped>
#app{
  width: 100%;
  height: 100%;
  overflow: hidden;
}
</style>