当前位置:   article > 正文

Vue3最佳实践 第四章 VUE常用 UI 库 2 ( ailwind 后台框架)_vue ui库

vue ui库

在这里插入图片描述
在这里插入图片描述

4.5 ailwind

  上面介绍的都是国内比较优秀的UI框架,现在我们在介绍一款国外比较流行的CSS UI框架ailwind 。官方网站https://tailwindcss.com/docs/guides/vite#vue CSShttps://flowbite.com/docs/getting-started/introduction/ 。这个ailwind 架构需要自己去写一些基础组件功能,它只提供了UI样式,所以扩展新和二次开发能力比较强,适合更高水平的开发者使用。

第一章 Vue3项目创建 1 Vue CLI 创建vue项目
第一章 Vue3项目创建 2 使用 Webpack 5 搭建 vue项目
第一章 Vue3项目创建 3 Vite 创建 vue项目
第二章 Vue3 基础语法指令
第三章 Vue Router路由器的使用
第四章 VUE常用 UI 库 1 ( element-plus,Ant ,naiveui,ArcoDesign)
第四章 VUE常用 UI 库 2 ( ailwind 后台框架)
第五章 Vue 组件应用 1( Props )
第五章 Vue 组件应用 2 ( Emit )
第五章 Vue 组件应用 3( Slots )
第五章 Vue 组件应用 4 ( provide 和 inject )
第五章 Vue 组件应用 5 (Vue 插件)
第六章 Pinia,Vuex与axios,VueUse 1(Pinia)
第六章 Pinia,Vuex与axios,VueUse 2(Vuex)
第六章 Pinia,Vuex与axios,VueUse 3(VueUse)
第六章 Pinia,Vuex与axios,VueUse 4(axios)
第七章 TypeScript 上
第七章 TypeScript 中
第七章 TypeScript 下 创建Trello 任务管理器
第八章 ESLint 与 测试 ( ESLint )
第八章 ESLint 与 测试 ( Jest )
第八章 ESLint 与 测试 (TypeScript 中Jest与检测环境集成)

创建一个新项目

npm init vite@latest vue-zht-app
cd vue-zht-app
npm install
  • 1
  • 2
  • 3

Vite环境中安装Tailwind CSS,导入ailwind UI样式与 CSS进入项目中来。

npm install -D tailwindcss postcss autoprefixer
  • 1

安装完成后,在项目文件目录中运行以下命令创建 Tailwind CSS 配置文件, tailwind.config.js 和 postcss.config.js 文件将被创建出来。

导入系统架构使用的图标库,我们安装的是 heroicons 图标库。

npx tailwindcss init -p     //目录中运行创建tailwind.config.js文件
npm install @heroicons/vue  //导入图标库
  • 1
  • 2

项目结构

vue-zht-app
   |---node_modules
   |---index.html        //运行html
   |---src               //代码源文件
   |    |--page           //页面架构
   |    |   |---layouts.vue  //架构页面
   |    |   |---top.vue      //头像组件   
   |    |   |---menu.vue     //菜单组件    
   |    |--components        //业务页面
   |    |   |---index.vue    //页面
   |    |   |---zht.vue      //页面      
   |    |--main.js       //入口文件
   |    |--App.vue       //模板入口路由
   |    |--router.js     //路由控制器   
   |----style.css        //ui 样式引入  
   |----package.json     //配置文件
   |---- tailwind.config.cjs //ui架构配置文件   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

1 tailwind.config.js设置

  在tailwind.config.js配置文件中设置ailwind项目配置。

module.exports = {
  purge: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'],
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {},
  },
  variants: {
    extend: {},
  },
  plugins: [],
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

2 style.css

  在 src 文件夹中创建 style.css 并添加 tailwind 指令。

@tailwind base;
@tailwind components;
@tailwind utilities;
  • 1
  • 2
  • 3

3 main.js

main.js文件中引入tailwind 样式

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
createApp(App).mount('#app')
  • 1
  • 2
  • 3
  • 4

4 App.vue
  在App.vue文件写入代码检测Tailwind CSS实用类是否引入到项目中来。

<script setup></script>
<template>
  <h1 class="text-3xl font-bold underline">
    欢迎使用tailwind
  </h1>
</template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在这里插入图片描述

4.5.1 框架页面布局

1 layouts.vue

​ 在src目录创建一个page文件夹,创建layouts.vue 布局页面。

<script setup>
</script>
<template>
  <div class="relative">
    <div class="fixed top-0 w-64 h-screen bg-white z-20">菜单</div>
    <div class="bg-gray-100 h-screen overflow-hidden pl-64">内容</div>
  </div>
