Vue后台项目知识点总结

ES6暴露

export { default as login } from "./acl/login"; // {default: {}}
export { default as user } from "./acl/user";
export { default as role } from "./acl/role";
export { default as permission } from "./acl/permission";
export { default as category } from "./category";
export { default as clientUser } from "./clientUser";
// 1. 引入默认暴露的内容重命名为order
// 2. 将order给分别暴露出去
export { default as order } from "./order";
export { default as trademark } from "./product/trademark";

// import { default as order } from './order' // 完整引入
// import order from './order' // 完整引入的简写
// export order;

/*
  {
    login: { login() {}... },
    user,
    role,
    permission,
    category,
    clientUser,
    order,
    trademark
  }
*/

两种特殊引入介绍

//当你 import result from './xxx' 引入时
//实际相当于 import { default as result } from './xxx' 写法

import result from "./test/es-module/test1";
import { default as result } from "./test/es-module/test1";

// 引入所有重命名为result
import * as result from "./test/es-module/test1";

默认导出

/* 默认导出,只能有一个 */
const a = 1;
// const b = 2;
export default a;
// export default b

默认暴露实际暴露的内容:
{
default: 1
}
当你 import result from ‘./xxx’ 引入时
实际相当于 import { default as result } from ‘./xxx’ 写法

import result from "./test/es-module/test1";
import { default as result } from "./test/es-module/test1";
console.log(result);

在这里插入图片描述

// 引入所有重命名为result
import * as result from "./test/es-module/test1";
console.log(result);

在这里插入图片描述

  • 若果暴露多个
    在这里插入图片描述
    在这里插入图片描述

分别导出

/* 分别导出,可以有多个 */
export const c = 4;
export const d = 5;

import { c, d } from "./test/es-module/test1";
console.log(c, d);
// 引入所有重命名为result
import * as result from "./test/es-module/test1";
console.log(result);

分别暴露实际暴露的内容:
{
b: 2,
c: 3
}

默认暴露和分别暴露可以共存
{
b: 2,
c: 3,
default: 1
}
在这里插入图片描述

统一暴露

/* 统一暴露 */
const e = 6;
const f = 7;
export { e, f };

import { e, f } from "./test/es-module/test1";
console.log(e, f);
import * as result from "./test/es-module/test1";
console.log(result);

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

深度选择器

  lang="less"
    完整写法
    深度选择器 /deep/
  lang="sass"
    可以省略 {}
    可以省略 ;
    深度选择器 /deep/  >>>
  lang="scss"
    完整写法

  lang="stylus"
    可以省略 {}
    可以省略 :
    可以省略 ;

  scoped
    让样式只在当前组件生效
    问题:加上scoped,会让设置的子组件样式失效
    解决:使用深度选择器

添加scoped以后样式失效

<style lang="sass" scoped>

>>>

<style lang="sass" scoped>
>>>.trademark-table
  margin: 20px 0
>>>.trademark-image
  width: 100px
>>>.trademark-pagination
  text-align: right
>>>.el-pagination__sizes
  margin-left: 250px
</style>

/deep/

<style lang="sass" scoped>
/deep/.trademark-table
  margin: 20px 0
/deep/.trademark-image
  width: 100px
/deep/.trademark-pagination
  text-align: right
/deep/.el-pagination__sizes
  margin-left: 250px
</style>

.sync/scope/$event

.sync

  :count="count"
  v-bind:count="count" //单向数据流 / 强制绑定数据
    //子组件只能读取不能修改
    //问题:子组件需要修改数据
    //解决:数据源在哪,更新数据的方法就定义在哪

  :count.sync="count" //给子组件传递xxx数据以及更新数据的方法update:xxx
    //相当于:
      :count="count" @update:count="xxx"

    .sync用于父子通信(子向父)
 -->
<Test :count="count" :updateCount="updateCount" /> 
 <Test :count.sync="count" /> 

scope

scope代表所有数据
scope.row 代表当前行所有数据

$event

:page-size.sync="limit"   //可以让limit更新变成同步更新
  :current-page.sync="page" //可以让page更新变成同步更新

  $event
    1.DOM事件中代表 event
    <button @click="handle(123, $event)"></button>
   // 触发事件是浏览器的行为,所以$event代表event

    2. 在自定义事件中代表 第一个参数
      <button @aaa="handle($event)"></button>
      假设这样触发自定义事件: this.$emit('aaa', 123, 456);
      那么$event就为123(第一个参数)

src图片

//前提允许跨域
   action="http://182.92.128.115/admin/product/fileUpload"
   目标服务器地址: 代理配置中 (vue.config.js)

//不允许跨域,就使用proxy
   action="/dev-api/admin/product/fileUpload"
   /dev-api -> request.js 代理
  在main.js中定义 Vue.prototype.$BASE_API = process.env.VUE_APP_BASE_API

:action="`${$BASE_API}/admin/product/fileUpload`"

错误解决

input无法自动聚焦

Autofocus processing was blocked because a document's URL has a fragment '#/product/attr/list'.
// input
autofocus
ref="attrInput"

// span
edit(row) {
  // 设置属性,让其确认显示哪个,手动聚焦
  this.$set(row, "edit", true);
  this.$nextTick(() => {
    this.$refs.attrInput.focus();
  });
},

keyup.enter无法使用

         事件修饰符:
            .native
            专门给组件绑定事件使用的
            会给组件中的第一个标签绑定相应的原生DOM事件
 @keyup.enter.native="row.edit = false"

响应式数据

直接给对象添加新属性不是响应式数据, 通过this.$set添加的属性才是响应式

