Giter Site home page Giter Site logo

knowledge_point's Introduction

  • 👋 Hi, I’m @ASkyBig
  • 👀 I’m interested in basketball and dota1.
  • 🌱 I’m currently learning low code.
  • 📫 How to reach me empzd2s4MTg=

knowledge_point's People

Contributors

askybig avatar

Watchers

 avatar

knowledge_point's Issues

vue cli 学习

vue.config.js 里面的代理配置,需要重启服务才行,调试了半天。。。


react 小结

  • setState 会触发渲染,有的时候你的数据没有改变,但是只要调用了 setState,就会重新渲染,浪费性能。所以就有了 shouldComponentUpdate 生命周期进行 propsstate 的对比,但是每次都要写就很麻烦,于是有了 PureComponent,自动帮你做了。后来,又出了函数组件,没有那些生命周期了,就增加了 React.memo (<your function component>) 来完成 shouldComponentUpdate 要做的事情。

  • m站列表多了一个0
    image
    原因是数组为空的逻辑错了,必须是 arr.length > 0 或者是 !!arr.length
    image
    image

  • 对于竞态条件,需要采用最后一次 ajax 请求
    比如下图,如果网络状况不好,你频繁切换不同的书籍后请求返回的时间不一样的话,很可能左右两边是对不上的。
    image
    你需要使用最后一次的 ajax 请求:
useEffect(() => {
    handleArticleClick(bookList[0].bookId, bookList[0].chapterCount)
  }, [props.bookList])
  useEffect(() => {
    const currentCount = countRef.current
    Axios.$get(`/api/v1/write/book/list?time=${Date.now()}`)
        .then(res => {
          console.log('currentCount', currentCount)
          console.log('countRef', countRef)
          if (currentCount !== countRef.current) {
             return
           }
          if (res.data.code === 0 && !!res.data.data) {
            let tempList = res.data.data.bookList
            setBookList(tempList)
            const bookItem = getBookItemById(bookId, tempList)
            if (bookItem) {
              setBookItemInfo(bookItem)
              setChapterCount(bookItem.chapterCount)
            }
          }
        })

    return () => {
      console.log('unmount')
      countRef.current += 1
    }
  }, [bookId])

  function handleArticleClick(bookId, chapterCount) {
    setBookId(bookId)
  }

  • 锚点使用
    umi 的组件即页面,url 里面的参数是有意义的。我们希望锚点不添加到url里面。
    方式一:scrollIntoView
    image
    image
    image
    image
    如果没有header,还是很好用的。
    方式二:scrollTo
    image
    image

node

1、http.createServer 会响应两次

因为浏览器默认一次会请求 favicon.ico,添加下面代码就行:

if (req.url === '/favicon.ico') {
    return;
}

2、Access-Control-Allow-Origin 设置多域名

 if (req.headers.origin === 'http://localhost:2999' || req.headers.origin === 'http://localhost:3000') {
      res.writeHead(200, {'content-Type':'text/html;charset=UTF-8', 'Access-Control-Allow-Origin': '*'})  
    }

3、遍历获取文件名和大小

const fs = require('fs');
const path = require('path');

const getAllFileName = (rootName, arr = []) => {
  const fileNameArr = fs.readdirSync(rootName);
  fileNameArr.forEach(fileName => {
    const fullPath = path.join(rootName, fileName);
    const stat = fs.statSync(fullPath);
    if (stat.isDirectory()) {
      getAllFileName(fullPath, arr)
    } else {
      arr.push({pathName: fullPath, fileSize: stat.size});
    }
    
  })
  return arr;
}

const res = getAllFileName('./src/pages/analysis')
console.log('res:', res);

4、创建多级文件夹

const enhanceMkdirsSync = dirname => {  
  if (fs.existsSync(dirname)) {  
    return true;  
  } else {
    if (enhanceMkdirsSync(path.dirname(dirname))) {  
      fs.mkdirSync(dirname);  
      return true;  
    }  
  }  
}

5、~ 和 ^ 的区别

~:匹配最后一位小版本
^:匹配中间一位版本
image

antd 使用

最近从Element UI转到了Antd

1、modal 隐藏 确定取消按钮

  <Modal
        title="查看导出记录"
        visible={false}
        onOk={() => {console.log('ok')}}
        onCancel={() => {
          console.log('cancel')
          setRecordShow(false)
        } }
        footer={
          [] // 设置footer为空,去掉 取消 确定默认按钮
        }
      >

2、datepick 只能选择当天

 // 禁止选择今天之前的日期
  const disabledDate =  useCallback((current) => {
    // 这里不能用 <=,你用=就不能选择今天了
    return current && current < moment().startOf('day').hours(0).minutes(0).seconds(0)
  }, [])

3、rangerpicker 作为受控组件,可以重置它的value

const [startTime, setStartTime] = useState(null)
const [endTime, setEndTime] = useState(null)

 <RangePicker
        showTime={{ format: 'HH:mm' }}
        format="YYYY-MM-DD"
        value={[startTime, endTime]}
        onChange={(value) => {
          // value 是个数组,清空后需要将起始结束时间置空
          if (value && value.length === 0) {
            setStartTime(null)
            setEndTime(null)
          } else {
            setStartTime(moment(value[0].format('YYYY-MM-DD')))
            setEndTime(moment(value[1].format('YYYY-MM-DD')))
          }
        }}
        onOk={([start, end]) => {
          setStartTime(moment(new Date(start).getTime()))
          setEndTime(moment(new Date(end).getTime()))
        }}
      />

 <Button
        onClick={() => {
          setStartTime(null)
          setEndTime(null)
        }}
      >
        重置
</Button>

4、antd 的 table 的rowkey一定要唯一,否则切换页码的时候会发生旧数据附加到请求的数据上

就是下面的这个 rowKey 有问题,cbid 会有重复的:
image

可以看到,请求的数据是10条,但是展示的不止10条,这个bug找了好久。
image

5、select 组件,如果 value 设置为空,那么 placeholder 不会显示,需要设置成 undefined

<Select value={ruleArr[index].type === '' ? undefined : ruleArr[index].type} placeholder={'标签类型'} style={{width: '20%'}} disabled={isPlatDisabled} onChange={handlePlatChange}>
                {
                  platOptions.map(item => <Option value={item.value}>{item.label}</Option>)
                }
</Select>

image

5、表格添加序号

const columns = [
  {
    title: '序号',
    key: 'index',
    render: (text, record, index) => index + 1,
  }
]

image

6、覆盖组件样式