</template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

页面分为左右两侧布局,左边是菜单,右边是系统内容部分。
在这里插入图片描述
2 App.vue
  修改App.vue内容,将 layouts.vue组件引入到App.vue中模板中,创建这个后台系统的页面架构。

<script setup>
import layouts from './page/layouts.vue';
</script>
<template>
  <layouts>系统建构组件</layouts>
</template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

3 设置菜单隐藏功能

  设置点击菜单图标将左边的菜单部分隐藏,再次点击后菜单部分显示。

让我们在菜单div与内容div中的class属性中添加一个菜单隐藏的动画功能, duration-300过度动画。

<script setup>
import { ref } from 'vue';
import {HomeIcon} from "@heroicons/vue/24/outline";
 //控制菜单部分隐藏
const show = ref(true);
</script>
<template>
<div class="relative">
<div
  class="fixed top-0 w-64 h-screen bg-white z-20 transform duration-300"
  :class="{ '-translate-x-full': !show }"
>
 菜单部分
</div>
<div
  class="fixed xl:hidden inset-0 bg-gray-900 opacity-50 z-10"
  @click="show = !show"
  v-show="show"
>灰色</div>
<div 
     class="bg-gray-100 h-screen overflow-hidden duration-300"
     :class="{ 'xl:pl-64': show }">
        <div class="bg-white rounded shadow m-4 p-4">
          <HomeIcon
            class="h-6 w-6 text-gray-600 cursor-pointer"
            @click="show = !show"
          />
        </div>
        <div>
            内容部分
          <slot />
        </div>
      </div>
    </div>
  </template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

浏览器中显示页面结构内容。
在这里插入图片描述

4.5.2 模式切换

  根目录中的 index.html 页面中加入样式模式class="dark"标签。

<!DOCTYPE html>
<html lang="en" class="dark">《----加入模式标签
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + Vue</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.js"></script>
  </body>
</html>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

1 layouts.vue加入黑夜css

  在layouts.vue框架页面菜单组件与内容组件中加入黑夜模式css样式 dark:bg-gray-800。

<template>
<div class="relative">
<div
class="fixed top-0 w-64 h-screen bg-white 
       dark:bg-gray-800 《-----加入黑夜样式
       z-20 transform duration-300"
:class="{ '-translate-x-full': !show }"
>
 菜单部分
</div>
<div
class="bg-gray-100 h-screen overflow-hidden 
       duration-300
       dark:bg-gray-900" 《-----加入黑夜样式
:class="{ 'xl:pl-64': show }"
>       
<div class="flex items-center justify-between bg-white 
            dark:bg-gray-800  《-----加入黑夜样式
            rounded shadow m-4 p-4"
>
  </div>      
</div>
<div class="dark:text-gray-300">
<slot />
</div>
</div>
</div>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

2 黑夜样式切换脚本
  加入黑夜与白天模式的切换代码脚本。

