工程源码 git clone -b simple-project https://github.com/wangzhengquan/react-redux-tpl

搭建一个react工程

  • 实现手机的页面切换的过度效果
  • 实现代码分片的懒加载

工程搭建步骤如下

1 下载一个脚手架
git clone -b scaff https://github.com/wangzhengquan/react-redux-tpl,因为这个工程是从旧有的项目中抽取出来的,还是基于react15 和 react-router2,所以修改package.json,如下:

"react": "^15.0.0",
"react-dom": "^15.0.0",
"react-router": "^2.8.1",复制代码

2 新建路由文件 src/router.js
该文件时负责配置页面路由访问的

import Modals from 'react-ui/modals'var  hideNavbar = falseconst rootRoute = {path: '/',component: require('./components/View'),indexRoute: {//懒加载处理,访问该页面时才会加载相关资源getComponents(nextState, cb) {//显示loaddingModals.showIndicator()//webpack split打包处理方式Promise.all([import('./components/home/HomeNavbar'),import('./components/home/HomePage')]).then( ([navbar, page]) => {cb(null, {navbar: hideNavbar ? null : navbar,page: page})document.querySelector('title').innerHTML='Home'Modals.hideIndicator()})}},childRoutes: [{path: 'product',getComponents(nextState, cb) {Modals.showIndicator()Promise.all([import('./components/product/ProductNavbar'),import('./components/product/ProductPage')]).then( ([navbar, page])  => {cb(null, {navbar: hideNavbar ? null : navbar,page: page})document.querySelector('title').innerHTML='Product'Modals.hideIndicator()})}}, {path: 'order',getComponents(nextState, cb) {Modals.showIndicator()Promise.all([import('./components/order/OrderNavbar'),import('./components/order/OrderPage')]).then( ([navbar, page])  => {cb(null, {navbar: hideNavbar ? null : navbar,page: page})document.querySelector('title').innerHTML='Product'Modals.hideIndicator()})}}]}export default rootRoute;复制代码

3 新建根组件文件 src/components/View.js

import React from 'react'
import ReactTransitionGroup from 'react-addons-transition-group'
import ReactUI from 'react-ui/react-ui'
import classNames from 'classnames';class View extends React.Component{constructor(props) {super(props);}render(){let navbar = this.props.navbarlet page = this.props.pagelet toolbar =this.props.toolbarreturn (<div className={classNames('view view-main', this.props.className)} >{/*-----navbar------*/}<ReactTransitionGroup component="div" className={classNames('navbar', {'navbar-hidden': !!!navbar})}>{navbar ? React.cloneElement(navbar, {key: (this.props.location ? this.props.location.pathname.concat('/navbar') : ReactUI.guid() ),pageName: location.pathname==='/' ? 'index' : location.pathname.charAt(0) === '/' ? location.pathname.substring(1) : location.pathname}) : '' }</ReactTransitionGroup>{/*-----pages-------*/}<ReactTransitionGroup className={classNames('pages')} component="div">{React.cloneElement(page, {className: {'navbar-through': !!navbar, 'toolbar-through': !!toolbar, 'tabbar-labels-through': !!toolbar},key: (this.props.location ? this.props.location.pathname : ReactUI.guid() ),pageName: location.pathname==='/' ? 'index' : location.pathname.charAt(0) === '/' ? location.pathname.substring(1) : location.pathname})}</ReactTransitionGroup>{/*-----Toobar-------*/}{ toolbar ? toolbar : ''}{/*-----toolbar end -------*/}</div>);}}module.exports = View复制代码

其中ReactTransitionGroup 是一个基础的动画组件,当子组件从中添加或移除时会触发相关的钩子函数,如:

componentWillAppear()
componentDidAppear()
componentWillEnter()
componentDidEnter()
componentWillLeave()
componentDidLeave()复制代码

4 新建src/components/Page.js。
在上面ReactTransitionGroup提供的几个hooks(钩子)函数的里面做动画处理,所有的page都继承该组件

  import React  from 'react';
import ReactDOM from 'react-dom';
import history from '../history'
import $ from 'react-ui/dom'
import classNames from 'classnames';
const transitionDuration= 400;
const params = {hideNavbarOnPageScroll : true ,hideToolbarOnPageScroll : false ,hideTabbarOnPageScroll : false ,showBarsOnPageScrollEnd : false ,showBarsOnPageScrollTop : true
}export default class Page extends React.Component{constructor(props) {super(props);this.destroyList = []}
// Set pages classess for animationEndanimatePages(page, action, direction, finishCallback) {// Loading new pagelet removeClasses = 'page-on-center page-on-right page-on-left';let transitionClass = null;let activeClass = null;if (direction === 'to-left') {if(action ==='leave') {transitionClass = 'page-from-center-to-left';activeClass = 'page-on-left'}else if(action === 'enter'){transitionClass = 'page-from-right-to-center';activeClass = 'page-on-center'}}// Go isBackelse if (direction === 'to-right') {if(action === 'enter'){transitionClass = 'page-from-left-to-center';activeClass = 'page-on-center'}else if(action  === 'leave'){transitionClass = 'page-from-center-to-right';activeClass = 'page-on-right'}}page.removeClass(removeClasses).addClass(transitionClass);page.animationEnd(function () {page.removeClass(transitionClass).addClass(activeClass);finishCallback()});}componentDidMount(){this.node = this.node || $(ReactDOM.findDOMNode(this));//this.initPageScrollToolbars(node)}componentWillUnmount(){this.destroy()}componentWillAppear(done) {// console.log('componentWillAppear', this.props.location && this.props.location.pathname);done()}componentDidAppear () {// console.log('componentDidAppear', this.props.location && this.props.location.pathname);}componentWillEnter (done) {if( !Page.anim ){done()return;}var page = $(ReactDOM.findDOMNode(this));if(history.isBack){this.animatePages(page, 'enter', 'to-right', done)}else{this.animatePages(page, 'enter', 'to-left', done)}}componentDidEnter () {// console.log('componentDidEnter', this.props.location && this.props.location.pathname);}componentWillLeave (done) {// console.log('componentWillLeave', this.props.location && this.props.location.pathname , history.paths);if (!Page.anim ){setTimeout(function(){Page.anim = true}, transitionDuration)done()return;}var page = $(ReactDOM.findDOMNode(this));if(history.isBack){this.animatePages(page, 'leave', 'to-right', done)} else {this.animatePages(page, 'leave', 'to-left', done)}}componentDidLeave () {// console.log('componentDidLeave', this.props.location && this.props.location.pathname);}initPageScrollToolbars  (pageContainer) {var me = thispageContainer = $(pageContainer);var scrollContent = pageContainer.find('.page-content');if (scrollContent.length === 0) return;var hideNavbar = (params.hideNavbarOnPageScroll || scrollContent.hasClass('hide-navbar-on-scroll') || scrollContent.hasClass('hide-bars-on-scroll')) && !(scrollContent.hasClass('keep-navbar-on-scroll') || scrollContent.hasClass('keep-bars-on-scroll'));var hideToolbar = (params.hideToolbarOnPageScroll || scrollContent.hasClass('hide-toolbar-on-scroll') || scrollContent.hasClass('hide-bars-on-scroll')) && !(scrollContent.hasClass('keep-toolbar-on-scroll') || scrollContent.hasClass('keep-bars-on-scroll'));var hideTabbar = (params.hideTabbarOnPageScroll || scrollContent.hasClass('hide-tabbar-on-scroll')) && !(scrollContent.hasClass('keep-tabbar-on-scroll'));if (!(hideNavbar || hideToolbar || hideTabbar)) return;var viewContainer = scrollContent.parents('.views' );if (viewContainer.length === 0) return;var navbar = viewContainer.find('.navbar'),toolbar = viewContainer.find('.toolbar'),tabbar;if (hideTabbar) {tabbar = viewContainer.find('.tabbar');if (tabbar.length === 0) tabbar = viewContainer.parents('.views' ).find('.tabbar');}var hasNavbar = navbar.length > 0,hasToolbar = toolbar.length > 0,hasTabbar = tabbar && tabbar.length > 0;var previousScroll, currentScroll;previousScroll = currentScroll = scrollContent[0].scrollTop;var scrollHeight, offsetHeight, reachEnd, action, navbarHidden, toolbarHidden, tabbarHidden;var toolbarHeight = (hasToolbar && hideToolbar) ? toolbar[0].offsetHeight : 0;var tabbarHeight = (hasTabbar && hideTabbar) ? tabbar[0].offsetHeight : 0;var bottomBarHeight = tabbarHeight || toolbarHeight;function handleScroll() {if (pageContainer.hasClass('page-on-left')) return;currentScroll = scrollContent[0].scrollTop;scrollHeight = scrollContent[0].scrollHeight;offsetHeight = scrollContent[0].offsetHeight;reachEnd =  currentScroll + offsetHeight >= scrollHeight - bottomBarHeight;navbarHidden = navbar.hasClass('navbar-hidden');toolbarHidden = toolbar.hasClass('toolbar-hidden');tabbarHidden = tabbar && tabbar.hasClass('toolbar-hidden');// console.log('reachEnd', reachEnd,  currentScroll + offsetHeight ,  scrollHeight - bottomBarHeight)if (reachEnd) {if (params.showBarsOnPageScrollEnd) {action = 'show';}}else if (previousScroll > currentScroll) {if (params.showBarsOnPageScrollTop || currentScroll <= 44) {action = 'show';}else {action = 'hide';}}else {if (currentScroll > 44) {action = 'hide';}else {action = 'show';}}if (action === 'show') {if (hasNavbar && hideNavbar && navbarHidden) {me.showNavbar(navbar);pageContainer.removeClass('no-navbar-by-scroll');navbarHidden = false;}if (hasToolbar && hideToolbar && toolbarHidden) {me.showToolbar(toolbar);pageContainer.removeClass('no-toolbar-by-scroll');toolbarHidden = false;}if (hasTabbar && hideTabbar && tabbarHidden) {me.showToolbar(tabbar);pageContainer.removeClass('no-tabbar-by-scroll');tabbarHidden = false;}}else {if (hasNavbar && hideNavbar && !navbarHidden) {me.hideNavbar(navbar);pageContainer.addClass('no-navbar-by-scroll');navbarHidden = true;}if (hasToolbar && hideToolbar && !toolbarHidden) {me.hideToolbar(toolbar);pageContainer.addClass('no-toolbar-by-scroll');toolbarHidden = true;}if (hasTabbar && hideTabbar && !tabbarHidden) {me.hideToolbar(tabbar);pageContainer.addClass('no-tabbar-by-scroll');tabbarHidden = true;}}previousScroll = currentScroll;}scrollContent.on('scroll', handleScroll);scrollContent[0].f7ScrollToolbarsHandler = handleScroll;}destroyScrollToolbars (pageContainer) {pageContainer = $(pageContainer);var scrollContent = pageContainer.find('.page-content');if (scrollContent.length === 0) return;var handler = scrollContent[0].f7ScrollToolbarsHandler;if (!handler) return;scrollContent.off('scroll', scrollContent[0].f7ScrollToolbarsHandler);}// Hide/Show Navbars/ToolbarshideNavbar (navbarContainer) {$(navbarContainer).addClass('navbar-hidden');return true;}showNavbar (navbarContainer) {var navbar = $(navbarContainer);navbar.addClass('navbar-hiding').removeClass('navbar-hidden').transitionEnd(function () {navbar.removeClass('navbar-hiding');});return true;}hideToolbar (toolbarContainer) {$(toolbarContainer).addClass('toolbar-hidden');return true;}showToolbar (toolbarContainer) {var toolbar = $(toolbarContainer);toolbar.addClass('toolbar-hiding').removeClass('toolbar-hidden').transitionEnd(function () {toolbar.removeClass('toolbar-hiding');});}destroy(){this.destroyList.forEach((fun) => {fun()})}render(){return (<div className={classNames('page', this.props.className)} data-page={this.props.pageName}></div>);}}
Page.anim = true复制代码

5 新建src/components/Navbar.js。
同上面的page一样的功能,做Navbar的动画处理,所有的Navbar都继承该Navbar

/* eslint no-console: 0 */
import React  from 'react';
import ReactDOM from 'react-dom';
import $ from 'react-ui/dom'
import history from '../history'
// import PARAMS from 'react-ui/params'
import Navbars from 'react-ui/navbars'
const transitionDuration = 400;
const animateNavBackIcon = trueexport default  class Navbar extends React.Component{constructor(props) {super(props);this.state = {title: this.props.title}}/*** Prepare navbar before animarion* @param  {[type]} newNavbarInner    [description]* @param  {[type]} newNavbarPosition [description]* @return {[type]}                   [description]*/prepareNavbar (newNavbarInner, newNavbarPosition) {if(newNavbarPosition === 'right'){newNavbarInner.addClass('navbar-on-right')} else if(newNavbarPosition === 'left'){newNavbarInner.addClass('navbar-on-left')}$(newNavbarInner).find('.sliding').each(function () {var sliding = $(this);var slidingOffset = newNavbarPosition === 'right' ? this.f7NavbarRightOffset : this.f7NavbarLeftOffset;if (animateNavBackIcon) {if (sliding.hasClass('left') && sliding.find('.back .icon').length > 0) {sliding.find('.back .icon').transform('translate3d(' + (-slidingOffset) + 'px,0,0)');}}sliding.transform('translate3d(' + slidingOffset + 'px,0,0)');});}/*** Set navbars classess for animation* @param  {[type]} navbarInner [description]* @param  {[type]} action      [description]* @param  {[type]} direction   [description]* @return {[type]}             [description]*/animateNavbars (navbarInner, action, direction, finishCallback) {// Loading new pagenavbarInner = $(navbarInner);var removeClasses = 'navbar-on-right navbar-on-center navbar-on-left';if (direction === 'to-left') {if(action === 'enter'){navbarInner.removeClass(removeClasses).addClass('navbar-from-right-to-center');// window.setTimeout(function () {//    navbarInner.removeClass('navbar-from-right-to-center').addClass('navbar-on-center');//    finishCallback()// }, transitionDuration)navbarInner.find('.sliding').each(function (index) {console.log('sliding', arguments)var sliding = $(this);sliding.transform('translate3d(0px,0,0)');if(index===0) {sliding.transitionEnd(function(){navbarInner.removeClass('navbar-from-right-to-center').addClass('navbar-on-center');finishCallback()})}if (animateNavBackIcon) {if (sliding.hasClass('left') && sliding.find('.back .icon').length > 0) {sliding.find('.back .icon').transform('translate3d(0px,0,0)');}}});} else if (action === 'leave'){navbarInner.removeClass(removeClasses).addClass('navbar-from-center-to-left');// window.setTimeout(function (e) {//    navbarInner.removeClass('navbar-from-center-to-left').addClass('navbar-on-left');//    finishCallback()// }, transitionDuration);let rightNavbarInner = navbarInner.closest('.navbar').find('.navbar-inner:first-child')navbarInner.find('.sliding').each(function (index) {var sliding = $(this);var rightText;if (animateNavBackIcon) {if (sliding.hasClass('center') && rightNavbarInner.find('.sliding.left .back .icon').length > 0) {rightText = rightNavbarInner.find('.sliding.left .back span');if (rightText.length > 0) this.f7NavbarLeftOffset += rightText[0].offsetLeft;}if (sliding.hasClass('left') && sliding.find('.back .icon').length > 0) {sliding.find('.back .icon').transform('translate3d(' + (-this.f7NavbarLeftOffset) + 'px,0,0)');}}// console.log('leave', this, this.f7NavbarLeftOffset)sliding.transform('translate3d(' + (this.f7NavbarLeftOffset) + 'px,0,0)');if(index === 0) {sliding.transitionEnd(function(){navbarInner.removeClass('navbar-from-center-to-left').addClass('navbar-on-left');finishCallback()})}});}}// Go backif (direction === 'to-right') {if(action === 'enter'){navbarInner.removeClass(removeClasses).addClass('navbar-from-left-to-center');//window.setTimeout(function () {//   navbarInner.removeClass('navbar-from-left-to-center').addClass('navbar-on-center');//   finishCallback()//}, transitionDuration);navbarInner.find('.sliding').each(function (index) {var sliding = $(this);sliding.transform('translate3d(0px,0,0)');if (animateNavBackIcon) {if (sliding.hasClass('left') && sliding.find('.back .icon').length > 0) {sliding.find('.back .icon').transform('translate3d(0px,0,0)');}}if(index === 0) {sliding.transitionEnd(function(){navbarInner.removeClass('navbar-from-left-to-center').addClass('navbar-on-center');finishCallback()})}});} else if(action === 'leave'){navbarInner.removeClass(removeClasses).addClass('navbar-from-center-to-right');// window.setTimeout(function () {//    navbarInner.removeClass('navbar-from-center-to-right').addClass('navbar-on-right');//    finishCallback()// }, transitionDuration);navbarInner.find('.sliding').each(function (index) {var sliding = $(this);if (animateNavBackIcon) {if (sliding.hasClass('left') && sliding.find('.back .icon').length > 0) {sliding.find('.back .icon').transform('translate3d(' + (-this.f7NavbarRightOffset) + 'px,0,0)');}}sliding.transform('translate3d(' + (this.f7NavbarRightOffset) + 'px,0,0)');if(index === 0) {sliding.transitionEnd(function(){navbarInner.removeClass('navbar-from-center-to-right').addClass('navbar-on-right');finishCallback()})}});}}}componentDidMount(){console.log('componentDidMount', this.props.location && this.props.location.pathname)var node = this.node = $(ReactDOM.findDOMNode(this));var onResize =  () => {Navbars.sizeNavbar(node)}$(window).on('resize', onResize);this.destroy = () => {$(window).off('resize', onResize)}Navbars.sizeNavbar(node)}componentWillUnMount(){this.destroy()}componentWillAppear(done) {console.log('componentWillAppear', this.props.location && this.props.location.pathname);done()}componentDidAppear () {console.log('componentDidAppear', this.props.location && this.props.location.pathname);//this._enterStyle();}componentWillEnter (done) {console.log('componentWillEnter', this.props.location && this.props.location.pathname);if (!Navbar.anim ){setTimeout(function(){Navbar.anim = true}, transitionDuration)done()return;}var node = this.node || $(ReactDOM.findDOMNode(this));if(history.isBack){this.prepareNavbar (node, 'left')setTimeout( () => {this.animateNavbars(node, 'enter', 'to-right', done)},0)}else{this.prepareNavbar (node, 'right')setTimeout( () => {this.animateNavbars(node, 'enter', 'to-left', done)}, 0)}}componentDidEnter () {console.log('componentDidEnter', this.props.location && this.props.location.pathname);}componentWillLeave (done) {console.log('componentWillLeave', this.props.location && this.props.location.pathname );if( !Navbar.anim ){done()return;}var node = this.node || $(ReactDOM.findDOMNode(this));if(history.isBack){this.animateNavbars(node, 'leave', 'to-right', done)} else {this.animateNavbars(node, 'leave', 'to-left', done)}}componentDidLeave () {console.log('componentDidLeave', this.props.location && this.props.location.pathname);}handleBackClick(e){e.preventDefault()history.go(-1)}render(){if(this.canBack === undefined){this.canBack = history.canBack;}return (<div className="navbar-inner" data-page={this.props.pageName}>{this.canBack ?<div className="left sliding" ><a onClick={this.handleBackClick.bind(this)} className="back link"><i className="icon icon-back" ></i><span>返回</span></a></div> : ''}<div className="center sliding">{this.state.title || ''}</div></div>)}
}
Navbar.sizeNavbar = Navbars.sizeNavbar;
Navbar.sizeNavbars = Navbars.sizeNavbars;Navbar.anim = true复制代码

6 新建 src/history.js

/* eslint no-console: 0 */import { browserHistory } from 'react-router'
// import { hashHistory } from 'react-router'
// var browserHistory = hashHistory
const PATHS_LENGTH = -1
let paths = browserHistory.paths = browserHistory.paths || []//防止测试环境加载两次的问题
if(!browserHistory.unlisten){browserHistory.unlisten = browserHistory.listen(location => {let pathname = location.pathnameif(pathname.charAt(0) !== '/'){pathname = '/'.concat(pathname)}let len = paths.length//isBack标记是否时回退到上一页,还是进入到新一页,以显示不同的动画效果browserHistory.isBack = (len > 1 && pathname === paths[len-2])if(browserHistory.isBack) {paths.pop()} else if (len === 0 || paths[len-1] !== pathname){if(PATHS_LENGTH === -1 || len < PATHS_LENGTH){//不限制历史记录长度paths.push(pathname)}else{//超出限制历史记录长度for(let i = 0; i < len - 1; i++){paths[i] = paths[i+1]}paths[len - 1] = pathname}}//canback标记是否显示navbar的回退按钮browserHistory.canBack = (paths.length > 1)})window.addEventListener('popstate', function () {browserHistory.isBack = true})
}export default browserHistory复制代码

7 新建router里配置的页面和导航条
src/home/HomeNavbar.js
src/home/HomePage.js
src/components/order/OrderNavbar.js
src/components/order/OrderPage.js
src/components/product/ProductNavbar.js
src/components/product/ProductPage.js
具体代码参考git仓库源码

8 测试
npm start

Build a react project step by step相关推荐

  1. windows 7 RTM build 7600.16385安装step by step(虚拟光驱双系统方式)

    windows 7 RTM build 7600.16385安装step by step(虚拟光驱双系统方式) windows 7 RTM版发布了.昨天最新的版本号是build 7600.16385. ...

  2. Qtxlsx无法编译,错误报告Error while building/deploying project …… When executing step “Make“

    编译从github上下载的Qtxlsx,直接打开pro文件,默认qt5.9.5+MinGW编译.Qt无法编译,错误报告Error while building/deploying project -- ...

  3. Followme Devops step by step

    接着上次分享的devops历程[Followme Devops实践之路], 大家希望能够出一个step by step手册, 那今天我就来和手把手来一起搭建这么一套环境, 演示整个过程! 实验环境需要 ...

  4. GoFrame Step by Step Demo - P1

    GoFrame Step by Step Demo P1 框架说明文档 GFTool 安装 Web框架学习 文章目录 GoFrame Step by Step Demo P1 参考Demo 记录 安装 ...

  5. 【Step By Step】将Dotnet Core部署到Docker上

    [Step By Step]将Dotnet Core部署到Docker上 原文: [Step By Step]将Dotnet Core部署到Docker上 本教程的前提是,你已经在Linux服务器上已 ...

  6. 数据库设计Step by Step (9)——ER-to-SQL转化

    2019独角兽企业重金招聘Python工程师标准>>> 引言:前文(数据库设计 Step by Step (8)--视图集成)讨论了如何把局部ER图集成为全局ER图.有了全局ER图后 ...

  7. Caffe使用step by step:caffe框架下的基本操作和分析

    Caffe使用step by step:caffe框架下的基本操作和分析 时间:2015-10-16 11:40:09      阅读:808      评论:0      收藏:0      [点我 ...

  8. 吴恩达深度学习课程deeplearning.ai课程作业:Class 4 Week 1 Convolutional Neural Networks: Step by Step

    吴恩达deeplearning.ai课程作业,自己写的答案. 补充说明: 1. 评论中总有人问为什么直接复制这些notebook运行不了?请不要直接复制粘贴,不可能运行通过的,这个只是notebook ...

  9. Step by Step Setup Git Server on Windows with CopSSH + msysGit and Integrate Git with Visual Studio

    Introduction First of all, let me clarify that Git doesn't need to specify the side for client and s ...

最新文章

  1. 8086汇编复习3 - 标志寄存器 - 使用emu8086
  2. 布局管理器 5-----绝对布局
  3. android 模糊度处理_图像处理评价指标之模糊度、清晰度(待更新)
  4. 将应用程序安装为Windows服务
  5. MySQL中order by中关于NULL值的排序问题
  6. python的编程环境都不会搭建_9102年你还不会搭建Python环境
  7. 问题 L: The 3n + 1 problem
  8. ffdshow 源代码分析 5: 位图覆盖滤镜(总结)
  9. css标准流/非标准流 盒子模型
  10. Azure CLI 简单入门
  11. [转]BVH文件介绍
  12. Django model 设置数据库 字段 编码
  13. NumPy学习挑战第一关-NumPy的下载与安装
  14. 金融行业网络安全等级保护测评指南
  15. r型聚类典型指标_SPSS聚类分析经典案例分享
  16. Layui拓展第三方图标
  17. Labplus:Scratch创作工具的替代与进步
  18. 搜索功能这样设计,大家都说我有点东西
  19. Imagination异构计算平台力助AI芯片厂商加速冲击110亿美元市场 | AIIA 2020
  20. 用python实现erp出入库_ERP采购入库成品入库流程(精)

热门文章

  1. Mapreduce编程1之WordCount
  2. 语义分割DeepLab v2--DeepLab: Semantic Image Segmentation with Deep Convolutional Nets, Atrous Convolut
  3. 使用python手写FFT算法
  4. 半环(semiring)的数学概念
  5. C++ 调试技术:addr2line
  6. 报错解决:InvalidArgumentError: Received a label value of 101 which is outside the valid range of [0, 101
  7. LeetCode 200. Number of Islands--c++ dfs解法
  8. php趣味小程序,php常用小程序
  9. mysql两列查询结果列拼接一个表输出_sql select语句,查询出两列结果拼接在一起...
  10. 宝塔mysql优化_宝塔面板下实现MySQL性能优化处理