您也可以以此项目为模板进行二次开拓,本项目的UI和功能实现均可作为参考。
如果有兴趣进一步互换的同学欢迎到本项目仓库提issues,也欢迎您的收藏和关注,感激!

仓库地址:https://github.com/konglingwen94/vue-seller-admin

线上地址: http://123.56.124.33:5000/admin

商城后台管理htmlVueElementUI搭建商家商号治理后台项目总结 SQL

部分运用页面截图

店铺配置页面

商品管理页面

商品编辑页面

运用开拓技能

核心技能架构:Vue@2.6.X+Element-ui@2.12.X

依赖包:vue-router v-charts(基于echarts封装的vue组件库)axios(http要求工具)

构建工具:vue-cli less

支配和运行:github-actions 云做事器

开拓过程中的案例先容

由于本运用利用场景较为广泛,这里有关业务场景的实现过程就不先容了。
在项目开拓完成后我总结了几个常用场景下的技能实现想在这分享一下。
如果你碰着了类型的功能需求可以参考下面的功能实现

二次封装uplod上传组件

组件源代码地址:https://github.com/konglingwen94/vue-seller-admin/blob/master/src/components/v-upload.vue

在多数的运用利用中我们都会碰着这样的需求,从本地电脑上传一张或多张图片到网站上,以上传的内容作为网站上须要为我们展现的内容。
在开拓这个功能的时候,对付用习气element-ui里的upload组件的我来说的话,对付上传一张和多张图片不同的业务处理我们还可以定制封装upload组件,这样的细粒度处理以便于更符合我们的业务需求。

常日用的最多的便是嵌入到表单里的图片上传功能,除了输入框等类型的表单可以用v-model的形式处理数据外,upload同样也可以,这样就大大便利了在提交表单时对付数据的处理过程。

首先给upload组件定义这样几个props。

props: { value: [String, Array], multipart: { type: Boolean, default: false } },

看过vue官方文档自定义v-model指令的基本先容的人都知道,value属性用于吸收组件上v-model指令的绑定值,相应的在组件内通过emit一个input事宜出去,传入的参数会自动更新到指令所绑定的值上。
其余一个multipart属性则表明了组件可一次上传的文件个数。
有了这两个props我们就有了大概实现全体组件功能的思路了。
下面就可以基于这两个属性实现emit一个input事宜的功能了。

对付所有的原生el-upload上文件更新的事宜监听器,根据multipart属性值的不同,这里以on-success事宜为例须要这样处理即可。

// 这里仅为部分代码handlerSuccess(res,file,fileList){if (!this.multipart) { if (fileList.length > 1) { fileList.shift(); } } const value = this.multipart ? fileList.map(item => { return (item.response && item.response.path) || item.url; }) : res.path; this.$emit("input", value);}

至此动态更新组件v-model指令绑定值的逻辑就处理完了,然而经由我的测试创造还有一个组件初始化的过程须要处理,也便是对付绑定到组件上的file-list字段的初始化过程。
首先须要在组件中定义一个fileList变量

data(){return { fileList:[] }}

有了这个fileList变量我们就可以对根本的upload组件初始化数据了,详细的绑定过程这里就不演示了,详细操作可以查看官方的组件利用办法。
但是经由测试这里还有一个问题,我们在表单里调用这个组件用v-model所绑定的值大多因此API要求的办法异步获取的,当要求完成时通过v-model指令传入的值并不能实时同步到fileList这个变量上,那要怎么办理这个问题呢?经由一番思考我想到了vue供应的$watch这个api,通过不雅观测组件的value属性我们就可以办理这个问题了

// 这里只须要在组件创建的时候一次性的不雅观测`value`属性值的变革created() { const unwatch = this.$watch("value", newVal => { this.fileList = Array(this.newVal) .flat() .map(item => ({ name: "", url: newVal })); unwatch && unwatch(); }); }

组件源代码: https://github.com/konglingwen94/vue-seller-admin/blob/master/src/components/v-upload.vue

现在再去测试组件创造可以完美的运行了

页面选项卡视图切换

效果图

源代码 https://github.com/konglingwen94/vue-seller-admin/blob/master/src/layout/basic.vue

选项卡视图是类似于浏览器页面浏览的一种通过标签点击切换页面的操作办法,我们可以在这里查看点击过的页面,通过点击关闭按钮可以关闭相应的标签。
选项卡组件自身的功能很大略,这里就不详细先容了。
下面紧张聊聊点击页面后的交互效果怎么去实现。

