第一章🚦前端项目初始化

645 阅读3分钟

🧑‍🎓 个人主页:花棉袄

📖 本章内容:【Vue:前端项目初始化

在这里插入图片描述

🌼Vue:搭建前端项目👉 Gitee仓库地址


一、图形化创建项目

🌳 Vue-cli脚手架

安装脚手架

npm i -g @vue/cli

初始化图形化页面

  • 使用命令窗口输入以下命令
vue ui

🌳 图形化页面

在这里插入图片描述


二、目录介绍

在这里插入图片描述

🍖 文件目录

  • public文件夹:静态资源,webpack进行打包的时候会原封不动打包到dist文件夹中

  • pubilc/index.html:是一个模板文件,作用是生成项目的入口文件 webpack打包的js,css也会自动注入到该页面中 我们浏览器访问项目的时候就会默认打开生成好的index.html

  • src文件夹(程序员代码文件夹)

- assets: 存放公用的静态资源
- components: 非路由组件(全局组件),其他组件放在views或者pages文件夹中
- App.vue: 唯一的根组件
- main.js: 程序入口文件,最先执行的文件
  • babel.config.js:配置文件(babel相关)
  • package.json:项目的详细信息记录
  • package-lock.json:缓存性文件(各种包的来源)

🍖 VUE代码模板

  • 👉🏽 文件->首选项->配置用户代码片段
{
  "生成 vue 模板": {
    "prefix": "vue",
    "body": [
      "<template>",
      "<div></div>",
      "</template>",
      "",
      "<script>",
      "//这里可以导入其他文件(比如:组件,工具 js,第三方插件 js,json文件,图片文件等等)",
      "//例如:import 《组件名称》 from '《组件路径》';",
      "",
      "export default {",
      "//import 引入的组件需要注入到对象中才能使用",
      "components: {},",
      "props: {},",
      "data() {",
      "//这里存放数据",
      "return {",
      "",
      "};",
      "},",
      "//计算属性 类似于 data 概念",
      "computed: {},",
      "//监控 data 中的数据变化",
      "watch: {},",
      "//方法集合",
      "methods: {",
      "",
      "},",
      "//生命周期 - 创建完成(可以访问当前 this 实例)",
      "created() {",
      "",
      "},",
      "//生命周期 - 挂载完成(可以访问 DOM 元素)",
      "mounted() {",
      "",
      "},",
      "beforeCreate() {}, //生命周期 - 创建之前",
      "beforeMount() {}, //生命周期 - 挂载之前",
      "beforeUpdate() {}, //生命周期 - 更新之前",
      "updated() {}, //生命周期 - 更新之后",
      "beforeDestroy() {}, //生命周期 - 销毁之前",
      "destroyed() {}, //生命周期 - 销毁完成",
      "activated() {}, //如果页面有 keep-alive 缓存功能,这个函数会触发",
      "}",
      "</script>",
      "<style lang='scss' scoped>",
      "//@import url($3); 引入公共 css 类",
      "$4",
      "</style>"
    ],
    "description": "生成 vue 模板"
  }
}

三、项目配置

🎍 浏览器自动打开

  • 🍁 package.json
  "scripts": {
    "serve": "vue-cli-service serve --open",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint"
  },

🎍 关闭eslint

  • 🍁 vue.config.js
module.exports = {
    //关闭eslint
    lintOnSave: false,
    //热部署
    devServer: {
        // true 则热更新,false 则手动刷新,默认值为 true
        inline: true,
        // development server port 8000
        port: 8001,
    }
}

四、解决跨域问题

  • 👉🏽 michale.js
/**
 * 项目设置
 * @type {{title: string, vuePort: number, adminUrl: string}}
 */
module.exports = {
    /**
     * 标题设置
     */
    title: "迈克管理系统",
    /**
     * 前端端口
     */
    vuePort: 80,
    /**
     * 后端接口
     */
    adminUrl: "http://localhost:8080",

    /**
     * 是否开启eslint保存检测,有效值:ture | false | 'error'
     */
    lintOnSave: true,
}
  • 👉🏽 .dev.development
