一、view组件及其重要属性

view最主要的功能是布局

微信小程序组件properties 微信小程序组件居中_xml

1.1 相关属性

属性1:hover-class 指定按下去的样式类

这个属性指定按下去的类样式,让容器有一个单击效果,
当hover-class="none"时,或者没有设置这个属性时,就没有单击态的效果。
单击、再松开手指之后,容器组件恢复之前的状态。

<view hover-class="bc_red" class="section__title">content</view>

微信小程序组件properties 微信小程序组件居中_微信小程序组件properties_02

hover-class 这个属性名称有一定的迷惑性,
在HTML开发中,mousehover事件指的是鼠标悬停事件,hover有悬停的意思,mousedown才是鼠标按下去的事件。


属性2:hover-stop-propagation 组织父节点出现单击态,

默认为false,不阻止

微信小程序组件properties 微信小程序组件居中_微信小程序组件properties_03

hover-stop-propagation="{{false}}"
单击子组件的时候,父组件同时也有了一个样式的改变。

hover-stop-propagation
子容器有单击态,父容器没有,
虽然父容器也设置了hover-class属性,
但触碰事件被子容器给阻止了。


事件三阶段

我们通过跟踪父子组件的tap事件,验证一下hover-stop-propagation属性的作用。

在示例中我们给两个view,一对父子容器同时绑定tap事件,
为方便追踪,为父子容器都分配了id,父容器id是parentView,子容器是childView。

单击一次父容器,输出一次。
单击一次子容器却输出两次。

为什么会触发两次的tap事件?
这是因为每个事件它都有捕捉、目标与冒泡三个阶段,
在view视图容器上使用bind绑定的事件,
默认会在目标与冒泡这两个阶段派发事件,
子组件的冒泡事件默认会向上传递。

微信小程序组件properties 微信小程序组件居中_xml_04


hover-stop-propagation这个属性

就是为了阻止父组件出现hover-class样式,

但是它还不能阻止冒泡事件向上传递、

当我们设置这个属性以后,

我们单击子组件,仍然可以看到两次输出。

微信小程序组件properties 微信小程序组件居中_xml_05

那么我们可以让子容器view的tap事件只派发一次吗
答案是肯定的,可以使用catch绑定事件函数,

catch与bind的作用相同,
与bind不同的是:
catch会阻止事件向上冒泡。
catch是在事件的捕捉阶段监听事件的。

子容器的bindtap改为catchtap
这样单击子容器组件的时候便不会输出两次了。

微信小程序组件properties 微信小程序组件居中_JSON_06

<!-- 事件三阶段-->
 <view id="parentView" bindtap="onTap" hover-class="bc_red" class="section__title">
            parent
	<view id="childView" bindtap="onTap" hover-stop-propagation hover-class="bc_green" class="section__title">
	    child view
	</view>
</view>

<!-- 5 子组件只输出一次-->
<!-- 阻止父节点出现hover状态,阻止冒泡 -->
<view id="parentView" bindtap="onTap" hover-class="bc_red" class="section__title">
parent
	<view id="childView" catchtap="onTap" hover-stop-propagation hover-class="bc_green" class="section__title">
		child view
	</view>
</view>
onTap(e){
  console.log(e.target)
}

属性3 :hover-start-time 按住后多久出现单击态 默认为50毫秒
设置hover-start-time这个属性,是为了方便开发者控制hover-class样式出现的时机。


属性4 :hover-stay-time 手指松开以后,单击态保留多长时间,单位均是毫秒

这两个属性的设置,说明在view容器组件内部,有代码肯定做了定时,
当touchstart事件发生时,开始计时,达到hover-start-time时,应用hover-class样式,
当touchstart事件结束,即touchend事件发生时,开始hover-stay-time的倒计时,时间到则移除hover-class样式。


1.2 了解苹果手机网页上为什么有300毫秒的延迟

当延迟超过100毫秒的时候,用户就会感觉到界面有明显的卡顿,
但是在移动设备上,特别是苹果的Safari浏览器上,我们不得不忍受300毫秒的延迟。
这是为什么呢?

2007年乔布斯在iphone发布会上演示这样一个功能,
对于一个Safari浏览器,在内容区快速单击,
苹果会帮助我们准确定位到文章的主题内容,并将其放大。
如果用户不小心在双击时,击到了一个链接,是马上跳转呢,还是等待用户的另外一次单击。
不然没办法判断它是不是双击事件。

