【PIT】React-Native(15) PanResponder,Animated,AsyncStorage,AppState,Dimensions,PixelRatio,StyleShee...

大纲
react-native-scrollable-tab-view在安卓模拟器上报错
react-native-echarts在安卓模拟器上不显示
react-native-echarts中的echarts源码版本过低,造成andorid柱状图点击主要图消失?下载最新版本修改源文件!
Animated动画组件
hooks中如何实现一个动画( rn中 )
Dimensions
PixelRatio
手势响应系统
PanResponder
Image,ImageBackground,Animated.Image
AppState
StyleSheet
FlatList
获取和清除缓存 react-native-http-cache
获取组件(或元素)的宽高等信息 => (两种方法)
react-native-debugger如何调试http请求,NetWork面板请求不显示问题
复习:
async函数
cookie

hooks中如何实现一个动画

例子1:
const List = () => {
  const left = new Animated.Value(-300)  // left的初始值,注意 Value是大写
  useEffect(() => {
    Animated.timing(left, { // 注意区分 timing,decay衰退,spring弹簧
      toValue: 110, // 终值
      duration: 1000
    }).start() // start开始动画
  })
  return (
    <Animated.View style={{left}}> // view的动画组件
      <Text>1111111</Text>
    </Animated.View>
  )
}



例子2:
- 使用 useRef 实现
- useRef 返回一个可变的ref对象,返回的对象将在组件的整个生命周期内存在
- useRef.current 初始化为传递的参数
const List = () => {
  const left = useRef(new Animated.Value(-300)).current
  useEffect(() => {
    Animated.timing(left, {
      toValue: 110,
      duration: 1000,
      useNativeDriver: false // 是否启用原生动画
    }).start()
  })
  return (
    <Animated.View style={{left}}>
      <Text>1111111111111</Text>
    </Animated.View>
  )
}



------------------------------------
例3:综合案例
import React, {useRef} from 'react';
import {Animated, PanResponder, Dimensions, StyleSheet} from 'react-native';
const {height} = Dimensions.get('window'); // 获取手机的宽和高
/**
 * @param {children} DOM reactElement
 * @param {initialTop} number 竖直方向初始值
 */
/* eslint-disable no-unused-vars, react/jsx-props-no-spreading */
function CardSheet({children, initialTop}) {
  const refCardAnimated = useRef(new Animated.Value(initialTop)).current;
  const panResponder = PanResponder.create({
    onStartShouldSetPanResponder: () => true, // 开始触摸时询问
    onStartShouldSetPanResponderCapture: () => true, // 父级获权,捕获
    onPanResponderRelease: (evt, gestureState) => {
      // 手势释放时触发
      // evt 原生的nativeEvent对象、gestureState手势对象
      // dy  -向上  +向下
      // dy 表示从触摸操作开始时的累计纵向路程
      Animated.timing(refCardAnimated, {
        toValue: gestureState.dy < 0 ? 0 : initialTop,
        duration: 50,
      }).start();
    },
  });
  return (
    <Animated.View
      pagingEnabled
      {...panResponder.panHandlers} // panHandlers对象
      style={[
        styles.container,
        {
          height,
          top: refCardAnimated,
        },
      ]}>
      {children}
    </Animated.View>
  );
}
const styles = StyleSheet.create({
  container: {
    width: '100%',
    position: 'absolute',
    overflow: 'scroll',
    zIndex: 99999,
    backgroundColor: 'white',
  },
});
export default CardSheet;

https://reactnative.cn/docs/panresponder/#docsNav
https://blog.codecentric.de/en/2019/07/react-native-animated-with-hooks/

(6) PanResponder

  • 将多点触摸操作协调成一个手势
  • 它在原生事件之外提供了一个新的 gestureState 对象