# 页面标题
VUE_APP_TITLE = 管理系统开发环境

# 开发环境配置
ENV = 'development'

# 管理系统/开发环境
VUE_APP_BASE_API = '/dev-api'

# 路由懒加载
VUE_CLI_BABEL_TRANSPILE_MODULES = true
const defaultSettings = require("./src/settings/michale")
const port = process.env.port || defaultSettings.vuePort
const url = defaultSettings.adminUrl
devServer: {
  // true 则热更新,false 则手动刷新,默认值为 true
  inline: true,
  // development server port 8000
  port: port,
  proxy: {
    // detail: https://cli.vuejs.org/config/#devserver-proxy
    [process.env.VUE_APP_BASE_API]: {
      target: url,
      changeOrigin: true,
      pathRewrite: {
        ['^' + process.env.VUE_APP_BASE_API]: ''
      }
    }
  },
}

五、打包配置

  • 👉🏽 vue.config.js
const CompressionPlugin = require('compression-webpack-plugin')
const path = require('path')

function resolve(dir) {
    return path.join(__dirname, dir)
}
css: {
    loaderOptions: {
        sass: {
            sassOptions: {outputStyle: "expanded"}
        }
    }
},
configureWebpack: {
    name: name,
    resolve: {
        alias: {
            '@': resolve('src')
        }
    },
    plugins: [
        // http://doc.ruoyi.vip/ruoyi-vue/other/faq.html#使用gzip解压缩静态文件
        new CompressionPlugin({
            cache: false,                   // 不启用文件缓存
            test: /.(js|css|html)?$/i,     // 压缩文件格式
            filename: '[path].gz[query]',   // 压缩后的文件名
            algorithm: 'gzip',              // 使用gzip压缩
            minRatio: 0.8                   // 压缩率小于1才会压缩
        })
    ],
},
chainWebpack(config) {
    config.plugins.delete('preload') // TODO: need test
    config.plugins.delete('prefetch') // TODO: need test

    // set svg-sprite-loader
    config.module
        .rule('svg')
        .exclude.add(resolve('src/assets/icons'))
        .end()
    config.module
        .rule('icons')
        .test(/.svg$/)
        .include.add(resolve('src/assets/icons'))
        .end()
        .use('svg-sprite-loader')
        .loader('svg-sprite-loader')
        .options({
            symbolId: 'icon-[name]'
        })
        .end()

    config
        .when(process.env.NODE_ENV !== 'development',
            config => {
                config
                    .plugin('ScriptExtHtmlWebpackPlugin')
                    .after('html')
                    .use('script-ext-html-webpack-plugin', [{
                        // `runtime` must same as runtimeChunk name. default is `runtime`
                        inline: /runtime..*.js$/
                    }])
                    .end()
                config
                    .optimization.splitChunks({
                    chunks: 'all',
                    cacheGroups: {
                        libs: {
                            name: 'chunk-libs',
                            test: /[\/]node_modules[\/]/,
                            priority: 10,
                            chunks: 'initial' // only package third parties that are initially dependent
                        },
                        elementUI: {
                            name: 'chunk-elementUI', // split elementUI into a single package
                            priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
                            test: /[\/]node_modules[\/]_?element-ui(.*)/ // in order to adapt to cnpm
                        },
                        commons: {
                            name: 'chunk-commons',
                            test: resolve('src/components'), // can customize your rules
                            minChunks: 3, //  minimum common number
                            priority: 5,
                            reuseExistingChunk: true
                        }
                    }
                })
                config.optimization.runtimeChunk('single'),
                    {
                        from: path.resolve(__dirname, './public/robots.txt'), //防爬虫文件
                        to: './' //到根目录下
                    }
            }
        )
}

image.png

六、完成路由组件

  • 在router文件下创建index.js文件