产品小姐姐说antd自带的跳转至某页的input太小了,显示不全:
image
所以需要覆盖样式,本来想自适应宽度,但是要监听输入的内容,会有重复渲染的问题,还是直接用一个宽度覆盖原样式:
image
image

7、表格列筛选条件

拿到请求结果后筛选出该列所有的情况,去重,设置成 {text, value} 的形式

const uniqueKeyArr = [...new Set(data.map(item => item.action_type))]
const actionFilterArr  = uniqueKeyArr.map(item => ({text: item, value: item}))

// table column
{
  title: '行为',
  dataIndex: 'action_type',
  width: '15%',
  filters: actionFilterArr,
  onFilter: (value, record) => record.action_type === value,
},

image

8、table 和 select 自定义空态

// table
   <Table 
      columns={columns} 
      dataSource={dataSource} 
      locale={{ emptyText: '暂无数据' }}
    />
// Select
<Select
      notFoundContent='暂无数据'
      allowClear
      onChange={(value: string) => {
      }}
    >
      {
        (groupList || []).map((item: {
          id: string | number,
          name: string | number
        }) => {
          return <Option key={item.id} value={item.id}>{item.name}</Option>
        })
      }
    </Select>

9、antd 组件的英文切换为中文


import { ConfigProvider } from 'antd';
import zhCN from 'antd/es/locale/zh_CN';
 