this.$set(row, "edit", true);

深度克隆

// 深度克隆:防止对象中对象还存在引用关系
this.attr = JSON.parse(JSON.stringify(attr));

效验与自定义效验

 // 效验
 rules: {
   spuName: [
     { required: true, message: "请输入SPU名称", trigger: "blur" },
   ],
   tmId: [{ required: true, message: "请选择品牌名称" }],
   description: [{ required: true, message: "请输入品牌描述" }],
   spuImage: [{ validator: this.spuImageValidator, required: true }],
   sale: [{ validator: this.saleValidator, required: true }],
 },
    // 属性选择效验
    saleValidator(rule, value, callback) {
      if (this.spuSaleAttr.length === 0) {
        callback(new Error("请至少选择一个销售属性"));
        return;
      }

      const res = this.spuSaleAttr.some(
        (item) => item.spuSaleAttrValueList.length === 0
      );

      if (res) {
        callback(new Error("请至少选择一个销售属性名称"));
        return;
      }

      callback();
    },

权限管理

功能介绍

  • 菜单管理

    • 设置用户可以访问的所有路由菜单和相应的按钮权限
  • 角色管理

    • 设置角色的访问权限(路由权限和按钮权限)
  • 用户管理

    • 给创建的用户绑定上某个角色(就会拥有这个角色的权限)

使用某个用户登录,只能访问这个用户对应角色拥有的权限路由和权限按钮

原理实现

  1. 路由权限
  • 在全局路由前置守卫完成的
  • 首先从 vuex 中取出 token,判断是否有 token
    • 有(代表用户之前登录过)

      • 优化:取出用户数据判断是否存在
        • 存在说明之前登录成功过且数据没问题,直接放行
        • 不存在,说明之前没有登录成功过,需要进行下面步骤
      • 需要验证 token 是否有效(是否是真实 token 且没有过期)
      • 通过发送请求请求用户数据,此时在拦截器中请求头会携带上了 token,后台会自动进行验证 token 的有效性(try catch)
      • 有效
        • 得到了用户数据(其中包含了按钮权限数据和菜单权限数据)
        • 菜单权限数据需要处理组件,组件需要使用真正的组件,使用递归遍历处理所有菜单
        • 通过 router.addRoutes(),来动态添加路由,从而路由生效
          • 一上来路由中只有登录、404、首页等路由配置,其他都没有,所以一上来用户只能访问这些页面
          • 一旦动态添加路由,用户访问的路由就更多了,从而实现路由的权限控制
        • 跳转到 to.path
      • 失效
        • 清空 token,跳转到登录页面
    • 没有(代表用户之前没有登录过)

      • 判断要去路由路径(to.path)是否是 login
        • 是 调用 next()放行
        • 不是 调用 next({ path: ‘/login’ })强行跳转到 login
          • 有一个对用户体验更好的小功能 - 重定向
            • 跳转到 login 时加上一个 query 参数 redirect,值为 to.path
            • 当将来登录成功时,会拿到 redirect 进行跳转,而不是首页
  1. 按钮权限
  • 在全局路由前置守卫获取用户数据的时候,同时也获取到了按钮权限列表,存在了 vuex 中
  • 按钮权限列表就是一个数组。数组有 n 个按钮的权限值(字符串、id)
  • 每一个路由组件的功能按钮也会有自己的权限值
  • 判断路由组件的功能按钮的权限值在不在请求回来按钮权限列表中
    • 在说明有权限。通过 v-if 来显示
    • 不在说明没有权限。通过 v-if 来隐藏
  • 从而实现按钮权限控制
  • 优化:因为很多按钮都有相同的判断,设计一个公共判断的方法 hasBtnPermission,挂载到 Vue 的原型上,从而所有组件实例都可以复用

理解区别2组业务概念

SPU与SKU

  SPU: 某个商品所有相关信息的集合, 包括所有可选择的图片, 可选择的平台属性与销售属性
  SKU: SPU下确定了图片列表/平台属性与销售属性数据的信息集合, 商品唯一标识
  关系: 一个SPU下可以对应多个SKU

平台属性与销售属性

  平台属性: 用于(出现)商品搜索的商品描述信息, 包含属性名与一系列的属性值
  销售属性: 出现在商品详情界面的商品描述信息, 包含属性名与一系列的属性值

作用域样式与深度样式选择器

	不声明scoped, 样式是全局的, 可以匹配影响所有的组件
	声明scoped, 就不会影响到子组件内部样式(根标签除外)
			标签的变化:
				当前组件的所有标签都增加一个data自定义属性: data-v-2e8d0da5 => 用来标识当前组件的
				子组件的根标签也会有此data属性, 子标签没有
			样式的选择器变化: 选择器的最右边添加了当前组件data属性的选择  
				.test2 .t2[data-v-2e8d0da5] {
					color: red;
				}
				==> 能匹配当前组件的所有元素
				==> 还能匹配子组件根标签, 但不可能匹配其子标签
	使用深度选择器, 修改子组件内部任意标签的样式
		编码: 
			.test2 >>> .t22 {
				font-size: 30px;
			}
			.test2 {
				/deep/ .t22 {
					color: hotpink;
				}
			}
		没用深度
			.test2 .t2[data-v-2e8d0da5] {
				color: red;
			}
		用了深度
			.test2[data-v-2e8d0da5] .t22 {
				font-size: 30px;
			}
		==> 属性选择从最右边转移到了左边  ==> 此选择对目标元素没有当前data属性的要求 ==> 可以子组件任意标签
	修改第三方组件库内部的样式: 使用deep选择器
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值