/**
 * Note: 路由配置项
 *
 * hidden: true                     // 当设置 true 的时候该路由不会再侧边栏出现 如401,login等页面,或者如一些编辑页面/edit/1
 * alwaysShow: true                 // 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面
 *                                  // 只有一个时,会将那个子路由当做根路由显示在侧边栏--如引导页面
 *                                  // 若你想不管路由下面的 children 声明的个数都显示你的根路由
 *                                  // 你可以设置 alwaysShow: true,这样它就会忽略之前定义的规则,一直显示根路由
 * redirect: noRedirect             // 当设置 noRedirect 的时候该路由在面包屑导航中不可被点击
 * name:'router-name'               // 设定路由的名字,一定要填写不然使用<keep-alive>时会出现各种问题
 * query: '{"id": 1, "name": "QQ"}' // 访问路由的默认传递参数
 * roles: ['admin', 'common']       // 访问路由的角色权限
 * permissions: ['a:a:a', 'b:b:b']  // 访问路由的菜单权限
 * meta : {
    noCache: true                   // 如果设置为true,则不会被 <keep-alive> 缓存(默认 false)
    title: 'title'                  // 设置该路由在侧边栏和面包屑中展示的名字
    icon: 'svg-name'                // 设置该路由的图标,对应路径src/assets/icons/svg
    breadcrumb: false               // 如果设置为false,则不会在breadcrumb面包屑中显示
    activeMenu: '/system/user'      // 当路由设置了该属性,则会高亮相对应的侧边栏。
  }
 */
  • 前提需要有路由组件在views文件夹下创建
  • 路由配置
import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

// 公共路由
export const constantRoutes = [
    {
        path: '/login',
        name: 'Login',
        component: () => import('@/views/login/login.vue')
    },

]

const router = new VueRouter({
    mode: 'history', // 去掉url中的#
    scrollBehavior: () => ({y: 0}),
    routes: constantRoutes
})

export default router
  • 👉🏽 防止连续点击多次路由报错
// 防止连续点击多次路由报错
let routerPush = VueRouter.prototype.push;
VueRouter.prototype.push = function push(location) {
    return routerPush.call(this, location).catch(err => err)
}
  • 在main.js中引入路由
import router from './router'

new Vue({
    router,
    render: h => h(App),
}).$mount('#app')
  • 路由组件需要有路由出口:在app.vue中添加
<template>
<div>
  <router-view></router-view>
</div>
</template>

🌳 所有的路由和非路由组件身上都会拥有routerrouter route属性

  • $router:一般进行编程式导航进行路由跳转
  • $route: 一般获取路由信息(name path params等)

🌳 路由跳转方式

  • 声明式导航router-link标签 ,可以把router-link理解为一个a标签,可以加class修饰
  • 编程式导航 :声明式导航能做的编程式都能做,而且还可以处理一些业务

七、使用Axios发生请求

🍎 安装Axios依赖

npm install axios --save
  • 👉 main.js中引入Axios
import axios from 'axios'
Vue.prototype.$ajax= axios
  • 就可以使用以下方式发送请求
this.$ajax.get('api/getNewsList')
.then((response)=>{
    this.newsList=response.data.data;
}).catch((response)=>{
    console.log(response);
})

🍎 安装element-ui

import Element from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';

Vue.use(Element)

🍎 使用Ajax发送请求

<template>
  <div class="login">
    <el-button @click="getCodeImage()">获取验证码</el-button>
  </div>
</template>

<script>
//这里可以导入其他文件(比如:组件,工具 js,第三方插件 js,json文件,图片文件等等)
//例如:import 《组件名称》 from '《组件路径》';

export default {
//import 引入的组件需要注入到对象中才能使用
  name:"Login_vue",
  components: {},
  props: {},
  data() {
//这里存放数据
    return {};
  },
//计算属性 类似于 data 概念
  computed: {},
//监控 data 中的数据变化
  watch: {},
//方法集合
  methods: {
    getCodeImage() {
      this.$ajax.get('http://localhost:8080/captchaImage')
          .then((response) => {
            console.log(response.data);
          }).catch((response) => {
        console.log(response);
      })
    }
  },
}
</script>

