Giter Club home page Giter Club logo

res-sharing-portal's Introduction

## 一、vue3组件通信方式 **通信仓库地址:https://gitee.com/jch1011/vue3_communication.git** 不管是vue2还是vue3,组件通信方式很重要,不管是项目还是面试都是经常用到的知识点。 **比如:vue2组件通信方式** **props:**可以实现父子组件、子父组件、甚至兄弟组件通信 **自定义事件**:可以实现子父组件通信 **全局事件总线$bus**:可以实现任意组件通信 **pubsub:**发布订阅模式实现任意组件通信 **vuex**:集中式状态管理容器,实现任意组件通信 **ref**:父组件获取子组件实例VC,获取子组件的响应式数据以及方法 **slot:**插槽(默认插槽、具名插槽、作用域插槽)实现父子组件通信........ ### 1.1 props props可以实现父子组件通信,在vue3中我们可以通过defineProps获取父组件传递的数据。且在组件内部不需要引入defineProps方法可以直接使用! **父组件给子组件传递数据** ```html ``` **子组件获取父组件传递数据:方式1** ```typescript let props = defineProps({ info: { type: String, //接受的数据类型 default: '默认参数', //接受默认数据 }, money: { type: Number, default: 0, }, }) ``` **子组件获取父组件传递数据:方式2** ```typescript let props = defineProps(['info', 'money']) ``` 子组件获取到props数据就可以在模板中使用了,但是切记props是只读的(只能读取,不能修改) ### 1.2自定义事件 在vue框架中事件分为两种:一种是原生的DOM事件,另外一种自定义事件。 原生DOM事件可以让用户与网页进行交互,比如click、dbclick、change、mouseenter、mouseleave.... 自定义事件可以实现子组件给父组件传递数据 #### 1.2.1 原生DOM事件 代码如下: ```html
      我是祖国的老花骨朵
 
``` 当前代码级给pre标签绑定原生DOM事件点击事件,默认会给事件回调注入event事件对象。当然点击事件想注入多个参数可以按照下图操作。但是切记注入的事件对象务必叫做$event. ```html
我要传递多个参数
``` 在vue3框架click、dbclick、change(这类原生DOM事件),不管是在标签、自定义标签上(组件标签)都是原生DOM事件。 **** #### 1.2.2 自定义事件 自定义事件可以实现子组件给父组件传递数据.在项目中是比较常用的。 比如在父组件内部给子组件(Event2)绑定一个自定义事件 ```html ``` 在Event2子组件内部触发这个自定义事件 ```vue

我是子组件2

点击我触发xxx自定义事件
``` 我们会发现在script标签内部,使用了defineEmits方法,此方法是vue3提供的方法,不需要引入直接使用。defineEmits方法执行,传递一个数组,数组元素即为将来组件需要触发的自定义事件类型,此方执行会返回一个$emit方法用于触发自定义事件。 当点击按钮的时候,事件回调内部调用$emit方法去触发自定义事件,第一个参数为触发事件类型,第二个、三个、N个参数即为传递给父组件的数据。 需要注意的是:代码如下 ```vue ``` 正常说组件标签书写@click应该为原生DOM事件,但是如果子组件内部通过defineEmits定义就变为自定义事件了 ```typescript let $emit = defineEmits(['xxx', 'click']) ``` ### 1.3 全局事件总线 全局事件总线可以实现任意组件通信,在vue2中可以根据VM与VC关系推出全局事件总线。 但是在vue3中没有Vue构造函数,也就没有Vue.prototype.以及组合式API写法没有this, 那么在Vue3想实现全局事件的总线功能就有点不现实啦,如果想在Vue3中使用全局事件总线功能 可以使用插件mitt实现。 **mitt:官网地址:https://www.npmjs.com/package/mitt** ### 1.4 v-model v-model指令可是收集表单数据(数据双向绑定),除此之外它也可以实现父子组件数据同步。 而v-model实指利用props[modelValue]与自定义事件[update:modelValue]实现的。 下方代码:相当于给组件Child传递一个props(modelValue)与绑定一个自定义事件update:modelValue 实现父子组件数据同步 ``` ``` 在vue3中一个组件可以通过使用多个v-model,让父子组件多个数据同步,下方代码相当于给组件Child传递两个props分别是pageNo与pageSize,以及绑定两个自定义事件update:pageNo与update:pageSize实现父子数据同步 ``` ``` ### 1.5 useAttrs 在Vue3中可以利用useAttrs方法获取组件的属性与事件(包含:原生DOM事件或者自定义事件),次函数功能类似于Vue2框架中$attrs属性与$listeners方法。 比如:在父组件内部使用一个子组件my-button ``` ``` 子组件内部可以通过useAttrs方法获取组件属性与事件.因此你也发现了,它类似于props,可以接受父组件传递过来的属性与属性值。需要注意如果defineProps接受了某一个属性,useAttrs方法返回的对象身上就没有相应属性与属性值。 ``` ``` ### 1.6 ref与$parent ref,提及到ref可能会想到它可以获取元素的DOM或者获取子组件实例的VC。既然可以在父组件内部通过ref获取子组件实例VC,那么子组件内部的方法与响应式数据父组件可以使用的。 比如:在父组件挂载完毕获取组件实例 父组件内部代码: ```

