share

本来说弄个vue的专享,但是这个可能有些地方还没你们了解的深入。
所以还是退而求其次来个技巧的分享吧。

只是简单的说说一些比较好用的技巧,首先聊聊scss的一些指令吧

@each 指令的格式是 $var in <list>, $var可以是任何变量名,比如 $length 或者 $name,而 <list>是一连串的值,也就是值列表。

@each 将变量 $var 作用于值列表中的每一个项目,然后输出结果,例如:

我的理解是有些类似于js中的字符串模板

//js字符串模板 
const shareName = ' 技巧分享 '
console.log(`${shareName }`)
//scss中声明的方式
.#{$var}-icon  //类名  #{$var}
background-image: url('/images/#{$var}.png');  //样式   字符串  #{$var}
text-align: $var !important;    //样式    $var

示例1

//注意  以下值列表的表现形式
@each $var in puma, sea-slug, egret, salamander {
  .#{$var}-icon {
    background-image: url('/images/#{$var}.png');
  }
}

编译为
.puma-icon {
  background-image: url('/images/puma.png'); 
}
.sea-slug-icon {
  background-image: url('/images/sea-slug.png'); 
}
.egret-icon {
  background-image: url('/images/egret.png'); 
}
.salamander-icon {
  background-image: url('/images/salamander.png'); 
}

示例2

// text align   文字位置  
//注意  以下值列表的表现形式
@each $var in (left, center, right) {
  .text-#{$var} {
    text-align: $var !important;
  }
}

//编译为
.text-left {
  text-align: left !important;
}
.text-center {
  text-align: center !important;
}
.text-right {
  text-align: right !important;
}

示例3

//colors  常用颜色
//值列表   键值对    map-get($colors,'bgc');
$colors: (
  'bgc': #fbfbfb,
  'bgh': #e7f3ff,
  'blue':#2e85ff,
);

.text-bgc {
  color: map-get($colors,'bgc');
}

//常见于组合使用
//设置之背景色和字体颜色
@each $colorKey, $color in $colors {
  .text-#{$colorKey} {
    color: $color;
  }
  .bg-#{$colorKey} {
    background-color: $color;
  }
}

//编译为
.text-bgc {
  color: #fbfbfb;
}
.bg-bgc {
  background-color: #fbfbfb;
}
.text-bgh {
  color: #e7f3ff;
}
.bg-bgh {
  background-color: #e7f3ff;
}
.text-blue {
  color: #2e85ff;
}
.bg-blue {
  background-color: #2e85ff;
}

示例4

//比如还有以下的多重循环   在项目中可能很多地方都会使用到固定的margin  padding值
//如以下三个值列表   在多重嵌套循环之后  就会编译为我们所需要的形式
$spacing-types: (
  m: margin,
  p: padding
);

$spacing-base-size: 1px;
$spacing-sizes: (
  10: 10,
  25: 25,
  55: 55
);

$spacing-directions: (
  t: top,
  r: right
);

// m-0, mx-0
@each $typeKey, $type in $spacing-types {
  @each $directionKey, $direction in $spacing-directions {
    @each $sizeKey, $size in $spacing-sizes {
      .#{$typeKey}#{$directionKey}-#{$sizeKey} {
        #{$type}-#{$direction}: $size * $spacing-base-size;
      }
    }
  }
}

//编译为
.mt-10 {
  margin-top: 10px;
}
.mt-25 {
  margin-top: 25px;
}
.mt-55 {
  margin-top: 55px;
}
.mr-10 {
  margin-right: 10px;
}
.mr-25 {
  margin-right: 25px;
}
.mr-55 {
  margin-right: 55px;
}
.pt-10 {
  padding-top: 10px;
}
.pt-25 {
  padding-top: 25px;
}
.pt-55 {
  padding-top: 55px;
}
.pr-10 {
  padding-right: 10px;
}
.pr-25 {
  padding-right: 25px;
}
.pr-55 {
  padding-right: 55px;
}

以上算是一个可以快速生成初始样式便捷方式!
当然除了@each 还有一些如 @mixin %box @function...

混合样式
//Mixin 可以传入参数,直接复制属性到每个选择器里。 通过`@include`指令调用
//由于是复制   所以会有很多重复的样式代码
@mixin box($width: 100px, $height: 100px) {
  width: $width;
  height: $height;
  box-shadow: 0px 0px 5px black;
  margin: 10px;
}

.smallBox {
  @include box(100px, 100px);
}

.bigBox {
  @include box(300px, 300px);
}

//编译后
.smallBox {
  width: 100px;
  height: 100px;
  box-shadow: 0px 0px 5px black;
  margin: 10px;
}

.bigBox {
  width: 300px;
  height: 300px;
  box-shadow: 0px 0px 5px black;
  margin: 10px;
}



占位符选择器
//必须通过 `@extend`指令调用    %
//比 Mixin 要省很多代码,它能将重复的代码进行提取
%box {
  box-shadow: 0px 0px 5px black;
  margin: 10px;
}

