{"id":26214431,"url":"https://github.com/ljunb/rn-countdown","last_synced_at":"2025-04-15T18:41:56.350Z","repository":{"id":92176797,"uuid":"99117877","full_name":"ljunb/rn-countdown","owner":"ljunb","description":"⏰ 纯 JavaScript 实现的针对 React Native App 的倒计时组件。","archived":false,"fork":false,"pushed_at":"2024-05-10T02:52:46.000Z","size":120,"stargazers_count":18,"open_issues_count":0,"forks_count":5,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-28T23:44:04.049Z","etag":null,"topics":["countdown","react-native","rn","verification"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ljunb.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-08-02T13:12:14.000Z","updated_at":"2024-05-10T02:52:49.000Z","dependencies_parsed_at":null,"dependency_job_id":"836a2e76-9f34-472a-a771-240b3a5db8e0","html_url":"https://github.com/ljunb/rn-countdown","commit_stats":{"total_commits":31,"total_committers":4,"mean_commits":7.75,"dds":0.09677419354838712,"last_synced_commit":"03c2a569b1366334d0e2b58eeddd14ea9db17b5a"},"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ljunb%2Frn-countdown","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ljunb%2Frn-countdown/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ljunb%2Frn-countdown/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ljunb%2Frn-countdown/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ljunb","download_url":"https://codeload.github.com/ljunb/rn-countdown/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248573640,"owners_count":21126876,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["countdown","react-native","rn","verification"],"created_at":"2025-03-12T10:16:57.675Z","updated_at":"2025-04-15T18:41:56.332Z","avatar_url":"https://github.com/ljunb.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# rn-countdown\n\n[![npm](https://img.shields.io/npm/v/rn-countdown.svg)](https://www.npmjs.com/package/rn-countdown)\n[![npm](https://img.shields.io/npm/dm/rn-countdown.svg)](https://www.npmjs.com/package/rn-countdown)\n[![npm](https://img.shields.io/npm/dt/rn-countdown.svg)](https://www.npmjs.com/package/rn-countdown)\n[![npm](https://img.shields.io/npm/l/rn-countdown.svg)](https://github.com/ljunb/rn-countdown/blob/master/LICENSE)\n\n适用于 React Native App 的一个倒计时组件，基于 `render-props` 方式实现，使用者可完全把重心放在 UI 定制上面，无须关注倒计时逻辑实现。\n\n## 重要更新\n由于组件进行了重构，之前版本的大部分 `props` 有重大变更，罗列如下：\n\n* `overTitle`：倒计时结束文本（移除）\n* `titleStyle`：文本样式（移除）\n* `countingStyle`：倒计时中的容器样式（移除）\n* `countingTitleTemplate`：文本模板（移除）\n* `countingTitleStyle`：倒计时中的文本样式（移除）\n* `timeFontStyle`：针对时间文本的样式（移除）\n* `shouldStartCountdown`：是否允许开始倒计时回调（移除）\n* `onCountdownOver`：重命名为 `onDidFinishCountdown`，触发机制保持与之前一致（更新）\n* `onNetworkFailed`：网络出错情况下，点击触发的回调（保留）\n* `style`：容器样式（保留）\n* `time`：倒计时总时长（单位秒，保留）\n* `activeOpacity`：点击时的透明度（新增）\n* `children`：添加对 `children` 的一个类型检测，必须为 `function`（新增）\n* `onPress`：点击组件的回调（新增，新版本组件将控制权交给了开发人员，通过实例方法按需开启，或是停止倒计时）\n\n以下实例方法将继续保留：\n* `startCountdown`：立即开始倒计时，如果网络错误，将触发 `onNetworkFailed` 回调，可按需进行弹框提示处理\n* `stopCountdown`：立即停止倒计时，将触发 `onDidFinishCountdown` 回调，按需添加后续处理\n\n## 支持的版本\nReact Native 版本 | 对应支持的组件版本\n----------------------- | ------------------------------ \n0.48.0+                 | v0.3.0+ (NetInfo change -\u003e connectionChange for eventListener)\n\u003c 0.48.0                | v0.2.1\n\n## 预览\n![demo](https://github.com/ljunb/screenshots/blob/master/rn-countdown.gif)\n\n## 安装\n\n通过 `npm` 安装:\n```\n// \u003e= 0.48.0\nnpm install rn-countdown --save\n\n// \u003c 0.48.0\nnpm install rn-countdown@0.2.1 --save \n```\n或者基于 `yarn` 安装:\n```\n// \u003e= 0.48.0\nyarn add rn-countdown\n\n// \u003c 0.48.0\nyarn add rn-countdown@0.2.1\n```\n\n## 使用\n\n```javascript\nimport React, { Component } from 'react'\nimport {\n    StyleSheet,\n    Text,\n    View,\n    Dimensions,\n    TextInput,\n    Button\n} from 'react-native'\nimport Countdown, { CountdownStatus } from 'rn-countdown'\n\nexport default class App extends Component {\n\n    state = {\n        hasText: false\n    };\n    phoneNumber = ''\n\n    handleClickCountdown = () =\u003e {\n        if (!this.phoneNumber) {\n            alert('电话号码不能为空!')\n            return\n        }\n        this.countdown \u0026\u0026 this.countdown.startCountdown()\n    };\n\n    handleNetworkFailed = () =\u003e alert('network failed')\n\n    handleStopCountdown = () =\u003e this.countdown \u0026\u0026 this.countdown.stopCountdown()\n\n    handleChangeText = text =\u003e {\n        this.phoneNumber = text;\n        this.setState({ hasText: !!this.phoneNumber })\n    }\n\n    handleCountdownOver = () =\u003e alert('over')\n\n    render() {\n        const { hasText } = this.state\n        return (\n            \u003cView style={styles.container}\u003e\n                \u003cView style={styles.phoneCell}\u003e\n                    \u003cView style={styles.phoneInfo}\u003e\n                        \u003cText\u003e账号:\u003c/Text\u003e\n                        \u003cTextInput\n                            style={styles.input}\n                            placeholder=\"请输入手机号码\"\n                            underlineColorAndroid=\"transparent\"\n                            onChangeText={this.handleChangeText}\n                        /\u003e\n                    \u003c/View\u003e\n                    \u003cCountdown\n                        ref={r =\u003e this.countdown = r}\n                        time={10}\n                        onPress={this.handleClickCountdown}\n                        onNetworkFailed={this.handleNetworkFailed}\n                        onDidFinishCountdown={this.handleCountdownOver}\n                    \u003e\n                        {({ status, time }) =\u003e {\n                            let title, containerStyle, titleStyle\n                            switch (status) {\n                                case CountdownStatus.Idle:\n                                    title = '发送验证码'\n                                    containerStyle = [\n                                        styles.countdown,\n                                        hasText \u0026\u0026 { backgroundColor: 'rgb(59, 197, 81)', borderWidth: 0 }\n                                    ]\n                                    titleStyle = [\n                                        styles.countdownTitle,\n                                        hasText \u0026\u0026 { color: '#fff' }\n                                    ]\n                                    break\n                                case CountdownStatus.Counting:\n                                    title = `发送中(${time})`\n                                    containerStyle = styles.countdown\n                                    titleStyle = styles.countdownTitle\n                                    break\n                                case CountdownStatus.Over:\n                                    title = '重新发送'\n                                    containerStyle = [\n                                        styles.countdown,\n                                        hasText \u0026\u0026 { backgroundColor: 'rgb(59, 197, 81)', borderWidth: 0 }\n                                    ]\n                                    titleStyle = [\n                                        styles.countdownTitle,\n                                        hasText \u0026\u0026 { color: '#fff' }\n                                    ]\n                                    break\n                            }\n                            return (\n                                \u003cView style={containerStyle}\u003e\n                                    \u003cText style={titleStyle}\u003e{title}\u003c/Text\u003e\n                                \u003c/View\u003e\n                            )\n                        }}\n                    \u003c/Countdown\u003e\n                \u003c/View\u003e\n                \u003cButton title=\"停止\" onPress={this.handleStopCountdown}/\u003e\n            \u003c/View\u003e\n        );\n    }\n}\n\nconst styles = StyleSheet.create({\n    container: {\n        flex: 1,\n        justifyContent: 'center',\n        alignItems: 'center',\n        backgroundColor: '#F5FCFF',\n    },\n    phoneCell: {\n        flexDirection: 'row',\n        alignItems: 'center',\n        justifyContent: 'space-between',\n        paddingHorizontal: 15,\n        height: 40,\n        borderBottomWidth: StyleSheet.hairlineWidth,\n        borderColor: '#ebebeb',\n        width: Dimensions.get('window').width,\n        backgroundColor: '#fff'\n    },\n    phoneInfo: {\n        flexDirection: 'row',\n        alignItems: 'center',\n    },\n    input: {\n        height: 30,\n        width: Dimensions.get('window').width * 0.4,\n        marginLeft: 10,\n        padding: 0,\n        fontSize: 14\n    },\n    countdown: {\n        borderRadius: 15,\n        borderWidth: StyleSheet.hairlineWidth,\n        borderColor: '#ebebeb',\n        height: 30,\n        width: 100,\n        justifyContent: 'center',\n        alignItems: 'center',\n    },\n    countdownTitle: {\n        color: '#ccc',\n        fontSize: 12\n    },\n})\n```\n\n## 参数说明\n\n名称              | 类型   | 是否可选 | 默认值      | 描述\n----------------  | ------ | -------- | -----------  | -----------\nstyle             | ViewPropTypes | 是      | 无  | 自定义容器样式，这里应该关注于容器相对于其父组件、兄弟组件的样式，比如：`margin`、`padding` 等，真正业务上的 UI 定制，可在 `children` 中进行定制\ntime              | number | 是      | 30s          | 倒计时时长\nactiveOpacity     | number | 是      | 0.75         | 按钮交互时的透明度 \nchildren          | function | 否      | 无         | 一个返回 `React` 元素的函数，该函数接受一个参数，其格式为: `({ status: CountdownStatus, time: number }) =\u003e React.Element\u003cany\u003e` \u003cbr/\u003e `status`:\u003cbr/\u003e - `Idle`: 默认状态\u003cbr/\u003e - `Counting`: 正在倒计时\u003cbr/\u003e - `Over`: 倒计时结束\nonPress           | function | 是 | 无 | 点击组件时必会触发的回调\nonNetworkFailed   | function | 是 | 无 | 网络出错情况下，点击组件的回调，按需添加弹窗处理\nonDidFinishCountdown| function | 是 | 无 | 倒计时结束回调\n\n\n## 方法\n名称            | 描述\n----------------  | -----------\nstartCountdown    | 立即开始倒计时，网络出错情况下，将触发 `onNetworkFailed` 回调\nstopCountdown     | 立即停止倒计时，将触发 `onDidFinishCountdown` 回调\n\n以上方法皆可通过 `ref` 进行引用触发，比如：`this.countdownRef \u0026\u0026 this.countdownRef.startCountdown()`。\n\n## 运行示例\n克隆之后，需要先开启 TypeScript 的编译监听：\n```\n// 根目录\n$ npm install\n$ npm start\n```\n\n然后进入到 `example` 目录，开启服务（当然也可以直接通过 Xcode 或是 Android Studio 运行）：\n```\n$ cd example\n$ npm install\n$ npm start\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fljunb%2Frn-countdown","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fljunb%2Frn-countdown","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fljunb%2Frn-countdown/lists"}