(1) gestureState对象
onPanResponderMove: (event, gestureState) => {}
- event: nativeEvent 对象
- gestureState:
  - dx - 从触摸操作开始时的累计横向路程
  - dy - 从触摸操作开始时的累计纵向路程   !!!!!!!!!!!! 注意:dy 是有正负的,向上是负数,向下是正数 !!!!!!!!!!!!! 
  - vx - 当前的横向移动速度
  - vy - 当前的纵向移动速度
  - d:是 distance 路程的缩写
  - v: 是 velocity 速度的缩写

(2) PanResponder.create()
- 返回一个 panHandlers 对象

(5) 手势响应系统

(1) 响应者生命周期

1. View要成为触摸事件响应者,有两个询问的方法:
- onStartShouldSetResponder: (evt) => true     -- 在 ( 开始触摸 ) 的时候询问
- onMoveShouldSetResponder: (evt) => true      -- 如果View不是响应者,在 ( 开始移动 ) 的时候再次询问



2. 如果View返回true,并开始成为响应者,则下列事件可以被触发:
- onResponderGrant: (evt) => {}      -- view要开始响应触摸事件了 ( grant: 是允许的意思 )
- onResponderReject: (evt) => {}     -- 响应者现在“另有其人”而且暂时不会“放权”,请另作安排。

- onResponderTerminationRequest: (evt) => true
  - 有其他组件请求接替响应者,当前的 View 是否“放权”?返回 true 的话则释放响应者权力。
  - Terminate: 是中止,结束的意思

- onResponderTerminate: (evt) => {}  -- 响应者权力已经交出。
  - 这可能是由于其他 View 通过onResponderTerminationRequest请求的
  - 也可能是由操作系统强制夺权(比如 iOS 上的控制中心或是通知中心)



3. evt 是一个合成事件
  - nativeEvent
    - changedTouches - 在上一次事件之后,所有发生变化的触摸事件的数组集合(即上一次事件后,所有移动过的触摸点)
    - locationX - 触摸点相对于当前元素的横坐标
    - locationY - 触摸点相对于当前元素的纵坐标
    - pageX - 触摸点相对于根元素的横坐标
    - pageY - 触摸点相对于根元素的纵坐标



4. 优先级 ( 捕获ShouldSet事件处理 )
- onStartShouldSetResponder 和 onMoveShouldSetResponder 是以冒泡的方式调用,所以最初点击的DOM最新调用
- 如果父元素想优先于子元素响应的话,可以在捕获期拦截,在下面的事件中返回true,并在对应的函数中做处理
  - onStartShouldSetResponderCapture: (evt) => true,  
  - onMoveShouldSetResponderCapture: (evt) => true,

(7) Animated动画组件

(1) 两种类型的值
- Animated.Value() 用于单个值
- Animated.ValueXY() 用于矢量值

(3) 三种动画类型
- Animated.decay() 以指定的初始速度开始变化,然后变化速度越来越慢,直至停下 (decay是衰退的意思)
- Animated.spring() 弹簧效果 (spring是弹簧,春天的意思)
- Animated.timing() easeinout函数

(4) 启动动画
- start()用来启动动画

(5) 启动原生驱动
- 在动画配置中指定 useNativeDriver:true 使用原生动画驱动

(6) 动画组件
- 注意:组件必须经过特殊处理才能用于动画
- 特殊处理指:把动画值绑定到属性上,并且在一帧帧执行动画时避免 react 重新渲染和重新调和的开销,此外还得在组件卸载时做一些清理工作
- 可以直接使用动画的组件:
  - Animated.View
  - Animated.ScrollView  
  - Animated.Text
  - Animated.Image

(8) Image,ImageBackground,Animated.Image

  • Animated.Image 可以直接使用的动画组件,注意使用该组件无需引入Image组件,是Animated的属性
  • ImageBackground 相当于web中的背景图片,可以在ImageBackground组件内添加任意多个子集

(9) AsyncStorage

  • 不推荐使用AsyncStorage,使用 react-native-storage 代替
  • Deprecated:不推荐使用,反对
  • AsyncStorage是一个简单,异步,持久的key-value存储系统,是全局的,可用用来代替localstorage
