Giter VIP home page Giter VIP logo

blog's People

Contributors

giscyw avatar

Stargazers

 avatar  avatar

Watchers

 avatar

blog's Issues

近期对业务和技术的一些思考

1.敬畏上线
所有的问题在测试的时候最好发现并且解决,而且是要自己主动发现。例如,项目上线之前,自己要在测试中mock可变数据来测试各种情况,不管是由于接口数据的可变性导致的多种场景,还是兼容性问题,等等,都是要马上发现并解决
2.对专业前后领域的理解
做业务的程序员必须要具备M型的能力,不仅要知道前端,还需要知道往前的业务,往后的后端逻辑和技术,如何能起到一个协调的角色,那确实很难得可贵,比技术本身的能力更加重要
3.先做起来
看到一个新的技术或者框架之类的,先用再说,要在用的过程中去感受它并调整自己对它的理解。

package-lock.json的使用

最近遇到两种代码报错的情况,一是我拉新的项目,跑起来之后在我这边报错,一种是我的项目本地build没有问题,服务器上构建就失败了。
前者是我执行了npm i,然后某个包安装了最新小版本,这个小版本的包本身存在错误。
后者是机器执行了npm i,然后某个包安装了最新小版本,这个小版本的包本身存在错误。
前者我们可以通过npm ci来解决,后者通过上传package-lock.json来解决

packagelock.json文件是需要上传git
该文件是用来避免在生产环境中因版本导致的构建错误或者运行时错误

场景:
但是我本地項目打包正常,線上的出錯,可能由於本地版本和線上版本不一致導致(某個小版本出現的 bug)的。通過查看package.json 配置的 clipboard: "^2.0.4",線上實際安裝版本是 2.0.7,而我本地實際安裝版本是 2.0.6因此定位到 2.0.7 出現的 “問題”。这个时候你不能在package.json中固定clipboard: "2.0.4",最好还是在pakcage.lock.json中固定。因为
packagelock.json 是锁定包的依赖树版本的Package.json是锁住单个包的大版本
首次npm i会根据package.json安装并生成packagelock.json,之后的npm i都会根据packagelock.json安装;npm i 某个包会更新package.json.

用npm ci还是npm install
npm ci首先会自动删除 node_modules,根据 package-lock.json 安装依赖,不会修改你的 package-lock.json,不能单独装包。
一般安装新的某个包用npm install,持续集成工具中更推荐是用 npm ci,保证构建环境的准确性

npm cache clean –force作用
Node模块的安装过程是这样的:

  1. 发出npm install命令
  2. npm 向 registry 查询模块压缩包的网址
  3. 下载压缩包,存放在~/.npm目录
  4. 解压压缩包到当前项目的node_modules目录
    npm cache clean –force 是强制清除~/.npm目录下的压缩包,如果你npm install 报错,不妨试试这个命令。

如何解决package-lock.json的冲突
参考https://juejin.cn/post/7000179306764714020#heading-2

活动开发常见问题

1.闪屏问题
2.页面宽度拉伸问题
3.点击无响应问题
4.上层数据更新了 底层组件没有更新

css描边

方法一 :使用属性 -webkit-text-stroke
对于该属性,只支持设置描边宽带和颜色,无法指定描边是外描边,还是内描边,还是居中描边,默认为居中描边。

.stroke {
-webkit-text-stroke: 2px red;
}
如果要实现外描边的效果,可以使用-webkit-text-stroke描边文字和非描边文字相互重叠覆盖的方法模拟,代码如下:

.strok-outside {
position: relative;
z-index: 0;
font-size: 40px;
}
.strok-outside::before {
content: attr(data-text);
position: absolute;
-webkit-text-stroke: 2px red;
z-index: -1;
}

重叠描边

方法二 :使用属性 text-shadow 该方法利用多层文字阴影模拟外描边效果,代码如下:

.strok-outside {
text-shadow: 0 1px red, 1px 0 red, -1px 0 red, 0 -1px red;
}
但是,实际上,该方法实现的效果,并不是真正的外描边效果。因为一个矩形四面投影的时候,四个角实际上会有空隙,所以,描边会有缺角,并不是完全包裹,在描边越宽的情况下越明显。如果设计师要求较高,可以通过上述【方法一】来实现。

HTML5 Audio与Video 兼容性

  1. H5 audio和video api是有些兼容性问题的,特别是video更为明显,在浏览器里面相对正常,但是到移动端APP内兼容性问题会更明显
  2. 移动端APP内,想播放音频与视频,最好使用app提供的播放能力,像vidoe.play在端内大部分情况下是播放不了视频的
  3. 试了一下,canplay和canplaythrough在iOS和安卓中是可以使用的,但是像loaddata、loadmetadata这些事件没有生效;而且,canplay和canplaythrough在IOS某个APP容器内是不能自动触发的,必须要利用端内播放能力播放视频,才能触发这两个事件,而且video元素必须要挂载到dom
    video/audio其他的坑点可以看这篇文章https://lq782655835.github.io/blogs/project/project-h5-video-summary.html

参考:
Safari HTML5 video element doesn't emit canplay event unless you're YouTube · Issue #1686 · video-dev/hls.js
video 移动端canplay不触发 - 掘金
H5 Video踩坑记录 | springleo's blog
HTML5 Audio & Video - 兼容性总结(一) - 掘金
javascript - 移动端 HTML5 video 视频兼容性问题 - SegmentFault 思否
load promise doesn't resolve on iOS Safari · Issue #2483 · shaka-project/shaka-player
javascript - HTML5 Video loadeddata event does not work in IOS Safari - Stack Overflow

react开发的原则与技巧

《**React 开发**纲领》**读完这份纲领,发现自己在react开发中存在了一些问题,主要总结如下:

通过删除冗余的状态来减少状态管理的复杂性

我们在开发中经常用setState来设置变量,可以这样做:通过setState得到大的data,然后其他可以通过推导计算出的变量,我们可以有以下几种方式

  • 在标签里面使用data.width * data.height
  • const h = data.width * data.height
  • const h = useMemo(() ⇒ data.width * data.height, [data])

一般,如果h不是有很多地方复用的话,就直接直接第一种;如果很多地方复用或者计算得到的表达式很长或者我是想用一个变量来命名它(这样容易看懂),可以使用第二和第三种

“传递香蕉,而不是拿着香蕉的大猩猩和整个丛林“

给组件设置属性的时候,只需要组件需要的属性,比如属性是data.width和data.height,我们不必把整个data设置为组件的属性。为了避免掉入这种坑,最好将基本类型(booleanstringnumber
 等)作为 props 传递。(传递基本类型也能更好的让你使用 React.memo进行优化)。

组件应该仅仅只了解和它运作相关的内容就足够了。应该尽可能地与其他组件产生协作,而不需要知道它们是什么或做什么。如果我们设置组件的属性为data,那这样组件就会因为这个data产生协作了,正常的思维应该是,我(组件)是这样的,你就按我这样传吧。

这样做的好处是,组件间的耦合会更松散,依赖程度会更低。低耦合更利于组件修改,替换和移除,而不会影响其他组件。

当然如果你是通过data一个属性来表示组件的数据源属性,可以把需要的数据放到data里面。

让你的组件小而简单

也就是单一职责原则

检查组件的 state,props 和 hooks,以及组件内部声明的变量和方法(不应该太多)。问问自己:是否这些内容必须组合到一起这个组件才能工作?如果有些不需要,可以考虑把它们抽离到其他地方,或者把这个大组件拆解成小组件。

函数也是一样的,如果单个函数或方法中的代码行数太多,考虑拆开它。

不过最难的地方是封装粒度确认的问题,就是特定场景下如果封装组件,这个是永久的话题。

其实没必要

你需要redux吗,你需要axios吗,你需要moment.js吗,你需要decimal.js吗,有时候真的没必要。