既然有了选项卡,我们须要的便是把浏览过的页面有状态的保留下来,下次页面切换回来的时候还保留离开时的状态。
说道这里我们很随意马虎能想到vue自身供应的keep-alive组件,通过用这个组件包裹我们动态切换的路由组件就可以缓存项目渲染过的组件了。
keep-alive详细的利用办法也不多说了,详情可以看官方文档先容。

为了存储选项卡和缓存组件的数据我们须要定义两个数组类型的变量,通过对这两个数组的操作处理来达到详细功能的实现。

/tab-tag 组件利用解释title:HTML原生属性 Stringclick:监听标签点击事宜 Functionclose:监听标签关闭事宜 Functionclosable:是否可以关闭 Booleanactive: 当前是否激活 Booleanlabel:展示笔墨,这里以插槽的办法传入 String/// 这里只展示干系的代码片段 <div class="tag-container"> <tab-tag :title="tag.label" @click="toggleTag(tag)" @close="closeTag(tag, index)" v-for="(tag, index) in tags" :key="index" :closable="!tag.isHome" :active="$route.path === tag.path" :style="{ width: `${100 / maxTags}%` }" >{{ tag.label }}</tab-tag> </div> <el-main> <keep-alive :max="maxTags" :include="cacheViews"> <router-view :key="$route.fullPath"></router-view> </keep-alive> </el-main>

