# bigEvent
**Repository Path**: yangxiaoyang-o/bigEvent
## Basic Information
- **Project Name**: bigEvent
- **Description**: ✔【项目】基于vue2.0+element ui 开发的黑马大事件项目。
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 0
- **Created**: 2023-06-13
- **Last Updated**: 2025-06-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: Vue, Element-UI, PC
## README
# 1. 项目前置分析
---
## 1.【重点】vue-cli
1. vue-cli
```js
npm install @vue/cli-init -g // vue2.0全局安装
npm install @vue/cli -g // vue3.0全局安装
```
2. 注意:全局安装脚手架 vue2.0 和 vue3.0,这里是因为项目有可能是使用 2.0 的脚手架,又有可能时使用 3.0 的脚手架,同时安装两个版本的脚手架目的是方便使用。
3. 脚手架版本不一样对应的组件库也是不一样的,例如:vue2.0 对应的 element ui 组件库,而 3.0 对应的是 element plus 组件库。
## 2. 组件化开发
**element-ui 组件安装:**
```js
npm i element-ui -S
```
**将 element-ui 引入到==main.js==文件中:**
```js
// require element-ui
import ElementUI from "element-ui"
import "element-ui/lib/theme-chalk/index.css"
import "@/assets/global.less"
import "@/assets/resize.css"
```
**引入完后记住一定要测试,引入是否成功。**
- 可以选择在==app.vue==根组件中进行测试,测试任意组件即可。
## 3. axios 数据请求
**axios 的安装:**
```js
npm install axios -S
```
**axios 封装(utils/request.js)文件:**
```js
// 1. utils/request.js文件
import axios from "axios"
// baseURL:基地址,在前端图片渲染的时候需要拼接图片地址,所以在这里作为一个变量到处
export const baseURL = "http://big-event-vue-api-t.itheima.net"
const myAxios = axios.create({
baseURL: baseURL
})
```
**axios 使用(api/index.js)文件:**
```js
// 2. api/index.js文件
// api下面的index.js文件属于接口文件,往后端的请求接口就定义在api/index.js文件里面。
// 在 index.js 文件中导入 request.js 文件。
import request from "@/utils/request.js"
/**
* 注册用户API
* @param {*} param0
* @returns promise 对象
*/
export const registerAPI = ({ username, password, repassword }) => {
return request({
url: "/api/reg",
method: "POST",
data: {
username,
password,
repassword
}
})
}
```
## 4. es-lint 开启
> es-lint 在搭建脚手架的时候就安装。或者使用命令安装:npm install eslint -S
**1. 在脚手架搭建时候安装:(我选用的是在安装脚手架的时候安装配置文件)**
```js
// 在创建项目的时候使用eslint,可以指定eslint为一个单独的配置文件:.eslintrc.js
vue create projectName
```
**2. 使用命令安装:**
```js
// 使用命令安装的eslint只能是将配置文件集中到package.json文件中,在package.json文件中进行配置。
npm install eslint -S
```
**3. 使用命令初始化一个文件:.eslintrc.js**
```js
npx eslint --init
// √ How would you like to use ESLint? · style
// √ What type of modules does your project use? · esm
// √ Which framework does your project use? · vue
// √ Does your project use TypeScript? · No / Yes
// √ Where does your code run? · browser
// √ How would you like to define a style for your project? · guide
// √ Which style guide do you want to follow? · standard-with-typescript
// √ What format do you want your config file to be in? · JavaScript
```
**4. .eslintrc.js 文件配置:**
```js
module.exports = {
root: true,
env: {
node: true
},
extends: ["plugin:vue/essential", "@vue/standard"],
parserOptions: {
parser: "@babel/eslint-parser"
},
rules: {
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
// 关闭组件命名规则
"vue/multi-word-component-names": "off",
"space-before-function-paren": [
"error",
{
anonymous: "always",
named: "never",
asyncArrow: "always"
}
],
camelcase: "off"
}
}
```
## 5. less 样式预处理
**在脚手架搭建时候安装:**
```js
// 在创建项目的时候使用css预处理语言
vue create projectName
```
**使用命令安装:**
```js
npm install less -S
```
# 2. 组件化问题
---
> 在当前项目中使用比较多的组件。
## 1. el-form分析
```html
登录
去注册
```
**el-form 组件属性分析:**
1. ref:是一个用于获取表单数据的对象,通过 DOM 元素获取,可以通过 DOM 使用组件中的变量和方法。
2. :module:表单数据对象。
3. :rules:表单验证规则。
**el-form-item 子组件属性分析:**
1. props:表单域 model 字段,在使用 validate、resetFields 方法的情况下必填。
**el-input 子组件属性分析:**
1. v-model:双向数据绑定,数据是表单数据对象的属性。
## 2. el-table分析
```html
修改
删除
```
**el-table 属性分析:**
1. :data:显示的数据(表单数据的绑定,拿到的是一个对象或数组)。
2. stripe:是否为斑马纹。默认是 false,添加该属性就变成 true 了。
**el-table-column 属性分析:**
1. prop:prop 属性用于绑定表单数据,数据是对象或数组的一个属性。
2. type="index" index 是索引值。
## 3. el-dialog分析
```html
```
**el-dialog 属性分析:**
1. title:dialog 框的标题。
2. :visible.sync="dialogFormVisible" 属性控制 dialog 的显示和隐藏。
- 默认情况下,dialogFormVisible 值是 false。
- 当 dialogFormVisible 值为 true 的时候,dialog 框显示。
3. fullscreen:是否为全屏,dialog为全屏显示。
## 5.【重点】el-form和dialog和数据回显
> 场景说明:编辑文章分类和添加文章分类使用的是同一个dialog框。
>
> Bug复现:el-form和el-dialog和数据回显,同时使用,就会出现Bug。
1. Bug复现:开发(先进行数据添加,不会出现任何问题),测试(先进行数据修改,再添加,发现输入框里面有值)
2. 原因:点击修改后,关闭对话框的时候,置空失效(置空输入框失效)。
3. 具体分析:主人公resetFilelds有问题。
4. 线索支持:
- Dialog 的内容是懒渲染的,即在第一次被打开之前,传入的默认值slot不会被渲染到DOM上,第二次后续只是做css的显示和隐藏。
- vue 数据改变(先执行所有同步)再去更新DOM(异步代码)。
5. 无问题:第一次打开网页,先点击新增按钮 ——> dialog出现 ——> el-form组件第一次挂载(关联addForm对象属性值为空字符串)
el-form组件内绑定了初始值,所以后续调用resetFileds的时候,它可以用到空字符串值来初始值来重置。
6. 有问题:第一次打开网页,先点击修改按钮 ——> 虽然dialog值为 true 了,但是同步代码把 addForm 对象里赋值了(默认值)——>
DOM更新异步 ——> dialog出现 ——> el-form组件第一次挂载(使用addForm内置做回显,然后第一次el-form内绑定了初始值(有值的))
——> 以后做的重置,它就用绑定的带值的做的重置。
7. **解决方案:让数据回显慢点执行。**
- 让el-dialog第一次挂载el-form时,先用addForm空字符串初始值绑定到内部,后续用作resetFileds重置。
- 所以让真实的DOM先创建并在内部绑定好"复制"好初始值,接着我们真实DOM更新好后绑定好了,咱们再给数据做回显。
- 注意:我们给v-model对象赋值只是影响当前显示的值,不会影响到resetFileds复制的初始值。
```js
// 使用$nextTick让数据回显慢点。
this.$nextTick(() => {
// 数据回显(回填)
this.addCateForm.cate_name = obj.cate_name
this.addCateForm.cate_alias = obj.cate_alias
})
```
## 6.【重点】分页组件问题
# 3.【重要】插件使用
---
## 1. 持久化插件
> 刷新vuex的值会回归初始化, 如果在保存到vuex时, 它能自动保存到浏览器本地, 默认从浏览器本地取。
>
> 也可以自己写localStorage.setItem,这个持久化插件,就可以不再使用localStorage,也能实现本地缓存。
**下载持久化插件:**
```js
npm install vuex-persistedstate // 默认安装最新版
```
**在src/store/index.js中, 导入并配置:**
```js
mport Vue from 'vue'
import Vuex from 'vuex'
// 导入vuex-persistedstate插件
import createPersistedState from 'vuex-persistedstate'
Vue.use(Vuex)
export default new Vuex.Store({
state: {},
getters:{},
mutations: {},
actions:{},
modules: {},
// 注意:配置为 vuex 的插件,plugins插件也是store里面重要的一部分。
// Store除了包含 state,getters,mutations,actions,modules外,还包含plugins。
plugins: [createPersistedState()]
})
```
## 2. dayjs 格式化时间
**1. 安装格式化时间的第三方包dayjs:**
```js
npm install dayjs
```
**2. 在项目入口文件==main.js==中导入并使用dayjs,定义全局属性,对应函数。**
> 建议:公共的工具方法可以挂载到Vue原型上,组件内可以直接使用this.调用访问。
```js
// 导入dayjs方法
import dayjs from 'dayjs'
// 定义时间格式化函数
Vue.prototype.$formaDate = (dateObj)=>{
return dayjs(dateObj).format('YYYY-MM-DD HH:mm:ss')
}
```
**3. 在组建中进行调用:**
```html
{{ $formatDate(scope.row.pub_date) }}
```
# 4.【重点】经验问题
---
## 1. 图片上传问题
**img的src属性值只能是下面两种情况:**
- **方式一**:只能是图片的"链接地址"(外链:http://开头,图片文件相对路径)。
```js
// 解决方式1:文件转成存储在内存临时地址(这个地址只能在js里内存里不能发给后台)
// 语法:URL.createObjectURL(files[0])
// 返回值:内存临时地址
// this.avatar = URL.createObjectURL(files[0])
```
- **方式二**:或者是图片的base64字符串(而且字符串还必须是data:image/png;base64,图片转为base64字符串)
```js
// 解决方式2:文件转换成base64字符串(此字符串是可以转发到后台的)
// 1. 创建FileReader对象
const fr = new FileReader()
// 2. 调用readAsDataURL函数,读取文件内容
fr.readAsDataURL(files[0])
// onload等待把文件读成base64字符串后会触发onload事件函数
// 3. 监听 fr 的 onload 事件
fr.onload = (e) => {
// 4. e.target.result的值就是读完的结果,这里是固定写法(值是字符串,base64格式的字符串)
this.avatar = e.target.result
}
```
**图片案例:**

```js
methods: {
// 选择图片--->点击事件--->让选择框出现(选择图片文件的框框出现)
chooseImg() {
// 模拟点击行为
this.$refs.iptRef.click()
},
// 选择图片确定了
onFileChange(e) { // e原生事件对象
const files = e.target.files // 拿到用户选择的文件数组
if (files.length === 0) {
// 证明刚刚文件选择窗口打开了,但是它一个文件都没有选择然后点击了确定关闭选择弹窗
// console.log(2)
} else {
// console.log(1)
// 证明它选择了文件,默认只能选一个,如果选择多个你需要给input标签加额外原生属性
// console.log(files[0])
// 目标:选择的图片文件,要给到img标签做纯前端的预览
// img的src属性值只能是下面两种情况:
// 方式一:只能是图片的"链接地址"(外链:http://开头,图片文件相对路径)
// 方式二:或者是图片的base64字符串(而且字符串还必须是data:image/png;base64,图片转为base64字符串)
// 解决方式1:文件转成存储在内存临时地址(这个地址只能在js里内存里不能发给后台)
// 语法:URL.createObjectURL(files[0])
// 返回值:内存临时地址
// this.avatar = URL.createObjectURL(files[0])
// 解决方式2:文件转换成base64字符串(此字符串是可以转发到后台的)
// 1. 创建FileReader对象
const fr = new FileReader()
// 2. 调用readAsDataURL函数,读取文件内容
fr.readAsDataURL(files[0])
// onload等待把文件读成base64字符串后会触发onload事件函数
// 3. 监听 fr 的 onload 事件
fr.onload = (e) => {
// 4. e.target.result的值就是读完的结果,这里是固定写法(值是字符串,base64格式的字符串)
this.avatar = e.target.result
}
}
},
// 上传图像事件
async upLoadFn() {
const { data: res } = await updataUserAvatarAPI(this.avatar)
if (res.code !== 0) {
return this.$message.error(res.message)
}
// 重新让vuex获取一下最新数据
this.$store.dispatch('getUserInfoAction')
// 更新图像成功
return this.$message.success(res.message)
}
}
}
```
## 2. 图片打包问题
1. webpack 会把图片变成一个base64字符串或者在打包后的图片临时地址。
2. 标签和样式中,引入图片文件直接写"静态路径"(把路径放在js的vue变量里在赋予是不行的)
> template模板中 img 的 src 属性,不能直接写成图片地址,这个是无法显示的。(下面两种方式都是无法识别的)
>
>
>
>
- 原因:webpack分析标签的时候,如果src的值是一个相对路径,它会去帮我们找到那个路径文件一起打包,打包的时候,会分析文件大小,小图转换成base64字符串赋予给src,如果是大图拷贝图片换个路径给img的src,运行时显示。
- vue变量中路径,赋予给标签,都会当作普通字符串使用。
- 以前:写代码时候,我们写的路径是在vscode看着文件夹写的,(图片地址好使的原因:你用live server或者磁盘双击打开,它都能通过相对路径,在指定路径文件夹下,找到图片文件真身)。
- 现在:写的是模板代码,是被webpack翻译处理转换的,你vscode里的代码,转换后打包到内存中或者dist文件夹下,相对路径就会发生变化,运行时,你写的固定路径字符串找不到那个文件的真身。
- 解决方案:js里引入图片,**就用import引入,导入的图片在赋值给vue中的data对象的变量**,让webpack把它当作模块数据,是转换成打包后的图片路径还是base64字符串。
3. 注意:只有相对路径本地图片需要注意,如果你是一个http://外链的图片地址,就可以随便使用。直接标签里写也行,或者在js用变量保存后赋予给标签,因为运行时,浏览器发现src地址是外链就不会找相对路径文件夹。
## 3. css的scoped问题
**scoped属性作用:**让style里的选择器,只能选中当前组件的标签,保证样式的独立性,而不影响其它组件。
**scoped原理:**webpack打包的时候,会给组件标签上添加相同的**data-v-hash**值,然后也会给所有选择器后面加上一个**[data-v-hash]**值的属性选择器。
```html
```
**注意事项:**scoped只会给当前组件所有原生标签添加 data-v-hash 值属性,还会给组件标签内根组件标签添加 data-v-hash 值属性,组件内标签不会添加。