🍎 封装Ajax工具

import Cookies from 'js-cookie'
Vue.use(Cookies)
import Cookies from 'js-cookie'

const TokenKey = 'Admin-Token'

export function getToken() {
  return Cookies.get(TokenKey)
}

export function setToken(token) {
  return Cookies.set(TokenKey, token)
}

export function removeToken() {
  return Cookies.remove(TokenKey)
}
const sessionCache = {
  set (key, value) {
    if (!sessionStorage) {
      return
    }
    if (key != null && value != null) {
      sessionStorage.setItem(key, value)
    }
  },
  get (key) {
    if (!sessionStorage) {
      return null
    }
    if (key == null) {
      return null
    }
    return sessionStorage.getItem(key)
  },
  setJSON (key, jsonValue) {
    if (jsonValue != null) {
      this.set(key, JSON.stringify(jsonValue))
    }
  },
  getJSON (key) {
    const value = this.get(key)
    if (value != null) {
      return JSON.parse(value)
    }
  },
  remove (key) {
    sessionStorage.removeItem(key);
  }
}
const localCache = {
  set (key, value) {
    if (!localStorage) {
      return
    }
    if (key != null && value != null) {
      localStorage.setItem(key, value)
    }
  },
  get (key) {
    if (!localStorage) {
      return null
    }
    if (key == null) {
      return null
    }
    return localStorage.getItem(key)
  },
  setJSON (key, jsonValue) {
    if (jsonValue != null) {
      this.set(key, JSON.stringify(jsonValue))
    }
  },
  getJSON (key) {
    const value = this.get(key)
    if (value != null) {
      return JSON.parse(value)
    }
  },
  remove (key) {
    localStorage.removeItem(key);
  }
}

export default {
  /**
   * 会话级缓存
   */
  session: sessionCache,
  /**
   * 本地缓存
   */
  local: localCache
}
/**
 * 参数处理
 * @param {*} params  参数
 */
export function tansParams(params) {
    let result = ''
    for (const propName of Object.keys(params)) {
        const value = params[propName];
        var part = encodeURIComponent(propName) + "=";
        if (value !== null && value !== "" && typeof (value) !== "undefined") {
            if (typeof value === 'object') {
                for (const key of Object.keys(value)) {
                    if (value[key] !== null && value[key] !== "" && typeof (value[key]) !== 'undefined') {
                        let params = propName + '[' + key + ']';
                        var subPart = encodeURIComponent(params) + "=";
                        result += subPart + encodeURIComponent(value[key]) + "&";
                    }
                }
            } else {
                result += part + encodeURIComponent(value) + "&";
            }
        }
    }
    return result
}
export default {
    '401': '认证失败,无法访问系统资源',
    '403': '当前操作没有权限',
    '404': '访问资源不存在',
    'default': '系统未知错误,请反馈给管理员'
}
import axios from 'axios'
import {Notification, MessageBox, Message} from 'element-ui'
import store from '@/store'
import {getToken} from '@/utils/token'
import errorCode from '@/utils/errorCode'
import {tansParams} from '@/utils/params'
import {sessionCache} from '@/utils/cache'
// 是否显示重新登录
export let isReLogin = {show: false};

axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
// 创建axios实例
const service = axios.create({
    // axios中请求配置有baseURL选项,表示请求URL公共部分
    baseURL: process.env.VUE_APP_BASE_API,
    // 超时
    timeout: 10000
})