import {HomeIcon,SunIcon,MoonIcon} from "@heroicons/vue/24/outline";
const theme = ref('light');
if (localStorage.theme === 'dark') {
  document.documentElement.classList.add('dark');
  theme.value = 'dark';
} else {
  document.documentElement.classList.remove('dark');
  theme.value = 'light';
}
const changeMode = (mode) => {
  theme.value = mode;
  theme.value === 'light'
    ? document.documentElement.classList.remove('dark')
    : document.documentElement.classList.add('dark');
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

模式选择图标加入到页面中。

<div class="flex items-center justify-between bg-white dark:bg-gray-800  rounded shadow m-4 p-4"
>
  <HomeIcon
   class="h-6 w-6 text-gray-600 cursor-pointer"
   @click="show = !show"
  />
  <div class="flex items-center space-x-4">   
  <MoonIcon
    class="w-7 h-7 text-gray-600 cursor-pointer"
    @click="changeMode('dark')"
    v-if="theme === 'light'"
  />   
  <SunIcon
  class="w-7 h-7 text-gray-300 cursor-pointer"
  @click="changeMode('light')"
  v-else
  />
  </div>
  </div>      
</div>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

黑夜模式的运行效果。

在这里插入图片描述

3 模式切换代码

<script setup>
import { ref} from 'vue';
import {HomeIcon,SunIcon,MoonIcon} from "@heroicons/vue/24/outline";
const show = ref(true);
const theme = ref('light');
if (localStorage.theme === 'dark') {
  document.documentElement.classList.add('dark');
  theme.value = 'dark';
} else {
  document.documentElement.classList.remove('dark');
  theme.value = 'light';
}
const changeMode = (mode) => {
  theme.value = mode;
  theme.value === 'light'
    ? document.documentElement.classList.remove('dark')
    : document.documentElement.classList.add('dark');
};
</script>
<template>
<div class="relative">
<div
class="fixed top-0 w-64 h-screen bg-white dark:bg-gray-800 z-20 transform duration-300"
:class="{ '-translate-x-full': !show }"
>
 菜单部分
</div>
<div
  class="fixed xl:hidden inset-0 bg-gray-900 opacity-50 z-10"
  @click="show = !show"
  v-show="show"
>灰色</div>
<div
class="bg-gray-100 h-screen overflow-hidden duration-300 dark:bg-gray-900"
:class="{ 'xl:pl-64': show }"
>
       
<div class="flex items-center justify-between bg-white dark:bg-gray-800  rounded shadow m-4 p-4"
>
  <HomeIcon
   class="h-6 w-6 text-gray-600 cursor-pointer"
   @click="show = !show"
  />
  <div class="flex items-center space-x-4">   
    
  <MoonIcon
    class="w-7 h-7 text-gray-600 cursor-pointer"
    @click="changeMode('dark')"
    v-if="theme === 'light'"
  />   
  <SunIcon
  class="w-7 h-7 text-gray-300 cursor-pointer"
  @click="changeMode('light')"
  v-else
  />
  </div>      
</div>
<div class="dark:text-gray-300">
<slot />
</div>
</div>
</div>
</template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63

4.5.3 头像与下拉

  我们将在顶部的菜单栏中设置一个人像,并设置为当单击该图像时,将显示一个下拉菜单。人像在 assets 文件夹中保存为 user.jpg。在page目录中创建一个头像组件top.vue。

<script setup></script>
<template>
  <div>
    <img
      src="../assets/user.png"
      class="rounded-full w-10 h-10 cursor-pointer"
    />
  </div>
</template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

  在 layouts.vue 文件中导入创建的 top.vue 文件。在深色模式切换图标旁边添加导入的 top 组件。使用flex在深色模式切换图标旁边设置了一个空格(space-x-4)。

<script setup>
import top from './top.vue'; 
</script>
<template>
<div class="flex items-center 
            justify-between 
            bg-white dark:bg-gray-800  
            rounded shadow m-4 p-4">
  <HomeIcon
   class="h-6 w-6 text-gray-600 cursor-pointer"
   @click="show = !show"
  />
  <div class="flex items-center space-x-4">     
  <MoonIcon
    class="w-7 h-7 text-gray-600 cursor-pointer"
    @click="changeMode('dark')"
    v-if="theme === 'light'"
  />   
  <SunIcon
  class="w-7 h-7 text-gray-300 cursor-pointer"
  @click="changeMode('light')"
  v-else
  />
  //映入头像部分菜单
  <top></top>
  </div>      
</div>
</template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

在这里插入图片描述
top.vue 中加入下拉菜单

  创建一个在单击图像时出现的下拉菜单。position relative设置为图片父元素的div,下拉菜单以absolute设置的图片父元素为准设置为top-16,right-0。设置了退出系统和我的信息链接,但这些页面不存在,所以我需要更改菜单中的列表以适应应用程序。

<script setup>
import { UserIcon, ArrowsPointingOutIcon } from "@heroicons/vue/24/outline";
</script>
<template>
    <div class="relative">
    <img
      src="../assets/user.png"
      class="rounded-full w-10 h-10 cursor-pointer"
    />
    <div
      class="absolute top-16 
             right-0 z-10 
             w-40
             py-2 bg-white 
             rounded-sm shadow">
      <ul>
        <li class="text-gray-700 
                   hover:bg-blue-100 
                   hover:text-blue-600 p-2">
          <a href="/#" class="flex items-center space-x-2">
            <UserIcon class="w-5 h-5" />
            <span class="text-sm font-bold">我的信息</span></a
          >
        </li>
        <li class="text-gray-700 
                   hover:bg-blue-100 
                   hover:text-blue-600 p-2">
          <a href="/#" class="flex items-center space-x-2">
            <ArrowsPointingOutIcon class="w-5 h-5" />
            <span class="text-sm font-bold">退出系统</span></a
          >
        </li>
      </ul>
    </div>  
  </div>
</template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

在这里插入图片描述
点击头像下拉菜单事件

  给img元素设置点击事件,设置函数toggle,这样就可以通过点击图片来显示或隐藏菜单。添加变量show,根据show的值切换菜单的显示/隐藏。使用toggle函数来切换show的值。如果 show 为 false,toggle 函数将其值更新为 true,如果为 true,则将其更新为 false。将 v-show 指令设置为下拉菜单元素。

  • 别忘了在下拉菜单中加入黑夜样式 dark:bg-gray-800
<script setup>
import { ref } from 'vue';
import { UserIcon, ArrowsPointingOutIcon } from "@heroicons/vue/24/outline";
const show = ref(false);
const toggle = () => {
  show.value = !show.value;
};
</script>
<template>
    <div class="relative">
    <img
      src="../assets/user.png"
      class="rounded-full w-10 h-10 cursor-pointer"
      @click="toggle" -------显示隐藏事件
      >
    />
    <div
      class="absolute top-16 right-0 z-10 w-40 py-2 
             bg-white rounded-sm shadow 
             dark:bg-gray-800" 《-----加入黑夜样式
      v-show="show" -------显示隐藏属性
      >
      <ul>
        <li class="  -------黑夜模式中高亮
        text-gray-700
        dark:text-gray-300
        hover:bg-blue-100
        dark:hover:bg-gray-700
        hover:text-blue-600
        dark:hover:text-blue-600
        p-2">
          <a href="/#" class="flex items-center space-x-2">
            <UserIcon class="w-5 h-5" />
            <span class="text-sm font-bold">我的信息</span></a
          >
        </li>
        <li class="  -------黑夜模式中高亮
        text-gray-700
        dark:text-gray-300
        hover:bg-blue-100
        dark:hover:bg-gray-700
        hover:text-blue-600
        dark:hover:text-blue-600">
          <a href="/#" class="flex items-center space-x-2">
            <ArrowsPointingOutIcon class="w-5 h-5" />
            <span class="text-sm font-bold">退出系统</span></a
          >
        </li>
      </ul>
    </div>  
  </div>
</template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52

在这里插入图片描述

点击头像以外的菜单隐藏

  上面的列子必须始终单击图像才能在显示和隐藏菜单之间切换。我们需要设置事件完成头像外单击也会从切换为菜单隐藏。这个功能需要注册和删除事件侦听器,因此会使用到 Vue 生命周期挂钩 onMounted 和 onUnmounted事件。同时添加一个变量 root 来存储整个 top 组件的元素信息。

<script setup>
import { ref,onMounted, onUnmounted  } from 'vue';
import { UserIcon, ArrowsPointingOutIcon } from "@heroicons/vue/24/outline";
const show = ref(false);
const root = ref(null);
const toggle = () => {
  show.value = !show.value;
};
 // 事件监听方法
const clickOutside = (e) => {
  if (!root.value.contains(e.target) && show.value) {
    show.value = false;
  }
};
//注册监听事件
onMounted(() => document.addEventListener('click', clickOutside));
//删除监听   
onUnmounted(() => document.removeEventListener('click', clickOutside));
</script>
<template>
    <div class="relative" ref="root">
       下拉页面html元素 
  </div>
</template>        
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

root.value 包含 < div class=“relative”>…< /div>。e.target 因您点击的位置而异,如果您点击仪表板文本,可以看到包含 < div class=“dark:text-gray-300”>…< /div>

4.5.4 菜单设置

  我们将在侧边栏中添加一个有徽标的菜单列表。

1 ment.vue

  在 page 文件夹中创建一个 ment.vue 文件,用于创建设置应用程序菜单组件功能。

<script setup></script>
<template>
  <div class="p-4">
    <div class="font-bold text-lg text-blue-600">LOGO</div>
  </div>
</template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2 layouts.vue 引入菜单组件

   layouts.vue页面 导入菜单组件,在左边的菜单位置中加入菜单组件。

<script setup>
import top from './top.vue';
 //创建菜单组件
import zhtmenu from './menu.vue';
</script>
<template>
<div class="relative">
<div
class="fixed top-0 w-64 
       h-screen bg-white
       dark:bg-gray-800 
       z-20 transform 
       duration-300
       dark:text-gray-300"
:class="{ '-translate-x-full': !show }"
>
 <zhtmenu/> <-----引入菜单组件
</div>
  其他html部分 
<template>    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

在这里插入图片描述

layouts.vue中的完整的代码内容。

<script setup>
import top from './top.vue';
import zhtmenu from './menu.vue';
import { ref} from 'vue';
import {HomeIcon,SunIcon,MoonIcon} from "@heroicons/vue/24/outline";
const show = ref(true);
const theme = ref('light');
if (localStorage.theme === 'dark') {
  document.documentElement.classList.add('dark');
  theme.value = 'dark';
} else {
  document.documentElement.classList.remove('dark');
  theme.value = 'light';
}
const changeMode = (mode) => {
  theme.value = mode;
  theme.value === 'light'
    ? document.documentElement.classList.remove('dark')
    : document.documentElement.classList.add('dark');
};
</script>
<template>
<div class="relative">
<div
class="fixed top-0 w-64 h-screen bg-white dark:bg-gray-800 z-20 transform duration-300 dark:text-gray-300"
:class="{ '-translate-x-full': !show }"
>
 //导入菜单部分
 <zhtmenu/>
</div>
<div
  class="fixed xl:hidden inset-0 bg-gray-900 opacity-50 z-10"
  @click="show = !show"
  v-show="show"
>灰色</div>
<div
class="bg-gray-100 h-screen overflow-hidden duration-300 dark:bg-gray-900"
:class="{ 'xl:pl-64': show }"
>
       
<div class="flex items-center justify-between bg-white dark:bg-gray-800  rounded shadow m-4 p-4"
>
  <HomeIcon
   class="h-6 w-6 text-gray-600 cursor-pointer"
   @click="show = !show"
  />
  <div class="flex items-center space-x-4">     
  <MoonIcon
    class="w-7 h-7 text-gray-600 cursor-pointer"
    @click="changeMode('dark')"
    v-if="theme === 'light'"
  />   
  <SunIcon
  class="w-7 h-7 text-gray-300 cursor-pointer"
  @click="changeMode('light')"
  v-else
  />

  <top></top>
  </div>      
</div>
<div class="dark:text-gray-300">
<slot />
</div>
</div>
</div>
</template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67

3 创建菜单

  使用 reactive 来保存列表中的菜单信息,在页面模板中使用 v-for 指令展开列表。在 lists 变量中,菜单列表由子列表分层,但是我们先不处理子分层。

<script setup>
import { reactive } from 'vue';
const menus = reactive([
    {name:"系统管理",id:10000,icon:"ServerIcon",
    child:[
        {name:"用户管理",id:100001,path:"/zht1"},
        {name:"部门管理",id:100002,path:"/zht1"}]},
    {name:"业务管理",id:20000,icon:"ShoppingCartIcon",
    child:[
        {name:"班组维修",id:20001,path:"/zht1"},
        {name:"工单管理",id:20002,path:"/zht1"}]}
]);
</script>
<template>
  <div class="p-4">
    <div class="font-bold text-lg text-blue-600">LOGO</div>
  </div>
  <ul class="text-gray-700">
    <li class="mb-1" v-for="list in menus" :key="list.id">
      <a
        class="block p-2 rounded-sm hover:text-white hover:bg-blue-400"
      >
        <span>{{ list.name }}</span>
      </a>
    </li>
  </ul> 
</template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

在这里插入图片描述

菜单图标设置

  使用component 动态加载图标对象进入组将,但是运行的时候会发现无法加载到@heroicons/vue/24/outline中的图标对象。

<script setup>
import { reactive } from 'vue';
import {ServerIcon,ShoppingCartIcon} from "@heroicons/vue/24/outline";
</script>
<template>

  <ul class="text-gray-700">
    <li class="mb-1" v-for="list in menus" :key="list.id">
      <a
        :href="list.child"
        class="flex
          items-center
          block
          p-2
          rounded-sm
          hover:text-white hover:bg-blue-400"
      >
      <component :is="list.icon" class="w-6 h-6 mr-2"></component>
      </a>
    </li>
  </ul> 
</template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

  这是因为list.icon 中获得的时menus列表中的icon属性中的字符串,不是图标heroicons对象引用,那么我们怎么解决这个问题呢。需要我们定义一个icons 集合对象装入图标heroicons对象,v-for指令中component通过字符串反射icons中的属性对象来获得图标组件。

const icons = {
  ServerIcon: ServerIcon,
  ShoppingCartIcon: ShoppingCartIcon,
};
<component :is="icons[list.icon]" class="w-6 h-6 mr-2"></component>
  • 1
  • 2
  • 3
  • 4
  • 5

menu.vue完成代码例子。

<script setup>
import { reactive } from 'vue';
    
import {ServerIcon,ShoppingCartIcon} from "@heroicons/vue/24/outline";
//图标引用集合
const icons = {
  ServerIcon: ServerIcon,
  ShoppingCartIcon: ShoppingCartIcon,
};
const menus = reactive([
    {name:"系统管理",id:10000,icon:"ServerIcon",
    child:[
        {name:"用户管理",id:100001,path:"/zht1"},
        {name:"部门管理",id:100002,path:"/zht1"}]},
    {name:"业务管理",id:20000,icon:"ShoppingCartIcon",
    child:[
        {name:"班组维修",id:20001,path:"/zht1"},
        {name:"工单管理",id:20002,path:"/zht1"}]}
]);
</script>
<template>
  <div class="p-4">
    <div class="font-bold text-lg text-blue-600">LOGO</div>
  </div>

  <ul class="text-gray-700">
    <li class="mb-1" v-for="list in menus" :key="list.id">
      <a
        :href="list.child"
        class="flex
          items-center
          block
          p-2
          rounded-sm
          hover:text-white hover:bg-blue-400"
      >
      <component :is="icons[list.icon]" class="w-6 h-6 mr-2"></component>
        <span>{{ list.name }}</span>
      </a>
    </li>
  </ul> 
</template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

在这里插入图片描述
子菜单设置

子菜单列表的使用用 v-for 展开child中的列表内容。

<script setup>
import { reactive } from 'vue';
import {ServerIcon,ShoppingCartIcon} from "@heroicons/vue/24/outline";
const icons = {
  ServerIcon: ServerIcon,
  ShoppingCartIcon: ShoppingCartIcon,
};
const menus = reactive([
    {name:"系统管理",id:10000,icon:"ServerIcon",
    child:[
        {name:"用户管理",id:100001,path:"/zht1"},
        {name:"部门管理",id:100002,path:"/zht1"}]},
    {name:"业务管理",id:20000,icon:"ShoppingCartIcon",
    child:[
        {name:"班组维修",id:20001,path:"/zht1"},
        {name:"工单管理",id:20002,path:"/zht1"}]}
]);
</script>
<template>
  <div class="p-4">
    <div class="font-bold text-lg text-blue-600">LOGO</div>
  </div>

  <ul class="text-gray-700">
    <li class="mb-1" v-for="list in menus" :key="list.id">
        <a
        :href="list.path"
        class="
          flex
          items-center
          block
          p-2
          rounded-sm
          hover:text-white hover:bg-blue-400
        "
      >
      <component :is="icons[list.icon]" class="w-6 h-6 mr-2"></component>
        <span>{{ list.name }}</span>
      </a>
    //二级菜单设置功能    
      <ul class="mt-1">
        <li class="mb-1" v-for="list in list.child" :key="list.name">
          <a
            :href="list.link"
            class="block p-2 rounded-sm hover:bg-blue-400 hover:text-white"
          >
            <span class="pl-8">{{ list.name }}</span>
          </a>
        </li>
      </ul>
    </li>
  </ul> 
</template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

在这里插入图片描述

4.5.5 手风琴菜单设置

  ment.vue中的代码加入以下功能,将菜单列表变成手风琴模式的菜单组件。将菜单列表中的一级菜单中增加show属性,来判断菜单手风琴组件开关属性。

const menus = reactive([
    {name:"系统管理",id:10000,icon:"ServerIcon",show:false,----默认关闭
    child:[
        {name:"用户管理",id:100001,path:"/zht1"},
        {name:"部门管理",id:100002,path:"/zht1"}]},
    {name:"业务管理",id:20000,icon:"ShoppingCartIcon",show:false,----默认关闭
    child:[
        {name:"班组维修",id:20001,path:"/zht1"},
        {name:"工单管理",id:20002,path:"/zht1"}]}
]);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

子列表被 v-show 隐藏与显示,加入ChevronDownIcon 上下图标菜单。

<script setup>
import { reactive } from 'vue';
import {ServerIcon,ShoppingCartIcon,ChevronDownIcon} from "@heroicons/vue/24/outline";
const icons = {
  ServerIcon: ServerIcon,
  ShoppingCartIcon: ShoppingCartIcon,
};
const menus = reactive([
    {name:"系统管理",id:10000,icon:"ServerIcon",show:false,
    child:[
        {name:"用户管理",id:100001,path:"/zht1"},
        {name:"部门管理",id:100002,path:"/zht1"}]},
    {name:"业务管理",id:20000,icon:"ShoppingCartIcon",show:false,
    child:[
        {name:"班组维修",id:20001,path:"/zht1"},
        {name:"工单管理",id:20002,path:"/zht1"}]}
]);
//菜单展开与关闭事件
const toggle = (list) => {
    // menus.forEach(m=>{
    //     m.show = false;
    // }); 
  list.show = !list.show;
};
</script>
<template>
  <div class="p-4">
    <div class="font-bold text-lg text-blue-600">LOGO</div>
  </div>

  <ul class="text-gray-700">
    <li class="mb-1" v-for="list in menus" :key="list.id">
        <div
        class="
            flex
            items-center
            justify-between
            p-2
            cursor-pointer
            rounded-sm
            hover:bg-blue-400 hover:text-white
        "
        @click="toggle(list)"
      >
      <div class="flex items-center">
         <component :is="icons[list.icon]" class="w-6 h-6 mr-2"></component>
        <span>{{ list.name }}</span>
      </div>
      //隐藏与显示图标设置      
    <ChevronDownIcon   
        class="w-4 h-4 transform duration-300"
        :class="!list.show ? 'rotate-0' : '-rotate-180'"/>
    </div>
        //隐藏与显示属性设置
      <ul class="mt-1" v-show="list.show">
        <li class="mb-1" v-for="list in list.child" :key="list.name">
          <a
            class="block p-2 rounded-sm hover:bg-blue-400 hover:text-white"
          >
            <span class="pl-8">{{ list.name }}</span>
          </a>
        </li>
      </ul>
    </li>
  </ul> 
</template>
<style scoped>

</style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69

2 手风琴菜动画效果
  Vue 模板中加入 transition 标签。 transition 标签中设置动画效果。用transition 动画标签包围子列表的 ul 元素,将溢出隐藏CSS样式加入 ul 元素中。如果不加overflow-hidden,ul列表的动画效果会将文字重叠,无法正常工作。

  <transition>
      <ul class="mt-1 overflow-hidden" v-show="list.show">
            <li class="mb-1" v-for="list in list.child" :key="list.name">
          </li>
      </ul>
</transition>
<style scoped>
.v-enter-from,
.v-leave-to {
  height: 0;
}
.v-enter-active,
.v-leave-active {
  transition: height 0.3s;
}
.v-enter-to,
.v-leave-from {
  height: 100px;
}
</style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

  加入黑夜模式样式到菜单组件中,在ul 元素的class=" dark:text-gray-300"中加入黑夜模式字体。

<script setup>
import { reactive } from 'vue';
import {ServerIcon,ShoppingCartIcon,ChevronDownIcon} from "@heroicons/vue/24/outline";
const icons = {
  ServerIcon: ServerIcon,
  ShoppingCartIcon: ShoppingCartIcon,
};
const menus = reactive([
    {name:"系统[管理",id:10000,icon:"ServerIcon",show:false,
    child
        {name:"用户管理",id:100001,path:"/zht1"},
        {name:"部门管理",id:100002,path:"/zht1"}]},
    {name:"业务管理",id:20000,icon:"ShoppingCartIcon",show:false,
    child:[
        {name:"班组维修",id:20001,path:"/zht1"},
        {name:"工单管理",id:20002,path:"/zht1"}]}
]);
const toggle = (list) => {
    // menus.forEach(m=>{
    //     m.show = false;
    // }); 
  list.show = !list.show;
};
</script>
<template>
  <div class="p-4">
    <div class="font-bold text-lg text-blue-600">LOGO</div>
  </div>
  //加入黑夜模式字体
  <ul class="text-gray-700 dark:text-gray-300">
    <li class="mb-1" v-for="list in menus" :key="list.id">
        <div
        class="
            flex
            items-center
            justify-between
            p-2
            cursor-pointer
            rounded-sm
            hover:bg-blue-400 hover:text-white
        "
        @click="toggle(list)"
      >
      <div class="flex items-center">
         <component :is="icons[list.icon]" class="w-6 h-6 mr-2"></component>
        <span>{{ list.name }}</span>
      </div>
    <ChevronDownIcon   
        class="w-4 h-4 transform duration-300"
        :class="!list.show ? 'rotate-0' : '-rotate-180'"/>
    </div>
    //动画部分
    <transition>
      <ul class="mt-1 overflow-hidden" v-show="list.show">
        <li class="mb-1" v-for="list in list.child" :key="list.name">
          <a
            class="block p-2 rounded-sm hover:bg-blue-400 hover:text-white"
          >
            <span class="pl-8">{{ list.name }}</span>
          </a>
        </li>
      </ul>
    </transition>
    </li>
  </ul> 
