2.1.6 如何解决Vue在main.js全局引入scss文件,组件里使用scss变量报错问题
报错: Syntax Error: SassError: Undefined variable.
我一开始的引入方式是这样的:
以为在main.js全局引入了就一劳永逸,写着常规css样式时还好好的,用到scss变量时就报错了。
- 解决方法一
在需要用到的 .vue 文件里单独引用 variable.scss 变量文件,但是达不到我们想要的“一劳永逸“效果,可能还会有奇奇怪怪的潜在问题,建议使用方法二。
- 解决方法二
通过配置,使得全局都能使用scss变量,而不用每个文件单独引入 。
1、vue-cli2创建的项目:
修改build中的utils.js文件,将 scss: generateLoaders(‘sass’),修改为如下:
scss: generateLoaders('sass').concat({ loader: 'sass-resources-loader', options: { //你自己的scss全局文件的路径 resources: path.resolve(__dirname, '../src/common/index.scss') } }),
2.vue-cli3创建的项目:
module.exports = { css: { loaderOptions: { // 不同 sass-loader 版本对应关键字, // v8-: data v8: prependData v10+: additionalData sass: { additionalData: `@import "@/assets/scss/index.scss";` }, scss: { additionalData: `@import "@/assets/scss/index.scss";` }, } } }
注意:scss 配置后面需要加 分号 ‘;’,否则会报错 Syntax Error: SassError: media query expression must begin with ‘(’
参考文档:https://cli.vuejs.org/zh/guide/css.html#css-modules
2.2 javascript开发技巧
2.2.1 数组操作
1、使用 includes 简化 if 判断
Bad Code
if(ticketCode === '01' || ticketCode === '02' || ticketCode === '03') { }
Good Code
if(['01', '02', '03'].includes(ticketCode)) { } // 下面这种也可以 if('01,02,03'.includes(ticketCode)) { }
2、使用every判断是否所有项都满足条件
Bad Code
let arr = [{checked: true}, {checked: false}, {checked: true}, {checked: false}] let isAllchecked = true // 是否全部选中 arr.forEach(item => { if(!item.checked) { isAllchecked = false } })
Good Code
数组的every方法只要有一项不满足条件就会返回false,不会再继续遍历
let arr = [{checked: true}, {checked: false}, {checked: true}, {checked: false}] let isAllchecked = arr.every(item => { console.log('item', item) return !!item.checked })
3、使用some判断是否有一项满足条件
Bad Code
let arr = [{checked: false}, {checked: true}, {checked: false}, {checked: true}] let isHaveChecked = false // 是否有选中的 arr.forEach(item => { if(item.checked) { isHaveChecked = true } })
Good Code
数组的some方法只要有一项满足条件就会返回true,不会再继续遍历
let arr = [{checked: false}, {checked: true}, {checked: false}, {checked: true}] let isHaveChecked = arr.some(item => { console.log('item', item) return !!item.checked })
4、使用reduce遍历数组处理求和等复杂逻辑
reduce()
方法对数组中的每个元素按序执行一个由您提供的 reducer 函数,每一次运行 reducer 会将先前元素的计算结果作为参数传入,最后将其结果汇总为单个返回值 。
第一次执行回调函数时,不存在“上一次的计算结果”。如果需要回调函数从数组索引为 0 的元素开始执行,则需要传递初始值。否则,数组索引为 0 的元素将被作为初始值 initialValue,迭代器将从第二个元素开始执行(索引为 1 而不是 0)。
语法
reduce(callbackFn) reduce(callbackFn, initialValue)
参数
callbackFn
一个“reducer”函数,包含四个参数:previousValue
:上一次调用callbackFn
时的返回值。在第一次调用时,若指定了初始值 initialValue,其值则为 initialValue,否则为数组索引为 0 的元素array[0]
。currentValue
:数组中正在处理的元素。在第一次调用时,若指定了初始值initialValue
,其值则为数组索引为 0 的元素array[0]
,否则为array[1]
。currentIndex
:数组中正在处理的元素的索引。若指定了初始值initialValue
,则起始索引号为 0,否则从索引 1 起始。array
:用于遍历的数组。initialValue
可选
作为第一次调用callback
函数时参数 previousValue 的值。若指定了初始值initialValue
,则currentValue
则将使用数组第一个元素;否则previousValue
将使用数组第一个元素,而currentValue
将使用数组第二个元素。
返回值
使用“reducer”回调函数遍历整个数组后的结果。
示例
(1)计算数组中每个元素出现的次数
let names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'] let nameNum = names.reduce((pre,cur)=>{ if(cur in pre) { pre[cur]++ } else { pre[cur] = 1 } return pre }, {}) console.log(nameNum); //{Alice: 2, Bob: 1, Tiff: 1, Bruce: 1}
(2)数组去重
let arr = [1,2,3,4,4,1] let newArr = arr.reduce((pre,cur)=>{ if(!pre.includes(cur)){ return pre.concat(cur) }else{ return pre } },[]) console.log(newArr);// [1, 2, 3, 4] // 简便写法 let newArr = [...new Set(arr)] let newArr = Array.from(new Set(arr))
(3)将二维数组转化为一维
let arr = [[0, 1], [2, 3], [4, 5]] let newArr = arr.reduce((pre,cur) => { return pre.concat(cur) }, []) console.log(newArr); // [0, 1, 2, 3, 4, 5] // 简便写法 let newArr = arr.flat() // 拉平二维数组
(4)将多维数组转化为一维
let arr = [[0, 1], [2, 3], [4,[5,6,7]]] const newArr = function(arr){ return arr.reduce((pre,cur)=>pre.concat(Array.isArray(cur)?newArr(cur):cur),[]) } console.log(newArr(arr)); //[0, 1, 2, 3, 4, 5, 6, 7]
2.2.2 对象操作
1、向对象有条件的添加属性
使用场景:
表单提交时针对个性化开关控制的必填参数可以通过该方式来添加到固定参数集合中。
const condition = true; const person = { id: 1, name: 'John Doe', ...(condition && { age: 16 }), }; // 如果 condition 为 false,JavaScript 会做这样的事情: const person = { id: 1, name: '前端小智', ...(false), }; // 展开 `false` 对对象没有影响 console.log(person); // { id: 1, name: 'John Doe' }
2、检查属性是否存在对象中
const example = {}; example.prop = 'exists'; // hasOwn 只会对直接属性返回 true:: Object.hasOwn(example, 'prop'); // returns true Object.hasOwn(example, 'toString'); // returns false Object.hasOwn(example, 'hasOwnProperty'); // returns false // in 会对直接或继承的属性返回 true: 'prop' in example; // returns true 'toString' in example; // returns true 'hasOwnProperty' in example; // returns true
3、使用Object.entries() 返回一个给定对象自身可枚举属性的键值对数组
const object1 = { a: 'somestring', b: 42 }; const arr = Object.entries(object1) //arr:[['a','somestring'],['b','42']] for (const [key, value] of arr) { console.log(`${key}: ${value}`); } // Expected output: // "a: somestring" // "b: 42"
4 、使用Object.fromEntries( ) 方法把键值对列表转换为一个对象
const entries = new Map([ ['foo', 'bar'], ['baz', 42] ]); const obj = Object.fromEntries(entries); console.log(obj); // Expected output: Object { foo: "bar", baz: 42 }
5、使用Object.freeze冻结对象(可在vue data定义非响应式变量使用)
const obj = { prop: 42 }; Object.freeze(obj); obj.prop = 33; // Throws an error in strict mode console.log(obj.prop); // Expected output: 42
2.2.3 字符串操作
1、字符串不满两位补零
ES2017 引入了字符串补全长度的功能。如果某个字符串不够指定长度,会在头部或尾部补全。padStart()
用于头部补全,padEnd()
用于尾部补全。
padStart()
和padEnd()
一共接受两个参数,第一个参数是字符串补全生效的最大长度,第二个参数是用来补全的字符串。
'x'.padStart(5, 'ab') // 'ababx' 'x'.padStart(4, 'ab') // 'abax' 'x'.padEnd(5, 'ab') // 'xabab' 'x'.padEnd(4, 'ab') // 'xaba'
如果原字符串的长度,等于或大于最大长度,则字符串补全不生效,返回原字符串。
'xxx'.padStart(2, 'ab') // 'xxx' 'xxx'.padEnd(2, 'ab') // 'xxx'
如果用来补全的字符串与原字符串,两者的长度之和超过了最大长度,则会截去超出位数的补全字符串。
'abc'.padStart(10, '0123456789') // '0123456abc'
如果省略第二个参数,默认使用空格补全长度。
'x'.padStart(4) // ' x' 'x'.padEnd(4) // 'x '
常用场景:
// 获取当前月份小于10前补0 let month = new Date().getMonth() +1 // 常规写法利用三木运算符处理 month = month < 10 ? '0' + month : month // 也可以利用pdaStart填充实现 month = String(month).padStart(2, '0') // 还可以按照以下方式实现 month = ('0' + month).slice(-2) console.log(month); // expected output: "01" // 银行卡号只显示后4位 const fullNumber = '2034399002125581'; const last4Digits = fullNumber.slice(-4); const maskedNumber = last4Digits.padStart(fullNumber.length, '*'); console.log(maskedNumber); // expected output: "************5581"
2、判断字符串前缀、后缀
判断字符串前缀、后缀不要一言不合就使用正则表达式:
const url = "https://bili98.cn"; const isHTTPS = /^https:\/\//.test(url); // true const fileName = "main.py"; const isPythonCode = /\.py$/.test(fileName); // true
推荐使用 String.prototype.startsWith 和 String.prototype.endsWith,语义性更好:
const url = "https://bili98.cn"; const isHTTPS = url.startsWith("https://") // true const fileName = "main.py"; const isPythonCode = fileName.endsWith(".py"); // true
3、使用replaceAll 方法替换所有匹配到的字符
ES2021新特性-替换一个字符串中的所有指定字符 replaceAll()方法的使用
在 ES2021 之前,要替换掉一个字符串中的所有指定字符,我们可以这么做:
const str = '2-4-6-8-10' const newStr = str.replace(/\-/g, '+') console.log(newStr) // 2+4+6+8+10
ES2021 则提出了 replaceAll 方法,并将其挂载在 String 的原型上,可以这么用:现在可以用String.prototype.replaceAll()替换全部字符串而不需要使用正则。
const str = '2-4-6-8-10' const newStr = str.replaceAll('-', '+') console.log(newStr) // 2+4+6+8+10
2.3 css开发技巧
2.3.1 巧妙使用伪类生成表单必填标识
::befor { content: "*"; color: red; margin-right: 4px; }
示例:(element ui里面的表单项必填标识)
2.3.2 增强用户体验,使用伪元素实现增大点击热区
在移动端,按钮通常都很小,但是有时由于设计稿限制,我们不能直接去改变按钮元素的高宽。那么这个时候有什么办法在不改变按钮原本大小的情况下去增加他的点击热区呢?
这里,伪元素也是可以代表其宿主元素来响应的鼠标交互事件的。借助伪元素可以轻松帮我们实现,如:
.btn::befoer{ content: ""; position: absolute; top: -10px; right: -10px; bottom: -10px; left: -10px; }
2.3.3 利用伪类实现鼠标移入时下划线向两边展开的效果
<html lang="en"> <head> <meta charset="UTF-8"> <title>鼠标移入下划线展开</title> <style type="text/css"> #underline{ width: 200px; height: 50px; background: #ddd; margin: 20px; position: relative; } #underline:after{ content: ""; width: 0; height: 5px; background: blue; position: absolute; top: 100%; left: 50%; transition: all .8s; } #underline:hover:after{ left: 0%; width: 100%; } </style> </head> <body> <div id="underline"></div> </body> </html>
效果展示:
1、在浏览器上随便找个网页打开f12;
2、点击元素栏选中html跟标签右键以html格式修改;
3、复制上述代码覆盖掉网页上的html代码完成修改;
4、鼠标移入显示元素即可看到效果。