data() { return { maxTags: 7, // 选项卡最大存储个数 tags: [ { label: "首页", // 标签内容 name: "seller-dashboard", // 对应页面路由的名称 path: "/seller/dashboard", // 对应页面路由的路径 isHome: true } ], // 选项卡初始化数据 cacheViews: [] // 缓存的页面组件,存储组件内手动声明的`name`值 };

有了上面在data函数里定义的变量,我们只须要把页面交互的功能实现就行了。
每一次的页面切换该当怎么存储呢? 处理这个问题须要我们实时不雅观测路由实例工具的变革,然后通过操作tags和cacheViews这两个变量以实现我们的需求

watch: { $route(newRoute) { const index = this.tags.findIndex(item => item.path === newRoute.path); if (index === -1) { if (this.tags.length >= this.maxTags) { this.tags.splice(1, 1); } if (!this.cacheViews.includes(this.$route.name)) { this.cacheViews.push(this.$route.name); } this.tags.push({ label: newRoute.meta.breadcrumbMenus[ newRoute.meta.breadcrumbMenus.length - 1 ], path: newRoute.path, name: newRoute.name }); // `meta.breadcrumbMenus`是我自己为了展示对应页面的面包屑菜单所设置的数据构造,你也可以定制自己的`label`字段。
} } },

在存储路由缓存和选项卡标签的时候须要把稳,我这里默认把设置的页面名称和路由名称保持同等,你也可以根据自己的须要灵巧的掌握,但是要担保cacheViews数组存储的一定是页面组件内定义的name值,这也是keep-alive组件在做缓存时所哀求的,不然的话动态组件不会被其缓存

实现了缓存页面组件以及存储选项卡标签的功能后,对付选项卡标签的切换和关闭功能也就很大略了,通过分别监听选项卡标签得click和close事宜来处理对应的逻辑

methods: { closeTag(tag, index) { this.tags.splice(index, 1); const isActive = this.$route.path === tag.path; this.cacheViews.splice(this.cacheViews.indexOf(tag.name), 1); if (isActive && !tag.isHome) { this.$router.push(this.tags[this.tags.length - 1].path); } }, toggleTag(tag, index) { if (tag.path === this.$route.path) { return; } this.$router.push(tag.path); } }

至此全体选项卡视图的功能就全部完成了,以上的先容是我自己项目的实现办法,部分代码没有通用化处理,,本功能还有待优化的地方,后续完成后我会及时更新,当你碰到类似需求的场景开拓时可以参照此实现办法,欢迎在评论区指示!

参考:https://juejin.cn/post/6844903968125124616

项目中利用到的技能小邪术分享Vue的computed属性

我们都知道vue的computed属性在项目开拓中无处不在,但是用的最多的是此属性的getter功能,深入理解computed属性的同学肯定知道他还有setter的功能可供我们利用,但是每每很多人不知道它的运用处景在哪,包括我自己在开拓本项目之前也是对这个setter的利用场景理解很少。
这里先先容一下computed属性全部语法的书写办法

// 这里以`formType`这个属性为例computed:{formType: { set(val) { this.form.type = val === "" ? -1 : val; }, get() { return this.form.type === -1 ? "" : this.form.type; }}

代码中formType属性是一个拥有了getter和setter的打算属性。
它的浸染比较像js里面的Object.defineProperty方法,通过拦截对一个工具属性的读取完成一些特定的逻辑。
可以看出对付formType属性的读取操作引发了其余一个数据的读取,这里就引出了form.type这个属性值了。
理解了它的基本利用办法后就须要我们进一步来运用他了

data(){return { form: { name: "", type: -1 }, // 由于实际项目表单项有多个,这里的`type`作为`form`工具的属性值定义 }}

从代码逻辑中不丢脸出,两段代码组合起来完成了formType和form.type关于''和-1这两个值相应式的分外对应关系。
那么这种分外的一对一的数据转化对应关系究竟适宜用到什么地方呢?这里我用了一个动态截图展示一下

先解释一下,表单中鼠标操作的选择框我用的以element-uiselect类型的选择框,选择框表单项的所绑定的值便是formType

组件html

<el-select v-model="formType" clearable placeholder="请选择优惠类型(可选)"> <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" ></el-option> </el-select>

js部分

data(){return { options: [ { value: 0, label: "满减" }, { value: 1, label: "折扣" }, { value: 2, label: "特价" }, { value: 3, label: "支持发票" }, { value: 4, label: "外卖保" } ], }}

从js部分的代码可以看出,表单项选择框里渲染的全部数据是这个样子的,选择框经由双向绑定后所取到的值是value这个字段。
由于做事真个一些设计规则返给前真个大多是number类型的数据,而经由我们用打算属性处理后的form.type字段值也刚好符合哀求。
因此当我编辑完表单后,其数据类型完备符合后真个须要,这让前端提交要求接口时免去了须要重新处理数据构造不一致的问题,也加强了组件数据自身的相应化过程。

自动支配

本项目是利用github-actions供应的集成支配环境,本地代码提交更新后自动支配到云做事器。
详细支配配置文件点这里 https://github.com/konglingwen94/vue-seller-admin/blob/master/.github/workflows/main.yml

管理员权限等级管理

对付比较大的管理后台系统会同时分配多个管理员,这些管理员之间也会有权限等级的分类。
本项目为了练手此业务功能划分为了超级和低级两个等级,线上环境登录的默认是低级管理员,在管理员列表里可以看到。

不同等级的管理员只能查看同级或比自身等级更低的注册用户,超级管理员可以查看所有用户。
想要以超级管理员的办法登录须要配套后端https://github.com/konglingwen94/elm-seller-server项目利用node环境初始化自动脚本后才可利用。

收成

通过本项目的开拓自己在B端运用上也有了更多的履历和技能上的收成,通过对Vue以及其组件库在实际项目中不断的实践运用,自己对前端开拓流程和规范也有了更多的思考。
以前做好一个项目考虑的是怎么实现需求,怎么用更少的代码实现功能。
而现在再让我去开拓一个项目,我会更多的考虑怎么用其余一个思路完成同样的需求,同一个功能需求可能会有很多个答案,考试测验更多的办理办法也能让自己在其他碰着的一些场景中用到,用一句话概括的话便是不同的办理办法有异曲同工之妙,这也会让自己的思路更开阔。

不只是在技能层面对前端有了更多的理解,在开拓规范上自己也理解的更多了。
比如代码的可读性,掩护性,变量命名的语义化等等。
就拿代码可读性来说,这个问题对付多人协作开拓的项目来说是很主要的,怎么让别人能最快的靠代码语义读懂你的项目,现在我在运用实践中也会更多的考虑这个问题。
在办理一个技能问题时,宁肯让代码量变得多的,也要担保代码的语义和可读性更好,不能追求逻辑代码的精简(学习API练习demo的时候可以这么干)从而危害到了全体项目的掩护性以及代码可读性问题。

项目预览

线上地址:http://123.56.124.33:5000/admin

github: https://github.com/konglingwen94/vue-seller-admin

其他关联项目

客户端线上地址:http://123.56.124.33:5000

客户端仓库地址:https://github.com/konglingwen94/vue-elm-seller

做事端仓库地址:https://github.com/konglingwen94/elm-seller-server

感谢

如果你对本项目有好的建议欢迎到仓库提issues,欢迎小伙伴们互换留言,感激!

感谢所有阅读,点赞和关注的小伙伴们!