Vue3+vite后台管理系统
项目概述:
通过Vue3+vite脚手架搭建项目,结合Element-Plus、Echarts、Axios、Mock、Vuex完善各功能模块,进行后台管理系统的开发。
实训中注重对图表的应用,数据的引入,数据可以mock生成也可以写静态数据
各官网地址:
Element-Plus
Echarts
Axios
Mock
Vuex
Vite
- 项目准备
- Node.js安装
进入node.js官网选择版本安装,选择较低版本,比较稳定。
同时按WIN+R输入cmd打开命令提示符窗口,输入node -v查看安装的版本,出现版本号即安装成功。注意vite需要Node.js版本>=12.0.0 。
-
- 项目搭建
- 确定好项目存放的位置,在存放路径下输入cmd进入控制台,输入代码:
npm create vite@latest ,完成项目名称填写,框架选择vue,语言选择javascript。
- cd到已经创建的项目中,使用npm i 安装依赖,安装成功后使用工具打
开整个项目文件夹,进入终端利用cnpm run dev 运行项目。
- 后台管理系统准备工作
- Element Plus
- 安装
- Element Plus
打开工具终端,输入npm install element-plus --save 进行安装(如果太慢,可以到文件管理器该项目目录下输入cmd进入终端,输入cnpm install element-plus --save ,后续安装操作都可以这样)
-
-
- 引入
-
这边采用局部(按需)引入,vue3的局部引用与全局引用相比不会复杂多少,但最后项目打包体积会减小很多。可以加快运行速度。
1、安装插件:
- npm install -D unplugin-vue-components unplugin-auto-import
2、进入vite.config.js文件,将以下代码复制进文件
- import AutoImport from 'unplugin-auto-import/vite'
- import Components from 'unplugin-vue-components/vite'
- import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
plugins中代码如下:
- plugins: [
- vue(),
- AutoImport({
- resolvers: [ElementPlusResolver()],
- }),
- Components({
- resolvers: [ElementPlusResolver()],
- }),
- ],
-
- Router
- 安装
- Router
打开终端输入:
- npm install vue-router -S
-
-
- 引入
-
- 在src文件夹下新建router文件夹,router文件夹下新建一个index.js文件。
- 打开index.js文件输入以下代码引入路由
import { createRouter,createWebHashHistory } from "vue-router";
- 在src下新建views文件夹,并在views文件夹下新建Main.vue文件。
- 在src下新建home文件夹,并在home文件夹下新建Home.vue文件。
- 打开router文件夹下的index.js文件,进行基本的路由配置如下
- const routes =[
- {
- path: '/',
- component:()=> import('../views/Main.vue'),
- redirect: '/home',
- children: [
- {
- path:'/home',
- name:'home',
- component: () => import('../views/home/Home.vue')
- },
- const router = createRouter({
- history: createWebHashHistory(),
- routes
- })
- export default router //暴露
redirect:‘/home‘表示运行项目后首先进入home页面,后续有了登录页可以改成rediect:’/login(登录页名)‘
6、进入main.js文件引入router
- import router from './router'
再使用router
- app.use(router)
7、进入App组件在<template>闭合标签中放入router-view表示位置
8、Main.vue中写入首页布局代码,以及变化路由
- <template>
- <div>左侧菜单</div>
- <div>头部</div>
- <div>这个部分是变化的
- <router-view />
- </div>
- </template>
9、进入Home.vue填入以下代码来做路由测试
- <template>
- <div>我是home组件</div>
- </template>
- 可视化大屏创建
- 组件
在src下创建views文件夹,在views文件夹下,创建Screen.vue文件,作为可视化大屏
-
- 样式
- 导入tailwindcss,(用于样式)利用以下代码安装。
npm install -D tailwindcss
npx tailwindcss init 此行代码会产生一个tailwind.config.js文件,打开它进行修改配置。
将文件中的content修改为: content: ["./src/**/*.{html,js}"]
- 找到src下的style.css文件添加以下代码:
@tailwind base;
@tailwind components;
@tailwind utilities;
-
- 可视化大屏布局
布局效果:
大致可以分为三列,八个图表,具体布局和图表数量可以自行修改。
- <template>
- <div class="bg-[url('assets/imgs/bgpic.jpg')] bg-cover bg-center h-screen text-white p-5 flex overflow-hidden >
- <!-- 左 -->
- <div class="flex-1 mr-5 bg-opacity-50 bg-slate-800 p-3 flex flex-col"></div>
- <!-- 中 -->
- <div class="w-1/2 mr-5 flex flex-col"> </div>
- <!-- 右 -->
- <div class="flex-1 bg-opacity-50 bg-slate-800 p-3 flex flex-col"> </div>
- </div>
- </template>
- <script setup>
- </script>
- <style lang="scss" scoped>
- .h-96{
- height: 500px;
- }
- </style>
-
- 可视化大屏组件
1、在src下,component文件夹中创建需要用到的图表组件,以饼图(遗失物品类)为例。
创建Pie.vue组件。并进行基本代码填充,分别为<template>、<script>、<style>,依格式将其余需要的图表组件创建完毕。
- <template>
- <div>
- <div>【遗失物品类】</div>
- </div>
- </template>
- <script>
- </script>
- <style>
- </style>
- 将创建好的组件依次导入Screen.vue,以饼图(遗失物品类)为例。
- <template>
- <div class="bg-[url('assets/imgs/bgpic.jpg')] bg-cover bg-center h-screen text-white p-5 flex overflow-hidden bg-opacity-30"
- v-if="data">
- <!-- 左 -->
- <div class="flex-1 mr-5 bg-opacity-50 bg-slate-800 p-3 flex flex-col">
- </div>
- <!-- 中 -->
- <div class="w-1/2 mr-5 flex flex-col">
- </div>
- <!-- 右 -->
- <div class="flex-1 bg-opacity-50 bg-slate-800 p-3 flex flex-col">
- <Pie class=" h-96 box-border p-4 mt-2"/>
- </div>
- </div>
- </template>
- <script setup>
- import Pie from '../components/Pie.vue';
- </script>
- <style lang="scss" scoped>
- </style>
- 后台管理页面创建
- 首页布局
打开Element Plus 组件内容,Container块寻找适合的布局。
这里选择红圈这个布局,有侧边栏Aside,头部Header,主体Main。点击小圈的<>图标即可查看代码,将相应代码复制进Main.vue。并将el-main中的内容替换回router-view
-
- Header模块
Header效果图
在components文件夹下,新建CommonHeader.vue组件完成template基本填充(基本填充意为在空vue文件中写好template、script、style)
- <template>
- <div>我是...</div>
- </template>
- <script>
- </script>
- <style>
- </style>
进入Main.vue在script闭合标签中引入CommonHeader组件如下:
- import { defineComponent } from 'vue';
- import CommonHeader from '../components/CommonHeader.vue';
- export default defineComponent({
- components: {
- CommonHeader,
- },
- });
并将原本布局中的
换为
添加进去。
因为header涉及到图标展示,我们需要使用到element plus中的icon组件
首先打开终端输入以下代码进行icon的全局安装:
- npm i @element-plus/icons-vue -S
安装好以后,进入main.js文件进行图标注册,
而后即可通过以下形式来使用icon
- <el-icon :size="20">
- <Menu />
- </el-icon>
icon名称可以进入element Plus找到icon组件进行查看
由上方效果图我们可以得知,header主要由icon菜单图标、可视化大屏跳转按钮、logo状下拉菜单组成。
Template:
- <template>
- <el-header>
- <div class="l-content">
- <!-- 图标展示 -->
- <el-button size="small" plain @click="handleCollapse">
- <el-icon :size="20">
- <Menu />
- </el-icon>
- </el-button>
- <!-- 面包屑 -->
- <el-breadcrumb separator="/" class="bread">
- <!-- 首页一定存在,因此写死 -->
- <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
- <el-breadcrumb-item :to="current.path " v-if="current">{{current.label}}</el-breadcrumb-item>
- </el-breadcrumb>
- </div>
- <div class="ScreenButton">
- <el-button type="primary" @click="GetScreen">水寻可视化</el-button>
- </div>
- <div class="r-content">
- <el-dropdown>
- <span class="el-dropdown-link">
- <img class="logo" :src="getImgSrc('logo')" alt="">
- </span>
- <template #dropdown>
- <el-dropdown-menu>
- <el-dropdown-item>管理员中心</el-dropdown-item>
- <el-dropdown-item>个人中心</el-dropdown-item>
- <el-dropdown-item @click="handleLoginOut">退出</el-dropdown-item>
- </el-dropdown-menu>
- </template>
- </el-dropdown>
- </div>
- </el-header>
- </template>
代码1-10行为按钮菜单
代码11-17行为静态面包屑--首页
代码21-23行为可视化大屏跳转按钮
代码25-35行为logo状下拉菜单
下拉菜单组件我们可以打开Element Plus找到Dropdown组件查看代码,然后根据需求删减action选项。
Script:
- <script>
- import { computed } from 'vue';
- import {useStore} from 'vuex';
- import { useRouter } from 'vue-router';
- export default {
- setup(){
- let store = useStore()
- let getImgSrc = (logo) =>{
- return new URL(`../assets/imgs/${logo}.png`, import.meta.url).href;
- };
- let handleCollapse = () =>{
- //调用vuex中的mutations
- store.commit('updateIsCollapse');
- };
- //计算属性
- const current = computed(()=>{
- return store.state.currentMenu;
- });
- const router =useRouter();
- const handleLoginOut =()=>{
- store.commit("cleanMenu");
- router.push({
- name:"login",
- })
- };
- const GetScreen =()=>{
- router.push({
- name:'screen',
- })
- }
- return{
- getImgSrc,
- handleCollapse,
- current,
- handleLoginOut,
- GetScreen,
- };
- },
- };
- </script>
代码2-4行分别引入所需的元素
代码7-11行用于动态引入下拉菜单的图片,图片可自行寻找,一般存放在src/assets/imgs路径下。
代码12-19行用于实现左侧菜单按钮的伸展和收缩,利用了vuex的状态管理,因此需要引入vuex。
代码20-26行用于使用下拉菜单中的退出按钮,执行从首页退出至登录页
代码27-31行用于从首页跳转到可视化页面
代码32-38行返回上面各函数,函数不反回无法调用。
CSS样式
- <style lang="less" scoped>
- header{
- display: flex;
- justify-content: space-between;
- align-items: center;
- width: 100%;
- background: RGB(36,77,106);
- }
- .r-content{
- .logo{
- width: 50px;
- height: 50px;
- border-radius: 10;
- }
- }
- .l-content{
- display: flex;
- align-items: center;
- .el-button{
- margin-right: 20px;
- }
- h3{
- color: #fff;
- }
- }
- }
- :deep(.bread span) {
- color: #fff !important;
- cursor: pointer;
- }
- .ScreenButton{
- margin-right: -1100px;
- box-shadow: #000;
- }
- </style>
具体样式可根据实际情况调整。
当运行以后发现显示有问题,可以通过在浏览器页面打开控制台,快捷键ctrl+shift+i,点击element来审查元素。
下方styles可以查看当前的样式代码,也可以在控制台编写样式代码来预览效果,效果合适以后再回到工具中进行具体修改。
-
- Aside模块
Aside效果图
侧边栏
Template
- <template>
- <el-aside :width="$store.state.isCollapse ? '180px':'64px'">
- <el-menu class="el-menu-vertical-demo"
- background-color="#479AD3"
- text-color="#fff"
- :collapse="!$store.state.isCollapse"
- :collapse-transition="false"
- >
- <h3 v-show="$store.state.isCollapse">水寻管理</h3>
- <h3 v-show="!$store.state.isCollapse">水寻</h3>
- <el-menu-item
- :index="item.path"
- v-for="item in noChildren()"
- :key="item.path"
- @click="clickMenu(item)"
- >
- <!-- 动态引入icon -->
- <component class="icons" :is="item.icon"></component>
- <span>{{ item.label }}</span>
- </el-menu-item>
- <el-sub-menu
- :index="item.label"
- v-for="item in hasChildren()"
- :key="item.path"
- >
- <template #title>
- <component class="icons" :is="item.icon"></component>
- <span>{{ item.label }}</span>
- </template>
- <el-menu-item-group >
- <el-menu-item
- :index="subItem.path"
- v-for="(subItem,subIndex) in item.children"
- :key="subIndex"
- @click="clickMenu(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>
代码2-8行设定侧边栏宽高与颜色,可自行根据需求修改。
代码10-11行配合header中的菜单按钮实现侧边栏的缩放和展开
代码13-25行判断是否有子菜单,并动态引入icon图标
代码27-48行用于子菜单的显示
Script:
- <script>
- import {useRouter} from 'vue-router'
- import { useStore } from 'vuex';
- export default {
- setup() {
- const store = useStore()
- const router = useRouter();
- const noChildren= () =>{
- return asyncList.filter((item) => !item.children);
- };
- const hasChildren = () =>{
- return asyncList.filter((item) => item.children);
- };
- const asyncList = store.state.menu;
- const clickMenu = (item) => {
- router.push({
- name: item.name,
- });
- //vuex 来管理
- store.commit('selectMenu',item);
- };
- return {
- noChildren,
- hasChildren,
- clickMenu,
- }
- },
- }
- </script>
Css样式
- <style lang="less" scoped>
- .icons{
- width: 18px;
- height: 18px;
- }
- .el-menu{
- border-right: none;
- h3{
- line-height: 48px;
- color: #fff;
- text-align: center;
- font-size: 20px;
- }
- }
- </style>
-
- Home模块
效果图
依图可知我们的home页面主要由一个el-card,一个el-card嵌套el-table,一个el-card组和一个海报走马灯组成。
Template
- <template>
- <el-row class="home" :gutter="20">
- <el-col :span="8" style="margin-top: 20px">
- <el-card shadow="hover">
- <div class="poster">
- <img src="../../assets/imgs/poster.jpg" alt="" />
- <div class="postinfo">
- <p class="name"></p>
- <p class="role"></p>
- </div>
- </div>
- <div class="login-info">
- <p>上次登录时间:<span>2024.01.05</span></p>
- <p>上次登录地点:<span>浙江水利水电学院</span></p>
- </div>
- </el-card >
- <!-- 失物招领信息数据 -->
- <el-card shadow="hover" style="margin-top: 20px" height="450px">
- <el-table :data="tableData">
- <el-table-column
- v-for="(val,key) in tableLabel"
- :key="key"
- :prop="key"
- :label="val">
- </el-table-column>
- </el-table>
- </el-card>
- </el-col>
- <el-col :span="16" style="margin-top: 20px;">
- <div class="name">
- <el-card :body-style="{display:'flex',padding:0}" v-for="item in lostData" :key="item.name"
- >
- <component class="icons" :is="item.icon" :style="{background: item.color}"></component>
- <div class="detail">
- <p class="number">{{item.value}}件</p>
- <p class="txt">{{item.name}}</p>
- </div>
- </el-card>
- </div>
- <div class="block text-center">
- <span class="demonstration"
- ></span
- >
- <el-carousel height="463px">
- <el-carousel-item v-for="(item,index) in carouseData" :key="index">
- <!-- <h3 class="small justify-center" text="2xl">{{ item }}</h3> -->
- <img :src="item.src" class="Pic" alt="" />
- </el-carousel-item>
- </el-carousel>
- </div>
- </el-col>
- </el-row>
- </template>
代码4-16行用于表现海报卡片
代码18-27行用于表现失物数据卡片
代码代码31-38行用于表现失物卡片组
代码44-49行用于表现海报走马灯
Script
- <script>
- import { defineComponent,onMounted,ref,getCurrentInstance, reactive } from "vue";
- export default defineComponent({
- setup() {
- const {proxy} = getCurrentInstance();
- let tableData =ref([]);
- let lostData = ref([]);
- const tableLabel={
- getTime:'捡到时间',
- picker:'拾取者',
- goods:'物品',
- position:'拾取位置'
- };
- const getTableList = async ()=>{
- let res = await proxy.$api.getTableData();
- tableData.value=res
- };
- //获取失物招领数据
- const getLostData =async () =>{
- let res=await proxy.$api.getLostData();
- lostData.value = res;
- };
- const getImageUrl =(name)=>{
- // return new URL(name,import.meta.url).href;
- return new URL(`../../assets/imgs/${name}.png`, import.meta.url).href
- }
- const carouseData = reactive([
- {src: getImageUrl('pic1')},
- {src: getImageUrl('pic2')},
- {src: getImageUrl('pic3')},
- {src: getImageUrl('pic4')},
- ]);
- onMounted(()=>{
- getTableList();
- getLostData();
- })
- return {
- tableData,
- tableLabel,
- lostData,
- carouseData,
- getImageUrl,
- };
- },
- })
- </script>
在home页面中我们会在第二章失物招领数据卡片上用到数据的引用,这涉及到axios数据请求以及mock模拟数据。上方准备工作已经完成了安装。现在我们来配置我们的mock数据。
- 在src下新建一个api文件夹。在api文件夹下新建api.js文件,mock.js文件,request.js文件。
- 打开request.js文件,输入以下代码进行数据拦截请求,这里会用到axios。
- import axios from 'axios'
- import config from '../config'
- import{ElMessage} from 'element-plus'
- const NETWORK_ERROR='网络请求异常,请稍后重试......'
- //创建一个axios实例对象
- const service = axios.create({
- baseURL: config.baseApi
- })
- //在请求之前
- service.interceptors.request.use((req)=>{
- //可以自定义header
- //jwt-token认证的时候
- return req
- })
- //在请求之后
- service.interceptors.response.use((res)=>{
- // console.log(res);
- const {code,data,msg}=res.data
- //根据后端 视情况而定
- if(code==200){
- return data
- }else{
- //网络请求错误
- ElMessage.error(msg || NETWORK_ERROR)
- return Promise.reject(msg || NETWORK_ERROR)
- }
- })
- //封装核心函数
- function request(options) {
- //{}
- options.method = options.method || 'get'
- if(options.method.toLowerCase() == 'get'){
- options.params =options.data
- }
- //对mock的处理
- let isMOCK = config.ismock //总体的mock
- if(typeof options.mock !=='undefined'){
- isMOCK = options.mock
- }
- //对线上环境做处理
- if(config.env == 'prod'){
- //不给用mock的机会
- service.defaults.baseURL = config.baseApi
- }else{
- service.defaults.baseURL = isMOCK ? config.mockApi : config.baseApi
- }
- return service(options)
- }
- export default request
- 打开mock.js进行获取数据的配置
- import Mock from 'mockjs'
- import homeApi from './mockData/home'
- import userApi from './mockData/user'
- import lostApi from './mockData/lost'
- import permissionApi from './mockData/permission'
- //本地拦截请求
- Mock.mock('/home/getData',homeApi.getHomeData)
- //本地获取user的数据
- Mock.mock(/user\/getUser/,'get',userApi.getUserList)
- Mock.mock(/user\/add/,'post',userApi.createUser)
- Mock.mock(/user\/edit/,'post',userApi.updateUser)
- Mock.mock(/user\/delete/,'get',userApi.deleteUser)
- Mock.mock(/permission\/getMenu/,'post',permissionApi.getMenu)
- //本地获取lost数据
- Mock.mock(/lost\/getLost/,'get',lostApi.getLostList)
- Mock.mock(/lost\/add/,'post',lostApi.createUser)
- Mock.mock(/lost\/edit/,'post',lostApi.updateUser)
- Mock.mock(/lost\/delete/,'get',lostApi.deleteUser)
这里的获取数据代码包括了整个项目中的数据,目前步骤仅到getHomeData,这里我们采用了两种方法,一种是本地mock生成数据,另一种则是线上mock生成数据。第二种更为重要。
方法如下:
- 我们打开fastmock快速mock网站,微信扫码登录账号,写我们自己的接口。
- 点击加号创建接口,其中需要设计接口根地址。创建完成后,点击新增接口。
我们就可以看到如图所示页面,随后填入我们的自定义接口名,返回类型,url地址,以及右侧我们的mock数据即可创建接口。Code 200的含义可以理解拦截数据时的验证码,相同在则拦截成功。
- 随后我们在src下创建config文件夹,并在下面创建index.js文件。在其中配置我们的环境配置文件如下:
- // 环境配置文件
- // 企业级项目中,有三个环境:
- //开发环境、测试环境、线上环境
- //用env取得当前环境,如果取不到,则为线上环境
- const env = import.meta.env.MODE || 'prod'
- const EnvConfig = {
- development: {
- daseApi:'/api',
- mockApi:'https://www.fastmock.site/mock/e98d3ea2f4ce5e0e5f85c638ab745984/lost-mockData',
- },
- test: {
- daseApi:'/test.api',
- mockApi:'https://www.fastmock.site/mock/e98d3ea2f4ce5e0e5f85c638ab745984/lost-mockData',
- },
- pro: {
- daseApi:'//pro.api',
- mockApi:'https://www.fastmock.site/mock/e98d3ea2f4ce5e0e5f85c638ab745984/lost-mockData',
- },
- }
- export default{
- env,
- //mock总开关
- mock:true,
- //解构导出api
- ...EnvConfig[env]
- }
其中的mock api即为我们fastmock上所创建的根接口地址。
4、随后我们进入api.js文件进行数据获取,通过创建函数来传送数据。
- // 对整个项目api的管理
- import request from "./request"
- export default{
- //home组件 首页失物招领卡片数据获取
- getTableData(params){
- return request({
- url:'/home/getTableData',
- method: 'get',
- data: params,
- mock: true
- })
- },
- getLostData(){
- return request({
- url:'/home/getLostData',
- method: 'get',
- mock: true
- })
- },
- getUserData(params){
- return request({
- url:'/user/getUser',
- method: 'get',
- mock:false, //该mock置为true则会采用线上的api地址
- data:params,
- //data:{total: 0,page: 1,}
- })
- },
- gettheLostData(params){
- return request({
- url:'/lost/getLost',
- method: 'get',
- mock:false, //该mock置为true则会采用线上的api地址
- data:params,
- //data:{total: 0,page: 1,}
- })
- },
- addUser(params){
- return request({
- url:'user/add',
- method:'post',
- mock: false,
- data: params,
- })
- },
- addLost(params){
- return request({
- url:'lost/add',
- method:'post',
- mock: false,
- data: params,
- })
- },
- editUser(params){
- return request({
- url:'/user/edit',
- method: 'post',
- mock:false, //该mock置为true则会采用线上的api地址
- data:params,
- })
- },
- editLost(params){
- return request({
- url:'/lost/edit',
- method: 'post',
- mock:false, //该mock置为true则会采用线上的api地址
- data:params,
- })
- },
- deleteUser(params){
- return request({
- url:'/user/delete',
- method: 'get',
- mock:false, //该mock置为true则会采用线上的api地址
- data:params,
- })
- },
- deleteLost(params){
- return request({
- url:'/lost/delete',
- method: 'get',
- mock:false, //该mock置为true则会采用线上的api地址
- data:params,
- })
- },
- //根据用户的用户名不同,返回不一样的菜单列表
- getMenu(params){
- return request({
- url:'/permission/getMenu',
- method:'post',
- mock:false,
- data:params
- })
- },
- getPicData(){
- return request({
- url:'/home/getPicData',
- method: 'get',
- mock: true
- })
- },
- getChartData(){
- return request({
- url:'home/getChartData',
- method: 'get',
- mock: true
- })
- }
- }
这里同样为整个项目的所有数据获取代码,当前仅看getTableData即可。
Css样式
- <style lang="less" scoped>
- .home{
- // background: #;
- .poster{
- display: flex;
- align-items: center;
- padding-bottom: 20px;
- border-bottom: 1px solid #ccc;
- margin-bottom: 20px;
- img{
- width:600px ;
- height:200px ;
- border-radius:5%;
- margin-right: 10px;
- }
- }
- .login-info{
- p{
- line-height: 30px;
- font-size: 14px;
- color: #999;
- span{
- color: #666;
- margin-left: 60px;
- }
- }
- }
- .name{
- display: flex;
- flex-wrap: wrap;
- justify-content: space-between;
- .el-card{
- width: 32%;
- margin-bottom: 20px;
- }
- .icons{
- width: 80px;
- height: 80px;
- font-size: 30px;
- text-align: center;
- line-height: 80px;
- color: #fff;
- }
- .detail{
- margin-left: 15px;
- display: flex;
- flex-direction: column;
- justify-content: center;
- .number{
- font-size: 30px;
- margin-bottom: 10px;
- }
- .txt{
- font-size: 14px;
- text-align: center;
- color: #999;
- }
- }
- }
- .demonstration {
- color: var(--el-text-color-secondary);
- }
- .el-carousel__item h3 {
- color: #475669;
- opacity: 0.75;
- line-height: 150px;
- margin: 0;
- text-align: center;
- }
- .el-carousel__item:nth-child(2n) {
- background-color: #99a9bf;
- }
- .el-carousel__item:nth-child(2n + 1) {
- background-color: #d3dce6;
- }
- .Pic{
- height: 463px;
- width: 100%;
- }
- }
- </style>