.bigBox {
  @extend %box;
  width: 300px;
  height: 300px;
}

.smallBox {
  @extend %box;
  width: 100px;
  height: 100px;
}

.bigBox {
  @extend %box;
  width: 300px;
  height: 300px;
}

//编译为
.bigBox, .smallBox {
  box-shadow: 0px 0px 5px black;
  margin: 10px;
}
.smallBox {
  width: 100px;
  height: 100px;
}
.bigBox {
  width: 300px;
  height: 300px;
}




函数指令
//以前做rem 布局时使用   现在px2rem-loader插件
//能将px单位转化为rem
@function rem($a) {
  @return $a / 100  + rem
};

.smallBox {
  width: rem(50);
  height: rem(50);
}

.bigBox {
  width: rem(150);
  height: rem(150);
}

//编译为
.smallBox {
  width: 0.5rem;
  height: 0.5rem;
}
.bigBox {
  width: 1.5rem;
  height: 1.5rem;
}

使用熟练了可以省掉很多代码的 三个类名就垂直居中了

<div class="d-flex jc-center ai-center">
  <div class='smallBox '>
    // doSomething   我是垂直居中的
  </div>
</div>


// flex 配置
.d-flex {
  display: flex;
}
$flex-jc: (
  start: flex-start,
  end: flex-end,
  center: center,
  between: space-between,
  around: space-around,
);
$flex-ai: (
  start: flex-start,
  end: flex-end,
  center: center,
  stretch: stretch,
);
@each $key, $value in $flex-jc {
  .jc-#{$key} {
    justify-content: $value;
  }
}

@each $key, $value in $flex-ai {
  .ai-#{$key} {
    align-items: $value;
  }
}
好用的require.context

以下是一个自动全局注册多个vue组件的脚本文件,避免了麻烦的一个个的找文件引入

import Vue from 'vue'

// 自动加载 common 目录下的 .js 结尾的文件
const componentsContext = require.context('./common', true, /\.js$/)

componentsContext.keys().forEach(component => {
  const componentConfig = componentsContext(component)
  /**
   * 兼容 import export 和 require module.export 两种规范
   */
  const ctrl = componentConfig.default || componentConfig
  Vue.component(ctrl.name, ctrl)
})

require.context:它是webpack的api,通过执行require.context函数会生成一个 context module(上下文模块)。该context module包含一个map(映射)对象,会把requests翻译成对应的模块id。
Request: 指在 require/import 语句中的表达式,如在 require("./common/" + name + ".js") 中的请求是 "./common/" + name + ".js"

//可以给这个函数传入三个参数
//要搜索的目录
//标记表示是否还搜索其子目录
//匹配文件的正则表达式。
require.context('./common', true, /\.js$/)
//源码如下
var map = {
    "./aa/index.js": "./src/components/common/aa/index.js",
    "./bb/index.js": "./src/components/common/bb/index.js",
    "./cc/index.js": "./src/components/common/cc/index.js"
};


function webpackContext(req) {
    var id = webpackContextResolve(req);
    return __webpack_require__(id);
}
function webpackContextResolve(req) {
    if(!__webpack_require__.o(map, req)) {
        var e = new Error("Cannot find module '" + req + "'");
        e.code = 'MODULE_NOT_FOUND';
        throw e;
    }
    return map[req];
}
webpackContext.keys = function webpackContextKeys() {
    return Object.keys(map);
};
webpackContext.resolve = webpackContextResolve;
module.exports = webpackContext;
webpackContext.id = "./src/components/common sync recursive \\.js$";

require.context执行后,返回一个方法webpackContext,这个方法又返回一个__webpack_require__,这个__webpack_require__就相当于require或者import。同时webpackContext还有二个静态方法keys与resolve,一个id属性。

  • id 是 context module 的模块 id。
  • keys 它返回一个数组,由所有可能被此 context module 处理的请求组成。
  • resolve 它返回 request 被解析后得到的模块 id。
  • webpackContext 返回的是一个模块,这个模块才是真正我们需要的。这个Module模块和使用import导入的模块是一样的。


    源码
结果

返回方法webpackContext,然后将key传进去,就能得到相应的整个模块。

全局注册

在前端工程中,从一个文件夹引入很多模块的情况的就会变得常见,此时建议使用这个api,它会遍历指定的文件夹中的文件,自动导入,使得你不需要每次显式的调用import导入模块。

比如请求接口的时候,会分很多模块,那么调用的时候需要一个个模块的去找,此时就可以使用这个api,将请求接口的方法统一引入。除此之外还有很多地方都可以使用这个api,如svg、router、axios...

image.png

image.png
组件传值

常用的就是

  • 通过prop向子组件传数据
    prop 是你可以在组件上注册的一些自定义特性。当一个值传递给一个 prop 特性的时候,它就变成了那个组件实例 的一个属性。
    一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop
    我们可以在父组件中使用 v-bind或简写 : 来动态传递prop
  • 通过事件向父级组件发送消息
    Vue 实例提供了一个自定义事件的系统来解决这个问题。我们可以调用内建的 $emit 方法并传入事件的名字,来向父级组件触发一个事件。
  • 访问元素 & 组件
    ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的$refs 对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例。

