创建项目

vite创建项目

注意:vite需要Node.js版本>=12.0.0
安装方式(不使用模板):

#使用 NPM:
npm init vite@latest
#yarn 【推荐】
yarn create vite
#pnpm
pnpm create vite

填写项目名->选择vue->选择TS->安装依赖(npm i)->启动项目(npm run dev)

清除项目&工程化项目搭建

  • src

    • api ajax工具管理文件夹
    • assets 静态资源目录
    • components 公共小组件
    • directives 自定义指令文件夹
    • hooks 全局hooks函数 文件夹
    • layout 框架
    • router 路由
    • store pinia仓库
    • utils 工具文件夹
    • views 页面级别组件文件夹
  • types 全局ts约束配置

重置样式&安装sass及配置

重置样式:拷贝一些样式文件到assets/styles下
安装sass: npm i sass -D
在main.ts文件中引入重置样式文件

import { createApp } from 'vue'
import App from './App.vue'import './assets/styles/index.scss'
const app = createApp(App)app.mount('#app')

使用重置样式中的变量,要先在vite.config.ts中配置

export default defineConfig({plugins: [vue()],css: {// CSS 预处理器preprocessorOptions: {scss: {additionalData: `@import '@/assets/style/variables.scss';`}}},
})

此时报错Can’t find stylesheet to import.,无法识别@ 继续配置别名

import { defineConfig, resolveBaseUrl } from 'vite'
import vue from '@vitejs/plugin-vue'// 之所以飘红 是应为 #node不带ts提示 需要安装 @types/node
import { resolve } from 'path'//引入插件
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'// https://vitejs.dev/config/
export default defineConfig({plugins: [vue(),createSvgIconsPlugin({iconDirs: [resolve(process.cwd(), 'src/assets/icons')],symbolId: '[name]'})],css: {// CSS 预处理器preprocessorOptions: {scss: {additionalData: `@import '@/assets/style/variables.scss';`}}},resolve: {alias: {'@': resolve(__dirname, 'src')}}
})

此时样式文件中的变量可以使用成功,但是飘红,需要继续安装npm i @types/node
css样式配置:body or html or root 里面配置全局样式变量

body{--primary: #007bff;
}

使用全局样式变量:

.app {height: 100%;#var 可以直接使用 全局样式变量background: var(--muted);
}

vue3 Svg的使用

  1. 打开iconfont 下载要使用的图标 (font class使用方式同以前一样)
  2. 使用Symbol方式:
    在main.ts中引入
// Symbol 引入iconfont.js
import './assets/icons/iconfont.js'

在.vue文件中使用

<template><div>
<svg class="icon" aria-hidden="true"><use xlink:href="#icon-shuju"></use>
</svg></div>
</template><script setup lang="ts"></script><style scoped lang="scss">.icon {width: 1em;height: 1em;vertical-align: -0.15em;fill: currentColor;overflow: hidden;
}
</style>
  1. 针对svg文件使用方法
    安装插件
npm i vite-plugin-svg-icons -D
//or
pnpm i vite-plugin-svg-icons -D#如果报错Cannot find package 'fast-glob'
安装插件 yarn add fast-glob -D

在vite.config.ts中引入插件

//引入插件
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'// 之所以飘红 是应为 #node不带ts提示 需要安装 @types/node
import { resolve } from 'path'//引入插件并在plugins中配置
import {createSvgIconsPlugin} from 'vite-plugin-svg-icons'// https://vitejs.dev/config/
export default defineConfig({plugins: [vue(),createSvgIconsPlugin({iconDirs: [resolve(process.cwd(), 'src/assets/icons')],symbolId: '[name]'})],css: {// CSS 预处理器preprocessorOptions: {scss: {additionalData: `@import '@/assets/style/variables.scss';`}}},resolve: {alias: {'@': resolve(__dirname, 'src')}}
})

报错的话就再安装插件

#如果报错Cannot find package 'fast-glob'
安装插件 yarn add fast-glob -D

在main.ts中注册svg图标

// 注册svg-icons
import 'virtual:svg-icons-register'

全局svg组件封装

创建组件/components/SvgIcon.vue
在SvgIcon.vue中

<template><svg class="icon" aria-hidden="true" :width="props.size + 'em'" :height="props.size + 'em'"><use :xlink:href="'#' + props.name" :fill="props.color"></use></svg>
</template><script setup lang="ts">
interface Props {name: stringcolor?: stringsize?: number
}
const props = withDefaults(defineProps<Props>(), {color: '',size: 1,
})
</script><style scoped lang="scss">
.icon {vertical-align: -0.15em;fill: currentColor;overflow: hidden;
}
</style>

在main.ts中全局注册

const app = createApp(App)// 引入SvgIcon组件
import SvgIcon from "@/components/SvgIcon.vue";
// 全局注册
app.component('SvgIcon', SvgIcon)app.mount('#app')

使用

<svg-icon name="user" :size="3" color="pink"></svg-icon>

针对一下代码使用@飘红的问题

// 引入SvgIcon组件
import SvgIcon from "@/components/SvgIcon.vue";

在vite-env.d.ts中配置即可

declare module "*.vue" {import type { DefineComponent } from "vue"const vueComponent: DefineComponent<{}, {}, any>export default vueComponent
}

安装 & 使用element plus & 中文化

官网:Element Plus
安装:

# NPM
$ npm install element-plus --save# Yarn
$ yarn add element-plus

完整引入在main.ts中

import { createApp } from 'vue'
import App from './App.vue'import './assets/style/index.scss'// Symbol 引入iconfont.js
import './assets/icons/iconfont.js'// 注册svg-icons
import 'virtual:svg-icons-register'const app = createApp(App)// 引入SvgIcon组件
import SvgIcon from "@/components/SvgIcon.vue";
// 全局注册
app.component('SvgIcon', SvgIcon)
//引入ElementPlus
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
app.use(ElementPlus)
app.mount('#app')

由于emlementPlus默认是英文,故还需配置成为中文
在main.ts中全局配置

// 全局注册
app.component('SvgIcon', SvgIcon)
//引入ElementPlus
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
//ElementPlus配置为中文
import zhCn from 'element-plus/es/locale/lang/zh-cn'
app.use(ElementPlus,{locale: zhCn,size: 'small',})
app.mount('#app')

此时即可正常使用

<template><div>
<el-button type="success">Success</el-button>
<el-popconfirm title="Are you sure to delete this?"><template #reference><el-button>Delete</el-button></template></el-popconfirm></div>
</template>

配置路由vue-router

1. 建立页面级别组件

在views文件夹下建立页面

2. 配置路由地址和页面级别组件的一一对应关系

安装路由npm install vue-router
在router/index.ts中

import { createRouter,createWebHashHistory} from "vue-router"//路由的配置数组,路径与页面的对映
const routes = []//路由实例
const router = createRouter({routes,history:createWebHashHistory(),
})//暴露
export default  router

在main.ts中使用路由

const app = createApp(App)
// 引入SvgIcon组件
import SvgIcon from "@/components/SvgIcon.vue";
// 全局注册
app.component('SvgIcon', SvgIcon)
//引入ElementPlus
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
//ElementPlus配置为中文
import zhCn from 'element-plus/es/locale/lang/zh-cn'app.use(ElementPlus,{locale: zhCn,size: 'small',})//导入路由import router from './router';app.use(router)app.mount('#app')

3. 给出口测试

在App.vue文件中配置一级路由出口

<!-- 一级路由出口 --><router-view></router-view>

在layout.vue文件中配置二级路由出口

<!-- 二级路由出口 --><router-view></router-view>

4.配置路由&路由自定义约束

在types文件下新建文件router.d.ts

//路由扩展types/router.d.tsimport type { RouteRecordRaw } from "vue-router";interface metaItem {title?: stringpath?: string
}interface RouteItem {hidden?: Booleanobj?: metaItem // 测试使用children?: RoutesType
}type myRouteType = RouteRecordRaw & RouteItemexport type RoutesType = Array<myRouteType>

在router/index.ts中

import { createRouter,createWebHashHistory} from "vue-router";
// import type { RouteRecordRaw } from "vue-router";import Layout from '@/views/layout/index.vue'//路由的配置数组,路径与页面的对映
import { RoutesType } from "../../types/router";const routes:RoutesType = [//登录{path:'/login',component:() => import('@/views/login/index.vue')},//数据中心{path:'/data',component: Layout,children: [{path: '',component: () => import('@/views/data/index.vue')}]},//用户管理{path:'/account',component: Layout,redirect:'/account/list',children: [{path: '/account/list',component: () => import('@/views/account/account-list.vue')},{path: '/account/add',component: () => import('@/views/account/account-add.vue')},{path: '/account/personal',component: () => import('@/views/account/personal.vue')}]},//文章管理{path:'/article',component: Layout,children: [{path: '',component: () => import('@/views/article/index.vue')}]},//excel管理{path:'/excel',component: Layout,redirect:'/excel/import',children: [{path: '/excel/import',component: () => import('@/views/excel/excel-import.vue')},{path: '/excel/export',component: () => import('@/views/excel/excel-export.vue')}]},//配置404{path: '/:pathMatch(.*)*',component: () => import('@/views/404/index.vue')}
]//路由实例
const router = createRouter({routes,history:createWebHashHistory(),
})//暴露
export default  router

主界面建框架

创建组件,实现大体框架布局

左边菜单栏

在leftMenu.vue中
引入menu组件

<template><div class="left-menu"><el-menudefault-active="/data"class="el-menu-vertical-demo"background-color="var(--el-color-danger-light-3)"text-color="var(--el-bg-color)"active-text-color="var(--el-color-danger-light-8)"unique-openedrouter><el-menu-item index="/data"><el-icon><svg-icon name="icon-shuju"/></el-icon><span>数据中心</span></el-menu-item><el-sub-menu index="1"><template #title><el-icon><svg-icon name="icon-yonghu"/></el-icon><span>用户管理</span></template><el-menu-item index="/account/list">用户列表</el-menu-item><el-menu-item index="/account/add">添加用户</el-menu-item><el-menu-item index="/account/personal">个人中心</el-menu-item></el-sub-menu><el-menu-item index="/article"><el-icon><svg-icon name="icon-bianjiwenzhang_huaban"/></el-icon><span>文章管理</span></el-menu-item><el-sub-menu index="2"><template #title><el-icon><svg-icon name="icon-file-excel"/></el-icon><span>excel管理</span></template><el-menu-item index="/excel/import">excel导入</el-menu-item><el-menu-item index="/excel/export">excel导出</el-menu-item></el-sub-menu>     </el-menu></div>
</template><script setup lang="ts"></script><style scoped>
.left-menu{background-color:#f89898;
}
</style>

解决菜单栏右侧边框问题

.el-menu {border-right: none !important;
}

默认选中菜单第一个default-active="/data"

点击菜单栏显示对应组件内容

添加router,配置index为对应路径
拿到路由信息对象

<script setup lang="ts">
import { useRoute } from 'vue-router';const $route = useRoute()
console.log($route.path);
</script>

再修改默认激活路径为:default-active="$route.path"

主要显示内容设置动画效果transition

vue3中内置组件transition官网地址:transition
在mainContent.vue中

<template><div class="p15"><!-- 二级路由出口 --><router-view v-slot="{ Component }"><transition name="fade" mode="out-in"><component :is="Component"></component></transition></router-view></div>
</template>
导航菜单栏折叠与收起

设置折叠收起按钮图标,安装:npm install @element-plus/icons-vue
引入:

<script setup lang="ts">
import { Expand } from "@element-plus/icons-vue"
</script>

使用:

<el-icon size="20" class="cursor-pointer"><Expand /></el-icon>

点击图标菜单栏折叠或收起,要修改collapse的值为true或false,将其存到pinia中
安装pinia:npm install pinia
在main.ts中

  //引入pinia并创建import { createPinia } from 'pinia'app.use(createPinia())

在store/index.ts中定义

//定义仓库
import { defineStore } from 'pinia'
import { ref } from 'vue'export const useStore = defineStore('app',() =>  {//定义collapse动态数据let collapse = ref<boolean>(false)return {collapse,}})

在leftMenu.vue中获取响应式collapse并修改:collapse="collapse"

import { useStore } from '@/store';
import { computed } from 'vue';//获取store的实例
const $appStore = useStore()
//获取响应式collapse
let collapse = computed(() => $appStore.collapse)
console.log(collapse);

在store/index.ts中

 //修改collapseconst changeCollapse = () =>{collapse.value = !collapse.value}return {collapse,changeCollapse}

在mainTo.vue中实现点击图标切换及左侧菜单栏改变

<template><div class="right-top df aic plr15"><el-icon @click="changeCollapse" size="20" class="cursor-pointer"><Expand v-show="collapse" /><Fold v-show="!collapse"/></el-icon>
右侧顶部</div>
</template><script setup lang="ts">
import { Expand,Fold } from "@element-plus/icons-vue"
import { useStore } from "@/store"
import { computed } from 'vue';//获取store对象
const $appStore = useStore()
const { changeCollapse } = $appStore
// console.log(changeCollapse);
const collapse = computed(() => $appStore.collapse)</script><style scoped lang="scss">
.right-top{height:40px;background-color:#fcd3d3;
}
</style>

若@符号无法识别,飘红找不到模块则在tsconfig,json中配置

"noEmit": true,"baseUrl": "./","paths": {"@/*": ["src/*"],"@": ["src"],"~/*": ["types/*"]}
侧边栏hooks适配

在store/index.ts中

//设置collapse的值const setCollapse = (val : boolean) =>{collapse.value=val}return {collapse,changeCollapse,setCollapse}

在hooks文件夹下新建useResize.ts文件

import { useStore } from "@/store"
import { onMounted, onUnmounted } from "vue"//在函数中监听屏幕的变化
export const useResize = () => {const minW = 700//屏幕固定值const $appStore = useStore()const { setCollapse } = $appStoreconst $_resize = () => {//获取屏幕的宽const w = document.body.clientWidthif (w > minW) {setCollapse(false)} else {setCollapse(true)}}onMounted(() => {$_resize()//初始化时要走一次故要调用一次window.addEventListener('resize', $_resize)})onUnmounted(() => {window.removeEventListener('resize', $_resize)})
}

在layout/index.ts中调用函数

//引入屏幕变化后 侧边栏状态变化的hooks函数
import {useResize} from "@/hooks/useResize"
useResize()

右边面包屑

静态–>使路由动态起来->配置路由下的meta,拿到title和path,凑成一个数组循环面包屑
router/index.ts

const routes: RoutesType = [//登录{path: '/login',component: () => import('@/views/login/index.vue')},//数据中心{path: '/data',component: Layout,meta: { title: '数据中心', path: '/data' },children: [{path: '',component: () => import('@/views/data/index.vue')}]},//用户管理{path: '/account',component: Layout,meta: { title: '用户管理', path: '/account' },redirect: '/account/list',children: [{path: '/account/list',meta: { title: '用户列表', path: '/account/list' },component: () => import('@/views/account/account-list.vue')},{path: '/account/add',meta: { title: '用户添加', path: '/account/add' },component: () => import('@/views/account/account-add.vue')},{path: '/account/personal',meta: { title: '个人中心', path: '/account/personal' },component: () => import('@/views/account/personal.vue')}]},//文章管理{path: '/article',component: Layout,meta: { title: '文章管理', path: '/article' },children: [{path: '',component: () => import('@/views/article/index.vue')}]},//excel管理{path: '/excel',component: Layout,meta: { title: 'excel管理', path: '/excel' },redirect: '/excel/import',children: [{path: '/excel/import',meta: { title: 'excel导入', path: '/excel/import' },component: () => import('@/views/excel/excel-import.vue')},{path: '/excel/export',meta: { title: 'excel导出', path: '/excel/export' },component: () => import('@/views/excel/excel-export.vue')}]},//配置404{path: '/:pathMatch(.*)*',component: () => import('@/views/404/index.vue')}
]

在mainTop.vue中,通过获取路由信息获取meta对象,判断matched是否为非空,非空则添加到循环数组中,点击菜单之后,面包屑也应该变化,故每点击一次,数据重新获取一次,将重新获取的数据添加到循环数组中,获取重新获取到的数据可以用:监听,计算属性,watchEffect

计算属性获取面包屑
import { useRoute } from 'vue-router'
import { metaItem } from '~/router'
//获取store对象
const $appStore = useStore()
const { changeCollapse } = $appStore
// console.log(changeCollapse);
const collapse = computed(() => $appStore.collapse)// 通过获取路由信息获取meta对象,判断matched是否为非空,非空则添加到循环数组中
//点击菜单之后,面包屑也应该变化,故每点击一次,数据重新获取一次,将重新获取的数据添加到循环数组中
//获取重新获取到的数据可以用:监听,计算属性,watchEffect
// 获取meta
const $route = useRoute()
console.log(111,$route.matched);
//计算属性设置面包屑
const breadList = computed(() => {let arr:Array<metaItem> =[]//循环当前路由下的meta$route.matched.forEach(item => {//判断当前meta是否有title或pathif(item.meta?.title){arr.push(item.meta)}})return arr
})
侦听器设置面包屑
import { computed,watch,ref} from 'vue';
//侦听器设置面包屑-监听某一个属性(),回调,立即执行
let breadList2 = ref<Array<metaItem>>([])
watch($route,()=>{breadList2.value=[]$route.matched.forEach(item => {//判断当前meta是否有title或pathif(item.meta?.title){breadList2.value.push(item.meta)}})},{immediate:true //立即执行}
)
watchEffect设置面包屑
import { computed,watch,ref,watchEffect} from 'vue';
//watcheffect设置面包屑  副作用监听 会初始化执行里面代码 里面有响应式数据变化都会执行代码
let breacList3 = ref<Array<metaItem>>([])
const stop = watchEffect((deCleanr) => {breacList3.value = []$route.matched.forEach(item => {if (item.meta?.title) {breacList3.value.push(item.meta)}})deCleanr(() => {// 清除副作用})
})
// 调用stop函数后,watchEffect将停止监听
stop()

右侧下拉菜单的实现,点击退出登录

<el-dropdown @command="handleCommand"><span class="el-dropdown-link">欢迎您,xxx<el-icon class="el-icon--right"><arrow-down /></el-icon></span><template #dropdown><el-dropdown-menu><el-dropdown-item command="/login">退出登录</el-dropdown-item></el-dropdown-menu></template></el-dropdown>
import { useRoute, useRouter } from "vue-router";
//下拉菜单的事件
const $router = useRouter();
const handleCommand = (command: string) => {$router.push(command);
};

登录页面

静态

登录验证实现

<template><div class="login df aic jcc"><div class="mr-1"><h2 class="font-weight">我是文字我是文字</h2><h1 class="font-weight mt-2 border-bottom-c pb-1">我是文字</h1><h2 class="font-weight mt-2">我是文字我是文字</h2></div><div class="right rounded p15"><h2 class="font-weight mb-3">欢迎登录</h2><el-form :model="loginFormData" :rules="rules" status-icon ref="loginFormRef"><el-form-item prop="account"><el-input v-model="loginFormData.account"><template #prefix><el-icon class="el-input__icon"><svg-icon name="icon-yonghu1"></svg-icon></el-icon></template></el-input></el-form-item><el-form-item prop="password"><el-input v-model="loginFormData.password" type="password"><template #prefix><el-icon class="el-input__icon"><svg-icon name="icon-tianchongxing-1"></svg-icon></el-icon> </template></el-input></el-form-item><el-form-item><el-button type="primary" class="login-btn" @click="handleLogin(loginFormRef)">登录</el-button></el-form-item></el-form></div></div>
</template><script setup lang="ts">
import { ref,reactive } from "vue";
import type { FormInstance, FormRules } from 'element-plus';
import { useRouter } from "vue-router"
//登录数据约束
interface loginForm {account: string;password: string;
}
//登录数据
const loginFormData = ref<loginForm>({account: "",password: "",
});
const loginFormRef = ref<FormInstance>()
const $router = useRouter()
//验证规则
const rules = reactive<FormRules>({account: [{ required: true, message: "请输入账号", trigger: "blur" },{ min: 3, max: 6, message: "账号需为3-6位", trigger: "blur" },],password: [{ required: true, message: "请输入密码", trigger: "blur" },{ min: 6, max: 12, message: "密码需为6-12位", trigger: "blur" },],
});//登录函数
const handleLogin = (formEl: FormInstance | undefined) => {if(!formEl) returnformEl.validate((valid)=>{$router.push('/data')})
}
</script><style scoped lang="scss">
.login {height: 100%;background-color: #e5e5e5;.right {width: 240px;height: 260px;background-color: white;.login-btn {width: 100%;}}
}
</style>

基于vue3+ts+scss的后台管理系统(一)相关推荐

  1. 基于vue3+ts+scss的后台管理系统(二)----excel的导入导出

    excel的导入导出 官网地址 https://docs.sheetjs.com/docs/getting-started/installation/standalone 安装XLSX插件:npm i ...

  2. 用 Vite+Vue3+Ts 搭建通用后台管理系统

    大厂技术  高级前端  Node进阶 点击上方 程序员成长指北,关注公众号 回复1,加入高级Node交流群 通用后台管理系统整体架构方案(Vue) 项目创建,脚手架的选择(vite or vue-cl ...

  3. 用vite+Vue3+ts搭建通用后台管理系统

    点击上方关注 前端技术江湖,一起学习,天天进步 通用后台管理系统整体架构方案(Vue) 项目创建,脚手架的选择(vite or vue-cli) vue-cli基于webpack封装,生态非常强大,可 ...

  4. 基于angular4+ng-bootstrap+bootstrap+scss的后台管理系统界面

    描述 在angular2刚才发布的不久,很多人不懂得怎么应用,直到现在也很多人不懂怎么用, 于是我在余业时间做了这么一个后台管理系统页面,希望对大家有帮助!! 从我个人的感觉来说,angular2语法 ...

  5. vue3+ts通用管理后台练习项目

    vue3-ts-cms 项目概述 一个基于 RBAC 设计的通用后台管理系统,支持通过配置文件批量完成特定功能,如搜索.表格数据显示,导入.导出.项目中封装了大量通用组件,如表单.表格.Echarts ...

  6. 基于Vue3+TS+Vite+Cesium创建项目

    基于Vue3+TS+Vite+Cesium创建项目 基于Vite构建项目 安装配置Cesium 创建Cesium三维视图 运行结果 随着近几年社会的发展,人们对三维可视化的需求也是越来越多,三维GIS ...

  7. .net宿舍管理系统 mysql_基于.NET CORE的精美后台管理系统-RuoYi C#版

    若依(RuoYi)是码云上一款精美的开源快速开发平台,作者毫无保留给个人及企业免费使用.RuoYi目前有三个版本:普通版本(RuoYi).前后端分离版本(RuoYi-Vue).微服务版本(RuoYi- ...

  8. 基于 Springboot 和 Mybatis 的后台管理系统 BootD

    源码名称:基于 Springboot 和 Mybatis 的后台管理系统 BootD 下载地址:https://www.chtml.cn/product/show/10867 项目介绍 面向学习型的开 ...

  9. Python VUE3 + Django Ninja的后台管理系统

    Python VUE3 + Django Ninja的后台管理系统 为什么使用 Django-Ninija 和 Vue3

最新文章

  1. 阿里云云服务器ECS上的Ubuntu16.04桌面安装及root账户登录错误处理
  2. 圆你“鸟人”梦,全身VR模拟飞行器Birdly带你飞
  3. 【转】强大的B树B+树
  4. Java自动化邮件中发送图表(一)
  5. ElasticSearch快速入门二(Restful介绍)
  6. java 无法import_ImportError:无法导入名称X
  7. Spring boot 之 dubbo 无xml 简单入门
  8. 2014阿里实习生面试题——mysql如何实现的索引
  9. matlab 自动交易系统设计2
  10. 北理珠计算机专业在广东排第几,重磅!省内同类院校第一 北理珠2019广东投档线公布!...
  11. 捕获javaw的输出
  12. ArcEngine中的ICommand和ITool
  13. python聊天智能回复_【微信】设置自动回复消息和智能聊天
  14. excel统计每个单元格内的单词及空格的个数
  15. 对计算机的认识与感想
  16. NO.15——使用Appium自动化测试爬取微信朋友圈数据
  17. 我给小楠讲历史—上下五千年
  18. VDI云桌面功能目标
  19. 西北工业大学大学物理(II)下2020-2021选填考题解析
  20. 注意力经济时代,网红是下一个风口?

热门文章

  1. 易点云冲刺上市:亏损收窄、债务高企,租电脑的生意能否长久?
  2. 《编译原理》求短语,直接短语,句柄,素短语,最左素短语 - 例题解析
  3. http ,https 等常用的默认端口号
  4. 加盐密码哈希:如何正确使用 (密码加密的经典文章)
  5. uni-app常见的生命周期
  6. 如何使用Nginx防御DDoS攻击?
  7. C语言习题:输入10个学生5门课的成绩,分别用函数求:①每个学生平均分;②每门课的平均分;③找出所有分数中最高分
  8. 《攻守道》笔记(3)
  9. Android11 热点开启流程
  10. IP地址这么重要的知识,居然听一个学弟说没用?