ref与$parent

``` 但是需要注意,如果想让父组件获取子组件的数据或者方法需要通过defineExpose对外暴露,因为vue3中组件内部的数据对外“关闭的”,外部不能访问 ``` ``` $parent可以获取某一个组件的父组件实例VC,因此可以使用父组件内部的数据与方法。必须子组件内部拥有一个按钮点击时候获取父组件实例,当然父组件的数据与方法需要通过defineExpose方法对外暴露 ``` 点击我获取父组件实例 ``` ### 1.7 provide与inject **provide[提供]** **inject[注入]** vue3提供两个方法provide与inject,可以实现隔辈组件传递参数 组件组件提供数据: provide方法用于提供数据,此方法执需要传递两个参数,分别提供数据的key与提供数据value ``` ``` 后代组件可以通过inject方法获取数据,通过key获取存储的数值 ``` ``` ### 1.8 pinia **pinia官网:https://pinia.web3doc.top/** pinia也是集中式管理状态容器,类似于vuex。但是核心概念没有mutation、modules,使用方式参照官网 ### 1.9 slot 插槽:默认插槽、具名插槽、作用域插槽可以实现父子组件通信. **默认插槽:** 在子组件内部的模板中书写slot全局组件标签 ```
``` 在父组件内部提供结构:Todo即为子组件,在父组件内部使用的时候,在双标签内部书写结构传递给子组件 注意开发项目的时候默认插槽一般只有一个 ```

我是默认插槽填充的结构

``` **具名插槽:** 顾名思义,此插槽带有名字在组件内部留多个指定名字的插槽。 下面是一个子组件内部,模板中留两个插槽 ```

todo

``` 父组件内部向指定的具名插槽传递结构。需要注意v-slot:可以替换为# ```

slot

//可以用#a替换
填入组件A部分的结构
//可以用#b替换
填入组件B部分的结构
``` **作用域插槽** 作用域插槽:可以理解为,子组件数据由父组件提供,但是子组件内部决定不了自身结构与外观(样式) 子组件Todo代码如下: ```

todo

``` 父组件内部代码如下: ```

slot