这点其实在开发中很常见,比如状态管理,我们现在用的是recoil,hook形式的库,非常贴近我们的开发方式,有的项目直接不用状态管理库了。

有些js实现的,我们用css也是可以实现的,用js其实也没必要。

一些react开发的技巧

可以在 setState 时传入回调函数,所以没必要把 state 作为一个依赖项

你不用把 setState和 dispatch放在 useEffect和 useCallback这些 hook 的依赖数组中。ESLint 也不会给你提示,因为 React 已经确保了它们不会出错。

 不太好
const decrement = useCallback(() => setCount(count - 1), [setCount, count])
const decrement = useCallback(() => setCount(count - 1), [count])

 推荐
const decrement = useCallback(() => setCount(count => (count - 1)), [])

如果你的 useMemo 或 useCallback 没有任何依赖,那你可能用错了

如果usememo和usecallback没有依赖,那就直接用常规的变量和函数吧

 不太好
const MyComponent = () => {
   const functionToCall = useCallback(x: string => `Hello ${x}!`,[])
   const iAmAConstant = useMemo(() => { return {x: 5, y: 2} }, [])
   /* 接下来可能会用到 functionToCall 和 iAmAConstant */
}

 推荐
const I_AM_A_CONSTANT =  { x: 5, y: 2 }
const functionToCall = (x: string) => `Hello ${x}!`
const MyComponent = () => {
   /* 接下来可能会用到 functionToCall 和 I_AM_A_CONSTANT */
}

巧用 hook 封装自定义的 context,会提升 API 可读性

它不仅看起来更清晰,而且你只需要 import 一次,而不是两次。

❌ 不太好

// 你每次需要 import 两个变量
import { useContext } from 'react';
import { SomethingContext } from 'some-context-package';

function App() {
  const something = useContext(SomethingContext); // 看起来 ok,但可以更好
  // ...
}

✅ 推荐

// 在另一个文件中,定义这个 hook
function useSomething() {
  const context = useContext(SomethingContext);
  if (context === undefined) {
    throw new Error('useSomething must be used within a SomethingProvider');
  }
  return context;
}

// 你只需要 import 一次
import { useSomething } from 'some-context-package';

function App() {
  const something = useSomething(); // 看起来会更清晰
  // ...
}

通过callback的方式改变state的值

一般的

const { data } = this.state;
this.setState({ data: {...data, key: 1 } });

其实可以通过下面的方式

this.setState(({ data }) => ({ data: {...data, key: 1 } }));
this.setState((state, props) => {
    return { counter: state.counter + props.step };
});

通过扩展运算符和解构赋值可以简化此操作

const Demo = ({ prop1, prop2, prop3, ...restProps }) => (
    <div>
        xxxx
        { restProps.something }
    </div>
)
// 父组件使用Demo
<Demo
    prop1={xxx}
    prop2={xxx}
    something={xxx}
/>
const { data, type, something } = this.state;
<Demo 
    data={data}
    type={type}
    something={something}
/>
可以换成下面的方式
const { data, type, something } = this.state;
<Demo 
    {...{ data, id, something }}
/>

推荐使用ReactDom.render创建弹层-挂载根节点外层,使用也更方便

创建弹层的三种方式:

  1. 普通组件通过state和样式控制,在当前组件中显示弹层-每次引入组件并且render里面控制显示,挂载节点在某组件里面
// 弹层
const Dialog = () => <div>弹层</div>
// 某组件
render() {
    return (
        this.state.showDialog && <Dialog />
    )
}

2.通过Portals创建通道,在根节点外部挂载组件-但还是需要每次引入并且在render里面调用

// 弹层
class Dialog extends React.Component {
  constructor(props) {
    super(props);
    this.el = document.createElement('div');
  }
  componentDidMount() {
    modalRoot.appendChild(this.el);
  }
  componentWillUnmount() {
    modalRoot.removeChild(this.el);
  }

