微信小程序开发学习笔记004--微信小程序语法结构
发布日期:2021-06-29 17:57:21
浏览次数:2
分类:技术文章
本文共 16369 字,大约阅读时间需要 54 分钟。
今天讲微信小程序的语法结构
技术交流QQ群:170933152
数据绑定:把数据声明后显示在页面上 渲染:条件渲染,循环渲染 模板:某个小需求,模块封装成模板 事件:点击一个按钮触发一个事件,发送一个请求给 服务器,然后服务器,处理请求,返回响应数据给 页面. ------------------------ 先看数据绑定,新建credemo04 然后用sublime打开项目: 首先我,在pages文件夹下新建 demo1.js demo1.wxss demo1.wxml ----------------------- 好,先在demo1.js中声明数据: demo1.js Page({ data:{ msg:'今天天气很好' }, onLoad:function(options){ }, onReady:function(){ }, onShow:function(){ }, onHide:function(){ }, onUnload:function(){ }, onPullDownRefresh:function(){ }, onReachBottom:function(){ } }) ----------------------------- 然后在demo1.wxml中显示数据: <view class="msg"> { {msg}}//1.这种形式显示数据 </view> 还可以在demo1.wxss中调整样式 .msg{ text-align:center; margin-top:100px; color:red; } ---------------------- 然后在app.json中配置设置首页 { "pages":[ "pages/demo1/demo1",//1.设置首页显示demo1 "pages/index/index", "pages/logs/logs" ], "window":{ "backgroundTextStyle":"light", "navigationBarBackgroundColor": "#fff", "navigationBarTitleText": "WeChat", "navigationBarTextStyle":"black" } } ----------------------------------- 看看,效果 再,写一个时间数据: demo1.js Page({ data:{ msg:'今天天气很好', //1.这里这个时间数据 // time:'2017.1.1' }, onLoad:function(options){ }, onReady:function(){ }, onShow:function(){ }, onHide:function(){ }, onUnload:function(){ }, onPullDownRefresh:function(){ }, onReachBottom:function(){ } }) ------------------------------------ demo1.wxml 显示数据: <view class="msg"> { {msg}} </view> <view> { {time}}//1.显示数据 </view> -------------------- 看看效果 好,当然也可以声明全局的数据 比如: app.js中可以声明全局的数据 //app.js App({ onLaunch: function () { //调用API从本地缓存中获取数据 var logs = wx.getStorageSync('logs') || [] logs.unshift(Date.now()) wx.setStorageSync('logs', logs) }, getUserInfo:function(cb){ var that = this if(this.globalData.userInfo){ typeof cb == "function" && cb(this.globalData.userInfo) }else{ //调用登录接口 wx.login({ success: function () { wx.getUserInfo({ success: function (res) { that.globalData.userInfo = res.userInfo typeof cb == "function" && cb(that.globalData.userInfo) } }) } }) } }, globalData:{ userInfo:null, //1.这里添加一个全局数据 name:'credream 哈哈哈' } }) ------------------------------ 然后使用: demo.js //1.使用的时候先通过getApp()方法获取 //全局的app // var app=getApp(); Page({ data:{ msg:'今天天气很好', time:'2017.1.1', //2.然后里面这样获取值 // name:app.globalData.name }, onLoad:function(options){ }, onReady:function(){ }, onShow:function(){ }, onHide:function(){ }, onUnload:function(){ }, onPullDownRefresh:function(){ }, onReachBottom:function(){ } }) ------------------ 使用获取的全局数据: <view class="msg"> { {msg}} </view> <view> { {time}}--{ {name}}//3.使用的时候和以前一样 </view> --------------------------------------- 看看效果 然后咱们再来看渲染: 页面是如何绘制出来的. 渲染: 好,咱们先看条件渲染: 我在 demo1.js中声明: var app=getApp(); Page({ data:{ msg:'今天天气很好', time:'2017.1.1', name:app.globalData.name, //1.定义一个condition // condition:100 }, onLoad:function(options){ }, onReady:function(){ }, onShow:function(){ }, onHide:function(){ }, onUnload:function(){ }, onPullDownRefresh:function(){ }, onReachBottom:function(){ } }) ----------------------------- 然后,咱们看看如何使用: demo1.wxml中: <view class="msg"> { {msg}} </view> <view> { {time}}--{ {name}} </view> //1.如果condition大于90,显示90 <view wx:if="{ {conditino>90}}"> 90 </view> //2.如果if else //也就是如果小于90,大于80显示 //80 <view wx:elif="{ {condition>80}}"> 80 </view> //3.否则就显示60 <view wx:else> 60 </view> ------------------------------------ 看看效果. 总结一下: <view class="msg"> { {msg}} </view> <view> { {time}}--{ {name}} </view> <view>第一种判断if elseif else</view> <view wx:if="{ {conditino>90}}"> 90 </view> <view wx:elif="{ {condition>80}}"> 80 </view> <view wx:else> 60 </view> <view>第二种判断if</view> <view wx:if="{ {conditino>90}}"> 90 </view> <view>第三种判断if else</view> <view wx:if="{ {conditino>90}}"> 90 </view> <view wx:else> 60 </view> --------------------- 好,接下来咱们看看循环,内容较多,建立一个新页面 demo2.js中 咱们看看有个集合,咱们循环出来: Page({ data:{ //1.数组的形式一个列表 list:[ {name:'cre01',address:'济南将军集团'}, {name:'cre02',address:'大连将军集团'}, {name:'cre03',address:'深圳将军集团'}, {name:'cre04',address:'湖北将军集团'} ] }, onLoad:function(options){ }, onReady:function(){ }, onShow:function(){ }, onHide:function(){ }, onUnload:function(){ }, onPullDownRefresh:function(){ }, onReachBottom:function(){ } }) ------------------------------------- 然后,咱们看: 在demo2.wxml中循环出来: <view class="abc" wx:for="{ {list}}"> { {index}}.{ {item.name}}--->{ {item.address}} </view> wx:for="{ {list}}":指定要循环的列表 { {index}}.{ {item.name}}--->{ {item.address}} { {item.name}}:通过item获取列表中的内容. item是微信底层定义的,可以直接用. { {index}}:获取编号,也是微信底层定义的,可以直接用. 当然这里不想用index和item,也可以自己指定: 比如: <view class="abc" wx:for="{ {list}}" wx:for-item="a" wx:for-index="b"> { {b}}.{ {a.name}}--->{ {a.address}} </view> wx:for-item="a" wx:for-index="b" 指定名字 好,然后:在app.json中添加上页面 { "pages":[ //1.添加demo2 "pages/demo2/demo2", "pages/demo1/demo1", "pages/index/index", "pages/logs/logs" ], "window":{ "backgroundTextStyle":"light", "navigationBarBackgroundColor": "#fff", "navigationBarTitleText": "WeChat", "navigationBarTextStyle":"black" } } ---------------------- 然后添加一下样式: demo2.wxss .abc{ padding:10px; margin-bottom:10px; border-bottom:1px solid #dfdfdf; } -------------------------- 看看效果 好,这就是这个循环的用法,然后咱们看看帮助文档: https://mp.weixin.qq.com/debug/wxadoc/dev/framework/view/wxml/list.html 咱们看看这个wx:key: wx:key 如果列表中项目的位置会动态改变或者有新的项目 添加到列表中,并且希望列表中的项目保持自己的特 征和状态(如 <input/> 中的输入内容,<switch/> 的选中状态),需要使用 wx:key 来指定列表中项目 的唯一的标识符。 wx:key 的值以两种形式提供 1.字符串,代表在 for 循环的 array 中 item 的某个 property,该 property 的值需要是列表中唯一的字符串或数字,且不能动态改变。 以上是帮助文档中提到的. 咱们看看,怎么用: wx:key=这个可以指定调试的时候显示的key,比如: 这里如果咱们写上: demo.wxml <view class="abc" wx:key="name" wx:for="{ {list}}" wx:for-item="item" wx:for-index="index"> { {index}}.{ {item.name}}--->{ {item.address}} </view> 好,再看看下面这个: 2.保留关键字 *this 代表在 for 循环中的 item 本身, 这种表示需要 item 本身是一个唯一的字符串或者数字, 如: 当数据改变触发渲染层重新渲染的时候, 会校正带有 key 的组件,框架会确保他们被重新排序, 而不是重新创建,以确保使组件保持自身的状态, 并且提高列表渲染时的效率。 这个可以提高性能的. 举个例子: demo2.js Page({ data:{ list:[ {name:'cre01',address:'济南将军集团'}, {name:'cre02',address:'大连将军集团'}, {name:'cre03',address:'深圳将军集团'}, {name:'cre04',address:'湖北将军集团'} ], //1.添加下面的这个数组 array:[1,2,3,4,5,6,7,8,9] }, onLoad:function(options){ }, onReady:function(){ }, onShow:function(){ }, onHide:function(){ }, onUnload:function(){ }, onPullDownRefresh:function(){ }, onReachBottom:function(){ } }) ----------------------- demo2.wxml <view class="abc" wx:key="name" wx:for="{ {list}}" wx:for-item="item" wx:for-index="index"> { {index}}.{ {item.name}}--->{ {item.address}} </view> <view wx:for="{ {array}}" wx:key="*this"> { {item}} </view> 像这样添加,就可以,添加以后可以提高性能,可以看 帮助文档. ------------------ 好,咱们继续看. wx:if 和hidden有什么区别: 好我在demo2.js中写上: Page({ data:{ list:[ {name:'cre01',address:'济南将军集团'}, {name:'cre02',address:'大连将军集团'}, {name:'cre03',address:'深圳将军集团'}, {name:'cre04',address:'湖北将军集团'} ], array:[1,2,3,4,5,6,7,8,9], //1.这里写上flag对吧 // flag:true }, onLoad:function(options){ }, onReady:function(){ }, onShow:function(){ }, onHide:function(){ }, onUnload:function(){ }, onPullDownRefresh:function(){ }, onReachBottom:function(){ } }) ------------------------ 好,然后咱们看看: demo2.wxml中: <view class="abc" wx:key="name" wx:for="{ {list}}" wx:for-item="item" wx:for-index="index"> { {index}}.{ {item.name}}--->{ {item.address}} </view> <view wx:for="{ {array}}" wx:key="*this"> { {item}} </view> <view wx:if="{ {flag}}"> 比较wx:if 和hidden </view> <view hidden="{ {flag}}"> 比较wx:if 和hidden </view> ------------------------------------ 然后,打开调试,看看wml中: 可以看懂都显示出来了对吧. 然后做个修改: demo2.js Page({ data:{ list:[ {name:'cre01',address:'济南将军集团'}, {name:'cre02',address:'大连将军集团'}, {name:'cre03',address:'深圳将军集团'}, {name:'cre04',address:'湖北将军集团'} ], array:[1,2,3,4,5,6,7,8,9], //1.设置false // flag:false }, onLoad:function(options){ }, onReady:function(){ }, onShow:function(){ }, onHide:function(){ }, onUnload:function(){ }, onPullDownRefresh:function(){ }, onReachBottom:function(){ } }) ------------------------------ 然后看看效果: 在调试窗口,wml窗口: 可以看到不输出调试信息了对吧,也就是 加上了以后,编译过程会把编译后的文件中,不在 加入调试输出信息,这样性能有所提高. 好,咱们添加一个: data-flag看看:这个data-flag其实就是一个标识 用来标识哪一个的,比如咱们举个例子: demo2.wxml <view class="abc" wx:key="name" wx:for="{ {list}}" wx:for-item="item" wx:for-index="index"> { {index}}.{ {item.name}}--->{ {item.address}} </view> <view wx:for="{ {array}}" wx:key="*this"> { {item}} </view> <view data-flag="1" wx:if="{ {flag}}"> 比较wx:if 和hidden </view> <view data-flag="2" hidden="{ {flag}}"> 比较wx:if 和hidden </view> ------------------------------------ 这里咱们添加data-flag以后,咱们可以看到 看看效果,当 demo2.js中定义的: Page({ data:{ list:[ {name:'cre01',address:'济南将军集团'}, {name:'cre02',address:'大连将军集团'}, {name:'cre03',address:'深圳将军集团'}, {name:'cre04',address:'湖北将军集团'} ], array:[1,2,3,4,5,6,7,8,9], //1.这个地方定义是false的时候 //那么只有2在调试控制台上, //显示出来了对吧 // flag:false }, onLoad:function(options){ }, onReady:function(){ }, onShow:function(){ }, onHide:function(){ }, onUnload:function(){ }, onPullDownRefresh:function(){ }, onReachBottom:function(){ } }) -------------------------- 在调试控制台的,wml窗口中可以看到: 有<view data-flag="2">比较wx:if和hidden</view> 对吧. 这说明: demo2.wxml中的: <view data-flag="1" wx:if="{ {flag}}"> 比较wx:if 和hidden </view> <view data-flag="2" hidden="{ {flag}}"> 比较wx:if 和hidden </view> wx:if:是根据flag的值,如果是true就显示 hidden:无论是true还是false,他的结构都是有的 只是显示的结构不一样,这个可以在控制台上看到. 对于hidden来说: false的时候显示: <view data-flag="2">比较wx:if和hidden</view> true的时候显示: <view hidden="" data-flag="2">比较wx:if和hidden</view> 好,咱们再看: 下面是block: 不是微信小程序中提供的,他是一个包裹元素 比如我写一个: 在demo2.wxml <view class="abc" wx:for="{ {list}}" wx:for-item="item" wx:for-index="index"> { {index}}.{ {item.name}}--->{ {item.address}} </view> <view wx:for="{ {array}}" > { {item}} </view> <view data-flag="1" wx:if="{ {flag}}"> 比较wx:if 和hidden </view> <view data-flag="2" hidden="{ {flag}}"> 比较wx:if 和hidden </view> //1.可以看到block的作用就是 //把两个<view>组件包裹起来 //没有其他作用. <block wx:if="{ {true}}"> <view>1111</view> <view>2222</view> </block> 看看效果,调试窗口,然后wml可以看到 block这个元素没有显示出来对吧, 说明他没有参与渲染对吧. ------------------- 好,再看最后一个 template这个是模板的意思: 在代码中可以写一些代码片段,比如我 新建一个页面demo3 新建一个文件夹demo3 demo3.js demo3.wxml demo3.wxss ----------------- demo3.wxml中,咱们看看: <template name="info"> <view> <text>{ {name}}</text> <text>{ {address}}</text> </view> </template> //1.下面这个是es6的语法,大家可以去看看 <template is="info" data="{ {...item}}"></template> ----------------------- 然后定义数据: demo3.js Page({ data:{ //1.这里这样定义数据. // item:{ name:'credream', address:'北京' } }, onLoad:function(options){ }, onReady:function(){ }, onShow:function(){ }, onHide:function(){ }, onUnload:function(){ }, onPullDownRefresh:function(){ }, onReachBottom:function(){ } }) --------------------------------- 然后,修改一下app.json把demo3页面设置 成首页: { "pages":[ "pages/demo3/demo3", "pages/demo2/demo2", "pages/demo1/demo1", "pages/index/index", "pages/logs/logs" ], "window":{ "backgroundTextStyle":"light", "navigationBarBackgroundColor": "#fff", "navigationBarTitleText": "WeChat", "navigationBarTextStyle":"black" } } 好,然后看看效果. ---------------------------- 好,上面: demo3.wxml中,咱们把 <text>{ {name}}</text> <text>{ {address}}</text> 分开写在两个<view>标签中,咱们看看: demo3.wxml <template name="info"> //1.可以看到这里 //name和address变成两行显示了对吧. // <view> <text>{ {name}}</text> </view> <view> <text>{ {address}}</text> </view> </template> //2.注意,这里的,info对应的上面写的info //item对应的是demo3.js //中的data中定义的那个item值. // <template is="info" data="{ {...item}}"></template> ---------------------------- 看看效果. 咱们还可以通过引用的方式: 咱们可以用import和include 引用 比如我新建一个item.wxml 把demo3.wxml中的一些内容,写到 item.wxml中. item.wxml咱们看看: <template name="info"> <view> <text>{ {name}}</text> </view> <view> <text>{ {address}}</text> </view> </template> --------------------------- 好,接下来,咱们可以在demo3.wxml中引用: item.wxml: demo3.wxml <import src="item.wxml"/> <template is="info" data="{ {...item}}"></template> 这里就用到这个import对吧,但一定要注意这里的路径的写法 要不就找不到对应的文件了对吧. 看看效果: ---------------------------- 好,咱们再来看看 include怎么用,其实跟import一样对吧, 咱们看看: demo3.wxml <include src="item.wxml"/> <template is="info" data="{ {...item}}"></template> 好,这里换成include,然后咱们看看效果 微信开发者工具,中没有显示出来对吧, 怎么回事呢? 这说明,include,他只支持把静态的文件,导入,静态的数据 导入,比如我再新建一个文件: tips.wxml <view>tips page</view> 好去改改,demo3.wxml demo3.wxml <include src="tips.wxml"/> <template is="info" data="{ {...item}}"></template> 好,修改以后,咱们看看效果,可以看到没有问题了对吧. ----------------------------- 这里涉及到,import和include的一个区别,就是说 import指的是引入一个文件,这个文件中的值可能 是引入到.js文件中data部分定义的值.这个时候 这个值是可以取得到的. 而include引入的文件,只能是一个静态的文件,也就是 文件定义的内容都是写死的静态内容.这样的文件,用 include就可以. ------------------------------ 好,咱们接下来看看,事件: 是怎么回事. 咱们说,当用户点击按钮,会触发某个事件而去调用 逻辑层的业务逻辑函数. 好,咱们看看事件: 先看看定义: 视图层到逻辑层的通讯方式 事件对象可以携带额外信息 事件的分类:冒泡和非冒泡事件 冒泡事件有: 冒泡【touch***,tap,longtap】 touchmove等等..tap,longtap都是冒泡事件,除了冒泡事件 其他都是非冒泡事件. 看看例子: 新建一个页面,叫demo4: 新建一个文件夹:demo4 demo4.wxss demo4.wxml demo4.js -------------- demo4.wxml //1.添加一个按钮,并且绑定一个事件 //func1 // <view> <button bindtap="func1">点我</button> </view> demo4.js 声明这个事件. Page({ data:{ }, //1.这里添加一个事件. //这里只是把接收到的事件进行绑定一下 //控制台输出一下. // func1:function(e){ console.log(e); }, onLoad:function(options){ }, onReady:function(){ }, onShow:function(){ }, onHide:function(){ }, onUnload:function(){ }, onPullDownRefresh:function(){ }, onReachBottom:function(){ } }) ---------------- 然后去页面看看,可以看到,点击点我的时候, 控制台输出了调试信息. 这样就说明: 第一点: 事件是视图层到逻辑层的通讯方式 -------------- 好,接下来再复杂一点: demo4.js Page({ data:{ //1.先声明一个消息,然后显示在demo4.wxml中 // msg:'test' }, func1:function(e){ console.log(e); this.setData({ msg:(new Date-0) }) }, onLoad:function(options){ }, onReady:function(){ }, onShow:function(){ }, onHide:function(){ }, onUnload:function(){ }, onPullDownRefresh:function(){ }, onReachBottom:function(){ } }) ----------- demo4.wxml <view> //1.这里显示 <view>{ {msg}}</view> <button bindtap="func1">点我</button> </view> 然后当点击点我的时候,我们让他换一换数据: Page({ data:{ msg:'test' }, func1:function(e){ console.log(e); //1.这里换数据 //换成一个日期就行. // this.setData({ msg:(new Date-0) }) }, onLoad:function(options){ }, onReady:function(){ }, onShow:function(){ }, onHide:function(){ }, onUnload:function(){ }, onPullDownRefresh:function(){ }, onReachBottom:function(){ } }) ----------------- 好,看下一点: 事件对象可以携带额外信息 举个例子: demo4.wxml <view> <view>{ {msg}}</view> <button data-hi="hello" data-a="nihao" bindtap="func1">点我</button> </view> data-hi="hello" data-a="nihao" 这就是给事件添加的数据. 好,然后回到开发者工具的,调试窗口,可以看到 在console窗口中的, 事件对象,object-->展开target-->dataset--> a:,hi:这里这两个数据对吧. 好,接下来,咱们看看怎么把这个两个数据,打印到控制台上. 比如: demo4.js Page({ data:{ msg:'test' }, func1:function(e){ console.log(e); //1.这里通过事件对象就可以取出来了 //咱们看了看效果 //对吧. console.log(e.target.dataset.a); console.log(e.target.dataset.hi); this.setData({ msg:(new Date-0) }) }, onLoad:function(options){ }, onReady:function(){ }, onShow:function(){ }, onHide:function(){ }, onUnload:function(){ }, onPullDownRefresh:function(){ }, onReachBottom:function(){ } }) ------------------------ 这就说明了: 事件对象可以携带额外信息 第三个咱们看看: 分类:冒泡和非冒泡事件 demo4.wxml <view> <view>{ {msg}}</view> <button data-hi="hello" data-a="nihao" bindtap="func1">点我</button> </view> //1.这里演示事件冒泡: // <view bindtap="func4"> outer <view bindtap="func3"> middle <view bindtap="func2"> inner </view> </view> </view> 在demo4.js中添加相应事件: Page({ data:{ msg:'test' }, func1:function(e){ console.log(e); console.log(e.target.dataset.a); console.log(e.target.dataset.hi); this.setData({ msg:(new Date-0) }) }, //1.添加上demo4中指定的 //几个事件 //func2,func3,func4 // func2:function(){ console.log('inner'); }, func3:function(){ console.log('middle'); }, func4:function(){ console.log('outer'); }, onLoad:function(options){ }, onReady:function(){ }, onShow:function(){ }, onHide:function(){ }, onUnload:function(){ }, onPullDownRefresh:function(){ }, onReachBottom:function(){ } }) ----------------------------------------- 看看效果,这就是冒泡对吧,一层层去冒泡对吧. 好,接下来,咱们看看 事件绑定【bind***,catch***】 bind不阻止冒泡事件向上冒泡 catch阻止冒泡事件向上冒泡 好,比如demo4.wxml中咱们看看: catch阻止冒泡事件向上冒泡 <view> <view>{ {msg}}</view> <button data-hi="hello" data-a="nihao" bindtap="func1">点我</button> </view> <view bindtap="func4"> outer <view bindtap="func3"> middle //1.这里这个换成catch // <view catchtap="func2"> inner </view> </view> </view> --------------------------------- 看看效果这个时候点击inner,不会再打印出outer和middle了对吧 说明catch会阻止冒泡 好,咱们再看看: https://mp.weixin.qq.com/debug/wxadoc/dev/framework/view/wxml/event.html 有不明白的到时候可以去查手册. 事件对象【type,timeStamp,target,currentarget】 这个在微信开发工具上的,右边的console控制台能看到: 比如:点击一个按钮,就会在控制台出现一个事件对象. type:代表事件类型 timestamp:触发事件所经过的毫秒数 Target:触发事件的源组件 currentTarget:事件绑定的当前对象 还有detail:等等 在帮助文档中有,咱们看看: 事件分类 事件分为冒泡事件和非冒泡事件: 冒泡事件:当一个组件上的事件被触发后,该事件会向父节点传递。 非冒泡事件:当一个组件上的事件被触发后,该事件不会向父节点传递。 WXML的冒泡事件列表: 类型 触发条件 touchstart 手指触摸动作开始 touchmove 手指触摸后移动 touchcancel 手指触摸动作被打断,如来电提醒,弹窗 touchend 手指触摸动作结束 tap 手指触摸后马上离开 longtap 手指触摸后,超过350ms再离开转载地址:https://credream.blog.csdn.net/article/details/56014895 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
能坚持,总会有不一样的收获!
[***.219.124.196]2024年04月27日 09时05分04秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
IE8下面parseInt('08')、parseInt('09')会转成0
2019-04-30
Tomcat重启脚本
2019-04-30
在同一台电脑部署多个Tomcat服务
2019-04-30
局域网不能访问本机IIS网站的解决方法
2019-04-30
MySQL 安装步骤
2019-04-30
SpringBoot执行定时任务
2019-04-30
win7 64位下redis的安装
2019-04-30
winform中读写SQLite数据库例子
2019-04-30
ECharts上手例子
2019-04-30
SQLite 查询时异常:该字符串未被识别为有效的 DateTime 错误
2019-04-30
c# Socket发送与接收方法
2019-04-30
C#实现快捷键(系统热键)响应
2019-04-30
Windows下nginx+tomcat实现简单的负载均衡
2019-04-30
winform中SQLite的分页
2019-04-30
C# WinForm窗体及其控件自适应各种屏幕分辨率
2019-04-30
winform中dataGridView的简单分页
2019-04-30
dataGridView几个小技巧
2019-04-30
RecyclerView Item 行高定义无效的BUG
2019-04-30
markdown发生HTML渲染组件出错的解决方案
2019-04-30
android ScrollView嵌套WebView高度为0的BUG
2019-04-30