# 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 ``` # 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 } ``` **图片案例:** ![](D:\DEMO\20230511-bigEvent\README\images\img.png) ```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 值属性,组件内标签不会添加。