苹果采用的是第二种方式,所有的Safari中的链接都要延迟300毫秒,
用这种方式观察用户是不是还要发出第二次单击事件,
如果没有,在跳转链接,这导致苹果手机中的HTML网页里面的单击反应都有一点的迟钝。

但是在微信小程序里,没有这个问题,hover-start-time默认时间是50毫秒,
只需要50毫秒,甚至更短的时间,就可以触发单击事件。
微信小程序已经迈过了300毫秒延迟的限制。

使用微信小程序开发产品,相比HTML5有什么优势
没有单击延迟,这就是在体验上一个很大的优势。

拒绝300毫秒延迟

微信小程序组件properties 微信小程序组件居中_微信小程序组件properties_07


1.3 hover-class的应用

使用hover-class定义按钮状态

微信小程序组件properties 微信小程序组件居中_JSON_08


1.4 相关问题

hover-start-time属性的值,最小可以设置为多少,
设置为1毫秒,可以吗?为什么?

答案是可以设置了,但是设置了也没有效果,因为在小程序当中,
所有界面效果都受限于小程序本身的渲染帧率,每秒渲染60帧,每帧用时大概17毫秒,
所以设置成1毫秒或者17毫秒,它的效果是一样的,没有区别。

二、flex布局中常用的样式及样式值

  • justify-content 调整内容在主轴方向的排列方式,
  • align-items 对齐元素在辅轴方向的对齐方式
  • align-content 对齐多行内容在辅轴方向上的排列方式
  • flex-direction
2.1 相关问题

如何把view上的内容绘制到画布上,生成一张海报?


解决方案:

2.1.1 在这里有一个开源的小程序组件 Painter,封装了通过JSON数据绘制海报的功能,
  • 安装
  • 1.https://github.com/Kujiale-Mobile/Painter 下载组件painter
  • 2.放在components文件夹下
  • 3.在JSON 组件声明
{   
"usingComponents": 
	{    
		"painter":"../../components/painter/painter", 
	} 
}
  • 使用
    1.pages/index

微信小程序组件properties 微信小程序组件居中_bc_09

微信小程序组件properties 微信小程序组件居中_JSON_10


index.wxml

<view class="section">
	生成分享图,将view转绘为图片 
	<button type="primary" class="intro" open-type="getUserInfo" bindgetuserinfo="getUserInfo" wx:if="{{!nickName}}">获取分享图头像昵称</button>
	<button type="primary" class="intro" bindtap="createShareImage" wx:else>点我生成分享图</button>
	<share-box isCanDraw="{{isCanDraw}}" bind:initData="createShareImage" />
</view>

index.js

//painter生成海报
Page({
	data: {
		nickName: '',
		avatarUrl: '',
		isCanDraw: false
	},
	onLoad() {
		this.setData({
			nickName: wx.getStorageSync('nickName') || '',
			avatarUrl: wx.getStorageSync('avatarUrl') || ''
		})
	},
	getUserInfo(e) {
		this.setData({
			nickName: e.detail.userInfo.nickName,
			avatarUrl: e.detail.userInfo.avatarUrl
		})
		wx.setStorageSync('avatarUrl', e.detail.userInfo.avatarUrl)
		wx.setStorageSync('nickName', e.detail.userInfo.nickName)
	},
	createShareImage() {
		this.setData({
			isCanDraw: !this.data.isCanDraw
		})
	},

})

index.json

{
  "usingComponents": {
     "share-box": "../../components/shareBox/index",
  }
}

2.components/shareBox pages/index/index.wxml index.js

isCanDraw drawPic

微信小程序组件properties 微信小程序组件居中_微信小程序组件properties_11

imgDraw sharePath

微信小程序组件properties 微信小程序组件居中_xml_12

  • 效果

2.1.2 或者使用weui中的wxml-to-canvas
  • 安装
  • 1.npm install --save wxml-to-canvas
  • 2.点击小程序开发工具的工具–构建npm
  • 3.JSON 组件声明
{
  "usingComponents": {
	"wxml-to-canvas": "wxml-to-canvas",
  }
}
  • 使用

微信小程序组件properties 微信小程序组件居中_xml_13

index.wxml

