搭建 Vite + Vue3 + Pinia + Element Plus 项目。

news/2024/3/29 2:22:48/文章来源:https://blog.csdn.net/renlimin1/article/details/132083121

一、基础项目搭建:

  • 技术栈
技术栈描述官网
Vue3渐进式 JavaScript 框架https://cn.vuejs.org/
Element Plus基于 Vue 3,面向设计师和开发者的组件库https://element-plus.gitee.io/zh-CN/
Vite前端开发与构建工具https://cn.vitejs.dev/guide/
TypeScript开发语言,是 JavaScript 的超集
Vue RouterVue.js 的官方路由https://router.vuejs.org/zh/
wangEditorTypescript 开发的 Web 富文本编辑器www.wangeditor.com/
Echarts开源可视化图表库https://echarts.apache.org/zh/
vue-i18nVue 国际化多语言插件https://vue-i18n.intlify.dev/
VueUse基于Vue组合式API的实用工具集(类比HuTool工具)http://www.vueusejs.com/guide/
  • 环境准备
环境名称
运行环境Node 16+
开发工具VSCode
VSCode插件Vue Language Features (Volar) TypeScript Vue Plugin (Volar),禁用Vetur

推荐安装nvm控制node版本

1. 项目初始化

按照 vite 官网搭建第一个 Vite 项目,执行以下命令完成 vue 、typescirpt 模板项目的初始化

 npm init vite@latest vue3-element-admin --template vue-ts

在这里插入图片描述

2. 使用Vscode启动项目

npm install
npm run dev

在这里插入图片描述

3. src 路径别名配置

相对路径别名配置,使用 @ 代替 src

配置 vite.config.ts

npm install @types/node
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import path from "path"; //这个path用到了上面安装的@types/node
const pathSrc = path.resolve(__dirname, "src");
// https://vitejs.dev/config/
export default defineConfig({// 路径别名resolve: {alias: {"@": pathSrc, // @代替src},},plugins: [vue()],
});
// src/App.vue
import HelloWorld from '../src/components/HelloWorld.vue'import HelloWorld from '@/components/HelloWorld.vue'

修改tsconfig.json

"compilerOptions": {..."baseUrl": "./", // 解析非相对模块的基地址,默认是当前目录"paths": { // 路径映射,相对于baseUrl"@/*": ["src/*"] }
}

二、使用Element Plus组件库

1. 安装

# 选择一个你喜欢的包管理器# NPM
$ npm install element-plus --save# Yarn
$ yarn add element-plus# pnpm
$ pnpm install element-plus

2. 用法

2.1 完整引入

如果你对打包后的文件大小不是很在乎,那么使用完整导入会更方便。

// main.ts
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'const app = createApp(App)app.use(ElementPlus)
app.mount('#app')

2.2 按需导入

您需要使用额外的插件来导入要使用的组件。

2.3 自动导入(推荐)

首先你需要安装unplugin-vue-components 和 unplugin-auto-import这两款插件

npm install -D unplugin-vue-components unplugin-auto-import

vite.config.ts - 自动导入配置

src目录下,新建 types 目录,用于存放自动导入函数和组件的TS类型声明文件。

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import AutoImport from "unplugin-auto-import/vite";
import Components from "unplugin-vue-components/vite";import path from "path"; //这个path用到了上面安装的@types/node
const pathSrc = path.resolve(__dirname, "src");
// https://vitejs.dev/config/
export default defineConfig({// 路径别名resolve: {alias: {"@": pathSrc, // @代替src},},plugins: [vue(),AutoImport({// 自动导入 Vue 相关函数,如:ref, reactive, toRef 等imports: ["vue"],eslintrc: {enabled: true, // 是否自动生成 eslint 规则,建议生成之后设置 falsefilepath: "./.eslintrc-auto-import.json", // 指定自动导入函数 eslint 规则的文件},dts: path.resolve(pathSrc, "types", "auto-imports.d.ts"), // 指定自动导入函数TS类型声明文件路径}),Components({dts: path.resolve(pathSrc, "types", "components.d.ts"), // 指定自动导入组件TS类型声明文件路径}),],
});

.eslintrc.cjs - 自动导入函数 eslint 规则引入

"extends": ["./.eslintrc-auto-import.json"
],