</template>
<style scoped>
.v-enter-from,
.v-leave-to {
  height: 0;
}
.v-enter-active,
.v-leave-active {
  transition: height 0.3s;
}
.v-enter-to,
.v-leave-from {
  height: 100px;
}
</style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80

在这里插入图片描述
在这里插入图片描述

4.5.6 路由设置

  导入路由组件 vue-router,将路由组件加入到项目中来。路由使用细节参考上面内容。

 npm install vue-router@4
  • 1

main.js设置

import { createApp } from 'vue'
import './style.css'
import router from './router'
import App from './App.vue'
const app = createApp(App)
app.use(router)
app.mount('#app')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

components目录中创建index.vue和zht.vue两个页面。

index.vue

<script setup></script>
<template>
  <div>欢迎来到zht代码世界</div>
</template>
  • 1
  • 2
  • 3
  • 4

zht.vue

<script setup></script>
<template>
  <div>业务内容一览</div>
</template>
  • 1
  • 2
  • 3
  • 4

router.js

路由内容设置

import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
    history: createWebHistory(import.meta.env.BASE_URL),
    routes: [
        {
            path: '/',
            name: 'index',
            component:()=>import('./components/index.vue'),
          } ,
        {
            path: '/zht1',
            name: 'zht1',
            component:()=>import('./components/zht.vue'),
          } 
    ]
  })