react-native-storage
- backend:后端

(1) storage.js
import Storage from 'react-native-storage';
import AsyncStorage from '@react-native-community/async-storage';
const storage = new Storage({
  size: 1000,
  storageBackend: AsyncStorage, // for web: window.localStorage
  defaultExpires: 1000 * 3600 * 24,
  enableCache: true,
  sync: {
  },
});
// add to global environment
// notice: should global import
global.storage = storage;
export default storage;



(2) 全局引入
- 在项目入口index.js中引入
- import '..../storage.js';
- 因为该模块只需要执行,而不用引入任何模块,所以直接import '路径/文件名' 即可 ( 即保证该文件执行过,才能挂载到global对象上 )

https://github.com/sunnylqm/react-native-storage

中文 https://github.com/sunnylqm/react-native-storage/blob/master/README.zh-CN.md

(10) AppState

  • AppState 应用是在前台还是后台,在状态变化时通知您
  • AppState 通常在处理推送通知的时候,用来决定内容和对应的行为
AppState 


(1) AppState.currentState 
- AppState.currentState 返回应用的当前状态,会一直保持更新
- 在应用启动过程中,AppState.currentState可能为null,知道AppState从原生代码得到通知


(2) 状态类型 status
- active 前台
- background 后台,分为几种情况
  - 在别的应用中
  - 停留在桌面
  - 对 Android 来说还可能处在另一个Activity中(即便是由你的应用拉起的)
- [iOS] inactive - 此状态表示应用正在前后台的切换过程中,或是处在系统的多任务视图,又或是处在来电状态中。


(3) 事件
- change
- focus (仅android, 用户和应用进行交互时触发)
- blur (仅android,用户下拉通知抽屉时触发)


(4) 方法
- addEventListener()
- removeEventListener()




---------------------------------
(5) 实例
---------------------------------
import React, { useState, useEffect } from 'react';
import { AppState } from 'react-native';

const statusObj = { // 支持的三种状态
  active: '应用正在前台运行',
  background: '应用正在后台运行',
  inactive: '应用切换中'
}

export const useAppStatus = () => {
  const [appStatus, setAppStatus] = useState(AppState.currentState) // AppState.currentState属性
  const listenStatus = (nextAppState) => {
    if (nextAppState in statusObj) {
      console.log(statusObj[nextAppState]);
      setAppStatus(statusObj[nextAppState])
    }
  }
  useEffect(() => {
    AppState.addEventListener('change', listenStatus) // AppState.addEventListener 事件
    return () => {
      AppState.removeEventListener('change', listenStatus) // AppState.removeEventListener 事件
    }
  }, [])

  return appStatus
}

(11) StyleSheet

  • marginVertical:上下两边的margin
  • marginHorizontal:左右两边的margin
  • transform: [{translateX: number}]
  • StyleSheet 提供了一种类似 CSS 样式表的抽象。
StyleSheet


(1) 方法
- StyleSheet.create(obj)
- StyleSheet.flatten(style) // 展平数组中的样式对象,或者样式对象,相同属性后面会覆盖前面的属性
- StyleSheet.compose(style1, style2) // 组合

(2) 属性 
- StyleSheet.hairlineWidth // 最细的线条,一像素边框
  - 可以用来实现一像素边框
  - 这一常量始终是一个整数的像素值(线看起来会像头发丝一样细),并会尽量符合当前平台最细的线的标准。
  - 如果模拟器缩放过,可能会看不到这么细的线。
- StyleSheet.absoluteFill

transform https://reactnative.cn/docs/transforms/#docsNav

(12) 获取和清除缓存

  • react-native-http-cache
import * as CacheManager from 'react-native-http-cache';