// request拦截器
service.interceptors.request.use(config => {
    // 是否需要设置 token
    const isToken = (config.headers || {}).isToken === false
    // 是否需要防止数据重复提交
    const isRepeatSubmit = (config.headers || {}).repeatSubmit === false
    if (getToken() && !isToken) {
        config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
    }
    // get请求映射params参数
    if (config.method === 'get' && config.params) {
        let url = config.url + '?' + tansParams(config.params);
        url = url.slice(0, -1);
        config.params = {};
        config.url = url;
    }
    if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {
        const requestObj = {
            url: config.url,
            data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
            time: new Date().getTime()
        }
        const sessionObj = sessionCache.getJSON('sessionObj')
        if (sessionObj === undefined || sessionObj === null || sessionObj === '') {
            sessionCache.setJSON('sessionObj', requestObj)
        } else {
            const s_url = sessionObj.url;                  // 请求地址
            const s_data = sessionObj.data;                // 请求数据
            const s_time = sessionObj.time;                // 请求时间
            const interval = 1000;                         // 间隔时间(ms),小于此时间视为重复提交
            if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
                const message = '数据正在处理,请勿重复提交';
                console.warn(`[${s_url}]: ` + message)
                return Promise.reject(new Error(message))
            } else {
                sessionCache.setJSON('sessionObj', requestObj)
            }
        }
    }
    return config
}, error => {
    console.log(error)
    Promise.reject(error).then(r => r)
})

// 响应拦截器
service.interceptors.response.use(res => {
        // 未设置状态码则默认成功状态
        const code = res.data.code || 200;
        // 获取错误信息
        const msg = errorCode[code] || res.data.msg || errorCode['default']
        // 二进制数据则直接返回
        if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
            return res.data
        }
        if (code === 401) {
            if (!isReLogin.show) {
                isReLogin.show = true;
                MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', {
                        confirmButtonText: '重新登录',
                        cancelButtonText: '取消',
                        type: 'warning'
                    }
                ).then(() => {
                    isReLogin.show = false;
                    store.dispatch('LogOut').then(() => {
                        location.href = '/index';
                    })
                }).catch(() => {
                    isReLogin.show = false;
                });
            }
            return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
        } else if (code === 500) {
            Message({
                message: msg,
                type: 'error'
            })
            return Promise.reject(new Error(msg))
        } else if (code !== 200) {
            Notification.error({
                title: msg
            })
            return Promise.reject('error')
        } else {
            return res.data
        }
    },
    error => {
        console.log('err' + error)
        let {message} = error;
        if (message === "Network Error") {
            message = "后端接口连接异常";
        } else if (message.includes("timeout")) {
            message = "系统接口请求超时";
        } else if (message.includes("Request failed with status code")) {
            message = "系统接口" + message.substr(message.length - 3) + "异常";
        }
        Message({
            message: message,
            type: 'error',
            duration: 5 * 1000
        })
        return Promise.reject(error)
    }
)
export default service

八、开发 - 生成环境

# 页面标题
VUE_APP_TITLE = 管理系统开发环境

# 开发环境配置
ENV = 'development'

# 管理系统/开发环境
VUE_APP_BASE_API = '/dev-api'

# 路由懒加载
VUE_CLI_BABEL_TRANSPILE_MODULES = true
# 页面标题
VUE_APP_TITLE = 管理系统生成环境

# 生产环境配置
ENV = 'production'

# 管理系统/生产环境
VUE_APP_BASE_API = '/prod-api'

九、请求接口统一封装

//当前模块,API进行统一管理,即对请求接口统一管理
import request from '@/utils/request'

// 查询缓存详细
export function getCodeImages() {
    return request({
        url: '/captchaImage',
        method: 'get'
    })
}
  • 当组件想要使用相关请求时,只需要导入相关函数即可
getCodeImages() {
  getImage().then.then(response => {
    console.log(response, "success");   // 成功的返回
  })
}

十、页面美化布局


🍑 刷新页面进度条

在这里插入图片描述

import axios from "axios";
   ...
//引入进度条
import nprogress from 'nprogress';
//引入进度条样式
import "nprogress/nprogress.css";


//1、对axios二次封装
    ...
//2、配置请求拦截器
requests.interceptors.request.use(config => {
    //config内主要是对请求头Header配置
    //比如添加token
    ...
    //开启进度条
    nprogress.start();
    return config;
})
//3、配置相应拦截器
requests.interceptors.response.use((res) => {
    //成功的回调函数
    ...
    //响应成功,关闭进度条
    nprogress.done()
    return  res.data;
},(error) => {
    //失败的回调函数
    console.log("响应失败"+error)
    return Promise.reject(new Error('fail'))
})
//4、对外暴露
export default requests;