<!-- wxml-to-canvas   weui生成海报  start -->
<!-- wxml -->
<view class="page-section">
    <view class="page-section-title">wxml</view>
    <view class="container">
        <view class="item-box red">
        </view>
        <view class="item-box green">
            <text class="text">yeah!</text>
        </view>
        <view class="item-box blue">
            <image class="img"
                src="https://cdn.nlark.com/yuque/0/2020/png/1252071/1590050624644-dd5948db-22fe-48d9-af37-8a2a9f099715.png">
            </image>
        </view>
    </view>
</view>

<!--  -->
<!-- 渲染wxml -->
<view class="page-section">
    <view class="page-section-title">渲染wxml</view>
    组件 
    <wxml-to-canvas class="widget"></wxml-to-canvas>
    <view class="page-section-title">导出图片</view>
     图片 
    <image src="{{src}}" style="width: {{width}}px; height: {{height}}px"></image>
</view>

<!-- btns -->
<view class="btn-area">
    <button type="primary" bindtap="renderToCanvas">渲染到canvas</button>
    <button bindtap="extraImage">导出图片</button>
    <button bindtap="onTapSaveBtn">保存图片</button>
</view>
<!-- wxml-to-canvas   end -->

index.js

//wxml-to-canvas  weui生成海报

const { wxml, style } = require('./demo')
Page({
    data: {
      src: ''
    },
    onLoad() {
      this.widget = this.selectComponent('.widget')
    },
    onTapSaveBtn(e){
      wx.saveImageToPhotosAlbum({
        filePath:this.data.src,
        complete(res) { 
          console.log(res)
        }
      })
    },
    renderToCanvas() {
      const p1 = this.widget.renderToCanvas({ wxml, style })
      p1.then((res) => {
        console.log('container', res.layoutBox)
        this.container = res
      })
    },
    extraImage() {
      const p2 = this.widget.canvasToTempFilePath()
      p2.then(res => {
        this.setData({
          src: res.tempFilePath,
          width: this.container.layoutBox.width,
          height: this.container.layoutBox.height
        })
      })
    }
  })

demo.js

const wxml = `
<view class="container" >
  <view class="item-box red">
  </view>
  <view class="item-box green" >
    <text class="text">yeah!</text>
  </view>
  <view class="item-box blue">
      <image class="img" src="https://cdn.nlark.com/yuque/0/2020/png/1252071/1590050624644-dd5948db-22fe-48d9-af37-8a2a9f099715.png"></image>
  </view>
</view>
`

const style = {
  container: {
    width: 300,
    height: 200,
    flexDirection: 'row',
    justifyContent: 'space-around',
    backgroundColor: '#ccc',
    alignItems: 'center',
  },
  itemBox: {
    width: 80,
    height: 60,
  },
  red: {
    backgroundColor: '#ff0000'
  },
  green: {
    backgroundColor: '#00ff00'
  },
  blue: {
    backgroundColor: '#0000ff',
    alignItems: 'center',
    justifyContent: 'center',
  },
  text: {
    width: 80,
    height: 60,
    textAlign: 'center',
    verticalAlign: 'middle',
  },
  img: {
    width: 40,
    height: 40,
    borderRadius: 20,
  }
}

module.exports = {
  wxml,
  style
}

index.scss

/* wxml-to-canvas  weui生成海报 */

.widget {

}

.container {
  width: 300px;
  height: 200px;
  min-height: 200px;
  flex-direction: row;
  justify-content: space-around;
  background-color: #ccc;
  align-items: center;
  padding: 60px 0 60px;
  display: flex;
}
.item-box {
  width: 80px;
  height: 60px;
  display: flex;
}
.red{
  background-color: #ff0000
}
.green {
  background-color: #00ff00
}
.blue{
  background-color: #0000ff;
  align-items: center;
  justify-content: center;
}
.text{
  width: 80px;
  height: 60px;
  text-align: center;
  vertical-align: middle;
  line-height: 60px;
}
.img{
  width: 40px;
  height: 40px;
  border-radius: 50%;
}
  • 效果
  • 微信小程序组件properties 微信小程序组件居中_微信小程序组件properties_14

  • bug
  1. 关于 Cancvas API 错误:createImage fail: http://tmp/xxx…png
    index.js use2dCanvas

index.js _drawImage

微信小程序组件properties 微信小程序组件居中_xml_15

index.js isTempFile isNetworkFile

微信小程序组件properties 微信小程序组件居中_bc_16

  1. 不随滚动的页面滚动与基础库有关系