但是最近看了风哥推荐的掘金小册。看了看组件这一块,平时也知道这种方式,但是一直没有去细想。细想来就发现了组件调用的终极方式。

//父组件
<template>
  <div id="app">
    app
    <aa></aa>
    <bb></bb>
    <cc></cc>
  </div>
</template>

<script>

export default {
  name: 'App',
  data(){
    return {
      name:'App1'
    }
  },
  methods:{
    getName(){
      console.log(`这是${this.name}`)
    }
  }
}
</script>

//子组件
<template>
    <div>
        aa组件
    </div>
</template>

<script>
export default {
    name: 'aa',
    data() {
        return {
            
        };
    },
    mounted() {
        //如何找到父组件的name
        console.log(this.$parent.name)
        //如何找到父组件的getName方法
        console.log(this.$parent.getName)
        this.$parent.getName()
        //如何找到兄弟组件
        console.log(this.$parent.$children)
        let children = this.$parent.$children.find(e => e.$options.name === 'cc')
        console.log(children)
        console.log(children.$options.name)
    }
};
</script>

<style lang="scss" scoped>

</style>
编译后

它的适用场景:

  1. 由一个组件,向上找到最近的指定组件
  2. 由一个组件,向上找到所有的指定组件
  3. 由一个组件,向下找到最近的指定组件
  4. 由一个组件,向下找到所有的的指定组件
  5. 由一个组件,找到指定组件的兄弟组件

我感觉比依赖注入provide、inject更好用,结合起来就能大展手脚。

Map()数据结构

JavaScript 的对象(Object),本质上是键值对的集合(Hash 结构)。
区别
传统Object键名只能是字符串形式
Map的键名可以是任意类型(包括对象)

特性

  • Map键名可以是任意类型
  • Map键名为对象类型时,与内存地址绑定,如果内存地址不同,就视为两个键
  • Map键名为简单类型(数值,字符串,布尔值),只要两个值严格相等(===),就认为是一个键。
  • NaN被视为同一个键,0和-0被视为同一个键
  • 相同键多次赋值,后覆盖前

实例的属性和方法

  • size属性
    返回Map成员总数
  • set(key, value)
    设置键值对,返回Map本身,所以可以链式
  • get(key)
    读取key对应的值,找不到返回undefined
  • has(key)
    返回布尔值,表示是否存在
  • delete(key)
    删除某键,返回布尔值,表示是否成功删除
  • clear()
    清空所有成员,无返回值。

以及遍历方法。

以下也简单的讲解一个例子说明其使用场景。

//如:需要根据用户权限 展示对应的操作按钮。
//在以下场景中使用这种方式就会显得非常快捷方便。
//键名不一样 值是json格式的数据
let btns = new Map([     // 数据结构map
  // 已取消
  ['00', [{
    text: '查看详情',
    key: 'details',
    btnClass: 'ybBtn',
    fun: (it) => this.gotoDetail(it.id)
  }]],
  // 待修改//已驳回
  ['01', [{
    text: '修改资料',
    key: 'modify',
    btnClass: 'ybBtn',
    fun: (it) => this.goModify(it)
  }, {
    text: '取消订单',
    key: 'cancel',
    btnClass: 'ybBtn',
    fun: (it) => this.goCancel(it)
  }, {
    text: '查看详情',
    key: 'details',
    btnClass: 'ybBtn',
    fun: (it) => this.gotoDetail(it.id)
  }]],
  // 待审核
  ['10', [{
    text: '取消订单',
    key: 'cancel',
    btnClass: 'ybBtn',
    fun: (it) => this.goCancel(it)
  }, {
    text: '查看详情',
    key: 'details',
    btnClass: 'ybBtn',
    fun: (it) => this.gotoDetail(it.id)
  }]],
  // 待支付
  ['20', [{
    text: '去支付',
    key: 'pay',
    btnClass: 'ybBtn',
    fun: (it) => this.goPay(it)
  }, {
    text: '取消订单',
    key: 'cancel',
    btnClass: 'ybBtn',
    fun: (it) => this.goCancel(it)
  }]]
])
console.log(btns)
console.table([...btns])
Map数据展示

同样是键值对的集合。但是键名不同的时候取值就会不那么便捷。如果是普通的map方法的话,要遍历数组啊,找键名一致的啊,然后再去原数组中取值等,步骤繁多,显得很冗长。但是使用Map来操作这种集合的时候。就能发现是真的好用。会显得很优雅。就一行。

//比如获取`00`权限
let normal = btns.get('00')
console.log(normal)
‘00’权限

愉快地时光总是短暂的
本期小技巧分享到此结束。

1、scss
2、require.context
3、组件传值
4、Map()数据结构

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351

推荐阅读更多精彩内容