分类
javascript

层叠上下文与事件流

事件流

image - 层叠上下文与事件流

层叠上下文

若子元素的层叠上下文在父元素下方,那么点击子元素位置时target只能到父元素这,即子元素无法触发到点击监听

分类
常识

移动端手势

37960a877cae628edf0dbefbf164561b r 833x1024 - 移动端手势
分类
javascript react

React函数式编程使用lodash的防抖

import React, { FC, useRef } from 'react'
import copy from 'copy-to-clipboard'
import { message } from 'hljd'
import { debounce } from 'lodash'
interface ColorPickerInputNativeProps {
  value?: string
  onChange?: (value: string) => void
}
const ColorPickerInputNative: FC<ColorPickerInputNativeProps> = ({ value, onChange }) => {
  const eRef = useRef('')
  const funcRef = useRef(
    debounce(() => {
      copy(eRef.current)
      onChange?.(eRef.current)
      message.success('颜色值已复制')
    }, 200)
  )
  const handleChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {
    eRef.current = e.target.value
    funcRef.current()
  }
  return <input type="color" value={value} onChange={handleChange} />
}
export { ColorPickerInputNative }

要点:

  • 改变的值存入useRef中
  • 在useRef中放置debounce
分类
javascript

postMessage没接收到值只接收到webpackOk

原因

当时的iframe是动态生成的,未加载好就发送postMessage,webpack帮助了发送,所以出现webpackOk

解决方案

const targetIframe = document.getElementById('targetIframe')
const info = { sign: '标识' }
targetIframe.onload = () => {
    targetIframe.contentWindow.postMessage(info,'*')
}
分类
CSS

grid布局细节

grid-auto-flow和grid中的auto-flow

grid-auto-flow:流动方向,可以设定row或column,类似于flex-direction。

auto-flow:可以在grid中设置缩写

gird: <grid-template-rows> / [auto-flow && dense?] <grid-auto-columns>
grid: <auto-flow && dense?> <grid-auto-rows> / <grid-template-rows>

在左侧说明是row,在右侧说明是column,与grid-auto-flow有相同的作用。

例如

grid:auto-flow dense 300px/200px 1fr

上述代码说明有两列为200px和1fr,然后稠密的向下流动,只有匿名单元格,匿名单元格的高度为300px。

grid-column-start

计数以1开始,包括边缘线,就是说如果水平有6块,则计数可以从1~7,可以是负数-1是右侧边缘线,可以从-7~-1

grid-column-start 与 grid-column-end 不需要考虑前者的数字比后者大或小。

分类
react

hooks使用心得

在React 函数式编程中写定时器

let [count, setCount] = useState(0)
    let intervalCb = useRef(null)
    let CountTimer
    useEffect(() => {
        intervalCb.current = () => {
            setCount(count+1)   
        }
    }, [count])

    useEffect(() => {
        function itvFn() {
            intervalCb.current()
        }
        CountTimer = window.setInterval(itvFn, 1000)
        return () => window.clearInterval(CountTimer)
    }, [])

const handleStop = () => { // 暂停
        window.clearInterval(CountTimer)
    }

如何获取一次数据

import React, { useState, useEffect } from 'react';
import axios from 'axios';
 
function App() {
  const [data, setData] = useState({ hits: [] });
 
  useEffect(() => {
    const fetchData = async () => {
      const result = await axios(
        'https://hn.algolia.com/api/v1/search?query=redux',
      );
 
      setData(result.data);
    };
 
    fetchData();
  }, []);
 
  return (
    <ul>
      {data.hits.map(item => (
        <li key={item.objectID}>
          <a href={item.url}>{item.title}</a>
        </li>
      ))}
    </ul>
  );
}
 
export default App;

useEffect尽量不要依赖不影响更新的依赖项

function App() {
  const [data, setData] = useState({ hits: [] });
  const [query, setQuery] = useState('redux');
  const [url, setUrl] = useState(
    'https://hn.algolia.com/api/v1/search?query=redux',
  );
 
  useEffect(() => {
    const fetchData = async () => {
      const result = await axios(url);
 
      setData(result.data);
    };
 
    fetchData();
  }, [url]);
 
  return (
    <Fragment>
      <input
        type="text"
        value={query}
        onChange={event => setQuery(event.target.value)}
      />
      <button
        type="button"
        onClick={() =>
          setUrl(`http://hn.algolia.com/api/v1/search?query=${query}`)
        }
      >
        Search
      </button>
 
      <ul>
        {data.hits.map(item => (
          <li key={item.objectID}>
            <a href={item.url}>{item.title}</a>
          </li>
        ))}
      </ul>
    </Fragment>
  );
}

将获取数据,loading,error的逻辑变为自定义钩子

import React, { Fragment, useState, useEffect } from 'react';
import axios from 'axios';
 
const useDataApi = (initialUrl, initialData) => {
  const [data, setData] = useState(initialData);
  const [url, setUrl] = useState(initialUrl);
  const [isLoading, setIsLoading] = useState(false);
  const [isError, setIsError] = useState(false);
 
  useEffect(() => {
    const fetchData = async () => {
      setIsError(false);
      setIsLoading(true);
 
      try {
        const result = await axios(url);
 
        setData(result.data);
      } catch (error) {
        setIsError(true);
      }
 
      setIsLoading(false);
    };
 
    fetchData();
  }, [url]);
 
  return [{ data, isLoading, isError }, setUrl];
};
 
function App() {
  const [query, setQuery] = useState('redux');
  const [{ data, isLoading, isError }, doFetch] = useDataApi(
    'https://hn.algolia.com/api/v1/search?query=redux',
    { hits: [] },
  );
 
  return (
    <Fragment>
      <form
        onSubmit={event => {
          doFetch(
            `http://hn.algolia.com/api/v1/search?query=${query}`,
          );
 
          event.preventDefault();
        }}
      >
        <input
          type="text"
          value={query}
          onChange={event => setQuery(event.target.value)}
        />
        <button type="submit">Search</button>
      </form>
 
      {isError && <div>Something went wrong ...</div>}
 
      {isLoading ? (
        <div>Loading ...</div>
      ) : (
        <ul>
          {data.hits.map(item => (
            <li key={item.objectID}>
              <a href={item.url}>{item.title}</a>
            </li>
          ))}
        </ul>
      )}
    </Fragment>
  );
}
 
export default App;

useState的setState

setState的第一个参数可以传入函数,函数中的第一个参数是state的值

createRef 与 useRef 的区别

– createRef 每次渲染都会返回一个新的引用 – useRef 每次都会返回相同的引用

useMemo缓存组件

const child1 = useMemo(() => <Child1 count={count} />, [count])