{{$row.title}}
``` ## 二、搭建后台管理系统模板 ### 2.1 项目初始化 今天来带大家从0开始搭建一个vue3版本的后台管理系统。一个项目要有统一的规范,需要使用eslint+stylelint+prettier来对我们的代码质量做检测和修复,需要使用husky来做commit拦截,需要使用commitlint来统一提交规范,需要使用preinstall来统一包管理工具。 下面我们就用这一套规范来初始化我们的项目,集成一个规范的模版。 #### 2.1.1 环境准备 - node v16.14.2 - pnpm 8.0.0 #### 2.1.2 初始化项目 本项目使用vite进行构建,vite官方中文文档参考:[cn.vitejs.dev/guide/](https://cn.vitejs.dev/guide/) **pnpm:performant npm ,意味“高性能的 npm”。[pnpm](https://so.csdn.net/so/search?q=pnpm&spm=1001.2101.3001.7020)由npm/yarn衍生而来,解决了npm/yarn内部潜在的bug,极大的优化了性能,扩展了使用场景。被誉为“最先进的包管理工具”** pnpm安装指令 ``` npm i -g pnpm ``` 项目初始化命令: ``` pnpm create vite ``` 进入到项目根目录pnpm install安装全部依赖.安装完依赖运行程序:pnpm run dev 运行完毕项目跑在http://127.0.0.1:5173/,可以访问你得项目啦 ### 2.2 项目配置 #### 一、eslint配置 **eslint中文官网:http://eslint.cn/** ESLint最初是由[Nicholas C. Zakas](http://nczonline.net/) 于2013年6月创建的开源项目。它的目标是提供一个插件化的**javascript代码检测工具** 首先安装eslint ``` pnpm i eslint -D ``` 生成配置文件:.eslint.cjs ``` npx eslint --init ``` **.eslint.cjs配置文件** ``` module.exports = { //运行环境 "env": { "browser": true,//浏览器端 "es2021": true,//es2021 }, //规则继承 "extends": [ //全部规则默认是关闭的,这个配置项开启推荐规则,推荐规则参照文档 //比如:函数不能重名、对象不能出现重复key "eslint:recommended", //vue3语法规则 "plugin:vue/vue3-essential", //ts语法规则 "plugin:@typescript-eslint/recommended" ], //要为特定类型的文件指定处理器 "overrides": [ ], //指定解析器:解析器 //Esprima 默认解析器 //Babel-ESLint babel解析器 //@typescript-eslint/parser ts解析器 "parser": "@typescript-eslint/parser", //指定解析器选项 "parserOptions": { "ecmaVersion": "latest",//校验ECMA最新版本 "sourceType": "module"//设置为"script"(默认),或者"module"代码在ECMAScript模块中 }, //ESLint支持使用第三方插件。在使用插件之前,您必须使用npm安装它 //该eslint-plugin-前缀可以从插件名称被省略 "plugins": [ "vue", "@typescript-eslint" ], //eslint规则 "rules": { } } ``` ##### 1.1 vue3环境代码校验插件 ``` # 让所有与prettier规则存在冲突的Eslint rules失效,并使用prettier进行代码检查 "eslint-config-prettier": "^8.6.0", "eslint-plugin-import": "^2.27.5", "eslint-plugin-node": "^11.1.0", # 运行更漂亮的Eslint,使prettier规则优先级更高,Eslint优先级低 "eslint-plugin-prettier": "^4.2.1", # vue.js的Eslint插件(查找vue语法错误,发现错误指令,查找违规风格指南 "eslint-plugin-vue": "^9.9.0", # 该解析器允许使用Eslint校验所有babel code "@babel/eslint-parser": "^7.19.1", ``` 安装指令 ``` pnpm install -D eslint-plugin-import eslint-plugin-vue eslint-plugin-node eslint-plugin-prettier eslint-config-prettier eslint-plugin-node @babel/eslint-parser ``` ##### 1.2 修改.eslintrc.cjs配置文件 ``` // @see https://eslint.bootcss.com/docs/rules/ module.exports = { env: { browser: true, es2021: true, node: true, jest: true, }, /* 指定如何解析语法 */ parser: 'vue-eslint-parser', /** 优先级低于 parse 的语法解析配置 */ parserOptions: { ecmaVersion: 'latest', sourceType: 'module', parser: '@typescript-eslint/parser', jsxPragma: 'React', ecmaFeatures: { jsx: true, }, }, /* 继承已有的规则 */ extends: [ 'eslint:recommended', 'plugin:vue/vue3-essential', 'plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended', ], plugins: ['vue', '@typescript-eslint'], /* * "off" 或 0 ==> 关闭规则 * "warn" 或 1 ==> 打开的规则作为警告(不影响代码执行) * "error" 或 2 ==> 规则作为一个错误(代码不能执行,界面报错) */ rules: { // eslint(https://eslint.bootcss.com/docs/rules/) 'no-var': 'error', // 要求使用 let 或 const 而不是 var 'no-multiple-empty-lines': ['warn', { max: 1 }], // 不允许多个空行 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', 'no-unexpected-multiline': 'error', // 禁止空余的多行 'no-useless-escape': 'off', // 禁止不必要的转义字符 // typeScript (https://typescript-eslint.io/rules) '@typescript-eslint/no-unused-vars': 'error', // 禁止定义未使用的变量 '@typescript-eslint/prefer-ts-expect-error': 'error', // 禁止使用 @ts-ignore '@typescript-eslint/no-explicit-any': 'off', // 禁止使用 any 类型 '@typescript-eslint/no-non-null-assertion': 'off', '@typescript-eslint/no-namespace': 'off', // 禁止使用自定义 TypeScript 模块和命名空间。 '@typescript-eslint/semi': 'off', // eslint-plugin-vue (https://eslint.vuejs.org/rules/) 'vue/multi-word-component-names': 'off', // 要求组件名称始终为 “-” 链接的单词 'vue/script-setup-uses-vars': 'error', // 防止 ``` 在src文件夹目录下创建一个index.ts文件:用于注册components文件夹内部全部全局组件!!! ``` // 引入全局组件 import SvgIcon from './SvgIcon/index.vue' // 全局对象 const globalComponent = { SvgIcon } export default { install(app) { Object.keys(globalComponent).forEach((key) => { app.component(key, globalComponent[key]) }) }, } ``` 在入口文件main.js引入components/index.ts文件,通过app.use方法安装自定义插件 ``` import gloablComponent from './components/index'; app.use(gloablComponent); ``` ### 3.5 集成sass 我们目前在组件内部已经可以使用scss样式,因为在配置styleLint工具的时候,项目当中已经安装过sass sass-loader,因此我们再组件内可以使用scss语法!!!需要加上lang="scss" ``` ``` 接下来我们为项目添加一些全局的样式 在src/styles目录下创建一个index.scss文件,当然项目中需要用到清除默认样式,因此在index.scss引入reset.scss ``` @import reset.scss ``` 在入口文件引入 ``` import '@/styles' ``` 但是你会发现在src/styles/index.scss全局样式文件中没有办法使用$变量.因此需要给项目中引入全局变量$. 在style/variable.scss创建一个variable.scss文件! 在vite.config.ts文件配置如下: ``` export default defineConfig((config) => { css: { preprocessorOptions: { scss: { javascriptEnabled: true, additionalData: '@import "./src/styles/variable.scss";', }, }, }, } } ``` **`@import "./src/styles/variable.less";`后面的`;`不要忘记,不然会报错**! 配置完毕你会发现scss提供这些全局变量可以在组件样式中使用了!!! ### 3.6 mock数据 安装依赖:https://www.npmjs.com/package/vite-plugin-mock ``` pnpm install -D vite-plugin-mock mockjs ``` 在 vite.config.js 配置文件启用插件。 ``` import { UserConfigExport, ConfigEnv } from 'vite' import { viteMockServe } from 'vite-plugin-mock' import vue from '@vitejs/plugin-vue' export default ({ command })=> { return { plugins: [ vue(), viteMockServe({ localEnabled: command === 'serve', }), ], } } ``` 在根目录创建mock文件夹:去创建我们需要mock数据与接口!!! 在mock文件夹内部创建一个user.ts文件 ``` //用户信息数据 function createUserList() { return [ { userId: 1, avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif', username: 'admin', password: '111111', desc: '平台管理员', roles: ['平台管理员'], buttons: ['cuser.detail'], routes: ['home'], token: 'Admin Token', }, { userId: 2, avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif', username: 'system', password: '111111', desc: '系统管理员', roles: ['系统管理员'], buttons: ['cuser.detail', 'cuser.user'], routes: ['home'], token: 'System Token', }, ] } export default [ // 用户登录接口 { url: '/api/user/login',//请求地址 method: 'post',//请求方式 response: ({ body }) => { //获取请求体携带过来的用户名与密码 const { username, password } = body; //调用获取用户信息函数,用于判断是否有此用户 const checkUser = createUserList().find( (item) => item.username === username && item.password === password, ) //没有用户返回失败信息 if (!checkUser) { return { code: 201, data: { message: '账号或者密码不正确' } } } //如果有返回成功信息 const { token } = checkUser return { code: 200, data: { token } } }, }, // 获取用户信息 { url: '/api/user/info', method: 'get', response: (request) => { //获取请求头携带token const token = request.headers.token; //查看用户信息是否包含有次token用户 const checkUser = createUserList().find((item) => item.token === token) //没有返回失败的信息 if (!checkUser) { return { code: 201, data: { message: '获取用户信息失败' } } } //如果有返回成功信息 return { code: 200, data: {checkUser} } }, }, ] ``` **安装axios** ``` pnpm install axios ``` 最后通过axios测试接口!!! ### 3.7 axios二次封装 在开发项目的时候避免不了与后端进行交互,因此我们需要使用axios插件实现发送网络请求。在开发项目的时候 我们经常会把axios进行二次封装。 目的: 1:使用请求拦截器,可以在请求拦截器中处理一些业务(开始进度条、请求头携带公共参数) 2:使用响应拦截器,可以在响应拦截器中处理一些业务(进度条结束、简化服务器返回的数据、处理http网络错误) 在根目录下创建utils/request.ts ``` import axios from "axios"; import { ElMessage } from "element-plus"; //创建axios实例 let request = axios.create({ baseURL: import.meta.env.VITE_APP_BASE_API, timeout: 5000 }) //请求拦截器 request.interceptors.request.use(config => { return config; }); //响应拦截器 request.interceptors.response.use((response) => { return response.data; }, (error) => { //处理网络错误 let msg = ''; let status = error.response.status; switch (status) { case 401: msg = "token过期"; break; case 403: msg = '无权访问'; break; case 404: msg = "请求地址错误"; break; case 500: msg = "服务器出现问题"; break; default: msg = "无网络"; } ElMessage({ type: 'error', message: msg }) return Promise.reject(error); }); export default request; ``` ### 3.8 API接口统一管理 在开发项目的时候,接口可能很多需要统一管理。在src目录下去创建api文件夹去统一管理项目的接口; 比如:下面方式 ``` //统一管理咱们项目用户相关的接口 import request from '@/utils/request' import type { loginFormData, loginResponseData, userInfoReponseData, } from './type' //项目用户相关的请求地址 enum API { LOGIN_URL = '/admin/acl/index/login', USERINFO_URL = '/admin/acl/index/info', LOGOUT_URL = '/admin/acl/index/logout', } //登录接口 export const reqLogin = (data: loginFormData) => request.post(API.LOGIN_URL, data) //获取用户信息 export const reqUserInfo = () => request.get(API.USERINFO_URL) //退出登录 export const reqLogout = () => request.post(API.LOGOUT_URL) ``` ### 3.9 router设置 安装vue-router: ``` pnpm install vue-router ``` ## 四、项目的资源地址 贾成豪老师代码仓库地址:https://gitee.com/jch1011/vue3_admin_template-bj1.git 项目在线文档: 服务器域名:http://sph-api.atguigu.cn swagger文档: http://139.198.104.58:8209/swagger-ui.html http://139.198.104.58:8212/swagger-ui.html#/ echarts:国内镜像网站 https://www.isqqw.com/echarts-doc/zh/option.html#title http://datav.aliyun.com/portal/school/atlas/area_selector # res-sharing-portal

res-sharing-portal's People

Contributors

thenleap avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.