export default router
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

App.vue

  主页面设置方法是将设置在页面框架中的slot组件中。

<script setup>
import layouts from './page/layouts.vue';
</script>
<template>
  <layouts><router-view></router-view></layouts>
</template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

menu.vue菜单

  menu.vue菜单面设置菜单路由事件,点击菜单后触发事件路由框架页移动页面到路由页面中去。

<script setup>
import { useRouter  } from 'vue-router'
const router = useRouter();
const onpage=(t) =>{
 //路由页面内容
router.push({ path:t.path})
}
</script>
<template>
        <li class="mb-1" v-for="list in list.child" :key="list.id">
          <a
            class="block p-2 
                   rounded-sm hover:bg-blue-400
                   hover:text-white"
            @click="onpage(list)"  ----》页面路由事件
            >
            <span class="pl-8">{{ list.name }}</span>
          </a>
        </li>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

menu.vue路由转发完整代码内容。

<script setup>
import { reactive } from 'vue';
import { useRouter  } from 'vue-router'
import {ServerIcon,ShoppingCartIcon,ChevronDownIcon} from "@heroicons/vue/24/outline";
const icons = {
  ServerIcon: ServerIcon,
  ShoppingCartIcon: ShoppingCartIcon,
};
const menus = reactive([
    {name:"系统管理",id:10000,icon:"ServerIcon",show:false,
    child:[
        {name:"用户管理",id:100001,path:"/zht1"},
        {name:"部门管理",id:100002,path:"/zht1"}]},
    {name:"业务管理",id:20000,icon:"ShoppingCartIcon",show:false,
    child:[
        {name:"班组维修",id:20001,path:"/zht1"},
        {name:"工单管理",id:20002,path:"/zht1"}]}
]);
//菜单手风琴打开关闭
const toggle = (list) => {
    // menus.forEach(m=>{
    //     m.show = false;
    // }); 
  list.show = !list.show;
};
const router = useRouter();
//路由访问移动页面
const onpage=(t) =>{
router.push({ path:t.path})
}