🍑 自定义icon

安装:svg-sprite-loader
  • 👉🏽 index.js
import Vue from 'vue'
import SvgIcon from '@/components/icon/SvgIcon.vue'// svg component

// register globally
Vue.component('svg-icon', SvgIcon)

const req = require.context('./svg', false, /.svg$/)
const requireAll = requireContext => requireContext.keys().map(requireContext)
requireAll(req)
  • 👉🏽 svgo.yml
plugins:

  - removeAttrs:
      attrs:
        - 'fill'
        - 'fill-rule'
  • 👉 validate.js
/**
 * @param {string} path
 * @returns {Boolean}
 */
export function isExternal(path) {
    return /^(https?:|mailto:|tel:)/.test(path)
}

/**
 * @param {string} str
 * @returns {Boolean}
 */
export function validUsername(str) {
    const valid_map = ['admin', 'editor']
    return valid_map.indexOf(str.trim()) >= 0
}
  • 👉🏽 SvgIcon组件
<template>
  <div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
  <svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
    <use :xlink:href="iconName" />
  </svg>
</template>

<script>
import { isExternal } from '@/assets/icon/validate.js'

export default {
    name: 'SvgIcon',
  props: {
    iconClass: {
      type: String,
      required: true
    },
    className: {
      type: String,
      default: ''
    }
  },
  computed: {
    isExternal() {
      return isExternal(this.iconClass)
    },
    iconName() {
      return `#icon-${this.iconClass}`
    },
    svgClass() {
      if (this.className) {
        return 'svg-icon ' + this.className
      } else {
        return 'svg-icon'
      }
    },
    styleExternalIcon() {
      return {
        mask: `url(${this.iconClass}) no-repeat 50% 50%`,
        '-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`
      }
    }
  }
}
</script>

<style scoped>
.svg-icon {
  width: 1em;
  height: 1em;
  vertical-align: -0.15em;
  fill: currentColor;
  overflow: hidden;
}

.svg-external-icon {
  background-color: currentColor;
  mask-size: cover!important;
  display: inline-block;
}
</style>
  • 👉 main.js引入icon
import '@/customize/icons/index' // icon
  • 👉🏽 vue.config.js
    • 打包路径一定要配置正确
// set svg-sprite-loader
config.module
    .rule('svg')
    .exclude.add(resolve('src/assets/icon'))
    .end()
config.module
    .rule('icons')
    .test(/.svg$/)
    .include.add(resolve('src/assets/icon'))
    .end()
    .use('svg-sprite-loader')
    .loader('svg-sprite-loader')
    .options({
        symbolId: 'icon-[name]'
    })
    .end()
  • 👉🏽 404.svg文件示例
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M121.718 73.272v9.953c3.957-7.584 6.199-16.05 6.199-24.995C127.917 26.079 99.273 0 63.958 0 28.644 0 0 26.079 0 58.23c0 .403.028.806.028 1.21l22.97-25.953h13.34l-19.76 27.187h6.42V53.77l13.728-19.477v49.361H22.998V73.272H2.158c5.951 20.284 23.608 36.208 45.998 41.399-1.44 3.3-5.618 11.263-12.565 12.674-8.607 1.764 23.358.428 46.163-13.178 17.519-4.611 31.938-15.849 39.77-30.513h-13.506V73.272H85.02V59.464l22.998-25.977h13.008l-19.429 27.187h6.421v-7.433l13.727-19.402v39.433h-.027zm-78.24 2.822a10.516 10.516 0 0 1-.996-4.535V44.548c0-1.613.332-3.124.996-4.535a11.66 11.66 0 0 1 2.713-3.68c1.134-1.032 2.49-1.864 4.04-2.468 1.55-.605 3.21-.908 4.982-.908h11.292c1.77 0 3.431.303 4.981.908 1.522.604 2.85 1.41 3.986 2.418l-12.26 16.303v-2.898a1.96 1.96 0 0 0-.665-1.512c-.443-.403-.996-.604-1.66-.604-.665 0-1.218.201-1.661.604a1.96 1.96 0 0 0-.664 1.512v9.071L44.364 77.606a10.556 10.556 0 0 1-.886-1.512zm35.73-4.535c0 1.613-.332 3.124-.997 4.535a11.66 11.66 0 0 1-2.712 3.68c-1.134 1.032-2.49 1.864-4.04 2.469-1.55.604-3.21.907-4.982.907H55.185c-1.77 0-3.431-.303-4.981-.907-1.55-.605-2.906-1.437-4.041-2.47a12.49 12.49 0 0 1-1.384-1.512l13.727-18.217v6.375c0 .605.222 1.109.665 1.512.442.403.996.604 1.66.604.664 0 1.218-.201 1.66-.604a1.96 1.96 0 0 0 .665-1.512V53.87L75.97 36.838c.913.932 1.66 1.99 2.214 3.175.664 1.41.996 2.922.996 4.535v27.011h.028z"/></svg>
  • 👉🏽 使用icon图标