2.4 手动导入

Element Plus 提供了基于 ES Module 的开箱即用的 Tree Shaking 功能。

但你需要安装 unplugin-element-plus 来导入样式。 配置文档参考 docs

App.vue

<template><el-button>我是 ElButton</el-button>
</template>
<script>import { ElButton } from 'element-plus'export default {components: { ElButton },}
</script>
// vite.config.ts
import { defineConfig } from 'vite'
import ElementPlus from 'unplugin-element-plus/vite'export default defineConfig({// ...plugins: [ElementPlus()],
})

三、使用全局状态管理工具 pinia

pinia 官网

1. pinia介绍

Pinia 是 Vue 的专属状态管理库,它允许你跨组件或页面共享状态。

pinia优点:

  1. 支持Vue2和Vue3,也就是老项目也可以使用Pinia。
  2. 足够轻量,压缩后的体积只有1kb左右。
  3. 完整的TypeScript支持,Vue3版本的一大优势就是对TypeScript的支持,所以Pinia也做到了完整的支持。如果你对Vuex很熟悉的化,一定知道Vuex对TS的语法支持不是完整的。
  4. 代码更加简洁,可以实现很好的代码自动分割。Vue2的时代,写代码需要来回翻滚屏幕屏幕找变量,非常的麻烦,Vue3的Composition api完美了解决这个问题。 可以实现代码自动分割,pinia也同样继承了这个优点。
  5. 去除 mutations,只有 state,getters,actions;actions 支持同步和异步。
  6. 不需要嵌套模块,让代码更加扁平化,只有 store 的概念,store 之间可以自由使用,每一个store都是独立的,符合Vue3的Composition api 。
  7. 无需手动添加 store,store 一旦创建便会自动添加。

1.1 安装

yarn add pinia
# 或者使用 npm
npm install pinia

1.2 引入

创建一个 pinia 实例 (根 store) 并将其传递给应用:

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'const pinia = createPinia()
const app = createApp(App)app.use(pinia)
app.mount('#app')

1.3 使用

src 文件夹下创建 store 文件夹,并添加 counter.js 文件。

2. Pinia中的Store

2.1 定义store

  1. Store (如 Pinia)是一个保存状态和业务逻辑的实体,它并不与你的组件树绑定。换句话说,它承载着全局状态。它有点像一个永远存在的组件,每个组件都可以读取和写入它。它有三个概念,stategetteraction,我们可以假设这些概念相当于组件中的 datacomputed methods
  2. store 是用 defineStore(name, function | options) 定义的,建议其函数返回的值命名为 use…Store 方便理解
  • 参数 name:必填值且唯一,简单点说就可以理解成是一个命名空间。
  • 参数 function | options:可以是对象或函数形式。
    • 对象形式【选项模式】,其中配置 stategettersactions 选项。
    • 函数形式【组合模式,类似组件组合式 API 的书写方式】,定义响应式变量和方法,并且 return 对应的变量和方法;ref() 相当于 state,computed() 相当于 getters,function() 相当于 actions。

2.2 使用store读取和写入 state

下面案例以选项模式为例:

store 文件夹下创建 counter.js 文件,这个文件就是存有关 counter 的一些相关的数据。

import {defineStore} from 'pinia'/*defineStore 是需要传参数的,其中第一个参数是id,就是一个唯一的值,
简单点说就可以理解成是一个命名空间.
第二个参数就是一个对象,里面有三个模块需要处理,第一个是 state,
第二个是 getters,第三个是 actions。
*/
const useCounter = defineStore("counter",{state:() => ({count:88,}),getters: {},actions: {}
})//暴露useCounter这个模块
export default useCounter

在页面中使用:

<template><div><el-button>我是 ElButton</el-button><div>store===>counter.js的count值:{{ counterStore.count }}</div></div>
</template><script setup>
// 引入创建的store
import useCounter from "./store/counter";
// 调用store里的方法
const counterStore = useCounter();
console.log("counterStore", counterStore.count);
</script><style scoped></style>

在这里插入图片描述

**注意:**在使用时 ,取值时不用和 vuex 一样还要.state,直接.state里面的count值就行了,写法:counterStore.count。

案例需求,点击按钮加一:

我们分别用两种方法取count值,一个解构,一个不解构

<template><div><h2>Home Word</h2><h2>展示pinia的counter的count值: {{ counterStore.count }}</h2><h2>展示解构出来的pinia的counter的count值: {{ count }}</h2><el-button @click="addCount">function count+1</el-button></div>
</template><script setup>
// 引入创建的store
import useCounter from "./store/counter";
// 调用store里的方法
const counterStore = useCounter();
// 结构count值
const { count } = counterStore;
function addCount() {//这里可以直接操作count,修改(写入)store,在vuex还要commit在mutaitions修改数据counterStore.count++;
}
</script>

在这里插入图片描述

我们发现解构出来的值 失去响应式了

解决方案:

为了从 store 中提取属性时保持其响应性,你需要使用 storeToRefs() 。它将为每一个响应式属性创建引用。当你只使用 store 的状态而不调用任何 action 时,它会非常有用。

<template><div><h2>Home Word</h2><!-- 使用useCounter的实例获取state中的值 --><h2>展示pinia的counter的count值: {{ counterStore.count }}</h2><h2>展示解构出来的pinia的counter的count值: {{ count }}</h2><el-button @click="addCount">function count+1</el-button></div>
</template><script setup>
import { storeToRefs } from "pinia";
// 引入创建的store
import useCounter from "./store/counter";
// 调用store里的方法
const counterStore = useCounter();
// 结构count值
const { count } = storeToRefs(counterStore);
function addCount() {//这里可以直接操作count,修改(写入)store,在vuex还要commit在mutaitions修改数据counterStore.count++;
}
</script>

在这里插入图片描述

2.3 修改state数据

  • 定义一个关于user的Store
import { defineStore } from 'pinia'const useUser = defineStore("user", {state: () => ({name: "why",age: 18,level: 100}),actions:{setCurrent () {this.level++}}
})export default useUser
  • 三种修改state的方法
<template><div><h2>Home Word</h2><h2>姓名: {{ name }}</h2><h2>年龄: {{ age }}</h2><h2>等级: {{ level }}</h2><el-button @click="updateStore">修改user信息</el-button><el-button @click="updateStoreLevel">修改level</el-button></div>
</template><script setup>
import useUser from "./store/user";
import { storeToRefs } from "pinia";
const userStore = useUser();
const { name, age, level } = storeToRefs(userStore);function updateStore() {// 方法一:一个个的修改状态// userStore.name = "zimo";// userStore.age = 20;// 方法二 :一次性修改多个状态// userStore.$patch({//   name: "zimo",//   age: 20,// });// 方法三:替换state为新的对象const oldState = userStore.$state;userStore.$state = {...userStore.$state,name: "curry",level: 200,};// 下面会返回trueconsole.log(oldState === userStore.$state);
}
// 方法四:通过actions修改
const updateStoreLevel = () => {userStore.setCurrent();
};
</script>

在这里插入图片描述在这里插入图片描述

2.4 重置state数据

新增一个重置按钮:

<el-button @click="resetStore">重置user信息</el-button>

新增一个重置方法:

function resetStore() {userStore.$reset();
}

在这里插入图片描述

3. Pinia中的getters

getters 类似于 vue 里面的计算属性,可以对已有的数据进行修饰。getters中可以定义接受一个state作为参数的函数,不管调用多少次,getters中的函数只会执行一次,且都会缓存。

3.1 定义getters

  • 基本使用
  • 一个getter引入另外一个getter
  • getters也支持返回一个函数
  • getters中用到别的store中的数据