</script>
<template>
  <div class="p-4">
    <div class="font-bold text-lg text-blue-600">LOGO</div>
  </div>

  <ul class="text-gray-700 dark:text-gray-300">
    <li class="mb-1" v-for="list in menus" :key="list.id">
        <div
        class="
            flex
            items-center
            justify-between
            p-2
            cursor-pointer
            rounded-sm
            hover:bg-blue-400 hover:text-white
        "
        @click="toggle(list)"
      >    
      <div class="flex items-center">
         <component :is="icons[list.icon]" class="w-6 h-6 mr-2"></component>
        <span>{{ list.name }}</span>
      </div>   
    <ChevronDownIcon   
        class="w-4 h-4 transform duration-300"
        :class="!list.show ? 'rotate-0' : '-rotate-180'"/>
    </div>
    <!------------     二级菜单列表        -------------->
    <transition>
      <ul class="mt-1 overflow-hidden" v-show="list.show">
        <li class="mb-1" v-for="list in list.child" :key="list.id">
          <a
            class="block p-2 rounded-sm hover:bg-blue-400 hover:text-white"
            @click="onpage(list)"
            >
            <span class="pl-8">{{ list.name }}</span>
          </a>
        </li>
      </ul>
    </transition>
    </li>
  </ul> 
</template>
<style scoped>
.v-enter-from,
.v-leave-to {
  height: 0;
}
.v-enter-active,
.v-leave-active {
  transition: height 0.3s;
}
.v-enter-to,
.v-leave-from {
  height: 100px;
}
</style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89

浏览器中跳转连接/zht1中显示zht1.vue内容。
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/118953?site
推荐阅读
相关标签
  

闽ICP备14008679号