解锁前端Vue3宝藏级资料 第四章 VUE常用 UI 库 2 ( ailwind 后台框架)

news/2024/7/24 11:21:03 标签: 前端, vue.js, 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 后台框架)

创建一个新项目

npm init vite@latest vue-zht-app
uiltin class-name">cd vue-zht-app
npm install

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

npm install -D tailwindcss postcss autoprefixer

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

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

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

项目结构

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 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: [],
}

2 style.css

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

@tailwind base;
@tailwind components;
@tailwind utilities;

3 main.js

main.js文件中引入tailwind 样式

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
createApp(App).mount('#app')

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

<script setup></script>
<template>
  <h1 class="text-3xl font-bold underline">
    欢迎使用tailwind
  </h1>
</template>

在这里插入图片描述

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>

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

<script setup>
import layouts from './page/layouts.vue';
</script>
<template>
  <layouts>系统建构组件</layouts>
</template>

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>

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

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 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>

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');
};

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

<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>

黑夜模式的运行效果。

在这里插入图片描述

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>

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>

  在 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>

在这里插入图片描述
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>

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

  给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>

在这里插入图片描述

点击头像以外的菜单隐藏

  上面的列子必须始终单击图像才能在显示和隐藏菜单之间切换。我们需要设置事件完成头像外单击也会从切换为菜单隐藏。这个功能需要注册和删除事件侦听器,因此会使用到 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>        

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>

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>    

在这里插入图片描述

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>

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>

在这里插入图片描述

菜单图标设置

  使用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>

  这是因为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>

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>

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

子菜单列表的使用用 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>

在这里插入图片描述

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"}]}
]);

子列表被 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>

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>

  加入黑夜模式样式到菜单组件中,在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>

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

4.5.6 路由设置

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

 npm install vue-router@4

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')

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

index.vue

<script setup></script>
<template>
  <div>欢迎来到zht代码世界</div>
</template>

zht.vue

<script setup></script>
<template>
  <div>业务内容一览</div>
</template>

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

App.vue

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

<script setup>
import layouts from './page/layouts.vue';
</script>
<template>
  <layouts><router-view></router-view></layouts>
</template>

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>

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>

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


http://www.niftyadmin.cn/n/5009369.html

相关文章

代码随想录 - Day34 - 回溯:递增子序列+排列问题

代码随想录 - Day34 - 回溯&#xff1a;递增子序列排列问题 491. 递增子序列 如果有相等的整数也算递增序列 递增子序列中至少有两个元素 (遍历的时候不用遍历nums中最后一个元素) 输入&#xff1a;nums [4,6,6,2,8] 输出&#xff1a;[[4,6],[4,6,6],[4,6,6,8],[4,6,8],[4,…

基于网络表示学习的 新闻推荐算法研究与系统实现

摘要 第1章绪论 新闻推荐通常是利用用户的阅读行为和习惯、阅读选择和爱好等信息,为 用户推荐新闻内容。新闻推荐能够减少用户在数量庞大数据信息中获取信息的 时间消耗,从而能够缓解“信息过载[7]”的难题。以文本为内容的新闻,和商品、 电影、短视频等推荐系统相比,新闻推…

WRFDA资料同化:如何轻松掌握

数值预报已经成为提升预报质量的重要手段&#xff0c;而模式初值质量是决定数值预报质量的重要环节。资料同化作为提高模式初值质量的有效方法&#xff0c;成为当前气象、海洋和大气环境和水文等诸多领域科研、业务预报中的关键科学方法。资料同化新方法的快速发展&#xff0c;…

智能小车之跟随小车、避障小车原理和代码

目录 1. 红外壁障模块分析​编辑 2. 跟随小车的原理 3. 跟随小车开发和调试代码 4. 超声波模块介绍 5. 摇头测距小车开发和调试代码 1. 红外壁障模块分析 原理和循迹是一样的&#xff0c;循迹红外观朝下&#xff0c;跟随朝前 TCRT5000传感器的红外发射二极管不断发射红外…

macbook如何通过命令行安装软件

作者&#xff1a;吴业亮 博客&#xff1a;wuyeliang.blog.csdn.net 通过命令行安装 macOS 上的 .dmg 文件需要进行一些额外的步骤&#xff0c;因为 .dmg 文件通常需要手动挂载和安装。下面以安装git为例。你可以按照以下步骤进行操作&#xff1a; 将下载的 dmg 文件挂载到文件…

Git与IDEA: 解决`dev`分支切换问题及其背后原因 为何在IDEA中无法切换到`dev`分支?全面解析!

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

dockerfile 中激活conda并安装package

遇错的dockerfile写法&#xff1a; WORKDIR /tmp RUN wget "https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-latest-Linux-x86_64.sh" -O ~/miniconda.sh \&& bash ~/miniconda.sh -b -p $HOME/miniconda \&& ~/miniconda/bi…

Spring编程常见错误50例-Spring Bean定义常见错误

隐式扫描不到Bean的定义 问题 当启动类放置在com.psj.A包中&#xff0c;控制器类放置在com.psj.B包中时&#xff0c;启动SpringBoot后是扫描不到控制器的 原因 SpringBoot的默认扫描规则是扫描启动类所在的包及其子包中是否存在控制器 解决方式 SpringBootApplication // Com…