  render() {
    return ReactDOM.createPortal(
      this.props.children || <div>xxxx</div>,
      this.el,
    );
  }
}
// 某组件
render() {
    return (
        this.state.showDialog && <Dialog />
    )
}

3.推荐使用ReactDom.render创建弹层-挂载根节点外层,使用也更方便

// demo
let dialog;
class Dialog {
    show(children) {    // 显示
        this.div = document.createElement('div');
        document.body.appendChild(this.div);

        ReactDom.render(children || <div>xxxx</div>, this.div);
    }
    destroy() {     // 销毁
        ReactDom.unmountComponentAtNode(this.div);
        this.div.parentNode.removeChild(this.div);
    }
}
export default {
    show: function(children) {
        dialog = new Dialog();
        dialog.show(children);
    },
    hide: xxxxx
};
// 某组件
import Dialog from 'xxx';
alert = () => {
    Dialog.show(xxxx);
}
render() {
    return (
        <button onClick={this.alert}>点击弹层</button>
    )
}

参考:

[React Bits](https://hateonion.github.io/react-bits-CN/)

[一份 2.5k star 的《React 开发**纲领》](https://juejin.cn/post/7076244324614144014#heading-8)

[React 开发必须知道的 34 个技巧【近1W字】](https://juejin.cn/post/6844903993278201870#heading-45)
「React进阶」 React全部api解读+基础实践大全(夯实基础2万字总结)
21个让React 开发更高效更有趣的工具

对象解构和数组解构的区别

数组解构是基于symbol.iterator的,它会调用迭代器,运行返回新的数组,如果没有实现迭代器方法,就会报错。
对象解构不会调用迭代器,直接运行结果返回对象
解构”分为数组解构和对象解构,虽然都使用三个点构成的扩展运算符,但它们的语义是不同的,仔细看就会发现它们的上下文也是不同的。

const obj = {...obj}
const array = [...array]

下面的写法会报错

const obj = { name: 'James' };

// ⛔️ Error: Type Object must have a '[Symbol.iterator]()'
// method that returns an iterator.ts(2488)
const result = [...obj];

应该改成

const obj = { name: 'James' };

const result = [...[obj]];

console.log(result); // 👉️ [{name: 'James'}]

参考
js 对象身上没有Symbol.iterator,为什么还能解构?

分析项目中本地打包后的文件与线上文件

image

从上面可以看到,html文件是不走cdn的,这样每次都是最新的,js和css文件是走cdn,html是通过主站域名访问的,而js和css是通过cdn域名访问的,当然其实html也是可以放在cdn上的,有些网站就是这么做的;另外可以看到线上是没有js和css的sourcemapwen文件的,而开发环境是有的。 前端puzzle,错误监控和性能监控相关的sdk的js文件都放在另外的域名上,这些域名都是各个平台的,自己去管理和使用; vconsole的是用unpkg的,这是一个前端公共的cdn地址,它能以快速而简单的方式提供任意包、任意文件。 react-dev-tools也下发了一个js文件,这个一般只有开启了才会有。

image

assets-manifest.json经常会在create-react-app这个脚手架的打包文件上看到,由webpack-manifest-plugin这个webpack插件产生。assets-manifest.json其实只是源文件和加哈希后文件的一个对比表,仅此而已。它不会对应用的运行产生任何影响,浏览器也不会去请求它。
image
另外还有runtime文件,这个主要是用来解析依赖关系等的。

<<css世界>>读后总结版

流的破坏与保护

  • float属性设计的本质的目的是为了实现文字浮动的效果。
  • float具有以下特性,包裹性、块状化并格式化上下文,破坏文档流,没有任何margin合并。块状化的意思是,元素一旦float的属性值不为none,则其display计算值就是block或者table。破坏文档流其中之一造成的坑就是父元素高度坍塌问题,但是也有好处,比如我们可以利用float破坏CSS正常流的特性,实现两栏或多栏的自适应布局。
  • Float的作用机制
  • clear:left应该是“清除左浮动”, clear:right应该是“清除右浮动”的意思,实际上,这种解释是有问题的,因为浮动一直还在,并没有清除。没错,并没有清除。clear属性是设置了clear属性的元素自身如何如何,而不是让float元素如何如何,比如left:左侧抗浮动,both:两侧抗浮动。凡是clear:left或者clear:right起作用的地方,一定可以使用clear:both替换!凡是clear:left或者clear:right起作用的地方,一定可以使用clear:both替换!
  • clear属性只有块级元素才有效的,而::after等伪元素默认都是内联水平,这就是借助伪元素清除浮动影响时需要设置display属性值的原因。
  • 由于clear:both的作用本质是让自己不和float元素在一行显示,并不是真正意义上的清除浮动,因此float元素一些不好的特性依然存在。clear:both只能在一定程度上消除浮动的影响,要想完美地去除浮动元素的影响,还需要使用其他CSS声明,比如bfc。
  • BFC的结界特性最重要的用途其实不是去margin重叠或者是清除float影响,而是实现更健壮、更智能的自适应布局。
  • 和基于纯流体特性实现的两栏或多栏自适应布局相比,基于BFC特性的自适应布局容错性更强。
  • 由于绝大多数的触发BFC的属性自身有一些古怪的特性,所以,实际操作的时候,能兼顾流体特性和BFC特性来实现无敌自适应布局的属性并不多。能担任自适应布局重任的主要是overflow:auto/hidden,display:inline-block, display:table-cell。
  • 要想彻底清除浮动的影响,最适合的属性不是clear而是overflow。一般使用overflow:hidden,利用BFC的“结界”特性彻底解决浮动对外部或兄弟元素的影响。不过话又说回来,overflow属性原本的作用指定了块容器元素的内容溢出时是否需要裁剪,也就是“结界”只是其衍生出来的特性,“剪裁”才是其本职工作。
  • overflow剪裁界线是border box,而不是paddingbox的内边缘
  • HTML中有两个标签是默认可以产生滚动条的,一个是根元素,另一个是文本域<textarea>。之所以可以出现滚动条,是因为这两个标签默认的overflow属性值不是visible,
  • overflow与滚动条的关系和浏览器有关系
  • overflow与锚点定位,锚点定位行为的发生,本质上是通过改变容器滚动高度或者宽度来实现的,锚点定位本质上是改变了scrollTop或scrollLeft值。
  • overflow:hidden元素依然可以滚动
  • 锚点定位有两种场景,URL地址锚链定位和focus锚点定位,虽然都是锚点定位,但是这两种定位方法的行为表现还是有差异的,“URL地址锚链定位”是让元素定位在浏览器窗体的上边缘,而“focus锚点定位”是让元素在浏览器窗体范围内显示即可,不一定是在上边缘。
  • position:absolute和float:left/float:right是兄弟关系,都兼具“块状化”“包裹性”“破坏性”等特性。例如,“块状化”和浮动类似,元素一旦position属性值为absolute或fixed,其display计算值就是block或者table。都有破坏性,破坏正常的流。两者都能“块状格式化上下文”,也就是BFC。两者都具有“包裹性”,也就是尺寸收缩包裹,同时具有自适应性,absolute天然具有“包裹性”,因此没有必要使用display:inline-block。
  • absolute需要注意的一个概念是包含块的概念,和常规元素相比,absolute绝对定位元素的“包含块”有以下3个明显差异。
  • 一个绝对定位元素,没有任何left/top/right/bottom属性设置,并且其祖先元素全部都是非定位元素,其位置在当前位置,不是在浏览器左上方。bsolute定位效果实现完全不需要父元素设置position为relative或其他什么属性就可以实现,我把这种没有设置left/top/right/bottom属性值的绝对定位称为“无依赖绝对定位”。很多场景下,“无依赖绝对定位”要比使用left/top之类属性定位实用和强大很多。
  • 按道理讲,absolute和float一样,都可以让元素块状化,应该不会受控制内联元素对齐的text-align属性影响,但是最后的结果却出人意料,text-align居然可以改变absolute元素的位置。需要注意的是,这里并不是text-align和absolute元素直接发生关系,absolute元素的display计算值是块状的,text-align是不会有作用的。这里之所以产生了位置变化,本质上是“幽灵空白节点”和“无依赖绝对定位”共同作用的结果。
  • overflow对absolute元素的剪裁规则,如果overflow 不是定位元素,同时绝对定位元素和 overflow 容器之间也没有定位元素,则overflow无法对absolute元素进行剪裁。
  • overflow元素自身transform的时候,Chrome和Opera浏览器下的overflow剪裁是无效的,这是唯一和有定位属性时的overflow剪裁不一样的地方。transform除了改变overflow属性原有规则,对层叠上下文以及position:fixed的渲染都有影响。因此,当大家遇到absolute元素被剪裁或者fixed固定定位失效时,可以看看是不是transform属性在作祟。
  • CSS世界中有些属性或者特性必须和其他属性一起使用才有效,比方说剪裁属性clip。clip属性要想起作用,元素必须是绝对定位或者固定定位
  • clip隐藏仅仅是决定了哪部分是可见的,非可见部分无法响应点击事件等;然后,虽然视觉上隐藏,但是元素的尺寸依然是原本的尺寸,在IE浏览器和Firefox浏览器下抹掉了不可见区域尺寸对布局的影响,Chrome浏览器却保留了。
  • 当absolute遇到left/top/right/bottom属性的时候,absolute元素才真正变成绝对定位元素
  • relative的定位有两大特性:一是相对自身;二是无侵入。
  • 相对定位元素的left/top/right/bottom的百分比值是相对于包含块计算的,而不是自身。注意,虽然定位位移是相对自身,但是百分比值的计算值不是。top和bottom这两个垂直方向的百分比值计算跟height的百分比值是一样的,都是相对高度计算的。同时,如果包含块的高度是auto,那么计算值是0,偏移无效,也就是说,如果父元素没有设定高度或者不是“格式化高度”,那么relative类似top:20%的代码等同于top:0。
  • 当相对定位元素同时应用对立方向定位值的时候,也就是top/bottom和left/right同时使用的时候,其表现和绝对定位差异很大。绝对定位是尺寸拉伸,保持流体特性,但是相对定位却是“你死我活”的表现,也就是说,只有一个方向的定位属性会起作用。而孰强孰弱则是与文档流的顺序有关的,默认的文档流是自上而下、从左往右,因此top/bottom同时使用的时候,bottom被干掉;left/right同时使用的时候,right毙命。
  • “relative的最小化影响原则”是我自己总结的一套更好地布局实践的原则
  • position:fixed固定定位元素的“包含块”是根元素,我们可以将其近似看成元素。换句话说,唯一可以限制固定定位元素的就是根元素,而根元素就这么一个
  • 有时候我们希望元素既有不跟随滚动的固定定位效果,又能被定位元素限制和精准定位,那该怎么办呢?我们可以使用position:absolute进行模拟,原理其实很简单:页面的滚动使用普通元素替代,此时滚动元素之外的其他元素自然就有了“固定定位”的效果了。

css将图片设置为正方形

需求:后端返回了一组图片,图片的宽度固定,高度不固定。前端要求图片展示为正方形,图片不能变形且自适应,如果图片高了则裁剪掉。

<div>
  <div class="img-wrap">
       <img src="">
   </div>
</div>

.img-wrap {
        position: relative;
        width: 100%;
        height: 0;
        padding-bottom: 100%;
        overflow: hidden;

}

.img-wrap img  {
        position: absolute;
        width: 100%;
        //height: 100%;
}

原理解析:img-wrap继承父元素的宽度,为了保证img-wrap容器的高度等于宽度,通过padding-bottom撑开高度,接下来图片只设置宽度让它等于父元素的宽度,图片的高度会自适应。父元素设置overflow:hidden,这样设置以后图片即使过高也能保证不变形,只是看起来像裁剪成了正方形。

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.