return (
  <ConfigProvider locale={zhCN}>
    <App />
  </ConfigProvider>

10、 message 默认延时 3s,可以自定义延时,如果设置为 0 则不会自动消失。

今天发生了一个问题,上传某个apk,产品说还没有成功loading就消失了,我看下了接口16s。。。我这边没有发生这个问题是因为我连接的有线,在loading的默认时间之前接口就好了,所以没有复现,所以要加上 0 这个参数

git 常用命令

镇楼:image

  • 新建分支并关联到远程分支
    如果远程新建了一个分支,本地没有该分支,可以利用 git checkout --track origin/branch_name ,这时本地会新建一个分支名叫 branch_name ,会自动跟踪远程的同名分支 branch_name。

  • 如果 readme 里面的 gif 过大,无法显示,并报错 Content length exceeded ,则使用 img 标签的形式就可以了。例子

远程分支不存在,本地新建分支并推送到远程

  • 本地 git checkout -b branch_name 之后,推送到远程,git push --set-upstream origin branch_name:branch_name ,这两个branch_name 之间不能有空格,否则会报
    error: dst ref xxx from more than one src

已经提交的文件需要 ignore

例如,gitlab 提交了 vscode 文件夹,本地不想删除,但是仓库也不想继续跟踪了:
https://segmentfault.com/q/1010000000430426

git rm -r  --cached .vscode  
更新 .gitignore 忽略掉目标文件
git commit -m "We really don't want Git to track this anymore!"
git push

重命名本地分支

git branch -m [old] [new]

查看某分支的父级

git reflog show [branch_name]
// or
git reflog <branch_name>

image

node 获取最近的提交分支及信息

const { execSync } = require('child_process');

const info = execSync('git log --pretty=format:"%an|%h|%s" -1').toString().trim().split('|');
const branchName = execSync('git rev-parse --abbrev-ref HEAD').toString().trim();

�恢复删除的分支

  • 使用 git log -g 找回之前提交的 commit
  • 使用 git branch recover_branch [新分支] commit_id 命令用这个 commit 创建一个分支
git branch recover_branch_abc 12345xxx

git branch -a
* develop
  recover_branch_abc
  remotes/origin-dev/develop
  • 切换到 recover_branch_abc 分支

Failed to connect to github.com port 443: Operation timed out

无法拉取远程分支,看看是否是代理的问题,去 /etc/hosts 文件里注释掉GitHub的代理

git 提交规范

使用 [commitlint](https://github.com/conventional-changelog/commitlint) 工具,常用有以下几种类型:

- feat :新功能
- fix :修复 bug
- chore :对构建或者辅助工具的更改
- refactor :既不是修复 bug 也不是添加新功能的代码更改
- style :不影响代码含义的更改 (例如空格、格式化、少了分号)
- docs :只是文档的更改
- perf :提高性能的代码更改
- revert :撤回提交
- test :添加或修正测试

举例
git commit -m 'feat: add list'

撤销本地 commit

git reset --soft HEAD^  // 撤销commit 代码改变仍然保留
或
git reset --soft HEAD~1
  • --mixed:表示不删除工作控件改动过的代码,撤销 commit,并且撤销 git add . 操作,这个为默认参数(git reset --mixed HEAD^ 和 git reset HEAD^ 操作效果一样)
  • --soft:表示不删除工作空间代码,撤销 commit,保留 git add . 操作
  • --hard:表示删除工作空间代码,撤销 commit,撤销 git add . 操作,在完成这个操作之后恢复到上一次 commit 的状态(丢弃改动的代码

CSS

  • vertical-align 起作用的前提是元素为 inline 水平元素或 table-cell 元素,包括 span, img,input, button, td 以及通过 display 改变了显示水平为 inline 水平或者 table-cell 的元素。这也意味着,默认情况下,div, p 等元素设置 vertical-align 无效

  • 绝对定位下 margin: 0 auto 不能居中

  • transform: translateZ (0) 可以用来开启硬件加速 。

  • transform 如果和 animation 连用,animation 里面 translate 会覆盖 transform 里的 translate 属性。所以如果我们的全局 loading 如果是 animation 动画的,要垂直居中就要写在 animation 里面。

// styled component
const PageLoadingBox = styled.div`
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background-color: rgba(143, 151, 173, 0.2);
`
const ImgRotate = keyframes`
  0% {
    transform: translate(-50%, -50%) rotate(0deg);
  }
  100% {
    transform: translate(-50%, -50%) rotate(360deg);
  }
`

const ImageBox = styled.img`
  position: absolute;
  top: 50%;
  left: 50%;
  width: 200px;
  height: 200px;
  animation: 2s ${ImgRotate} infinite linear;
`
  • clientWidthoffsetWidth 的区别
    clientWidth 不包括边框,offsetWidth 包括边框
    image
    image

  • Css module 使用技巧:

Css module 作者建议:
(1). 不使用选择器,只使用 class 名来定义样式
(2). 不层叠多个 class,只使用一个 class 把所有样式定义好
(3). 不嵌套
(4). 使用 composes 组合来实现复用

.demo::-webkit-scrollbar {
  display: none; /* Chrome Safari */
}

.demo {
  scrollbar-width: none; /* firefox */
  -ms-overflow-style: none; /* IE 10+ */
  overflow-x: hidden;
  overflow-y: auto;
}

话萌APP开发总结

1、自己开发的模块中的调试信息例如 debuggerconsole.log 等提交到 git 之前要删掉,否则对其他人来说是个干扰。还会影响性能。


2、作为前端,要尽早让后端把 mock 接口和数据写好,否则会阻塞前端进度,并且开发都看不到效果。


3、再说后端数据返回的不对的前提,先看看自己传过去的表单对不对。(很尴尬,发送了一个格式化的时间,后端要的是时间戳==! )

  • 有没有漏字段
  • 字段类型是不是和约定的一致

4、1 > undefined 结果为 false


5、代码提交需要遵循一个规范

这是一个 规范


6、Object.assign 要注意不同对象中的同名字段

今天遇到的一个 bug,一个 model 对象合并两个数据对象,一个是该条记录的 id, 一个是显示 index 的 id,一个合并就把该条记录 id 覆盖了。
如果有同名字段就要注意了,下面两种写法 id 就不一样了。

Object.assign(model, data.posInfo, data.advInfo);
Object.assign(model, data.advInfo, data.posInfo);

image


7、接口不同页面的相同字段应该保持一致
列表页的时间是 timestamp,那编辑页的时间字段不应该是 onlineTime,接口评审的时候应该提醒后端同学。

列表页接口:

列表页接口

编辑页接口:

编辑页接口


8、for 循环记得带 break,减少遍历次数,还有注意里面的异步方法可能导致的闭包问题。

 for (var i=1; i<=5; i++) {
   if( i === 3) break;
   setTimeout( function timer() {
     console.log( i );
   }, i*1000 );
} // 3, 3

9、如果前端一条请求依赖后端多个接口,不需要后端作为中间层统一调完给我们,直接分开请求,避免中间层多个请求的最长路径。


10、控制台 console 菜单里面的 filter 过滤输入框是实时的,如果你发现输入的内容没有打印出来,看看是不是 filter 里面不经意输入了啥。

没有输入(空格不影响):

image

有输入:

image


11、一些较小的 icon 按钮可以增大点击区域,方便点击。

image

这不,测试提了一个 bug:

image


12、bug 单和邮箱关联,及时改 bug
image


13、Android 的默认字体是灰色,iOS 是黑色,要让两端统一,记得加颜色。


14、如果后端缺少字段,就加个默认值,不影响开发。
image


15、有默认值的用三目运算符,不要用逻辑运算符。
后台管理有一个图片上传功能,然后显示后端返回的图片大小。默认值我设置的是 0。
但是后端 size 返回空的时候,this.width 就变成了 false。不过讲道理,应该返回大小给我的:D

// 这样不好    
this.width = !!data.posInfo.imageSize && data.posInfo.imageSize.match(/\d+/g)[0]; // false && 1 返回 false
this.height = !!data.posInfo.imageSize && data.posInfo.imageSize.match(/\d+/g)[1];
// 这样好
this.width = data.posInfo.imageSize ? data.posInfo.imageSize.match(/\d+/g)[0] : 0;
this.height = data.posInfo.imageSize ? data.posInfo.imageSize.match(/\d+/g)[1] : 0;

image


16、setHours() 方法用于设置指定的时间的小时字段。比如,展示某些列表记录的时间,你从后台获得时间戳,看它是 一天前 还是 两天前 还是 一年前

let timestampFromBackend = new Date(new Date().getTime() - 86400 * 1000 -1).getTime()
new Date(timestampFromBackend).setHours(0, 0, 0, 0) // 这就是这个时间戳的当天零点

ps,有些代码判断 一年前 是通过365天,一个月30天来判断,其实是不准确的,下面这个才对(里面的字符串自己拼接):
image

代码片段

css 旋转裁剪图片

<View style='padding-bottom: 18px; width: 88px; height: 93px; transform: rotate(10deg); overflow: hidden;'>
	<Image style='width: 88px;height: 93px;border-radius: 20px; padding-top: 19px; padding-left: 137px;margin-left: -129px; transform: rotate(-10deg);'
	          src={banner3}
	 />
</View>
<View style="position: absolute;margin-left: 97px;padding-right: 112px;padding-top: 14px;overflow: hidden;padding-bottom: 18px;height: 93px;width: 88px;transform: rotate(10deg);">
	<Image style='transform: rotate(-10deg);width: 88px;height: 93px;border-radius: 20px; padding-bottom: 15px;margin-left: -149px;padding-left: 138px;padding-top: 19px;'
	     src={banner2}
	 />
</View>

image


function DateFormate (time, fmt) {
  var o = {
    "M+" : time.getMonth()+1,                 //月份
    "d+" : time.getDate(),                    //日
    "h+" : time.getHours(),                   //小时
    "m+" : time.getMinutes(),                 //分
    "s+" : time.getSeconds(),                 //秒
    "q+" : Math.floor((time.getMonth()+3)/3), //季度
    "S"  : time.getMilliseconds()             //毫秒
  };

  if(/(y+)/.test(fmt)){
    fmt=fmt.replace(RegExp.$1, (time.getFullYear()+"").substr(4 - RegExp.$1.length));
  }
        
  for(var k in o){
    if(new RegExp("("+ k +")").test(fmt)){
      fmt = fmt.replace(
        RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)));  
    }       
  }

  return fmt;
}
DateFormate(new Date(), "yyyy-MM-dd hh:ss") // "2019-10-30 19:21"

图片大小尺寸前端验证

 handlePreview (file) {
      if (!file) {
        return
      }
      const img = new Image()
      img.src = URL.createObjectURL(file.raw)
      img.onload = (e) => {
        if (e.target.width !== 1000 || e.target.height !== 280) {
            this.$message.error('图片尺寸或大小错误,请重新上传');
            return;
        }
        if (file.size > 150 * 1024) {
            this.$message.error('图片尺寸或大小错误,请重新上传');
            return;
        }
        uploadImg(file.raw, '/upload/image').then((result) => {
          console.log('result', result)
          this.imageUrl = result.data.data.url;
        })
      }
    }

转义字符

const escapeHTML = str =>
  str.replace(
    /[&<>'"]/g,
    tag =>({'&': '&amp;', '<': '&lt;', '>': '&gt;', "'": '&#39;', '"': '&quot;' }[tag] || tag)
  );

全角转半角

        let newStr = ''
	for (let i = 0; i < strTelNum.length; i++) {
		let code = strTelNum.charCodeAt(i)
		if (code >= 65281 && code <= 65373) {
			newStr += String.fromCharCode(strTelNum.charCodeAt(i) - 65248)
		} else if (code == 12288) {
			newStr += String.fromCharCode(strTelNum.charCodeAt(i) - 12288 + 32)
		} else {
			newStr += strTelNum.charAt(i)
		}
	}

字符串数字相加

由于精度限制,两个数字相加会有问题。比如我们公司的 BookId 就很长,超过了 2^53 - 1。

var bigAdd = function(str1, str2) {
    let arr1 = str1.length > str2.length ? str1.split('').map(Number) : str2.split('').map(Number)
    let arr2 = str1.length > str2.length ? str2.split('').map(Number) : str1.split('').map(Number)

    let len = arr1.length
    let temp_arr = Array(len - arr2.length).fill(0).concat(arr2)
    let res = []
    let flag = false // 标记是否有进位
    for(let i = len - 1; i >= 0; i--) {
        let val = arr1[i] + temp_arr[i]
        if (flag) {
            if (i === 0) {
                if ( val + 1 >= 10) {
                    res.unshift(val + 1 - 10)
                    res.unshift(1)
                } else {
                    res.unshift(val + 1)
                }
            } else {
                if ( val + 1 >= 10) {
                    res.unshift(val + 1 - 10)
                    flag = true
                } else {
                    res.unshift(val + 1)
                    flag = false
                }
            }
            
        } else {
            if (i === 0) {
                if (val >= 10) {
                    res.unshift(val - 10)
                    res.unshift(1)
                } else {
                    res.unshift(val)
                }
            } else {
                if (val >= 10) {
                    res.unshift(val - 10)
                    flag = true
                } else {
                    res.unshift(val)
                    flag = false
                }
            } 
        }
    }
    return res.join('')
};

bigAdd('9007199254740992', '9') // '9007199254741001'

readme 目录结构代码方式

├── README.md                  
├── dist/             
├── package.json
├── src
│   ├── app.js
│   ├── assets                        // 全局资源
│   ├── components/             // 全局通用组件
│   ├── global.less                  // 全局样式     
│   ├── layouts/                      // 全局模版
│   ├── pages                         // 页面
│   ├── styles
│   │   └── _var.less                 
│   └── utils
│       └── request.js              // 请求的简易封装
│       └── tools.js                  // 工具类方法
└── webpack.config.js

设置当天的cookie

function setCurDayCookie(name, value) {
        var curDate = new Date(); // Sat Sep 18 2021 13:55:02 GMT+0800 (**标准时间)
	var curTime = curDate.getTime(); // 1631944649281
	var curDay = curDate.toLocaleDateString(); // 2021/9/18

	var curNearNextDayTime = new Date(curDay).getTime() - 1; // 当天零点开始的时间戳,-1 是防止 00:00:00
	var todayPassedTime = curTime - curNearNextDayTime; // 今天已经过去的时间
	var leftTimestamp = 24 * 60 * 60 * 1000 - todayPassedTime; // 今天剩下的时间
	var timeSet = curTime + leftTimestamp; // 可以缓存的时间的时间戳

	document.cookie = name + "=" + value + ";expires=" + new Date(timeSet).toUTCString() + ";path=/";
}

或者

 // 获取用户本地剩余时间(时间戳)
  var leftTime = ((new Date()).getTime()) % (86400000);
  // 计算用户今天还剩下多少时间(时间戳)
  var cookieTime = 86400000 - leftTime;

docker 知识

最近做一个内部项目,没有后端,得自己搞,正在学习 docker。

docker-compose

Docker Compose 是一个用来定义和运行复杂应用的 docker 工具。
可以通过使用 Compose 在一个文件中定义一个多容器应用,使用 docker-compose up 命令来启动应用。

docker-compose up -d

up 参数
构建,(重新)创建,启动,链接一个服务相关的容器。
链接的服务都将会启动,除非他们已经运行。
默认情况, docker-compose up 将会整合所有容器的输出,并且退出时,所有容器将会停止。
如果使用 docker-compose up -d ,将会在后台启动并运行所有的容器。
默认情况,如果该服务的容器已经存在, docker-compose up 将会停止并尝试重新创建他们(保持使用 volumes-from 挂载的卷),以保证 docker-compose.yml 的修改生效。如果你不想容器被停止并重新创建,可以使用 docker-compose up --no-recreate。如果需要的话,这样将会启动已经停止的容器。

mysql 命令

1、查看所有的表

show tables;

image

2、查看某一个表

select * from tablename;

image
【注】这里你必须要加分号,否则他会认为你还没有输入完。

3、查看表列名

show columns from tablename;

image

4、查看表某列的全部信息

select columnname from tablename;

image

5、创建一个表

create table image(
    -> id INT NOT NULL AUTO_INCREMENT,
    -> name varchar(255) not null,
    -> type int not null,
    -> height double not null,
    -> width double not null,
    -> metadata text not null,
    -> url varchar(255) not null,
    -> is_deleted tinyint(4),
    -> parent_image_id int not null,
    -> PRIMARY KEY(id)
    -> )ENGINE=InnoDB DEFAULT CHARSET=utf8;

image

6、向表中增加一列

 alter table tablename add column columnname varchar(255) not null;

image

7、查询表中某列数据

select columnname from tablename;

image

8、更新某列数据

 update tablename set columnname='1080x375';

image

9、修改字段名

字段的类型要有,不然就会报错:

 alter table [tablename] change [cloumnname] [newColumnname] [columnType];

image

10、删除某个字段

 alter table [tablename] drop [fieldname];

image

11、删除多个字段

alter table [tablename] drop [columnname1], drop [columnname2]

image

12、增加多个字段

alter table [tablename] add [columnname1] [type], add [columnname2] [type];

image

设计理念

待在体验设计部,还是要学点体验上的知识哦:)

1、提高列表的可读性

image


2、轮播图两端都露出来,让用户感知

我们做的小程序


3、文件上传

  • 要限制文件格式,让用户尽可能快就能找到文件
    image
  • apk 文件类型:MIME 类型中填写 apk 的 MIME 类 application/vnd.android.package-archive

4、下拉框选择

  • 要让用户经常选择的选项放到前面,而不用去手动查询
    image

5、列表顺序

  • 要考虑列表内容的性质,按照最新还是最老进行数据的展示

photoShop

  • 1、多个元素成组,Command + G

  • 2、菜单要是不小心按掉了,窗口 =》 工作区 =》 复位基本功能

  • 3、编辑背景图片

清除背景:橡皮擦
框选:command+J 复制图层
选择:移动
改变size:command+T

原图
image
改变后
image

你不知道的 js 知识点

小时候我的成绩相当好:)考试我有一个经验,和别人拉开差距的地方就是一些不常用的知识点。常用的只要你不是特别笨都会做。写代码应该也是一样的,我要把一些大家容易忽略的记录下来,扎实我的基本功:)看到了就要条件反射想到这些东西