const formatCache = cache => {
  let cacheSize = Math.floor(cache / 1024);
  console.log(cacheSize, 'cacheSize');
  switch (true) {
    case cacheSize / 1024 > 1: {
      cacheSize = `${Math.floor(cacheSize / 1024)} MB`;
      break;
    }
    default: {
      cacheSize = `${cacheSize} KB`;
      break;
    }
  }
  console.log('cache-size =>', cacheSize);
  return cacheSize;
};

export const getCacheSize = async () => { // 获取缓存大小,注意getCacheSize()返回的是promise
  const cache = await CacheManager.getCacheSize();
  return formatCache(cache);
};

export const clearCache = async () => { // 清除缓存
  const res = await CacheManager.clearCache(); // clearCache()返回的也是promise
  console.log('清除缓存的返回值 =>', res);
  return res;
};

安卓报错修改路径:node_modules\react-native-http-cache\android\src\main\java\cn\reactnative\httpcache

gitbub https://github.com/reactnativecn/react-native-http-cache
安卓按readme配置后报错:https://www.jianshu.com/p/b99d3a46947f
修改方法:
//FileCache cache1 = ImagePipelineFactory.getInstance().getMainDiskStorageCache();
FileCache cache1 = ImagePipelineFactory.getInstance().getMainFileCache();
//FileCache cache2 = ImagePipelineFactory.getInstance().getSmallImageDiskStorageCache();
FileCache cache2 = ImagePipelineFactory.getInstance().getSmallImageFileCache(
安卓报错修改路径:node_modules\react-native-http-cache\android\src\main\java\cn\reactnative\httpcac

(13) 获取组件(或元素)的宽高等信息

(1)方法一
- 在 View 组件中有 onLayout 事件
- {nativeEvent: { layout: {x, y, width, height}}}
  - 通过 e.nativeEvent.layout 获取 x, y, width, height
  - 注意:这个事件会在布局计算完成后立即调用一次,不过收到此事件时新的布局可能还没有在屏幕上呈现,尤其是一个布局动画正在进行中的时候。
  - 如果遇到合成事件异步访问相关的警告,使用 event.persist()
- 缺点:只在初次渲染的时候才会触发这个函数,而且此种方法获取的是组件相对于父组件的位置坐标。
const onLayout = (e) => {
  e.persist();
  setCopyRightWidth(Math.floor(e.nativeEvent.layout.width))
}



(2)方法二
- UIManager, findNodeHandle

import { UIManager,  findNodeHandle } from 'react-native';
<MyComponent  ref={(ref)=>this.myComponent=ref} />
UIManager.measure(findNodeHandle(this.myComponent),(x,y,width,height,pageX,pageY)=>{
   //todo
})

http://erichuang.top/2018/05/21/ReactNative/React%20Native%E4%B9%8B%E8%8E%B7%E5%8F%96%E7%BB%84%E4%BB%B6%E4%BD%8D%E7%BD%AE%E4%B8%8E%E5%A4%A7%E5%B0%8F/

https://www.jianshu.com/p/20c63afc04b8

(14) react-native-debugger如何调试http请求

react-native-debugger如何调试http请求 ---- NetWork面板请求不显示问题


解决办法:
- 路径:   node_modules\react-native\Libraries\Core\setUpXHR.js
- 注释掉: // polyfillGlobal('XMLHttpRequest', () => require('../Network/XMLHttpRequest'));

https://www.cnblogs.com/zhangtao1990/p/10016559.html

(1) react-native-scrollable-tab-view

react-native-scrollable-tab-view

解决方案:

(1) 解决方案:
yarn add @react-native-community/viewpager
react-native link @react-native-community/viewpager


(2) 关于link
添加包含原生代码的库需要几个步骤:
1. npm install 某个带有原生依赖的库
2. react-native link 某已安装的具体库名(注意:现在rn不需要link了,rn会自动link, 不需要手动link)
经过以上两步,现在原生依赖就成功地链接到你的 iOS/Android 项目了。


(3) 单词
community:是社区的意思
unpack: 打开,取出

issues https://github.com/ptomasroos/react-native-scrollable-tab-view/issues/1050

(2) react-native-echarts在安卓模拟器上不显示

react-native-echarts在安卓模拟器上不显示


1. 安装 react-native-webview
- npm install react-native-webview -S

2. 将node_modules\native-echarts\src\components\Echarts下的tpl.html复制到android\app\src\main\assets目录下,
   assets需要自己新建文件夹

3. 修改react-native-echarts的源码
- 在node_modules\native-echarts\src\components\Echarts下的index.js文件进行修改:
- 将Webview组件的source配置项修改为:
- source={Platform.OS === 'ios' ? require('./tpl.html') : {uri:'file:///android_asset/tpl.html'}}


        import { View, StyleSheet, Platform } from 'react-native';
        <WebView
          ref="chart"
          scrollEnabled = {false}
          injectedJavaScript = {renderChart(this.props)}
          style={{
            height: this.props.height || 400,
            backgroundColor: this.props.backgroundColor || 'transparent'
          }}
          scalesPageToFit={Platform.OS !== 'ios'}
          originWhitelist={['*']}
          source={Platform.OS === 'ios' ? require('./tpl.html') : {uri:'file:///android_asset/tpl.html'}}
          onMessage={event => this.props.onPress ? this.props.onPress(JSON.parse(event.nativeEvent.data)) : null}
        />

https://www.cnblogs.com/lude1994/p/10647842.html
de

(3) react-native-echarts中的echarts源码版本过低,造成andorid柱状图点击主要图消失?下载最新版本修改源文件!

修改前

修改后
1. 下载最新版本的echarts,建议定制化下载,并开启代码压的缩
2. 找到RN中的native-echarts源码,修改native-echarts/src/components/Echarts/中的echarts.min.js和tpl.html
3. tpl.html文件中的script标签中加载的就是echarts的源码,直接拷贝最新版的echarts.min.js替换掉

4. 还要拷贝tpl.html文件到andorid/app/src/main/assets/tpl.html,替换掉这里的tpl.html
// 如果没有assets文件夹自己新建一个

(4) Dimensions

  • dimensions: 是尺寸,范围的意思
const {height, width} = Dimensions.get('window');

(5) PixelRatio

PixelRatio
- pixel:像素
- pixelRatio:像素比
- PixelRatio.get()
- PixelRatio.getFontScale()
- PixelRatio.getPixelSizeForLayoutSize()


(1) PixelRatio.get() 
  - 返回设备的像素密度 // 1 2 3 3.5

(2) PixelRatio.getFontScale() 
  - 返回字体缩放比例
  - 该比例用于计算绝对字体的大小

(3)PixelRatio.getPixelSizeForLayoutSize() 
  - 将布局尺寸转换为像素尺寸,一定是返回一个整数数值
  - dp -> px






复习 async函数

  • async函数返回一个promise对象,可以使用then方法添加回调函数
  • 一旦遇到await就会先返回,等异步操作执行完后,才会执行函数体后面的语句
async 函数语法

(1) 基本语法
- async 函数返回一个promise对象
- async 函数内部 return 语句的(返回值),会成为 then 方法回调函数的 (参数)
- async 函数内部抛出错误,会导致返回的promise对象变成reject对象,可以被catch函数捕捉到


(2) 状态变化
- async 函数返回的promise对象,必须等到async函数内部所有await命令后面的promise对象执行完才会发成改变,除非遇到return或者抛出错误
  即:只有async函数内所有异步操作执行完成后,才会只执行then方法指定的回调函数、

await命令

- 如果 await 命令后是一个 promise 对象,返回该对象的结果,如果不是promise对象,就会直接返回后面对应的值
- 如果 await 命令后是一个thenable对象(即定义了then方法的对象),await会将其等同于promsie对象
- await命令 后面的promise对象如果变成reject状态,reject的参数会被catch捕获
- 任何一个await命令后面的promise对象变为reject状态,整个async函数就会中断执行

- 需求:如果希望前一个异步操作失败,也不要中断后面的异步操作
- 两种方法
- 1.
    const go = async () => {
      try {
        await Promise.reject('出错了')
      } catch(e) {
      }
      return await Promise.resolve('还是执行了') // 前面的promise报错了,但是该promise仍然执行了
    }
    go().then(res => console.log(res, 'res'))
- 2.
async function f() {
  await Promise.reject('出错了')
    .catch(e => console.log(e));
  return await Promise.resolve('hello world');
}
f()
.then(v => console.log(v))
// 出错了
// hello world
使用注意点

- await命令后的promise对象可能是reject,所以最好使用try...catch保证能捕获错误,并且不会影响其他的await命令后的promise
- await命令只能用在async函数中,用在普通函数中就会报错


- async可以保留运行堆栈
(1)
const a = () => {
  b().then(() => c());
};
- 上面b执行时,a并没有中断执行而是继续执行,当b执行完时,可能a已经执行完
- 所以b或者c函数中如果运行出错,则错误堆栈将可能不包括a
---------
(2)
const a = async () => {
  await b();
  c();
};
- 上面b执行时,a是中断执行的,a的上下文环境仍然保留
- 所以b或者c出错,错误堆栈将包括a

复习 cookie

  • cookie是服务器保存在浏览器的一小段文本信息
  • cookie的大小不能超过 4kb
  • 浏览器每次向服务器发送请求都会携带上cookie
  • cookie主要用来分辨两个请求是否来自同一个浏览器,和保存一些状态信息
cookie


1. cookie包含的信息
- cookie的名字
- cookie的值
- 到期时间
- 所属域名,默认是当前域名
- 生效的路径,默认是当前网址
- 总结下是 key value expires max-age domain path secure http-only
如:
  - cookie中有 www.example.com
    - 如果根路径是  / ,==========> 表示该cookie对该域名的根路径和它的所有子路径有效
    - 如果根路径是  /forums,=====> 表示cookie只有在访问 www.example.com/forums及其子路径时才有效
  - forum:是论坛的意思

2. 浏览器可以设置不接受cookie,也可以设置不向服务器发送cookie
- window.navigator.cookieEnabled
- document.cookie
- window.navigator.cookieEnabled => 浏览器是否打开cookie功能,boolen值
- document.cookie => 返回当前网页的cookie,可读写

3. 浏览器对cookie的大小和数量限制
- 数量:不超过30个,单个域名的cookie数量不应超过30个
- 大小:不超过4kb

4. 共享cookie的条件
- 两个网址的域名和端口相同,就可以共享cookie
- 不要求协议相同

5. cookie由http协议生成,也主要供http协议消费

6. 服务器如何在浏览器中------------------------------------------------------------------------> 服务器保存cookie
- 需要http回应头中,放置 set-Cookie 字段
- Set-Cookie
- Set-Cookie:foo=bar // 在浏览器保存一个名为foo的cookie,值是bar
- Set-Cookie: <cookie-name>=<cookie-value>; Domain=<domain-value>; Secure; HttpOnly 
  Set-Cookie除了cookie的值,还可以附加多个cookie的属性,没有顺序要求
- 服务器如果希望在浏览器保存 Cookie,就要在 HTTP 回应的头信息里面,放置一个Set-Cookie字段。
- 注意:HTTP回应可以包含多个 set-Cookie 字段

7. 服务器如何修改已经存在的 cookie -------------------------------------------------------------> 服务器修改cookie
- 必须满足四个条件:( key,domain,path,secure ) 都要匹配
- 只要有一个属性不同,就会产生一个全新的 cookie,而不是替换原来的 cookie

8. 浏览器发送cookie ---------------------------------------------------------------------------> 浏览器发送cookie
- HTTP的头字段中设置 Cookie 字段
- Cookie: foo=bar
- Cookie字段可以包含多个cookie,用分号隔开

9. 服务器收到浏览器发来的cookie,有两点是无法知道的
- Cookie的各种属性
- 那个域名设置的cookie,是一级域名还是二级域名等

10. cookie的属性 ------------------------------------------------------------------------------> cookie的属性
- Expires
- Max-Age
- Domain
- Path
- Secure
- HttpOnly

Expires
- 指定一个具体的到期时间,时间到了后,浏览器就不会向服务器发送cookie
- 值是 UTC 格式,可以使用Date.prototype.toUTCString()进行格式转换
- 注意:如果Expires设置null,或者不设置,cookie只在当前会话有效,关闭浏览器后,cookie就会被删除
- 注意:上面要 Expires 和 Max-Age 都未设置时,cookie在是会话cookie
- 注意:浏览器是根据本地时间,决定cookie是否过期的

Max-Age ----------------------------------------------------> 优先级 ( Max-Age > Expires ),同时设置,将采用 Max-Age
------------------------------------------------------------> 都未设置,则为会话cookie,只在当前会话有效
- 指定从现在开始,cookie存在的秒数,单位是秒
- 保存一年即 360 * 24 * 60 * 60

Domain
- 指定浏览器在发出HTTP请求时,哪些域名会附带这个cookie
- 未指定,则默认是当前url的一级域名

Path
- 指定浏览器在发出HTTP请求时,哪些路径要携带这个cookie

Secure
- 指定浏览器只有在加密协议HTTPS下,才能将这个cookie发送到服务器
- 如果当前协议是HTTP,则浏览器会忽略服务端发来的Secure属性

HttpOnly
- 指定该cookie无法通过js脚本拿到
- 注意是该cookie,响应头中可以存在多个Set-Cookie字段,即多个cookie
- ( Document.cookie,XMLHttpRequest对象,Request API 都拿不到cookie )

11. Document.cookie
- 读写当前网页的cookie
- 读取 --------------------------------> 返回当前网页的 ( 所有cookie  )
- 写入 --------------------------------> 一次只能写入 ( 一个cookie )
- 浏览器向服务器发送cookie,-------------> 用一行 ( 全部发送 )
- 服务器向浏览器设置cookie,-------------> Set-Cookie是一行设置 ( 一个cookie )
- document.cookie读写行为的差异(一次可以读出全部 Cookie,但是只能写入一个 Cookie),与 HTTP 协议的 Cookie 通信格式有关
- 写入cookie时要注意:
  - Expires是 UTC 时间,可以通过 Date.prototype.toUTCString() 进行日期格式化转换
  - Max-Age单位是 秒
  - Path是绝对路径
  - Domain必须是当前发送cookie的域名的一部分

12. 删除cookie的唯一办法 
----------------------------------------------------------------> 删除cookie的唯一办法是设置 Expires 为一个过去的时间

推荐阅读更多精彩内容

  • 持续更新中...... 一套企业级的 UI 设计语言和 React 实现。 https://mobile.ant....
    日不落000阅读 4,429评论 0 35
  • React Native着力于提高多平台开发的开发效率 —— 仅需学习一次,编写任何平台。(Learn once,...
    分贝丶阅读 561评论 1 2
  • 之前有个项目学习了react-native,js社区从来不缺好用的第三方插件。如果项目允许的话,使用合适的插件绝对...
    Even_Cyw阅读 192评论 0 4
  • 今天,关于母亲,世界似乎都温暖起来! 我本来只想在心里默默的思念,独享一下只有自己才能感受到的那种滋味,这应该算不...
    梅花岛上的菜园子阅读 182评论 0 2
  • 说来也奇怪,盛夏一过,秋天的气息接踵而来,太阳的温度降了许多,空气里弥漫着成熟的味道,阳光下树叶的影子连在一起,中...
    夹心天空阅读 89评论 0 0