wordpress博客主题哪个好,东莞网站排名优化报价,天津建设工程信息网 官网首页,免费推广网站怎么做距离vue2学习已经一年度了#xff0c;现在开始vue3的学习。
一、webpack
#xff08;1#xff09;创建列表隔行变色项目及webpack使用#xff1a;
新建项目空白目录#xff0c;并运行npm init -y命令#xff0c;初始化包管理配置文件package.json#xff1b;
新建sr…距离vue2学习已经一年度了现在开始vue3的学习。
一、webpack
1创建列表隔行变色项目及webpack使用
新建项目空白目录并运行npm init -y命令初始化包管理配置文件package.json
新建src源代码目录新建src - index.html首页和src - index.js脚本文件初始化首页基本的结构 运行npm install jquery -s命令安装jQuery通过ES6模块化的方式导入jQuery实现列表隔行变色效果。其中ul-li快速创建ulli{这是第$个li}*9回车。
webpack可以帮助用户将兼容性代码转为非兼容性代码
在代码文件根目录执行命令
cnpm i webpack-dev-server webpack-cli webpack -D
2webpack使用
①在项目根目录创建名为webpack.config.js的webpack配置文件并初始化如下的配置文件:
module.exports {mode: development // mode 用来制定构建模式可选值有development 和 production
}
②在package.json的scripts节点下添加dev脚本如下
scripts: {test: echo \Error: no test specified\ exit 1,dev: webpack },
③在终端中运行npm run dev命令启动webpack进行项目的打包构建。会生成dist文件夹(里面是main.js)index.html引入的js替换为../dist/main.js这样html就可以正常运行了。
3webpack.config.js 文件的作用
webpack.config.js 是 webpack的配置文件。webpack在真正开始打包构建之前会先读取这个配置文件从而基于给定的配置对项目进行打包。 注意由于webpack是基于node.js 开发出来的打包工具因此在它的配置文件中支持使用node.js 相关的语法和模块进行webpack的个性化配置。
4webpack中的默认约定
》在webpack中有如下的默认约定: ①默认的打包入口文件为src - index.js ②默认的输出文件路径为dist - main.js 注意:可以在webpack.config.js中修改打包的默认约定
》自定义打包的入口与出口 在webpack.config.js配置文件中通过entry节点指定打包的入口。通过output节点指定打包的出口。示例代码如下:
const path require(path)
module.exports {mode: development, // mode 用来制定构建模式可选值有development 和 productionentry: path.join(__dirname, ./src/index.js), // 打包入口文件的路径output: {path: path.join(__dirname, ./dist), //输出文件的存放路径filename: bundle.js // 输出文件的名称}
}5webpack插件的作用
通过安装和配置第三方的插件,可以拓展webpack的能力从而让webpack用起来更方便。最常用的webpack插件有如下两个: ①webpack-dev-server ●类似于node.js阶段用到的nodemon工具 ●每当修改了 源代码, webpack会自动进行项目的打包和构建即package.json的scripts节点的dev值改为“webpack serve”
②html-webpack-plugin ●webpack 中的HTML插件( 类似于于一个模板引擎插件) ●可以通过此插件自定制index.html页面的内容
cnpm i html-webpack-plugin -D
配置方式 效果如下
const path require(path)
// 导入插件得到构造函数
const HtmlPlugin require(html-webpack-plugin)
// 创建插件的实例对象
const htmlPlugin new HtmlPlugin({template: ./src/index.html,filename: ./index.html
})module.exports {mode: development, // mode 用来制定构建模式可选值有development 和 productionentry: path.join(__dirname, ./src/index.js), // 打包入口文件的路径output: {path: path.join(__dirname, ./dist), //输出文件的存放路径filename: bundle.js // 输出文件的名称},plugins: [htmlPlugin] // 挂载插件的实例对象
}注意通过HTML插件复制到项目根目录中的index.html页面也被放到了内存中HTML插件在生成的index.html页面的底部自动注入了打包的bundle.js 文件。
6devServer节点
在webpack.config.js配置文件中可以通过devServer节点对webpack-dev-server插件进行更多的配置open初次打包之后直接打开浏览器、host实时打包所用的主机地址、portd端口号
7loader
在实际开发过程中webpack默认只能打包处理以.js后缀名结尾的模块。其他非.js后缀名结尾的模块webpack 默认处理不了需要调用loader加载器才可以正常打包否则会报错!
7.1 处理css的loader
在index.js里面导入cssimport ./css/index/css
①npm i style-loader css-loader -D安装css的loader②在webpack.config.js的module-rules数组里面添加规则其中test表示匹配的文件烈性use表示要调用的loader,loader顺序不能错。
module: {rules: [{ test: /\.css$/, use: [style-loader, css-loader] }]} 7.2 处理less的loader ①运行npm i less-loader less -D命令②在webpack.config.js的moudle-rules数组添加规则
rules: [{ test: /\.css$/, use: [style-loader, css-loader] },{ test: /\.less$/, use: [style-loader, css-loader, less-loader] }]
其中安装的less是less-loader的内置依赖项。
7.3 打包处理样式表中与url相关的文件
在webpack5中url-loader、file-loader已经弃用。
二、vue3简介
1. vue3的优势
更容易维护组合式API更好的TypeScript支持更快的速度重写diff算法模版变异优化更高效的组件初始化更小的提价良好的TreeShaking,按需引入更优的数据响应式Proxy
2. 认识create-vue
creat-vue是Vue官方新的脚手架工具底层切换到了vite(下一代构建工具)。
前提环境条件node 版本高于16.0。创建一个vue应用npm init vuelastest这一指令将会安装并执行Create-vue。安装慢的话需要用到npm 使用快速的安装源(nrm)npm 使用快速的安装源(nrm) - 编程教程 按照绿字的提示输入命令这样就可以打开一个vue3的项目了。使用vscode打开该项目查看项目结构和目录。
vue2项目的main.js使用new vue()创建一个应用实例vue3使用createApp() / createRouter() createStore()将创建实例进行了封装保证每个实例的独立封闭性mount设置挂载点#app(id魏app的盒子即index.html里面id为app的div)。vue3需要vscode安装volar插件具体如下 3. 组合式api
3.1 setup
3.1.1、setup选项的执行时机beforeCreate钩子之前自动执行 3.1.2.、setup写代码的特点定义数据函数然后以对象方式return 3.1.3、script setup解决了什么问题?经过语法糖的封装更简单的使用组合式API 3.1.4、setup中的this还指向组件实例吗?指向undefined
3.2 reactive和ref函数
推荐声明数据统一使用ref。
3.2.1 reactive()
作用接受对象函数类型数据的参数传入并返回一个响应式的对象
步骤从vue包导入reactive函数在script setup中执行reactive函数并传入类型为对象的初始值并使变量接收返回的值。 3.2.2 ref()
作用接受简单类型或复杂类型返回一个响应式的对象本质上是在原有传入数据的基础上外层包了一层对象包成了复杂类型。
注意点script访问数据需要通过.valuetemplate里面不需要.value
3.3、computed计算属性函数
计算属性基本思想和Vue2的完全一致组合式API下的计算属性只是修改了写法。
核心步骤1.导入computed函数2.执行函数在回调参数中return基于响应式数据做计算的值用变量接收。 注意1计算属性中不应该有“副作用”比如异步请求/修改dom2避免直接修改计算属性的值计算属性应该是只读的特殊情况可以配置get set参见响应式 API核心 | Vue.js。 3.4、watch
3.4.1 侦听单个数据
1导入watch函数2执行watch函数传入要侦听的响应式数据ref对象 和回调函数。 3.4.2 侦听多个数据
同时侦听多个响应式数据的变化不管哪个数据变化都要触发回调。 3.4.3 immediate
说明在侦听器创建时立即触发回调响应式数据变化之后继续执行回调。 3.4.4 deep:true
说明深度监视默认watch进行的是浅层监视const ref1 ref(简单类型可以直接监视const ref2 ref(复杂类型监视不到复杂类型内部数据的变化。
如果不开启deep的前提要精确侦听对象的某个属性如下写法 3.4.5 总结
1作为watch函数的第一个参数ref对象要添加.value吗?不要第一个参数就是传ref 对象
2watch只能侦听单个数据吗?单个或者多个
3不开启deep直接监视复杂类型修改属性能触发回调吗?不能默认是浅层侦听。
4不开启deep精确侦听对象的某个属性?可以把第一个参数写成函数的写法返回要监听的具体属性。
3.5、生命周期函数 比如 3.6、父子通信
3.6.1 父传子
基本思想父组件给子组件绑定属性子组件内部通过props选项接收。 子组件由于写了setup所以无法直接配置 props选项所以此处需要借助于“编译器宏”函数接收子组件传递的数据对于props传递过来的数据模板中可以直接使用。
3.6.2 子传父
基本思想父组件中给子组件标签通过绑定事件子组件内部通过emit方法触发事件。 3.6.3 总结
3.6.3.1 父传子
1父传子的过程中通过什么方式接收props? defineProps({属性名:类型}) 2setup语法糖中如何使用父组件传过来的数据? const props defineProps({属性名:类型}) props.xxx
3.6.3.2 子传父
1子传父的过程中通过什么方式得到emit方法? defineEmits([事件名称]) 2怎么触发事件 emit(自定义事件名参数)
3.7、模板引用
通过ref标识获取真实的dom对象或者组件实例对象。 通过ref函数生成一个ref对象名称要和模版元素ref一致通过ref标识绑定ref对象到标签。 默认情况下在script setup语法糖下组件内部的属性和方法是不开放给父组件访问的,可以通过defineExpose编译宏指定哪些属性和方法允许访问。 总结
获取模板引用的时机是什么?组件挂载完毕 defineExpose编译宏的作用是什么?显式暴露组件内部的属性和方法
3.8、provide和inject
跨层传递普通数据1.顶层组件通过provide函数提供数据2.底层组件通过inject函数获取数据。
跨层传递响应式数据在调用provide函数时第二个参数设置为ref对象。
跨层传递方法顶层组件可以向底层组件传递方法底层组件调用方法修改顶层组件中的数据
4、vue3.3新特性
背景说明: 有script setup之前如果要定义propsemits 可以轻而易举地添加一个与setup平级的属性。但是用了script setup后就没法这么干了setup属性已经没有了自然无法添加与其平级的属性。 为了解决这一问题引入了defineProps 与defineEmits 这两个宏。但这只解决了props与emits这两个属性。如果我们要定义组件的name或其他自定义的属性还是得回到最原始的用法——再添加一个普通的script标签。这样就会存在两个script标签。让人无法接受。 所以在Vue 3.3中新引入了defineOptions宏。顾名思义主要是用来定义Options API的选项。可以用defineOptions定义任意的选项props, emits, expose, slots 除外因为这些可以使用defineXXX来做到)
4.1、defineOptions 4.2、defineModel
在Vue3中自定义组件上使用v-model相当于传递一个modelvalue属性同时触发 update:modelvalue 事件。我们需要先定义props再定义emits。其中有许多重复的代码。如果需要修改此值还需要手动调用emit 函数。 如果使用defineModel代码如下需要修改vite.config.js开启defineModel重启 5、Pinia
Pinia使Vue3的官方状态管理工具是Vuex的替代品。
1提供更加简单的API去掉了mutation ) 2提供符合组合式风格的API和Vue3新语法统一) 3去掉了modules的概念每一个store都是一个独立的模块 4配合TypeScript更加友好提供可靠的类型推断
5.1、使用
按照官方文档安装pinia到项目。Pinia | Pinia
5.1.1 开始
// main.js
import { createApp } from vue
import App from ./App.vue
import { createPinia } from piniaconst pinia createPinia()
const app createApp(App)app.use(pinia).mount(#app)
5.1.2 定义store
// /store/counter.js
import { defineStore } from pinia
import { computed, ref } from vueexport const useCounterStore defineStore(counter, () {const count ref(0)const increment () {count.value}const decrement () {count.value--}const double computed(() count.value * 2)const msg ref(hello pinia)return { count, msg, double, increment, decrement }
})// /store/channels.js 支持异步
import { defineStore } from pinia
import { ref } from vue
import axios from axiosexport const useChannelStore defineStore(channel, () {// 声明数据const channelList ref([])// 声明操作数据的方法const getList async () {const {data: { data }} await axios.get(http://geek.itheima.net/V1_0/channels)channelList.value data.channelsconsole.log(data.channels)}// 声明getters相关return { channelList, getList }
})5.1.3 使用store
!-- App.vue子组件可忽略 --
script setup
import Son1 from /components/SonView1.vue
import Son2 from /components/SonView2.vueimport { useCounterStore } from /store/counter
const counterStore useCounterStore()
import { useChannelStore } from /store/channel.js
const channelStore useChannelStore()
/scripttemplatedivh3APP.vue根组件 -{{ counterStore.count }} -{{ counterStore.msg }} - {{ counterStore.double }}/h3Son1 /Son2 /hr /button typebutton clickchannelStore.getListchannel/buttonulli v-foritem in channelStore.channelList :keyitem.id{{ item.name }}/li/ul/div
/templatestyle scoped/style
另一种写法为了从 store 中提取属性时保持其响应性你需要使用 storeToRefs()。它将为每一个响应式属性创建引用。当你只使用 store 的状态而不调用任何 action 时它会非常有用。请注意你可以直接从 store 中解构 action因为它们也被绑定到 store 上。
// 官网代码
script setup
import { storeToRefs } from pinia
const store useCounterStore()
// name 和 doubleCount 是响应式的 ref
// 同时通过插件添加的属性也会被提取为 ref
// 并且会跳过所有的 action 或非响应式 (不是 ref 或 reactive) 的属性
const { name, doubleCount } storeToRefs(store)
// 作为 action 的 increment 可以直接解构
const { increment } store
/script
5.1.4 pinia持久化插件
官方文档快速开始 | pinia-plugin-persistedstate
1安装插件npm i pinia-plugin-persistedstate
2main.js使用
// main.js
import { createApp } from vue
import App from ./App.vue
import { createPinia } from pinia
import persist from pinia-plugin-persistedstateconst pinia createPinia()
const app createApp(App)app.use(pinia.use(persist)).mount(#app)3store仓库中pereist:true开启
5.1.5 总结
1Pinia是用来做什么的?新一代的状态管理工具替代vuex 2Pinia中还需要mutation吗?不需要action既支持同步也支持异步 3Pinia如何实现getter?computed计算属性函数 4Pinia产生的Store如何解构赋值数据保持响应式?storeToRefs 5Pinia 如何快速实现持久化?pinia-plugin-persistedstate
6. 项目大事件管理系统
简介使用vue3 compositionAPIPinia/Pinia持久化处理Element Plus表单校验、表格处理、组件封装pnpm包管理升级Eslintprettier更规范的配置huskyGit hooks工具代码提交之前进行校验球球模块设置VueRouter4路由设计AI大模型开发一整个项目模块掌握最新的开发方式
6.1 pnpm包管理器
一些优势:比同类工具快2倍左右、节省磁盘空间... https://www.pnpm.cn/
安装方式:npm install -g pnpm 创建项目pnpm create vue。注意不要在磁盘根目录创建项目否则可能报权限不足。 6.2 Eslint配置代码风格
配置文件.eslintrc.cjs
1prettier风格配置https://pretties.io。禁用prettier code format插件安装Eslint插件 修改.eslintrc.cjs
module.exports {...rules: {// 禁用格式化插件prettier format on save,// 安装Eslint插件并配置保存时自动修复。// prettier关注代码美观度prettier/prettier: [warn,{singleQuote: true, // 单引号semi: false, // 无分号printWidth: 80, // 每行宽度至多80字符trailingComma: none, // 不加对象|数组最后逗号endOfLine: auto // 换行符号不限制win mac 不一致}],// eslint关注规范vue/multi-word-component-names: [warn,{ignores: [index] // vue组件名称多单词组成忽略index.vue}],vue/no-setup-props-destructure: [off], // 关闭 props 解构的校验// 添加未定义变量错误提示create-vue3.6.3 关闭这里加上是为了支持下一个章节演示。no-undef: error}
}
2修改vscode的setting.json:
...
editor.formatOnSave: false, // #值设置为true时每次保存的时候自动格式化
editor.codeActionsOnSave: {source.fixAll: true
},
...
6.3 提交前做代码检查
6.3.1 husky
husky是一个git hooks工具( git的钩子工具可以在特定时机执行特定的命令)
1初始化git仓库执行git init即可。
2初始化husky工具配置执行pnpm dlx husky-init pnpm install 即可、https://typicode.github.io/husky/
3修改.husky/pre-commit文件。
#!/usr/bin/env sh
. $(dirname -- $0)/_/husky.sh# npm test
pnpm lint
pnpm lint检验的是全部代码。
6.3.2 暂存区eslint校验
1. 安装lint-staged包pnpm i lint-staged -D 2. package.json配置lint-staged命令
jsx
{// ... 省略 ...lint-staged: {*.{js,ts,vue}: [eslint --fix]}
}
{scripts: {// ... 省略 ...lint-staged: lint-staged}
}3. .husky/pre-commit文件修改
jsx
pnpm lint-staged6.4 目录调整
默认生成的目录结构不满足我们的开发需求所以这里需要做一些自定义改动。主要是以下工作: 1.删除一些初始化的默认文件主要是components、assets、router/index.js 2.修改剩余代码内容主要是App.vue 3.新增调整我们需要的目录结构;比如api文件夹 4.拷贝全局样式和图片安装预处理器支持:pnpm add sass -D
6.5 Vue-Router4 路由代码解析
6.5.1 路由初始化 以上为Vue2 Vue3的router变化
1创建路由实例由createRouter 实现 2路由模式history模式使用createwebHistory()hash模式使用createWebHashHistory()参数是基础路径默认/
// router/index.js
import { createRouter, createWebHistory } from vue-router// createRouter创建路由实例
// 配置history模式
// 1. history模式:createwebHistory地址栏不带#
// 2. hash模式: createwebHashHistory地址栏带#
// vite环境变量import.meta.env.BASE_URL
const router createRouter({history: createWebHistory(import.meta.env.BASE_URL),routes: []
})export default router
修改import.meta.env.BASE_URL需要在vite.config.js添加base参数参看环境变量和模式 | Vite 官方中文文档
script setup
import { useRoute, useRouter } from vue-router
const router useRouter()
const route useRoute()const goList () {router.push(/list)console.log(router, route)
}
/scripttemplatedivAPP/divbutton click$router.push(/home)跳首页/buttonbutton clickgoList跳列表页/button
/templatestyle scoped/style
一种是直接在html里面使用$router.push()一种是在script里面用useRouter函数。
6.6 按需引入Element Plus
6.6.1 官网地址
设计 | Element Plus 6.6.2 步骤
// 1. 安装
pnpm install element-plus// 2. 插件
pnpm add -D unplugin-vue-components unplugin-auto-import// 3.修改vite.config.js的引入项以及plugins参数
import { fileURLToPath, URL } from node:urlimport { defineConfig } from vite
import AutoImport from unplugin-auto-import/vite
import Components from unplugin-vue-components/vite
import { ElementPlusResolver } from unplugin-vue-components/resolvers
import vue from vitejs/plugin-vue// https://vitejs.dev/config/
export default defineConfig({plugins: [vue(),AutoImport({resolvers: [ElementPlusResolver()]}),Components({resolvers: [ElementPlusResolver()]})],resolve: {alias: {: fileURLToPath(new URL(./src, import.meta.url))}}
})// 4. 重启服务button直接改成el-button即可无须导入。el-button click$router.push(/home)跳首页/el-buttonel-button clickgoList跳列表页/el-button默认components 下的文件也会被自动注册。
6.7 pinia构建用户仓库和持久化
6.7.1 示例目标 6.7.2 步骤
1新建stores仓库
// stores/user.js
import { defineStore } from pinia
import { ref } from vueexport const useUserStore defineStore(big-user,() {const token ref()const setToken (newToken) {token.value newToken}const removeToken () {token.value }return {token,setToken,removeToken}},{persist: true // 持久化}
)
2安装持久化插件
pnpm add pinia-plugin-persistedstate -D
3使用main.js
jsx import persist from pinia-plugin-persistedstate ... app.use(createPinia().use(persist))
4配置 stores/user.js
添加persist参数最终看上面的代码:
... { persist: true // 持久化 }
...
6.7.3 pinia仓库统一管理
1pinia独立维护由 stores 统一维护在 stores/index.js 中完成 pinia 初始化交付 main.js 使用
2仓库统一导出由 stores/index.js 统一导出导入路径统一 ./stores而且仓库维护在 stores/modules 中。
新建stores/index.js
// stores/index.js
import { createPinia } from pinia
import persist from pinia-plugin-persistedstateconst pinia createPinia().use(persist)pinia.use(persist)export default piniaexport * from ./modules/user
export * from ./modules/counter
修改main.js
// main.js
import { createApp } from vueimport pinia from ./stores/index.js
import App from ./App.vue
import router from ./router
import /assets/main.scssconst app createApp(App)app.use(pinia)
app.use(router)app.mount(#app)
修改app.vue
script setup
...
import { useUserStore, useCounterStore } from /stores
...
const userStore useUserStore()
const counterStore useCounterStore()
/script6.8 数据交互-请求工具设计
使用 axios 来请求后端接口, 一般都会对 axios 进行一些配置 (比如: 配置基础地址等)一般项目开发中, 都会对 axios 进行基本的二次封装, 单独封装到一个模块中, 便于使用。
新建 utils/request.js 封装 axios 模块利用 axios.create 创建一个自定义的 axios 来使用axios中文文档|axios中文网 | axios
import { useUserStore } from /stores
import axios from axios
import router from /router
import { ElMessage } from element-plusconst baseURL http://big-event-vue-api-t.itheima.netconst instance axios.create({// TODO 1. 基础地址超时时间baseURL,timeout: 100000
})
// 请求拦截器
instance.interceptors.request.use((config) {// TODO 2. 携带tokenconst userStore useUserStore()if (userStore.token) {config.headers.Authorization userStore.token // 根据实际使用修改}return config},(err) Promise.reject(err)
)
// 响应拦截器
instance.interceptors.response.use((res) {// TODO 3. 处理业务失败// TODO 4. 摘取核心响应数据if (res.data.code 0) {// 根据实际使用修改return res}ElMessage({ message: res.data.message || 服务异常, type: error })return Promise.reject(res.data)},(err) {ElMessage({message: err.response.data.message || 服务异常,type: error})console.log(err)// TODO 5. 处理401错误 权限不足或token过期if (err.response?.status 401) {router.push(/login)}return Promise.reject(err)}
)export default instance
export { baseURL }6.9 整体路由设计
6.9.1 实现目标
- 完成整体路由规划【搞清楚要做几个页面它们分别在哪个路由下面怎么跳转的.....】 - 通过观察, 点击左侧导航, 右侧区域在切换, 那右侧区域内容一直在变, 那这个地方就是一个路由的出口 - 我们需要搭建嵌套路由 - 把项目中所有用到的组件及路由表, 约定下来。
该项目的路由结构如下 import { createRouter, createWebHistory } from vue-router// createRouter创建路由实例
// 配置history模式
// 1. history模式:createwebHistory地址栏不带#
// 2. hash模式: createwebHashHistory地址栏带#
// vite环境变量import.meta.env.BASE_URL
const router createRouter({history: createWebHistory(import.meta.env.BASE_URL),routes: [{ path: /login, component: () import(/views/login/loginPage.vue) },{path: /,component: () import(/views/layout/LayoutContainer.vue),redirect: /article/manage,children: [{path: /article/manage,component: () import(/views/article/ArticleManage.vue)},{path: /article/channel,component: () import(/views/article/ArticleChannel.vue)},{path: /user/profile,component: () import(/views/user/UserProfile.vue)},{path: /user/avatar,component: () import(/views/user/UserAvatar.vue)},{path: /user/password,component: () import(/views/user/UserPassword.vue)}]}]
})export default router 6.9.2 登录注册
6.9.2.1 使用element-plus编写模型
1结构相关 el-row表示一行一行分成24份 el-col表示列 (1.1) :span12 代表在一行中占12份 (50%) (1.2) :span6 表示在一行中占6份 (25%) (1.3) :offset3 代表在一行中左侧margin份数 el-form 整个表单组件 el-form-item 表单的一行 一个表单域 el-input 表单元素输入框
2校验相关 (2.1) el-form :modelruleForm 绑定的整个form的数据对象 { xxx, xxx, xxx } (2.2) el-form :rulesrules 绑定的整个rules规则对象 { xxx, xxx, xxx } (2.3) 表单元素 v-modelruleForm.xxx 给表单元素绑定form的子属性 (2.4) el-form-item prop配置生效的是哪个校验规则 (和rules中的字段要对应)
6.9.2.2 script编写规则
1整个表单的校验规则 3.1非空校验 required: true message消息提示 trigger触发校验的时机 blur change 3.2长度校验 min:xx, max: xx 3.3正则校验 pattern: 正则规则 \S 非空字符 3.4自定义校验 自己写逻辑校验 (校验函数)
2 validator: (rule, value, callback) (4.1) rule 当前校验规则相关的信息 (4.2) value 所校验的表单元素目前的表单值 (4.3) callback 无论成功还是失败都需要 callback 回调 - callback() 校验成功 - callback(new Error(错误信息)) 校验失败
6.9.2.3 注册功能
封装注册api进行注册注册成功切换到登录
1新建 api/user.js 封装
import request from /utils/requestexport const userRegisterService ({ username, password, repassword }) request.post(/api/reg, { username, password, repassword })
2页面中调用
const register async () {await form.value.validate()await userRegisterService(formModel.value)ElMessage.success(注册成功)// 切换到登录isRegister.value false
}
3eslintrc 中声明全局变量名, 解决 ElMessage 报错问题
module.exports {...globals: {ElMessage: readonly,ElMessageBox: readonly,ElLoading: readonly}
}
6.9.2.4 登录前的预校验
1登录请求之前需要对用户的输入内容进行校验校验通过才发送请求。
2封装登录API点击按钮发送登录请求登录成功存储token存入pinia 和 持久化本地storage跳转到首页给提示
...
import { useUserStore } from /stores/
import { useRouter } from vue-router
......
const userStore useUserStore()
const router useRouter()
...
6.9.3 登录访问拦截
只有登录页可以未授权的时候访问其他所有页面都需要先登录再访问
// 登录访问拦截 默认是直接放行的
// 根据返回值决定是放行还是拦截
// 返回值
// 1. undefined / true 直接放行
// 2. false 拦回from的地址页面
// 3. 具体路径或路径对象拦截到对应的地址
// return /login 或 {name: login}
router.beforeEach((to) {const userStore useUserStore()if (!userStore.token to.path ! /login) return /login
})
6.9.4 用户基本信息获取渲染
1api/user.js封装接口
export const userGetInfoService () request.get(/my/userinfo)
2stores/modules/user.js 定义数据
const user ref({})
const getUser async () {const res await userGetInfoService() // 请求获取数据user.value res.data.data
} 3layout/LayoutContainer页面中调用
import { useUserStore } from /stores
const userStore useUserStore()
onMounted(() {userStore.getUser()
})
6.9.5 退出功能 [element-plus 确认框]
!-- 注册点击事件 --
el-dropdown placementbottom-end commandonCommandel-dropdown-menuel-dropdown-item commandprofile :iconUser基本资料/el-dropdown-itemel-dropdown-item commandavatar :iconCrop更换头像/el-dropdown-itemel-dropdown-item commandpassword :iconEditPen重置密码/el-dropdown-itemel-dropdown-item commandlogout :iconSwitchButton退出登录/el-dropdown-item
/el-dropdown-menu
// 添加退出功能
const onCommand async (command) {if (command logout) {await ElMessageBox.confirm(你确认退出大事件吗, 温馨提示, {type: warning,confirmButtonText: 确认,cancelButtonText: 取消})userStore.removeToken()userStore.setUser({})router.push(/login)} else {router.push(/user/${command})}
}
// pinia user.js 模块 提供 setUser 方法
const setUser (obj) {user.value obj}
三.项目练手
1、vue3知识回顾
1.1、setup选项的手法和执行时机 1setup选项的执行时机?beforeCreate钩子之前 自动执行 2setup写代码的特点是什么?定义数据 函数 然后以对象方式return 3script setup解决了什么问题?经过语法糖的封装更简单的使用组合式API 4setup中的this还指向组件实例吗?指向undefined
1.2 reactive 和 ref函数
reactive和ref有什么区别_ref和reactive的区别-CSDN博客
1reactive()作用: 接受对象类型数据的参数传入并返回一个响应式的对象
2ref()作用:接收简单类型或者对象类型的数据传入并返回一个响应式的对象
①reactive和ref函数的共同作用是什么?用函数调用的方式生成响应式数据 ② reactive vs ref ? 1.reactive不能处理简单类型的数据 2.ref参数类型支持更好但是必须通过.value访问修改 3.ref函数的内部实现依赖于reactive函数 ③在实际工作中推荐使用哪个?推荐使用ref函数更加灵活小免鲜项目主用ref
1.3 计算属性
最佳实践 1计算属性中不应该有“副作用。比如异步请求/修改dom 2避免直接修改计算属性的值。计算属性应该是只读的
1.4 watch
1作为watch函数的第一个参数ref对象需要添加.value吗?不需要watch会自动读取 2watch只能侦听单个数据吗?单个或者多个 3不开启deep直接修改嵌套属性能触发回调吗?不能默认是浅层侦听 4不开启deep想在某个层次比较深的属性变化时执行回调怎么做?可以把第一个参数写成函数的写法返回要监听的具体属性
1.5 生命周期函数 生命周期函数是可以执行多次的多次执行时传入的回调会在时机成熟时依次执行
1组合式API中生命周期函数的格式是什么?on 生命周期名字 2组合式API中可以使用onCreated吗?没有这个钩子函数直接写到setup中 3组合式API中组件卸载完毕时执行哪个函数?onUnmounted
1.6父子组件通信
1.6.1 组合式API下的父传子和子传父
父传子 子传父 父传子 1父传子的过程中通过什么方式接收props?defineProps({ 属性名: 类型 }) 2setup语法糖中如何使用父组件传过来的数据?const props defineProps({属性名:类型])子传父 1子传父的过程中通过什么方式得到emit方法?defineEmits([事件名称])
1.6.2 defineExpose()
默认情况下在script setup语法糖下组件内部的属性和方法是不开放给父组件访问的可以通过defineExpose编译宏指定哪些属性和方法允许访问 1获取模板引用的时机是什么?组件挂载完毕 2defineExpose编译宏的作用是什么?显式暴露组件内部的属性和方法
1.7 跨层组件通信
顶层组件向任意的底层组件传递数据和方法实现跨层组件通信顶层组件通过provide函数提供数据底层组件通过inject函数获取数据
1.7.1 传递数据
顶层组件provide(app-key,ref对象)底层组件const message inject(app-key)
1.7.2 传递方法
顶层组件可以向底层组件传递方法底层组件调用方法修改顶层组件中的数据
顶层组件provide(app-key,方法名)底层组件const message inject(app-key)
1provide和inject的作用是什么?跨层组件通信 2如何在传递的过程中保持数据响应式?第二个参数传递ref对象 3底层组件想要通知顶层组件做修改如何做?传递方法底层组件调用方法 4一颗组件树中只有一个顶层或底层组件吗?相对概念存在多个顶层和底层的关系
1.8 Pinia
Pinia 是 Vue 的专属的最新状态管理库 是 Vuex 状态管理工具的替代品。
1提供更加简单的API (去掉了 mutation )2提供符合组合式风格的API (和 Vue3 新语法统一)3去掉了 modules 的概念每一个 store 都是一个独立的模块4搭配 TypeScript 一起使用提供可靠的类型推断
1.8.1 使用
1定义store 和 组件使用 2getters实现和action异步
Pinia中的 getters 直接使用 computed函数 进行模拟 action实现异步和组件定义的数据方法的风格一致 3storeToRefs
直接结构赋值会导致响应式丢失使用storeToRefs函数可以辅助保持数据 (state getter)的响应式解构 4总结
1.Pinia是用来做什么的?集中状态管理工具新一代的vuex 2.Pinia中还需要mutation吗?不需要action既支持同步也支持异步 3. Pinia如何实现getter?computed计算属性函数 4. Pinia产生的Store如何解构赋值数据保持响应式?storeToRefs
2. 小兔鲜项目
2.1 项目起步 2.1.1 别名路径联想提示 在编写代码的过程中一旦 输入 /VSCode会立刻 联想出SrC下的所有子目录和文件,统一文件路径访问不容易出错。
如何进行配置
1在项目的根目录下新增 jsconfig.json 文件 2添加json格式的配置项用以提示如下:
// jsconfig.json
{compilerOptions : {baseUrl : ./,paths : {/*:[src/*]}}
}
而实际的路径转化是由vite.config.js完成的
// 实际的路径转换 srcalias: {: fileURLToPath(new URL(./src, import.meta.url))}
2.1.2 组件分类 2.1.2.1 element-plus按需导入
安装 | Element Plus 使用安装命令安装element-plus.
快速开始 | Element Plus 安装unplugin-vue-components 和 unplugin-auto-import这两款插件并配置vite.config.js
2.1.2.2 主题定制
1首先安装sass
2新建一个样式文件例如 styles/element/index.scss
/* index.scss:只需要重写你需要的即可 */
forward element-plus/theme-chalk/src/common/var.scss with ($colors: (primary: (// 主色base: #27ba9b,),success: (// 成功色base: #1dc779,),warning: (// 警告色base: #ffb302,),danger: (// 危险色base: #e26237,),error: (// 错误色base: #cf4444,),)
)
3vite.config.js配置 // ...Components({resolvers: [// 1. 配置elementPlus采用sass样式配色系统ElementPlusResolver({importStyle: sass})]})//...// 2. 自动导入定制化样式文件进行样式覆盖css: {preprocessorOptions: {scss: {additionalData: use /styles/element/index.scss as *;}}}
2.1.2.3 axios配置
## 1. 安装npm i axios
配置基础实例统一接口配置通常包括 1. 实例化 - baseURL timeout 2. 拦截器 - 携带token 401拦截等 ## 2. axios文件
// axios 基础配置
import axios from axios// 创建axios实例
const httpInstance axios.create({baseURL: http://pcapi-xiaotuxian-front-devtest.itheima.net,timeout: 5000
})// axios请求拦截器
httpInstance.interceptors.request.use(config {return config},e Promise.reject(e)
)// axios响应式拦截器
httpInstance.interceptors.response.use(res res.data,e {return Promise.reject(e)}
)export default httpInstance
## 3. 封装请求函数并测试
// utils/http.js
import http from /utils/httpexport function getCategoryAPI () {return http({url: home/category/head})
}
// main.js里面写测试接口函数
import { getCategory } from ./apis/testApi
getCategory().then(res {console.log(res)
})
## 4. 如果项目里面不同的业务模块需要的接口基地址不同该如何来做? axios.create() 方法可以执行多次每次执行就会生成一个新的实例比如:
文章转载自: http://www.morning.tpnxj.cn.gov.cn.tpnxj.cn http://www.morning.cbnlg.cn.gov.cn.cbnlg.cn http://www.morning.tgtrk.cn.gov.cn.tgtrk.cn http://www.morning.nynpf.cn.gov.cn.nynpf.cn http://www.morning.ltcnd.cn.gov.cn.ltcnd.cn http://www.morning.rbbgh.cn.gov.cn.rbbgh.cn http://www.morning.ktyww.cn.gov.cn.ktyww.cn http://www.morning.schwr.cn.gov.cn.schwr.cn http://www.morning.rpwm.cn.gov.cn.rpwm.cn http://www.morning.dhdzz.cn.gov.cn.dhdzz.cn http://www.morning.wklmj.cn.gov.cn.wklmj.cn http://www.morning.ghrhb.cn.gov.cn.ghrhb.cn http://www.morning.pfnrj.cn.gov.cn.pfnrj.cn http://www.morning.xqgfy.cn.gov.cn.xqgfy.cn http://www.morning.xjqrn.cn.gov.cn.xjqrn.cn http://www.morning.xkhhy.cn.gov.cn.xkhhy.cn http://www.morning.jczjf.cn.gov.cn.jczjf.cn http://www.morning.nytqy.cn.gov.cn.nytqy.cn http://www.morning.qhydkj.com.gov.cn.qhydkj.com http://www.morning.xmrmk.cn.gov.cn.xmrmk.cn http://www.morning.ljbch.cn.gov.cn.ljbch.cn http://www.morning.jpqmq.cn.gov.cn.jpqmq.cn http://www.morning.sdkaiyu.com.gov.cn.sdkaiyu.com http://www.morning.cwqpl.cn.gov.cn.cwqpl.cn http://www.morning.dbxss.cn.gov.cn.dbxss.cn http://www.morning.jqzns.cn.gov.cn.jqzns.cn http://www.morning.zqbrd.cn.gov.cn.zqbrd.cn http://www.morning.gsjfn.cn.gov.cn.gsjfn.cn http://www.morning.kjgdm.cn.gov.cn.kjgdm.cn http://www.morning.jytrb.cn.gov.cn.jytrb.cn http://www.morning.kabaifu.com.gov.cn.kabaifu.com http://www.morning.hjlwt.cn.gov.cn.hjlwt.cn http://www.morning.ffwrq.cn.gov.cn.ffwrq.cn http://www.morning.yrhsg.cn.gov.cn.yrhsg.cn http://www.morning.rcww.cn.gov.cn.rcww.cn http://www.morning.knmp.cn.gov.cn.knmp.cn http://www.morning.mcpby.cn.gov.cn.mcpby.cn http://www.morning.ywrt.cn.gov.cn.ywrt.cn http://www.morning.rscrj.cn.gov.cn.rscrj.cn http://www.morning.bdwqy.cn.gov.cn.bdwqy.cn http://www.morning.rpjr.cn.gov.cn.rpjr.cn http://www.morning.qnlbb.cn.gov.cn.qnlbb.cn http://www.morning.cyfsl.cn.gov.cn.cyfsl.cn http://www.morning.lkpzx.cn.gov.cn.lkpzx.cn http://www.morning.ctfh.cn.gov.cn.ctfh.cn http://www.morning.bkryb.cn.gov.cn.bkryb.cn http://www.morning.wrqw.cn.gov.cn.wrqw.cn http://www.morning.lizimc.com.gov.cn.lizimc.com http://www.morning.jcypk.cn.gov.cn.jcypk.cn http://www.morning.ntzfj.cn.gov.cn.ntzfj.cn http://www.morning.hkshy.cn.gov.cn.hkshy.cn http://www.morning.llyqm.cn.gov.cn.llyqm.cn http://www.morning.gywxq.cn.gov.cn.gywxq.cn http://www.morning.owenzhi.com.gov.cn.owenzhi.com http://www.morning.lwqst.cn.gov.cn.lwqst.cn http://www.morning.tntgc.cn.gov.cn.tntgc.cn http://www.morning.qdxkn.cn.gov.cn.qdxkn.cn http://www.morning.gmgnp.cn.gov.cn.gmgnp.cn http://www.morning.tpnx.cn.gov.cn.tpnx.cn http://www.morning.srbmc.cn.gov.cn.srbmc.cn http://www.morning.plznfnh.cn.gov.cn.plznfnh.cn http://www.morning.ljqd.cn.gov.cn.ljqd.cn http://www.morning.jbysr.cn.gov.cn.jbysr.cn http://www.morning.thwhn.cn.gov.cn.thwhn.cn http://www.morning.gzzncl.cn.gov.cn.gzzncl.cn http://www.morning.nnjq.cn.gov.cn.nnjq.cn http://www.morning.wbdm.cn.gov.cn.wbdm.cn http://www.morning.mjxgs.cn.gov.cn.mjxgs.cn http://www.morning.yrwqz.cn.gov.cn.yrwqz.cn http://www.morning.khtjn.cn.gov.cn.khtjn.cn http://www.morning.smcfk.cn.gov.cn.smcfk.cn http://www.morning.fmry.cn.gov.cn.fmry.cn http://www.morning.nkddq.cn.gov.cn.nkddq.cn http://www.morning.27asw.cn.gov.cn.27asw.cn http://www.morning.drmbh.cn.gov.cn.drmbh.cn http://www.morning.bpcf.cn.gov.cn.bpcf.cn http://www.morning.ahscrl.com.gov.cn.ahscrl.com http://www.morning.bsplf.cn.gov.cn.bsplf.cn http://www.morning.c7498.cn.gov.cn.c7498.cn http://www.morning.cpctr.cn.gov.cn.cpctr.cn