parseInt

parseInt () 函数可解析一个字符串,并返回一个整数。如果第二个参数小于 2 或者大于 36,则 parseInt () 将返回 NaN。这个反正我没有用过。

这个常见的用法就是parseInt('16px') ,拿到数字16。
要记住两点

  • 开头和结尾的空格是允许的。
    parseInt(' 16px ') 也是可以的,不需要 trim 字符串

  • 如果它以 “0x” 或 “0X” 开头,将以 16 为基数。我们在使用时,要考虑字符串有没有可能出现这种情况
    parseInt(' 0xA ') 返回 10


判断是不是数组

大多数人只会两种方式,我们也要知道另外两种方式

1、Array.isArray(obj),这是最常用的
2、Object.prototype.toString.call(arrObj) === '[object Array]',这个用的也很多,一般用在工具方法中
3、Array.prototype.isPrototypeOf (obj),这个基本见不到,检测一个对象是否存在于另一个对象的原型链中
4、arrObj.constructor === Array,这个也不常用,这个构造函数其实不在arrObj上,而是在 Arrry.prototype 上

浏览器知识

  • 如果下载 CSS 文件阻塞了,会阻塞 DOM 树的合成吗?会阻塞页面的显示吗?
    当从服务器接收 HTML 页面的第一批数据时,DOM 解析器就开始工作了,在解析过程中,如果遇到了 JS 脚本,如下所示:
<html>
    <body>
        极客时间
        <script>
        document.write("--foo")
        </script>
    </body>
</html>

那么 DOM 解析器会先执行 JavaScript 脚本,执行完成之后,再继续往下解析。

那么第二种情况复杂点了,我们内联的脚本替换成 js 外部文件,如下所示:

<html>
    <body>
        极客时间
        <script type="text/javascript" src="foo.js"></script>
    </body>
</html>

这种情况下,当解析到 JavaScript 的时候,会先暂停 DOM 解析,并下载 foo.js 文件,下载完成之后执行该段 JS 文件,然后再继续往下解析 DOM。这就是 JavaScript 文件为什么会阻塞 DOM 渲染。

我们再看第三种情况,还是看下面代码:

<html>
    <head>
        <style type="text/css" src = "theme.css" />
    </head>
    <body>
        <p> 极客时间 </p>
        <script>
            let e = document.getElementsByTagName('p')[0]
            e.style.color = 'blue'
        </script>
    </body>
</html>

当我在 JavaScript 中访问了某个元素的样式,那么这时候就需要等待这个样式被下载完成才能继续往下执行,所以在这种情况下,CSS 也会阻塞 DOM 的解析。

所以 JS 和 CSS 都有可能会阻塞 DOM 解析

js 随手记

Array.prototype.slice()

  • MDN上的slice()方法介绍:Array.prototype.slice() 方法返回一个新的数组对象,这一对象是一个由 begin和 end(不包括end)决定的原数组的浅拷贝。原始数组不会被改变。

原数组不会改变应该针对简单类型:

var arr = [1, 2, 3];
var arr_new = arr.slice(1) // arr_new: [2, 3], arr: [1, 2, 3]
arr_new[0] = 0; // arr_new: [0,3], arr: [1, 2, 3]

要是是个复杂类型就会改变:

var arr = [{a: 1}, {b: 2},  {c: 3}]
var arr_new = arr.slice(1) // arr_new: [{b: 2},  {c: 3}], arr: [{a: 1}, {b: 2},  {c: 3}]
arr_new[0].b = 0; // arr_new: [{b: 0},  {c: 3}], arr: [{a: 1}, {b: 0},  {c: 3}]

JSON.parse(JSON.stringify()) 实现深拷贝要小心呐

var target = {
    a: 1,
    b: 2,
    hello: function() { 
            console.log("Hello, world!");
    }
};
var target_new = JSON.parse(JSON.stringify(target));
console.log(target_new);   // {a: 1, b: 2}

判断当前浏览器是否支持webP格式

function checkWebp() {
	try {
		return document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp') == 0
	}
	catch(err) {
                 return false
        }
}

类不存在变量提升(hoist),这一点与 ES5 完全不同。 ES6 不会把类的声明提升到代码头部。这种规定的原因与继承有关,必须保证子类在父类之后定义。


子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用super方法,子类就得不到this对象。


数组一维扁平化