// 定义关于counter的store
import { defineStore } from 'pinia'const useCounter = defineStore("counter", {state: () => ({count: 99}),getters: {// 1.基本使用doubleCount(state) {return state.count * 2},// 2.一个getter引入另外一个getterdoubleCountAddOne() {// this是store实例,可以直接使用另一个getterreturn this.doubleCount + 1},// 3.getters也支持返回一个函数getFriendById(state) {return function(id) {return id}},// 4.getters中用到别的store中的数据showMessage(state) {//获取user信息,拿到useUser模块const userStore = useUser()//拼接信息return `name:${userStore.name}-count:${state.count}`}  },
})export default useCounter

3.2 访问getters

<template><div><!-- 在模板中使用 --><h2>基本使用:doubleCount: {{ counterStore.doubleCount }}</h2><h2>一个getter引入另外一个getter:doubleCountAddOne:{{ counterStore.doubleCountAddOne }}</h2><h2>函数id-99: {{ counterStore.getFriendById(99) }}</h2><h2>getters中获取另一个store中的state/getters数据==>showMessage:{{counterStore.showMessage}}</h2></div>
</template><script setup>
import useCounter from "./store/counter";const counterStore = useCounter();
// 在js文件中使用
const doubleCount = counterStore.doubleCount;
const doubleCountAddOne = counterStore.doubleCountAddOne;
const frend = counterStore.getFriendById(99);
</script>

在这里插入图片描述
**注意:**getters中用别的store中的数据 ,在counter模块中拿user模块的store数据,要引入user模块。

4. Pinia中的actions

actions 相当于组件中的 methods

可以使用 defineStore() 中的 actions 属性定义,并且它们非常适合定义一些业务逻辑。

getters 一样,在 action 中可以通过 this 访问整个 store 实例的所有操作。

4.1 同步

  • 定义关于counter的store
// 定义关于counter的store
import { defineStore } from 'pinia'const useCounter = defineStore("counter", {state: () => ({count: 99,}),// 定义actionsactions: {increment() {this.count++},incrementNum(num) {this.count += num}}
})export default useCounter
  • 同步使用方式
<template><div><h2>Home Word</h2><h2>doubleCount: {{ counterStore.count }}</h2><el-button @click="changeState">修改state</el-button></div>
</template><script setup>
import useCounter from "./store/counter";const counterStore = useCounter();
function changeState() {// 可以通过counterStore对象直接使用counterStore.increment();// counterStore.incrementNum(10);
}
</script>

4.2 异步

结合async await 修饰

  • 定义store
import { defineStore } from 'pinia'const Login = () => {return new Promise((resolve) => {setTimeout(() => {resolve({name: 'Rlm',isLogin: true})}, 3000)})
}const useUser = defineStore("user", {state: () => ({user: {},name: "123"}),actions:{async getLoginInfo() {const result = await Login()this.user = result;}}
})export default useUser
  • 页面使用
<template><div><h2>Home Word</h2><h2>user: {{ userStore.user }}</h2><el-button @click="Login">获取user</el-button></div>
</template><script setup>
import useUser from "./store/user";
const userStore = useUser();
const Login = () => {userStore.getLoginInfo();
};
</script>
  • 多个action互相调用getLoginInfo setName
import { defineStore } from 'pinia'const Login = () => {return new Promise((resolve) => {setTimeout(() => {resolve({name: 'Rlm',isLogin: true})}, 3000)})
}const useUser = defineStore("user", {state: () => ({user: {},name: "123"}),actions:{async getLoginInfo() {const result = await Login()this.user = result;this.setName(result.name)},setName (name) {this.name = name;}}
})export default useUser

在这里插入图片描述

5. Pinia的API

5.1 重置 state

$reset() 将会把state所有值 重置回 原始状态。前面2.4 重置state数据有写到。

5.2 订阅 state

类似于 Vuex 的 subscribe 方法,你可以通过 store 的 $subscribe() 方法侦听 state 及其变化。比起普通的 watch(),使用 $subscribe() 的好处是 subscriptions 在 patch 后只触发一次 (例如,当使用上面的函数版本时)。

  • 定义user store
import { defineStore } from 'pinia'const useUser = defineStore("user", {state: () => ({name: "why",age: 18,level: 100}),actions:{setCurrent () {this.level++}}
})export default useUser
  • 页面使用
<template><div><h2>Home Word</h2><h2>姓名: {{ name }}</h2><h2>年龄: {{ age }}</h2><h2>等级: {{ level }}</h2><el-button @click="updateStore">修改user信息</el-button><el-button @click="updateStoreLevel">修改level</el-button><el-button @click="resetStore">重置user信息</el-button></div>
</template><script setup>
import useUser from "./store/user";
import { storeToRefs } from "pinia";
const userStore = useUser();
const { name, age, level } = storeToRefs(userStore);userStore.$subscribe((mutation, state) => {// mutation.type // type的三种类型 'direct' | 'patch object' | 'patch function'// 和 cartStore.$id 一样// mutation.storeId // 'user'// payload只有 mutation.type === 'patch object'的情况下才可用// mutation.payload // 传递给 cartStore.$patch() 的补丁对象。console.log(mutation, state);// 每当状态发生变化时,将整个 state 持久化到本地存储。localStorage.setItem("user", JSON.stringify(state));
});function updateStore() {// 方法一:一个个的修改状态  订阅 state type 为 'direct'// userStore.name = "zimo";// userStore.age = 20;// 方法二 :一次性修改多个状态  订阅 state type 为 'patch object'userStore.$patch({name: "zimo",age: 20,});// 方法三:替换state为新的对象 订阅 state type 为 'patch function'// const oldState = userStore.$state;// userStore.$state = {//   ...userStore.$state,//   name: "curry",//   level: 200,// };// 下面会返回true// console.log(oldState === userStore.$state);
}
// 方法四:通过actions修改 订阅 state type 为 'direct'
const updateStoreLevel = () => {userStore.setCurrent();
};// 重置user信息方法
function resetStore() {userStore.$reset();
}
</script>

在这里插入图片描述
在这里插入图片描述
默认情况下,state subscription 会被绑定到添加它们的组件上 (如果 store 在组件的 setup() 里面)。这意味着,当该组件被卸载时,它们将被自动删除。如果你想在组件卸载后依旧保留它们,请将 { detached: true } 作为第二个参数,以将 state subscription 从当前组件中分离:

userStore.$subscribe((mutation, state) => {// mutation.type // 'direct' | 'patch object' | 'patch function'// 和 cartStore.$id 一样// mutation.storeId // 'user'// 只有 mutation.type === 'patch object'的情况下才可用// mutation.payload // 传递给 cartStore.$patch() 的补丁对象。console.log(mutation, state);// 每当状态发生变化时,将整个 state 持久化到本地存储。localStorage.setItem("user", JSON.stringify(state));},{detached: true,}
);

5.3 订阅 action

你可以通过 store.$onAction() 来监听 action 和它们的结果。传递给它的回调函数会在 action 本身之前执行。after 表示在 promise 解决之后,允许你在 action 解决后执行一个回调函数。同样地,onError 允许你在 action 抛出错误或 reject 时执行一个回调函数。这些函数对于追踪运行时错误非常有用,类似于Vue docs 中的这个提示。

  • 定义store
import { defineStore } from 'pinia'const Login = () => {return new Promise((resolve) => {setTimeout(() => {resolve({name: 'Rlm',isLogin: true})}, 3000)})
}const useUser = defineStore("user", {state: () => ({user: {},name: "123",count:1}),actions:{async getLoginInfo() {const result = await Login()this.user = result;this.setName(result.name)},setName (name) {this.name = name;},testOnAction(id) {this.count++console.log(this.count)return Promise.resolve('这是testOnAction返回的值')},testOnAction2(...args) {console.log(...args)return Promise.reject('这是testOnAction222错误返回的值')}}
})
  • 页面使用
<template><div><h2>Home Word</h2><h2>user: {{ userStore.user }}</h2><h2>name: {{ userStore.name }}</h2><el-button @click="Login">获取user</el-button></div>
</template><script setup>
import useUser from "./store/user";
const userStore = useUser();
const Login = () => {userStore.getLoginInfo();
};
// 订阅 action
const unsubscribe = userStore.$onAction(({name, // action 名称store, // store 实例,类似 `someStore`args, // 传递给 action 的参数数组after, // 在 action 返回或解决后的钩子onError, // action 抛出或拒绝的钩子}) => {// 这将在执行 "store "的 action 之前触发。console.log(`Start "${name}" with params [${args.join(", ")}].`);if (name === "testOnAction") {// 这将在 action 成功并完全运行后触发。// 它等待着任何返回的 promiseafter((reject) => {//这里可以执行一些操作console.log("订阅 action---after===>", reject);});}// 如果 action 抛出或返回一个拒绝的 promise,这将触发onError((error) => {console.log(error);});}
);// 手动删除监听器
// unsubscribe();userStore.testOnAction(1);
userStore.testOnAction2(1, 2, 3, 45);
</script>

在这里插入图片描述

6. Pinia 数据持久化

6.1 使用插件

  • 安装 pinia-plugin-persist
npm i pinia-plugin-persist
  • main.js中引入插件
// 引入pinia
import { createPinia } from 'pinia'
import piniaPluginPersist from 'pinia-plugin-persist'
const pinia = createPinia()
pinia.use(piniaPluginPersist)
app.use(pinia)
  • 定义store时,开启persist
import { defineStore } from 'pinia'export default defineStore('commonStore', {//开启数据存储persist: { enabled: true },state: () => {return {info: {} }},
})
  • persist配置项
 persist: {enabled: true,strategies: [{key: 'all', //存储的key值,默认为store名,storage: localStorage, //存储的位置,默认为sessionStoragepaths: ['info'] //需要存储的state状态,默认为所有}]},

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_340075.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mapping温度分布验证选择数据记录仪时需要考虑的13件事

01 什么是温度分布验证&#xff1f; 温度分布验证是通过在规定的研究时间内测量定义区域内的多个点来确定特定温度控制环境或过程&#xff08;如冷冻柜、冰箱、培养箱、稳定室、仓库或高压灭菌器&#xff09;的温度分布的过程。温度分布验证的目标是确定每个测量点之间的差异&…

新手用户选择阿里云服务器地域、实例、带宽、操作系统经验参考

无论是个人还是企业用户&#xff0c;部署自己的网站或者APP客户端、小程序等&#xff0c;都需要用到服务器&#xff0c;现在流行的都是使用云服务器&#xff0c;考虑到性价比大家现在都喜欢选择阿里云服务器。但是新手用户往往在面对阿里云服务器地域、实例、带宽、操作系统等众…

读书笔记-《ON JAVA 中文版》-摘要21第十九章 类型信息-2]

文章目录 第十九章 类型信息7. 动态代理8. Optional类9. 接口和类型10. 本章小结 第十九章 类型信息 7. 动态代理 代理是基本的设计模式之一。一个对象封装真实对象&#xff0c;代替其提供其他或不同的操作—这些操作通常涉及到与“真实”对象的通信&#xff0c;因此代理通常…

Springboot部署ELK实战

Springboot部署ELK实战 1、部署docker、docker-compose环境安装docker安装docker-compose 2、搭建elk1、构建目录&&配置文件1、docker-compose.yml 文档2、Kibana.yml3、log-config.conf 2、添加es分词器插件3、启动 3、Springboot项目引入es、logStash配置1、引入依赖…

后端进阶之路——Spring Security构建强大的身份验证和授权系统(四)

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 「推荐专栏」&#xff1a; ★java一站式服务 ★ ★前端炫酷代码分享 ★ ★ uniapp-从构建到提升★ ★ 从0到英雄&#xff0c;vue成神之路★ ★ 解决算法&#xff0c;一个专栏就够了★ ★ 架…

WebDAV之π-Disk派盘 + DEVONthink

DEVONthink是由一家来自德国的老牌软件开发商发布的「知识管理」软件,运行于 Mac/iOS 平台。官方自己定位为全方位(中文环境下略有遗憾)帮助你实现知识管理,可以称之为“模块级”应用了。 DEVONthink还支持各种云服务同步,文件管理您的终极文件管理应用、文件、图片与连接远…

Centos7 安装yum

1、检查主机名和网络并且配置/etc/hosts文件 查看主机名&#xff1a;hostname 查看ip :ifconfig vi /etc/hosts//添加把主机名和IP配置进去hosts文件192.18.56.111 orcale12c2、关闭防火墙 systemctl status firewalld.service//检查防火墙状态 暂时关闭防火墙&#xff0c;下…

20.4 HTML 表单

1. form表单 <form>标签: 用于创建一个表单, 通过表单, 用户可以向网站提交数据. 表单可以包含文本输入字段, 复选框, 单选按钮, 下拉列表, 提交按钮等等. 当用户提交表单时, 表单数据会发送到服务器进行处理.action属性: 应指向一个能够处理表单数据的服务器端脚本或UR…

安卓证书生成教程

1.下载安装JDK文件&#xff08;如已安装请跳过&#xff09; 根据电脑系统版本下载JDK版本文件 下载地址&#xff1a;[https://www.oracle.com/java/technologies/downloads/](https://www.oracle.com/java/technologies/downloads/) 如果电脑上安装过JDK文件可以跳过2.生成密钥…

Spring源码篇(九)自动配置扫描class的原理

文章目录 前言ClassLoader如何加载jar包里的class自动配置扫描class的原理spring中的加载方式源码总结 前言 spring是怎样通过ComponentScan&#xff0c;或者自动配置扫描到了依赖包里class的&#xff1f; ClassLoader 这里涉及到了class Loader的机制&#xff0c;有些复杂&…

达芬奇架构 DaVinci Core - 小记

文章目录 官方文档 &#xff1a; HUAWEI Da Vinci Architecture https://support.huaweicloud.com/intl/en-us/odevg-A800_9000_9010/atlaste_10_0007.htmlPPT : DaVinci: A Scalable Architecture for Neural Network Computing https://www.cmc.ca/wp-content/uploads/2020/0…

一篇文章带你基本了解Java 集合框架、核心接口、以及需要掌握的各个数据结构

一篇文章带你基本了解Java 集合框架 基本概念&#xff1a; ​ 早在 Java 2 中之前&#xff0c;Java 就提供了特设类。比如&#xff1a;Dictionary, Vector, Stack, 和 Properties 这些类用来存储和操作对象组。 ​ Java集合框架&#xff08;Java Collections Framework&…

Pytorch Tutorial【Chapter 2. Autograd】

Pytorch Tutorial 文章目录 Pytorch TutorialChapter 2. Autograd1. Review Matrix Calculus1.1 Definition向量对向量求导1.2 Definition标量对向量求导1.3 Definition标量对矩阵求导 2.关于autograd的说明3. grad的计算3.1 Manual手动计算3.2 backward()自动计算 Reference C…

极光笔记 | 浅谈企业级SaaS产品的客户成长旅程管理(上)—— 分析篇

本文作者&#xff1a;陈伟&#xff08;极光用户体验部高级总监&#xff09; “企业级SaaS产品与C端互联网产品特征差异很大&#xff0c;有些甚至是截然相反&#xff0c;这些特征也会成为后续客户成长旅程的重要影响变量。本文就如何设计并服务好企业级SaaS产品客户成长旅程进行…

全网最强,Python接口自动化测试实战-接口参数关联(购物实例)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 什么是参数关联&a…

Spring之浅谈AOP技术

目录 前言 1.AOP的作用 2.AOP核心 Spring实现AOP 3.AOP工作流程 4.AOP核心概念 5.AOP通知类型 5.1类型介绍 5.2通知类型的使用 前置通知 后置通知 ​​​​​​​环绕通知 前言 AOP&#xff1a;Aspect Oriented Programming&#xff08;面向切面编程&#xff09;&…

收藏!9款好用的前端可视化工具推荐

“可视化开发”是上个世纪90年代软件界最大的热点之一。 当初&#xff0c;可视化开发主要专注于用户界面的构建&#xff0c;让开发者通过简单的拖拽操作&#xff0c;快速搭建用户界面&#xff0c;一些成熟产品更是实现了“所见即所得”。在与当时最先进的高级编程语言相比较时&…

01-序言

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan 简介&#xff1a; 此专栏是学习“线性代数”课程做的笔记&#xff0c;教程来自B站的3Blue1Brown​​​​​​​d​​​​​​​。 视频作者是Grant Sanderson&#xff0c; 他本人是斯坦…

Redis两种持久化方案RDB持久化和AOF持久化

Redis持久化 Redis有两种持久化方案&#xff1a; RDB持久化AOF持久化 1.1.RDB持久化 RDB全称Redis Database Backup file&#xff08;Redis数据备份文件&#xff09;&#xff0c;也被叫做Redis数据快照。简单来说就是把内存中的所有数据都记录到磁盘中。当Redis实例故障重启…

【ASP.NET MVC】使用动软(三)(11)

一、问题 上文中提到&#xff0c;动软提供了数据库的基本操作功能&#xff0c;但是往往需要添加新的功能来解决实际问题&#xff0c;比如GetModel&#xff0c;通过id去查对象&#xff1a; 这个功能就需要进行改进&#xff1a;往往程序中获取的是实体的其他属性&#xff0c;比如…