Taro基本用法
[[toc]]
常用的小方法
//运行时的尺寸转换 Taro.pxTransform(10) // 小程序:rpx,H5:rem
//tabbar右上角的数字 Taro.setTabBarBadge({ index: 0, text: '1' })
//弹框 Taro.showToast({ title: '成功', icon: 'loading', duration: 2000 });
//loading图 Taro.showLoading({ title: '加载中...' });
// 打电话 Taro.makePhoneCall({ phoneNumber: '18331883557', });
// 屏幕最亮 0-1 Taro.setScreenBrightness({ value: 1 });
// 震动 Taro.vibrateShort() / Taro.vibrateLong()
//弹框 Taro.showToast({ title: '成功', icon: 'success', duration: 2000 });
//动态修改title Taro.setNavigationBarTitle({ title: '当前页面' })
//底部对话框 Taro.showActionSheet({ itemList: ["不感兴趣"] })
//点击tabbar,仅weapp支持 onTabItemTap(res) { console.log(res); }
//监听用户下拉刷新事件 onPullDownRefresh() 需要在全局配置的 window 选项中或页面配置中开启 enablePullDownRefresh Taro.startPullDownRefresh()//触发下拉刷新 Taro.stopPullDownRefresh() //停止当前页面的下拉刷新
//上拉加载 onReachBottom() 可以在全局配置的 window 选项中或页面配置中设置触发距离 onReachBottomDistance
//监听用户滑动页面事件 onPageScroll(res){ console.log(res); }
//滚定到顶部 Taro.pageScrollTo({ scrollTop: 0 });
//转发按钮 onShareAppMessage(res) { if (res.from === 'button') { // 来自页面内转发按钮 console.log(res.target) } //imageUrl:'https://storage.360buyimg.com/mtd/home/111543234387022.jpg' return { title: '工作台', path: '/pages/functionArea/index', } } // 页面内部转发 <Button open-type="share" onClick={this.onShareAppMessage}>分享</Button>
//获取系统信息同步接口。 const res = Taro.getSystemInfoSync() console.log(res.model)//手机型号 console.log(res.pixelRatio)//设备像素比 console.log(res.windowWidth)//可使用窗口宽度 console.log(res.windowHeight)//可使用窗口高度 console.log(res.language)//微信设置的语言 console.log(res.version)//微信版本号 console.log(res.platform)//客户端平台
// 打开设置页面 Taro.openSetting({ success (res) { console.log(res.authSetting) } })
//向用户发起授权请求 Taro.getSetting({ //查看用户授权结果 success(res) { if (!res.authSetting['scope.userLocation']) { Taro.authorize({ scope: 'scope.userLocation', success() { console.log('打开userLocation'); } }) } } })
// 导航栏展示loading Taro.showNavigationBarLoading(); // open Taro.hideNavigationBarLoading(); // close
|
路由功能
Taro.navigateTo({ url: '/pages/page/path/name', success:function, fail:function, complete:function })
// 跳转到目的页面,在当前页面打开 Taro.redirectTo({ url: '/pages/page/path/name' })
//跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面 Taro.switchTab({ url: '/pages/page/path/name' })
//关闭当前页面,返回上一页面或多级页面 Taro.navigateBack({ delta: 2 })
//关闭所有页面,打开到应用内的某个页面 wx.reLaunch({ url: 'test?id=1', }) // 传入参数 id=2&type=test Taro.navigateTo({ url: '/pages/page/path/name?id=2&type=test' })
//his.$router.params 获取到传入的参数 class C extends Taro.Component { componentWillMount () { console.log(this.$router.params) } }
Taro.getCurrentPages()
|
组件的外部样式和全局样式
#a { } /* 在组件中不能使用 */ [a] { } button { } .a > .b { }
:host { color: yellow; }
|
外部样式类
如果想传递样式给引用的自定义组件,直接传递 className)不可行,在react是可以的,在taro中:
注意:externalClasses 需要使用 短横线命名法 (kebab-case),而不是 React 惯用的 驼峰命名法 (camelCase)。否则无效。
export default class CustomComp extends Component { static externalClasses = ['my-class']
render () { return <View className="my-class">这段文本的颜色由组件外的 class 决定</View> } }
export default class MyPage extends Component { render () { return <CustomComp my-class="red-text" /> } }
.red-text { color: red; }
|
使用taro注意事项
1.必须声明 Taro 和组件
即使变量 View 没有被调用,但也必须从 @tarojs/components 中引入声明。变量 Taro 也是一个必须引入声明的变量,因为我们在编译期和运行时会依赖这个变量做一些特殊处理。**当你引入了其他组件时,一定要使用,不要出现没有使用的变量**。
当你只用支持微信小程序时,可以不用引入组件例如 View 这样的声明。但我们仍然强烈推荐你在顶部引入你将要使用的组件,这样编辑器/IDE 能更好地提前发现可能出现的问题,也为将来可能需要的多端转换留有余地。
|
2.首字母大写与驼峰式命名
<home_page message="Hello World!" /> //不支持 <Home_Page message="Hello World!" /> //支持 <HomePage message="Hello World!" /> //支持
|
3.JavaScript 表达式
不能在包含 JSX 元素的 map 循环中使用 if 表达式; 解决方案:尽量在 map 循环中使用条件表达式或逻辑表达式。
|
<View {...this.props} />
render () { const { id, title } = obj return <View id={id} title={title} /> }
|
4.JS 编码必须用单引号
在 Taro 中,JS 代码里必须书写单引号,特别是 JSX 中,如果出现双引号,可能会导致编译错误。
|
5.组件传递函数属性名以 on 开头
class Parent extends Component { handleEvent () {} render () { return ( <Custom onTrigger={this.handleEvent}></Custom> ) } }
|
6.小程序端不要在组件中打印传入的函数
7.小程序端不要在组件中打印 this.props.children
8.小程序端不要将在模板中用到的数据设置为 undefined
由于小程序不支持将 data 中任何一项的 value 设为 undefined ,在 setState 的时候也请避免这么用。你可以使用 null 来替代。
|
9.组件 state 与 props 里字段重名的问题
不要在 state 与 props 上用同名的字段,因为这些字段在微信小程序中都会挂在 data 上。
|
10.小程序中页面生命周期 componentWillMount 不一致问题
render () { const abc = this.$router.params.abc return <Custom adc={abc} /> }
componentWillMount () { const abc = this.$router.params.abc this.setState({ abc }) } render () { return this.state.abc && <Custom adc={abc} /> }
|
11.环境变量 process.env 的使用
const { NODE_ENV = 'development' } = process.env if (NODE_ENV === 'development') { ... }
if (process.env.NODE_ENV === 'development') { }
|
12.要添加包裹的元素
const Block = (props) => props.children const Block = (props) => <div>{props.children}</div>
|
13.小程序
若使用 微信小程序预览模式 ,则需下载并使用微信开发者工具添加项目进行预览,此时需要注意微信开发者工具的项目设置 需要设置关闭 ES6 转 ES5 功能,开启可能报错 需要设置关闭上传代码时样式自动补全,开启可能报错 需要设置关闭代码压缩上传,开启可能报错
|
组件
跟react 基本保持一致
使用 this.$componentType
来判断当前 Taro.Component
是页面还是组件
this.$componentType
可能取值分别为 PAGE
和COMPONEN
T,开发者可以根据此变量的取值分别采取不同逻辑。
使用 PropTypes 检查类型
随着应用日渐庞大,你可以通过类型检查捕获大量错误。要检查组件的属性,你需要配置特殊的 propTypes 属性:
import PropTypes from 'prop-types';
class Greeting extends Component { render() { return ( <h1>Hello, {this.props.name}</h1> ); } } Greeting.defaultProps = { name: 'word' } Greeting.propTypes = { name: PropTypes.string };
|
事件处理
使用匿名函数
自 v1.2.9 开始支持
柯里化
自 v1.3.0-beta.1 开始支持
handleClick = (index) => (e) => { e.stopPropagation() this.setState({ currentIndex: index }) }
|
函数式组件
const App = () => { const [c1, setC1] = useState(0); const [c3, setC3] = useState(0);
const increment = c => c + 1
const increment1 = useCallback(() => setC1(increment), [c1]);
return (<View> <Text> Counter 1 is {c1} </Text> <Text> Counter 3 is {c3} </Text> <View> <Button onClick={increment1}>Increment Counter 1</Button> <Button onClick={() => setC3(increment)}>Increment Counter 3</Button> </View> </View>) }
|
任何组件的事件传递都要以 on 开头
在 v1.3.0-beta.0 之后,自定义组件间的事件传递可以不用 on 开头,但内置组件的事件依然是以 on 开头的,为了一致性我们仍然推荐你以 on 开头命名你的事件。
条件渲染
if-else
逻辑运算符 &&
三元运算符(条件表达式)
枚举条件渲染
第一次看到,感觉还挺好玩的
function Loading (props) { const { loadingText, LOADING_STATUS, loadingStatus, onRetry } = props return ( <View className='loading-status'> { { 'loading': loadingText, 'fail': <View onClick={onRetry}> 加载失败, 点击重试 </View>, 'no-more': '没有更多了' }[loadingStatus] } </View> ) }
|
Refs 引用
使用字符串创建 ref
此方法在react中已经废弃
class MyComponent extends Component { componentDidMount () { if (process.env.TARO_ENV === 'weapp') { } else if (process.env.TARO_ENV === 'h5') { } }
render () { return <Input ref='input' /> } }
|
通过函数创建 ref
Taro推荐使用
class MyComponent extends Component { refCat = (node) => this.cat = node render () { return <Cat ref={this.refCat} /> } }
|
通过 createRef 创建 ref
class MyComponent extends Component { this.cat = Taro.createRef() componentDidMount(): void { this.cat.current } render () { return <Cat ref={this.cat} /> } }
|
内置环境变量
process.env.TARO_ENV
render () { return ( <View> {process.env.TARO_ENV === 'weapp' && <ScrollViewWeapp />} {process.env.TARO_ENV === 'h5' && <ScrollViewH5 />} </View> ) }
|
统一接口的多端文件
内置环境变量虽然可以解决大部分跨端的问题,但是会让代码中充斥着逻辑判断的代码,影响代码的可维护性,而且也让代码变得愈发丑陋,为了解决这种问题, 开发者可以通过将文件修改成原 文件名 + 端类型
的命名形式
多端组件 👍
假如有一个 Test 组件存在微信小程序、百度小程序和 H5 三个不同版本,那么就可以像如下组织代码
test.js 文件,这是 Test 组件默认的形式,编译到微信小程序、百度小程序和 H5 三端之外的端使用的版本
test.h5.js 文件,这是 Test 组件的 H5 版本
test.weapp.js 文件,这是 Test 组件的 微信小程序 版本
test.swan.js 文件,这是 Test 组件的 百度小程序 版本
四个文件,对外暴露的是统一的接口,它们接受一致的参数,只是内部有针对各自平台的代码实现
而我们使用 Test 组件的时候,引用的方式依然和之前保持一致,import 的是不带端类型的文件名,在编译的时候会自动识别并添加端类型后缀
import Test from '../../components/test'
<Test argA={1} argA={2} />
|
小程序原生作用域获取
this.$scope
通用配置
const config = { projectName: 'kj', date: '2018-6-8', designWidth: 750, sourceRoot: 'src', outputRoot: 'dist', plugins: { babel: { sourceMap: true, presets: ['env'], plugins: ['transform-class-properties', 'transform-decorators-legacy', 'transform-object-rest-spread'] } }, defineConstants: {}, copy: { patterns: [ ], options: { } }, weapp: { module: { postcss: { autoprefixer: { enable: true }, url: { enable: true, config: { limit: 10240 } } } }, jsxAttributeNameReplace: {} }, h5: { publicPath: '/', staticDirectory: 'static', output: { filename: 'js/[name].[hash:8].js', chunkFilename: 'js/[name].[chunkhash:8].js' }, miniCssExtractPluginOption: { filename: 'css/[name].[hash:8].css', chunkFilename: 'css/[name].[chunkhash:8].css' }, imageUrlLoaderOption: { limit: 5000, name: 'static/images/[name].[hash:8].[ext]' }, module: { postcss: { autoprefixer: { enable: true } } }, router: { mode: 'browser', customRoutes: { '/pages/login/index': '/login', '/pages/functionArea/index': '/functionArea', '/pages/personCenter/index': '/personCenter', '/pages/message/index': '/message', '/pages/ticketCode/index':'/ticketCode', '/pages/ticketList/index':'/ticketList', '/pages/activityCode/index':'/activityCode', '/pages/activityList/index':'/activityList', '/pages/activityVerify/index':'/activityVerify', '/pages/analysis/index':Analysis, '/pages/feedBack/index':'/feedBack', '/pages/set/index':'/set', '/pages/scenicList/index':'/scenicList', '/pages/selectPosition/index':'/selectPosition', '/pages/selectActivity/index':'/selectActivity', '/pages/codeResult/index':'/codeResult', } }, webpackChain: {}, devServer: { "proxy": { "/api": { "target": "https://www.v2ex.com/api/", "changeOrigin": true, "secure": false, "pathRewrite": { "^/api": "" } } }, } } };
module.exports = function(merge) { if (process.env.NODE_ENV === 'development') { return merge({}, config, require('./dev')); } return merge({}, config, require('./prod')); };
|
编译配置详情
config目录下面的index
defineConstants
用来配置一些全局变量供代码中进行使用,例如:
defineConstants: { A: '"a"' // JSON.stringify('a') }
|
alias
alias: { '@': path.resolve(__dirname, '..', 'src') }
|
{ "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["./src/*"], } } }
|
但若要在 Sass 中使用别名,如 @styles 指向 src/styles:
@import "@styles/theme.scss";
|
plugins: { sass: { importer: function(url) { const reg = /^@styles\/(.*)/ return { file: reg.test(url) ? path.resolve(__dirname, '..', 'src/styles', url.match(reg)[1]) : url } } } }
|
还需要额外的配置(Taro 对样式的处理是 node-sass -> postcss,在 sass 这步就报错了,不能用 postcss-import 插件解决):
通过环境变量实现 config 的多元控制
package.json
"scripts": { "dev:weapp:mock": "MOCK=1 npm run dev:weapp" }
|
demo
jsximport Taro, { Component, PageConfig } from '@tarojs/taro'; class ReportList extends Component {
config: PageConfig = { navigationBarTitleText: '可疑数据汇总', enablePullDownRefresh: true, backgroundTextStyle: "dark", backgroundColor:'#f7f7f7' }
}
onPullDownRefresh = () :void => { Taro.showLoading({ title: 'loading....' }) this.getList(); this.unselect(); Taro.hideLoading(); Taro.stopPullDownRefresh(); }
|
更新Taro
//更新 Taro CLI 工具 taro $ taro update self npm $ npm i -g @tarojs/cli@latest yarn $ yarn global add @tarojs/cli@latest
//更新项目中 Taro 相关的依赖 $ taro update project
$ taro info 打印的信息 $ taro doctor 诊断项目的依赖、设置、结构,以及代码的规范是否存在问题,并尝试给出解决方案。
|
Taro的注意事项
1. 在H5端 周期函数里面使用动态修改tabbar的内容,会循环执行钩子函数
2. taro路由在h5端 ,不能使用引用的变量
const method='navigateTo'; Taro[method]({ url })
|
3. H5下ScrollView,只显示首屏,下面的都是空白,TaroUI里面overflow:hidden
4. cssModules 在字节头条里面,修改全局的样式必须声明在最外面
5. H5下:global{}后的样式,有污染的影响,前提是兼容tt
6. TaroUI在路由组件里面可以修改全局的样式,但是拆分组件之后,就不能修改样式,h5下正常显示【cssModules】
小程序的 addGlobalClass 只能使 page 页面上的样式可以影响
7. 自定义若干个外部样式类 用 static externalClasses = ['class-name-style'];
,然后传递给子组件
缺陷 1.H5端不兼容;2.必须用小驼峰
8. 小程序拆包在tt下需要手动放到pages里面,在H5下正常显示
9. 阻止冒泡
{ [1, 2, 3].map((item) => { return ( <View key={item} onClick={this.parent(item)}> <Text> 我是父盒子{item} </Text> <View onClick={this.son(item)}> <Text> 我是子盒子 {item} </Text> </View> </View> ) }) }
parent = (val) => () => { console.log('parent', val); }; son = (val) =>(e)=> { e.stopPropagation(); console.log('son', val); };
|
函数式组件
H5
柯理化函数阻止冒泡成功
bind阻止冒泡成功
weapp
柯理化函数阻止冒泡失效
bind阻止冒泡失效
类组件
H5
柯理化函数阻止冒泡成功
bind阻止冒泡成功
weapp
柯理化函数阻止冒泡失效
bind阻止冒泡成功
通用
1.普通的箭头函数,所有兼容,有局限性;
2.行内阻止冒泡,写业务代码
10. iconfont只能使用下载本地的方式,直接使用链接页面显示方框
<Text className={classNames('icon', 'icon-home', styles.setIcon)}/>
<Text className={'icon'}></Text>
<AtIcon prefixClass='icon' value='home' size='20' color='#fff'/>
|
11. TaroUI在H5模式下编译报错
请在 config/index.js 文件中添加如下配置项:
h5: { esnextModules: ['taro-ui'] }
|