function flatten(arr) {
		return arr.reduce((result, item) => {
			return result.concat(Array.isArray(item) ? flatten(item) :item;
		}, [])
	}

判断空对象

 JSON.stringify(obj) === '{}'

for in 是遍历对象的可枚举属性,两点:1、可枚举,2、属性,不是属性值。


chrome 控制台输出的数据,你可用 copy(data) 复制到剪切板


js map 方法不会对空数组进行检测,也不会改变原数组。

var arr =[];
arr[1] = 2;
arr[2] = 3;

var newArr = arr.map(value => ++value); // newArr: [empty, 3, 4], arr: [empty, 2, 3]


距今天多久的代码段

const timeFormat1 = ( timestamp ) => {
  let nowTime = new Date().getTime()
  let duration = (nowTime - timestamp) / 1000
  let result

  switch (true) {
    case duration <= 60: {
      result = '刚刚'
      break
    }
    case duration <= 60 * 60: {
      let time = Math.ceil(+`${duration / 60}`)
      result = `${time}分钟前`
      break
    }
    case duration <= 60 * 60 * 24: {
      let time = Math.ceil(+`${duration / 60 / 60}`)
      result = `${time}小时前`
      break
    }
    case duration <= 60 * 60 * 24 * 30: {
      let time = Math.ceil(+`${duration / 60 / 60 / 24}`)
      result = `${time}天前`
      break
    }
    case duration <= 60 * 60 * 24 * 30 * 12: {
      let time = Math.ceil(+`${duration / 60 / 60 / 24 / 30}`)
      result = `${time}个月前`
      break
    }
    default: {
      let time = Math.ceil(+`${duration / 60 / 60 / 24 / 30 / 12}`)
      result = `${time}年前`
    }
  }

  return result
}
const timeFormat2 = ( timestamp ) => {
  let nowTime = new Date().getTime()
  let todayBeginTime = new Date().setHours(0,0,0,0) // 今天零点的时间戳

  let yesTime = nowTime - 1000 * 60 * 60 *24 // 获取昨天这个时候的时间
  let yesBeginTime = new Date(yesTime).setHours(0,0,0,0) // 昨天零点的时间戳

  let beforeYesTime = new Date(nowTime) - 1000 * 60 * 60 * 24 * 2 // 获取前天这个时候的时间
  let beforeYesBeginTime = new Date(beforeYesTime).setHours(0,0,0,0) // 前天零点的时间戳

  let thisYearTime = new Date(new Date().getFullYear()  + '-01-01').getTime() // 今年的一月一号时间戳
  let duration = (nowTime - timestamp) / 1000
  let result

  switch (true) {
    case duration < 60: {
      result = '刚刚'
      break
    }
    case duration < 60 * 60: {
      let time = Math.ceil(+`${duration / 60}`)
      result = `${time}分钟前`
      break
    }
    case timestamp > todayBeginTime: {
      let hour = new Date(timestamp).getHours()
      let min = new Date(timestamp).getMinutes()
      result = `今天 ${hour > 9 ? hour : `0${hour}`}:${min > 9 ? min : `0${min}`}`
      break
    }
    case timestamp > yesBeginTime: {
      let hour = new Date(timestamp).getHours()
      let min = new Date(timestamp).getMinutes()
      result = `昨天 ${hour > 9 ? hour : `0${hour}`}:${min > 9 ? min : `0${min}`}`
      break
    }
    case timestamp > beforeYesBeginTime: {
      let hour = new Date(timestamp).getHours()
      let min = new Date(timestamp).getMinutes()
      result = `前天 ${hour > 9 ? hour : `0${hour}`}:${min > 9 ? min : `0${min}`}`
      break
    }
    case timestamp > thisYearTime: {
      let mon = new Date(timestamp).getMonth() + 1
      let date = new Date(timestamp).getDate()
      let hour = new Date(timestamp).getHours()
      let min = new Date(timestamp).getMinutes()
      result = `${mon > 9 ? mon : `0${mon}`}-${date > 9 ? date : `0${date}`} ${hour > 9 ? hour : `0${hour}`}:${min > 9 ? min : `0${min}`}`
      break
    }
    default: {
      let year = new Date(timestamp).getFullYear()
      let mon = new Date(timestamp).getMonth() + 1
      let date = new Date(timestamp).getDate()
      result = `${year}-${mon > 9 ? mon : `0${mon}`}-${date > 9 ? date : `0${date}`}`
    }
  }

  return result
}

12、hash 属性是一个可读可写的字符串,该字符串是 URL 的锚部分(从 # 号开始的部分)


13、npm install -g 的安装目录 user/local/lib/node_modules

如果全局安装后命令没有生效,可能是没有装上
image


14、后端返回的 json 中的整型数据到 js 会丢失精度,记得用 bigInt 或者字符串

image


15、for in 和 for of

let aArray = ['a',123,{a:'1',b:'2'}]
for(let index in aArray){
    console.log(`${aArray[index]}`);
}

image

for(var value of aArray){
    console.log(value);
}

image

aArray.name = 'demo'
for(let index in aArray){
    console.log(`${aArray[index]}`);
}

image

for(var value of aArray){
    console.log(value);
}

image


16、清空数组的小技巧

let arr = [1, 2, 3]
arr.length = 0
// arr: []

17、map 和 foreach 的区别

  • map 依次执行后会返回一个数组
  • foreach 只会执行回调,并返回 undefined

18、setTimeout 有好多参数

一直都用了两个,其实后面可以加参数:

function foo(p1, p2) {
    console.log('p1==', p1, 'p2==', p2)
}
setTimeout(foo, 2000, 'a', 'b')
// p1== a p2== b

19、利用 Math.random() 生成 1~16 位随机数字

function randomNum(len) {
    return Math.random().toString().substr(2, len) // 2 是因为去掉前面的 '0.'
}

20、驼峰命名和中划线相互转换

// "abcDefGh"
"abc-def-gh".replace(/-\w+/g, item => item.charAt(1).toUpperCase() + item.slice(2))

// "abc-def-gh"
"abcDefGh".replace(/[A-Z]/g, item => '-' + item.toLowerCase())

21、数字千位分隔符

// 12345678 ===> 12,345,678
// way 1
'12345678'.replace(/(?=(\d{3})+$)/g, ',')
// way 2
'12345678'.split('').reverse().join('').replace(/\d{3}/g, item => item + ',').split('').reverse().join('')
// way 3
Number(12345678).toLocaleString()

22、String.raw

// "Hi\n5!"
String.raw`Hi\n${2+3}!` 

// "Hi
// 5!"
`Hi\n${2+3}!` 

23、不要直接用 obj.hasOwnProperty([property])

// 如果对象里面有这个属性则会报错
var obj = { hasOwnProperty: 1, a: 1 }
obj.hasOwnProperty('a') // Uncaught TypeError: obj.hasOwnProperty is not a function

如果恶意的客户端传给服务器的 json 里面有类似的字段,则会导致服务奔溃。
正确的方式:Object.prototype.hasOwnProperty.call(obj, 'a') // true


24、console.log({a})可以输出键值对

var a = 1
console.log({a})
// {a: 1}

25、计算字符串的字节

new Blob(['a']).size // 1
new Blob([1, 2, 3]).size // 3

26、setTimeout

浏览器的页面是通过消息队列和事件循环系统来驱动的。settimeout 的函数会被加入到延迟消息队列中,
等到执行完 Task 任务之后就会执行延迟队列中的任务。然后分析几种场景下面的 setimeout 的执行方式。

  1. 如果执行一个很耗时的任务,会影响延迟消息队列中任务的执行
  2. 存在嵌套带调用时候,系统会设置最短时间间隔为 4s(超过 5 层)
  3. 未激活的页面,setTimeout 最小时间间隔为 1000ms
  4. 延时执行时间的最大值 2^31 - 1 = 2147483647,溢出会导致定时器立即执行
  5. setTimeout 设置回调函数 this 会是回调时候对应的 this 对象,可以使用箭头函数解决

var name= 1;
var MyObj = {
  name: 2,
  showName: function(){
    console.log(this.name);
  }
}
setTimeout(MyObj.showName,1000)

// 方法一 箭头函数
setTimeout(() => {
    MyObj.showName()
}, 1000);
//或者function函数
setTimeout(function() {
  MyObj.showName();
}, 1000)
// 方法二
setTimeout(MyObj.showName.bind(MyObj), 1000)

27、When will requestAnimationFrame be executed?

28 根据 [0, 7) || (0, 7] 判断星期几

function getWeekDay(n) {
    return '星期' + ['日', '一', '二', '三', '四', '五', '六'][n%7]
}

29、循环请求

命令式:

for (let i = 0; i < 5; i++) {
  $.post('/api/' + i, data[i])
}

函数式:

[1,2,3,4,5].forEach(item => {
  $.post('/api' + item, data[item])
})

30、Unix时间戳和js时间戳不一样

unix是按照秒算的,js的是毫秒,所以会导致后台传过来的时候显示成1970年
image

31、timestamp format

// 格式化时间
const dateTimeFormat = (time, fmt) => {
  const t = new Date(time)
  let o = {
    "M+": t.getMonth() + 1, //月份
    "D+": t.getDate(), //日
    "h+": t.getHours(), //小时
    "m+": t.getMinutes(), //分
    "s+": t.getSeconds(), //秒
    "q+": ~~((t.getMonth() + 3) / 3), //季度
    "S": t.getMilliseconds() //毫秒
  }
  if (/(y+)/i.test(fmt)) {
    fmt = fmt.replace(RegExp.$1, (t.getFullYear() + "").substr(4 - RegExp.$1.length))
  }
  for (let k in o) {
    if (new RegExp("(" + k + ")").test(fmt))
      fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)))
  }
  return fmt
}

