本来说弄个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...
组件传值
常用的就是
-
通过
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>
它的适用场景:
- 由一个组件,向上找到最近的指定组件
- 由一个组件,向上找到所有的指定组件
- 由一个组件,向下找到最近的指定组件
- 由一个组件,向下找到所有的的指定组件
- 由一个组件,找到指定组件的兄弟组件
我感觉比依赖注入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
来操作这种集合的时候。就能发现是真的好用。会显得很优雅。就一行。
//比如获取`00`权限
let normal = btns.get('00')
console.log(normal)
愉快地时光总是短暂的
本期小技巧分享到此结束。
1、scss
2、require.context
3、组件传值
4、Map()数据结构