<svg-icon icon-class="404" /> // icon-class 为 icon 的名字
  • 👉🏽 改变icon颜色
<span class="svg-container">
  <svg-icon icon-class="404" style="fill:red"/>
</span>

🍑 消息提示插件

import { Message, MessageBox, Notification, Loading } from 'element-ui'
let loadingInstance;
export default {
    // 消息提示
    msg(content) {
        Message.info(content)
    },
    // 错误消息
    msgError(content) {
        Message.error(content)
    },
    // 成功消息
    msgSuccess(content) {
        Message.success(content)
    },
    // 警告消息
    msgWarning(content) {
        Message.warning(content)
    },
    // 弹出提示
    alert(content) {
        MessageBox.alert(content, "系统提示")
    },
    // 错误提示
    alertError(content) {
        MessageBox.alert(content, "系统提示", { type: 'error' })
    },
    // 成功提示
    alertSuccess(content) {
        MessageBox.alert(content, "系统提示", { type: 'success' })
    },
    // 警告提示
    alertWarning(content) {
        MessageBox.alert(content, "系统提示", { type: 'warning' })
    },
    // 通知提示
    notify(content) {
        Notification.info(content)
    },
    // 错误通知
    notifyError(content) {
        Notification.error(content);
    },
    // 成功通知
    notifySuccess(content) {
        Notification.success(content)
    },
    // 警告通知
    notifyWarning(content) {
        Notification.warning(content)
    },
    // 确认窗体
    confirm(content) {
        return MessageBox.confirm(content, "系统提示", {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            type: "warning",
        })
    },
    // 提交内容
    prompt(content) {
        return MessageBox.prompt(content, "系统提示", {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            type: "warning",
        })
    },
    // 打开遮罩层
    loading(content) {
        loadingInstance = Loading.service({
            lock: true,
            text: content,
            spinner: "el-icon-loading",
            background: "rgba(0, 0, 0, 0.7)",
        })
    },
    // 关闭遮罩层
    closeLoading() {
        loadingInstance.close();
    }
}
import modal from './message'
export default {
    install(Vue) {
        // 模态框对象
        Vue.prototype.$modal = modal
    }
}
  • 🕰️ 安装插件: src/main.js
import plugins from './utils/plugins' //plugins 
Vue.use(plugins)
  • 🕰️ 使用消息提示插件
getList() {
  this.getList().then(()=>{
      this.$modal.msgSuccess("操作成功");
  });
},

🚦其他文件

标题
🌳public 👉🏽是一个模板文件,作用是生成项目的入口文件
🌳Layout👉🏽layout布局
🌳assets👉🏽静态页面

扫码_搜索联合传播样式-标准色版.png

📢🌥️如果文章对你有帮助【关注👍点赞❤️收藏⭐】