32、随机色

const randomColour = () => '#'+(Math.random()*0xFFFFFF<<0).toString(16);

33、判断浏览器是否支持 passive:

// 检查浏览器是否支持 passive 属性
export let passiveSupported = false;

try {
    var options = Object.defineProperty({}, 'passive', {
        get: function () {
            passiveSupported = true;
            return passiveSupported
        }
    });

    window.addEventListener('test', null, options);
} catch (err) {
    // do nothing
}
// 设置passive: true 可以提高性能
target.addEventListener(event, handler, passiveSupported
  ? { passive: true }
   : false
 );

Object.defineProperty

比如,你需要禁止设置对象某些属性,可以考虑这样:

const arr = ['a', 'b', 'c'];
const obj = {}
arr.forEach(item => {
    Object.defineProperty(obj,item, {
        get() {
            throw new Error('not support')
        }
    })
})

obj.a; // Uncaught Error: not support

多条件判断可以利用数组:

如果是下面这样的,可扩展性不是很高,你加一个条件需要再 if 里面加 day === xx

function test(day) {
  if (day === 'Monday' || day === 'Tuesday') {
    //  do something
  }
}

可以改成这样,这样你再扩展时,直接加到数组里面即可:

function test(day) {
  const dayArr = ['Monday', 'Tuesday']
  if (dayArr.includes(day)) {
    //  do something
  }
}

对象数组去重

利用对象的 key 是唯一的这个特性。
例如,对同名的属性进行去重:

const objArr = [{name: 'axe', age: 20}, {name: 'spe', age: 21}, {name: 'axe', age: 20}]

let res = {}
for (let i = 0; i < objArr.length; i++) {
    res[objArr[i]['name']] = objArr[i]
}
res = Object.values(res) // [{name: 'axe', age: 20}, {name: 'spe', age: 21}]

当然,可能是 name 一样,但是 age 不一样,这个时候不想去重:

const objArr = [{name: 'axe', age: 20}, {name: 'spe', age: 21}, {name: 'axe', age: 20}, {name: 'axe', age: 10}]

let res = {}
for (let i = 0; i < objArr.length; i++) {
    res[`${objArr[i]['name']}-${objArr[i]['age']}`] = objArr[i]
}
res = Object.values(res)
/*
*  [{"name": "axe", "age": 20},
*   {"name": "spe", "age": 21},
*   {"name": "axe", "age": 10}]
*/

当然,你可能还想把名字相同的放到一起:

const objArr = [{name: 'axe', age: 20}, {name: 'spe', age: 21}, {name: 'axe', age: 20}, {name: 'axe', age: 10}]

let res = {}
for (let i = 0; i < objArr.length; i++) {
    res[`${objArr[i]['name']}-${objArr[i]['age']}`] = objArr[i]
}
res = Object.values(res).sort((a, b) => a.name > b.name ? 1 : -1)
/*
*  [{"name": "axe", "age": 10},
*   {"name": "axe", "age": 20},
*   {"name": "spe", "age": 21}]
*/

更进一步,对相同 name 的根据 age 的大小排序:

const objArr = [{name: 'axe', age: 20}, {name: 'spe', age: 21}, {name: 'axe', age: 20}, {name: 'axe', age: 30}, {name: 'axe', age: 5}]

let res = {}
for (let i = 0; i < objArr.length; i++) {
    res[`${objArr[i]['name']}-${objArr[i]['age']}`] = objArr[i]
}
const sortFn = (a, b) => {
    if (a.name > b.name) return 1
    else if (a.name < b.name) return -1
    else if (a.age > b.age) return 1
    else return -1
}
res = Object.values(res).sort(sortFn)
/*
*  [{"name": "axe", "age": 5},
*   {"name": "axe", "age": 20},
*   {"name": "axe", "age": 30},
*   {"name": "spe", "age": 21}]
*/

布尔值取反

1、利用 异或,对于每一个比特位,当两个操作数相应的比特位有且只有一个 1 时,结果为 1,否则为 0。简而言之,相同为 0, 不同为 1.

let isA = true;
isA ^= 1; // 0
isA ^= 1; // 1

2、利用 取反
ture * 1 为 1

let isA = true
isA = !isA*1 // 0
isA = !isA*1 // 1

async 函数

async 函数返回值是一个 Promise,如果要用到里面的返回值,需要 then 来接收:

const foo = async () => {return 1;}
const a = foo(); // Promise {<fulfilled>: 1}
a.then(res => console.log('res ===', res)); // res === 1

保留四位小数,移除多余的 0

toFixed

  • 语法:NumberObject.toFixed(num)
  • num默认值为0
  • 返回字符串

parseFloat

  • 语法: parseFloat(string)
  • 字符串中只返回第一个数字
  • 开头和结尾的空格是允许的
  • 如果字符串的第一个字符不能被转换为数字,那么 parseFloat() 会返回 NaN
  • 如果小数点后面有多余的 0,会自动移除,parseFloat('10.00') 返回 10,parseFloat('10.10') 返回 10.1
(Number(text).toFixed(4)).replace(/(\.?0+)$/, '')
// or
parseFloat(Number('123.1020111').toFixed(4))

随机生成中文字符串

// 0x9FA5 和 0x4E00 是十六进制数,分别对应十进制的 40869 和 19968。这两个数值是 Unicode 编码中汉字的起始和结束的编码。
// 0x9FA5 - 0x4E00 这个表达式的结果是汉字在 Unicode 编码中的范围,即 20901。这意味着 Unicode 编码中有 20901 个汉字。

String.fromCharCode(Math.floor(Math.random() * (0x9FA5 - 0x4E00 + 1) ) + 0x4E00)

浏览器兼容性问题

  • js new Date 在 iOS端出现 NaN
// 在 ios 端中,使用如下方法会获得 NaN,安卓手机则是正常计算
new Date("2020-04-25 12:00:00").getTime()
// 解决方法:用正则把 '-' 换成 '/' ,让时间格式变成以下格式
const date ="2020/04/25 12:00:00".replace(/-/g,"/")
new Date(date).getTime()

seo 相关问题

最近需要做 seo,先熟悉一下相关名词

SEO 优化中的 TDK 三大标签是什么

  • TDK 标签包括标题标签(title)也就是 T,网站的描述标签(description)也就是 D,关键词标签(keywords)也就是 K 等。
  • 在优化网站的时候,每个网页都要布局 TDK 标签,如主页,列表,栏目页,文章内容等。
  • title 也就是一个网页的名字,要覆盖优化的关键词,高度概括网页的主题内容

nofollow 标签是什么

nofollow 标签是 HTML 页面中 a 标签的属性值,主要是用来告诉搜索引擎不要追踪某个页面或者特定链接,以避免权重的流失。
简而言之,如果 A 网页上的链接指向 B 网页,如果在此链接上添加 nofollow 标签,那么搜索引擎蜘蛛将不会再从 A 网页访问 B 网页,也不会将 A 网页计算为 B 网页的外链,自然也不会分散 A 网页的权重。

初探微信小游戏

  • 小游戏的运行环境在 iOS 上是 JavaScriptCore,在 Android 上是 V8,都是没有 BOM 和 DOM 的运行环境,没有全局的 document 和 window 对象。因此当你希望使用 DOM API 来创建 Canvas 和 Image 等元素的时候,会引发错误。

  • 音效在面板可以控制是否静音,有一次静音了,后来忘记了,还以为代码出了bug呢
    image

  • canvas的绘制顺序会影响界面效果,bg要第一个绘制

HTTP 学习

  • HTTPS 是 HTTP Secure,还是 HTTP

  • 以共享秘钥方式加密时必须将秘钥也发给对方。如果秘钥可以安全送达,那数据也可以送达,那要秘钥干嘛呢

  • HTTP 422 返回码 表示服务器理解请求实体的 content type, 并且请求实体的语法是正确的,但是服务器不能处理所包含的指示。
    重要提示:客户端不应在不修改的情况下重复發送此请求。

  • 今天遇到了 HTTTP 501 返回码
    image
    image

  • http-only 的 Cookie 只能通过服务器修改,前端不能改的。
    image

  • http1.0 的 Connection 默认值是 close,http1.1 的默认值是 keep-alive。
    image

  • Cookie 相同域名不同端口也是可以共享的。
  • 如果 Set-Cookie 中有 secure 属性值,那么只有在 https 的时候才会发送 Cookie。

  • 状态码 413 是发送内容过大,今天发送Excel的时候遇到了,是 nginx 转发那层要增加 size
    image

  • 状态码 415 是文件类型不支持
    image

  • 状态码 400 是参数类型不一致

echarts 使用

legend 不显示全部数据

image

  const selectObj = {};
  topTenBookArr.forEach((item, index) => {
    if (index >= 5) {
      selectObj[item.bookName] = false
    }
  })
//...

   legend: {
      data: topTenBookArr.map(item => item.bookName),
      // selected_item.key_name = false; 会报错
      // 原因是: json 解析时 key_name 都按字符串解析,不识别变量.
      selected: selectObj
    },

Mac 快捷键

  • 新建一个文件
touch index.js
  • 显示隐藏文件
command + shift + .
  • 打开 Chrome 控制台
command + option + i
  • 打开控制台移动模式
command + shift + m
  • 打开 .ssh 文件
open ~/.ssh
  • webstorm 代码格式化
command + option + L
  • 打开 host 文件
command + shift + g
/etc/hosts

image

  • 查看Mac ip
    长按 option,点击网络标志
    image

  • 放大或者缩小腾讯表格
    长按 commmand,鼠标单指前后滑动

  • 显示隐藏dock

command + option + D
  • Mac 终端打开vscode
  1. 打开控制面板(⇧⌘P)
  2. 输入 shell command
    在提示里看到 Shell Command: Install ‘code’ command in PATH, 就可以了。
  3. 使用: code .
  • docker 从副屏幕还原到主屏幕
    鼠标缓慢滑到主屏幕下面

Linux 命令

  • rz
    上传文件,不能是文件夹

  • rm 参数

-i 删除前逐一询问确认。
-f 即使原档案属性设为唯读,亦直接删除,无需逐一确认。
-r 将目录及以下之档案亦逐一删除。
  • uname
    uname -auname -all , 查看系统信息

  • curl cip.cc
    查看位置信息

正则

  • 数字、字母、汉字5个字之内
/^[\u4e00-\u9fa5a-zA-Z0-9]{1,5}$/.test(str)
  • 只能输入数字、-,并且中划线 - 只能是一位,不能在首尾出现,整个长度范围是 5~10 位
/^\d(?!(\d*-\d*){2,}$)(\d|-){3,8}\d$/.test(str)
  • 金钱千位符
'12345678'.replace(/(?=(\d{3})+$)/g, ',') // 12,345,678
  • html 结构代码替换
// 将 h1 下面的 <br /> 标签移除,不影响其他标签下的 <br />
// 懒惰
"<html><body><h2>我是<br /> h2</h2><h1> sdfsdfs<br/> sdfsfsdf<br/></h1>2343242<h1> sdfsdfs<br/> sdfsfs</h1></body></html>".replace(/<h1>.*?<\/h1>/g, item => {
    return item.replace(/<br\s*\/>/g, '')
}) // "<html><body><h2>我是<br /> h2</h2><h1> sdfsdfs sdfsfsdf</h1>2343242<h1> sdfsdfs sdfsfs</h1></body></html>"
  • . \s\S \w\W

\s 表示,只要出现空白就匹配
\S 表示,非空白就匹配

\w 匹配包括下划线的任何单词字符。等价于 “[A-Za-z0-9_]"。
\W 匹配任何非单词字符。等价于 “[^A-Za-z0-9_]"。

那么它们的组合,表示所有的都匹配,与它相对应的,有 [\w\W] 等,意义完全相同、

另外要说的一点是,为什么有 "." 这个通配符了,还要这样的用法。

其实,[\s\S] 与 [\w\W] 这样的用法,比 "."所匹配的还要多,因为"." 是不会匹配换行的,所有出现有换行匹配的时候,人们就习惯 使用 [\s\S] 或者 [\w\W] 这样的完全通配模式。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.