# 组件的公共属性和事件

每个组件都有属性和事件。有些属性和事件,是所有组件都支持的。

# 组件公共属性

  • id
  • ref
  • style
  • class
  • data-

# # 示例

hello uni-app x

<template>
 <!-- #ifdef APP -->
 <scroll-view style="flex: 1">
   <!-- #endif -->
   <view>
     <page-head :title="title"></page-head>
     <view class="uni-padding-wrap container">
       <view
         :id="generalId"
         :class="generalClass"
         :name="generalName"
         :title="generalTitle"
         :data-test="generalData"
         :style="generalStyle"
         ref="general-target"
       >
         <text>id: {{ generalId }}</text>
         <text>class: {{ generalClass }}</text>
         <text>name: {{ generalName }}</text>
         <text>title: {{ generalTitle }}</text>
         <text>data-test: {{ generalData }}</text>
         <text>style: {{ generalStyle }}</text>
       </view>
       <view
         class="btn btn-style uni-common-mt"
         @click="validateGeneralAttributes"
       >
         <text class="btn-inner">{{ validateGeneralAttrText }}</text>
       </view>
       <view class="btn btn-ref uni-common-mt" @click="changeHeight">
         <text class="btn-inner">{{changeHeightByRefText}}</text>
       </view>
       <view class="view-class" :hover-class="hoverClass" ref="view-target">
         <text class="text">按下 50 ms 后背景变红</text>
         <text class="text">抬起 400 ms 后背景恢复</text>
       </view>
       <view
         class="view-class"
         :hover-class="hoverClass"
         :hover-start-time="1000"
         :hover-stay-time="1000"
         ref="view-target"
       >
         <text class="text">按下 1000 ms 后背景变红</text>
         <text class="text">抬起 1000 ms 后背景恢复</text>
       </view>
     </view>
   </view>
   <!-- #ifdef APP -->
 </scroll-view>
 <!-- #endif -->
</template>

<script lang="uts">
export default {
 data() {
   return {
     title: 'general-attribute',
     generalId: 'general-id',
     generalClass: 'general-class',
     generalName: 'general-name',
     generalTitle: 'general-title',
     generalData: 'general-data',
     generalStyle: 'background-color: aqua',
     validateGeneralAttrText: '验证基础属性',
     hoverClass: 'hover-class',
     validateViewAttrText: '验证 view 属性',
     changeHeightByRefText: '通过 ref 修改高度',
   }
 },
 methods: {
   validateGeneralAttributes() {
     const generalTarget = this.$refs['general-target'] as Element
     const generalId = generalTarget.getAttribute('id')
     if (generalId != this.generalId) {
       this.validateGeneralAttrText = '基础属性 id 验证失败'
       return
     }
     const classList = generalTarget.ext['classList'] as string[]
     if (!classList.includes('general-class')) {
       this.validateGeneralAttrText = '基础属性 class 验证失败'
       return
     }
     const generalName = generalTarget.getAttribute('name')
     if (generalName != this.generalName) {
       this.validateGeneralAttrText = '基础属性 name 验证失败'
       return
     }
     const generalTitle = generalTarget.getAttribute('title')
     if (generalTitle != this.generalTitle) {
       this.validateGeneralAttrText = '基础属性 title 验证失败'
       return
     }
     const generalData = generalTarget.getAttribute('data-test')
     if (generalData != this.generalData) {
       this.validateGeneralAttrText = '基础属性 data-test 验证失败'
       return
     }
     this.validateGeneralAttrText = '基础属性验证成功'
   },
   changeHeight(){
     const generalTarget = this.$refs['general-target'] as Element
     this.changeHeightByRefText = '已通过 ref 修改高度'
     generalTarget.style.setProperty('height', '200px')
   }
 },
}
</script>

<style>
.btn {
 height: 50px;
 display: flex;
 align-items: center;
 justify-content: center;
 background-color: #409eff;
 border-radius: 5px;
}
.btn-inner {
 color: #fff;
}
.general-class {
 margin-left: 40px;
 padding: 10px;
 width: 260px;
 height: 160px;
 background-color: antiquewhite;
}
.view-class {
 margin: 20px 0 0 50px;
 padding: 10px;
 width: 240px;
 height: 100px;
 background-color: antiquewhite;
}
.view-class .text {
 margin-top: 5px;
 text-align: center;
}
.hover-class {
 background-color: red;
}
</style>

# 组件公共事件

  • @touchstart
  • @touchmove
  • @touchend
  • @touchcancel
  • @tap
  • @click //与tap等价
  • @longpress
  • @transitionend

在多点触摸的屏幕上,touch事件返回数组,包含了每个touch点对应的x、y坐标。

# transition 事件

  • @transitionend

    transition 效果结束时触发

    # 兼容性

    安卓 3.93+ 版本开始支持

<template>
  <image class="transition-transform" id="transition-transform" @transitionend="onEnd" src="/static/uni.png"></image>
</template>
<script>
  export default {
    data() {
      return {}
    },
    onReady() {
      var element = uni.getElementById('transition-transform')
      element!.style.setProperty('transform', 'rotate(360deg)')
    },
    methods: {
      onEnd() {
        console.log("transition效果结束")
      }
    }
  }
</script>

<style>
  .transition-transform {
    transition-duration: 2000;
    transition-property: transform;
    transform: rotate(0deg);
  }
</style>

# 冒泡事件系统

DOM事件主要有三个阶段:捕获阶段、目标阶段和冒泡阶段。

以点击事件为例,当触发点击时,

  1. 首先从根节点逐级向下分发,直到监听点击事件的节点为止(捕获阶段);
  2. 然后事件到达当前节点并触发点击事件(目标阶段);
  3. 接着继续向上逐级触发父节点的点击事件,直到根节点为止(冒泡阶段)。

注意,虽然有3个阶段,但第2个阶段(“目标阶段”:事件到达了元素)并没有单独处理:捕获和冒泡阶段的处理程序都会在该阶段触发。

我们一般使用默认的事件注册机制,将事件注册到冒泡阶段,相对来说,大多数处理情况都在冒泡阶段。

uvue 目前暂不支持事件的捕获阶段。

# 阻止冒泡

在事件回调中,可以通过调用event.stopPropagation方法阻止事件冒泡。

handleClick (event : MouseEvent) {
    // 阻止继续冒泡.
    event.stopPropagation();
}

# 阻止默认行为

在事件回调中,可以通过调用event.preventDefault方法阻止默认行为。event.preventDefault仅处理默认行为,事件冒泡不会被阻止。

<template>
	<scroll-view style="flex: 1;">
		<view style="width: 750rpx;height: 1750rpx;background-color: bisque;">
			滑动框中区域修改进度并阻止滚动,滑动其余空白区域触发滚动
			<view style="width: 750rpx;height: 40rpx; margin-top: 100rpx;border:5rpx;" @touchmove="slider">
				<view ref="view1" style="background-color: chocolate;width: 0rpx;height: 30rpx;"></view>
			</view>
		</view>
	</scroll-view>
</template>
<script>
	export default {
		data() {
			return {
				$view1Element: null as UniElement | null
			}
		},
    onReady() {
      this.$view1Element = this.$refs['view1'] as UniElement
    },
		methods: {
			slider(e : TouchEvent) {
				e.preventDefault() // 阻止外层scroll-view滚动行为
				this.$view1Element!.style?.setProperty('width', e.touches[0].screenX);
			}
		}
	}
</script>

# Event

# # 构造函数

名称 类型 必备 默认值 描述
type string - -
eventInit UTSJSONObject - -

# # Event 属性值

名称 类型 必备 默认值 描述
type string - 事件类型
target Element - 触发事件的组件
currentTarget Element - 当前组件
timeStamp number - 事件发生时的时间戳

# Event 方法

# # stopPropagation()

阻止当前事件的进一步传播

# # preventDefault()

阻止当前事件的默认行为

# CustomEvent

# # 构造函数

名称 类型 必备 默认值 描述
type string - -
CustomEventOptions CustomEventOptions<T> -

# # CustomEvent 属性值

名称 类型 必备 默认值 描述
detail T - -
type string - 事件类型
target Element - 触发事件的组件
currentTarget Element - 当前组件
timeStamp number - 事件发生时的时间戳

# CustomEvent 方法

# # stopPropagation()

阻止当前事件的进一步传播

# # preventDefault()

阻止当前事件的默认行为

# CustomEventOptions

# # 构造函数

名称 类型 必备 默认值 描述
detail T - -

# # CustomEventOptions 属性值

名称 类型 必备 默认值 描述
detail T - -

# MouseEvent

# # 构造函数

名称 类型 必备 默认值 描述
type string - -
x number - -
y number - -
clientX number - -
clientY number - -
pageX number - -
pageY number - -
screenX number - -
screenY number - -

# # MouseEvent 属性值

名称 类型 必备 默认值 描述
clientX number - 相对于页面可显示区域左边的距离
clientY number - 相对于页面可显示区域顶部的距离
x number - 相对于页面可显示区域左边的距离,同clientX
y number - 相对于页面可显示区域顶部的距离,同clientY
pageX number - 相对于文档左边的距离
pageY number - 相对于文档顶部的距离
screenX number - 相对于屏幕左边距离
screenY number - 相对于屏幕顶部的距离
type string - 事件类型
target Element - 触发事件的组件
currentTarget Element - 当前组件
timeStamp number - 事件发生时的时间戳

# MouseEvent 方法

# # stopPropagation()

阻止当前事件的进一步传播

# # preventDefault()

阻止当前事件的默认行为

# TouchEvent

# # TouchEvent 属性值

名称 类型 必备 默认值 描述
touches Array<Touch> - 当前停留在屏幕中的触摸点信息的数组
changedTouches Array<Touch> - 当前变化的触摸点信息的数组
type string - 事件类型
target Element - 触发事件的组件
currentTarget Element - 当前组件
timeStamp number - 事件发生时的时间戳

# TouchEvent 方法

# # stopPropagation()

阻止当前事件的进一步传播

# # preventDefault()

阻止当前事件的默认行为

# Touch

# # Touch 属性值

名称 类型 必备 默认值 描述
clientX number - 相对于页面可显示区域左边的距离
clientY number - 相对于页面可显示区域顶部的距离
identifier number - 触摸点的标识符。这个值在这根手指所引发的所有事件中保持一致,直到手指抬起。
pageX number - 相对于文档左边的距离
pageY number - 相对于文档顶部的距离
screenX number - 相对于屏幕左边距离
screenY number - 相对于屏幕顶部的距离
force number - 返回当前触摸点按下的压力大小

# # 示例

hello uni-app x

<template>
 <!-- #ifdef APP -->
 <scroll-view style="flex: 1">
 <!-- #endif -->
   <page-head title="触摸方块测试相关事件"></page-head>
   <view class="uni-padding-wrap uni-common-mt container">
     <view class="target" @touchstart="onTouchStart" @touchcancel="onTouchCancel" @touchmove="onTouchMove"
       @touchend="onTouchEnd" @tap="onTap" @click="onClick" @longpress="onLongPress"></view>
     <view v-if="touchStartEvent !== null">
       <text class="title1">touchStart Event: </text>
       <text class="title2">touches: </text>
       <template v-for="(touch, index) in touchStartEvent!.touches" :key="index">
         <text class="title3">touch[{{ index }}]:</text>
         <text>identifier: {{touch.identifier}}</text>
         <text>pageX: {{ touch.pageX }}, pageY: {{ touch.pageY }}</text>
         <text>clientX: {{ touch.clientX }}, clientY: {{ touch.clientY }}</text>
         <text>screenX: {{ touch.screenX }}, screenY: {{ touch.screenY }}</text>
       </template>
       <text class="title2 uni-common-mt">changedTouches: </text>
       <template v-for="(touch, index) in touchStartEvent!.changedTouches" :key="index">
         <text class="title3">touch[{{ index }}]:</text>
         <text>identifier: {{touch.identifier}}</text>
         <text>pageX: {{ touch.pageX }}, pageY: {{ touch.pageY }}</text>
         <text>clientX: {{ touch.clientX }}, clientY: {{ touch.clientY }}</text>
         <text>screenX: {{ touch.screenX }}, screenY: {{ touch.screenY }}</text>
       </template>
     </view>
     <view v-if="touchCancelEvent !== null">
       <text class="title1">touchCancel Event: </text>
       <text class="title2">touches: </text>
       <template v-for="(touch, index) in touchCancelEvent!.touches" :key="index">
         <text class="title3">touch[{{ index }}]:</text>
         <text>identifier: {{touch.identifier}}</text>
         <text>pageX: {{ touch.pageX }}, pageY: {{ touch.pageY }}</text>
         <text>clientX: {{ touch.clientX }}, clientY: {{ touch.clientY }}</text>
         <text>screenX: {{ touch.screenX }}, screenY: {{ touch.screenY }}</text>
       </template>
       <text class="title2 uni-common-mt">changedTouches: </text>
       <template v-for="(touch, index) in touchCancelEvent!.changedTouches" :key="index">
         <text class="title3">touch[{{ index }}]:</text>
         <text>identifier: {{touch.identifier}}</text>
         <text>pageX: {{ touch.pageX }}, pageY: {{ touch.pageY }}</text>
         <text>clientX: {{ touch.clientX }}, clientY: {{ touch.clientY }}</text>
         <text>screenX: {{ touch.screenX }}, screenY: {{ touch.screenY }}</text>
       </template>
     </view>
     <view v-if="touchMoveEvent !== null">
       <text class="title1">touchMove Event: </text>
       <text class="title2">touches: </text>
       <template v-for="(touch, index) in touchMoveEvent!.touches" :key="index">
         <text class="title3">touch[{{ index }}]:</text>
         <text>identifier: {{touch.identifier}}</text>
         <text>pageX: {{ touch.pageX }}, pageY: {{ touch.pageY }}</text>
         <text>clientX: {{ touch.clientX }}, clientY: {{ touch.clientY }}</text>
         <text>screenX: {{ touch.screenX }}, screenY: {{ touch.screenY }}</text>
       </template>
       <text class="title2 uni-common-mt">changedTouches: </text>
       <template v-for="(touch, index) in touchMoveEvent!.changedTouches" :key="index">
         <text class="title3">touch[{{ index }}]:</text>
         <text>identifier: {{touch.identifier}}</text>
         <text>pageX: {{ touch.pageX }}, pageY: {{ touch.pageY }}</text>
         <text>clientX: {{ touch.clientX }}, clientY: {{ touch.clientY }}</text>
         <text>screenX: {{ touch.screenX }}, screenY: {{ touch.screenY }}</text>
       </template>
     </view>
     <view v-if="longPressEvent !== null">
       <text class="title1">longPress Event: </text>
       <text class="title2">touches: </text>
       <template v-if="longPressEvent!.touches.length > 0" v-for="(touch, index) in longPressEvent!.touches"
         :key="index">
         <text class="title3">touch[{{ index }}]:</text>
         <text>identifier: {{touch.identifier}}</text>
         <text>pageX: {{ touch.pageX }}, pageY: {{ touch.pageY }}</text>
         <text>clientX: {{ touch.clientX }}, clientY: {{ touch.clientY }}</text>
         <text>screenX: {{ touch.screenX }}, screenY: {{ touch.screenY }}</text>
       </template>
       <text class="title2 uni-common-mt">changedTouches: </text>
       <template v-for="(touch, index) in longPressEvent!.changedTouches" :key="index">
         <text class="title3">touch[{{ index }}]:</text>
         <text>identifier: {{touch.identifier}}</text>
         <text>pageX: {{ touch.pageX }}, pageY: {{ touch.pageY }}</text>
         <text>clientX: {{ touch.clientX }}, clientY: {{ touch.clientY }}</text>
         <text>screenX: {{ touch.screenX }}, screenY: {{ touch.screenY }}</text>
       </template>
     </view>
     <view v-if="touchEndEvent !== null">
       <text class="title1">touchEnd Event: </text>
       <text class="title2">touches: </text>
       <template v-if="touchEndEvent!.touches.length > 0" v-for="(touch, index) in touchEndEvent!.touches"
         :key="index">
         <text class="title3">touch[{{ index }}]:</text>
         <text>identifier: {{touch.identifier}}</text>
         <text>pageX: {{ touch.pageX }}, pageY: {{ touch.pageY }}</text>
         <text>clientX: {{ touch.clientX }}, clientY: {{ touch.clientY }}</text>
         <text>screenX: {{ touch.screenX }}, screenY: {{ touch.screenY }}</text>
       </template>
       <text class="title2 uni-common-mt">changedTouches: </text>
       <template v-for="(touch, index) in touchEndEvent!.changedTouches" :key="index">
         <text class="title3">touch[{{ index }}]:</text>
         <text>identifier: {{touch.identifier}}</text>
         <text>pageX: {{ touch.pageX }}, pageY: {{ touch.pageY }}</text>
         <text>clientX: {{ touch.clientX }}, clientY: {{ touch.clientY }}</text>
         <text>screenX: {{ touch.screenX }}, screenY: {{ touch.screenY }}</text>
       </template>
     </view>
     <view v-if="tapEvent !== null">
       <text class="title1">tap Event: </text>
       <text>x: {{ tapEvent!.x }}, y: {{ tapEvent!.y }}</text>
     </view>
     <view v-if="clickEvent !== null">
       <text class="title1">click Event: </text>
       <text>x: {{ clickEvent!.x }}, y: {{ clickEvent!.y }}</text>
     </view>
   </view>
 <!-- #ifdef APP -->
 </scroll-view>
 <!-- #endif -->
</template>
<script lang="uts">
 export default {
   data() {
     return {
       title: 'general-event',
       onTouchStartTime: 0,
       touchStartEvent: null as TouchEvent | null,
       touchCancelEvent: null as TouchEvent | null,
       onTouchMoveTime: 0,
       touchMoveEvent: null as TouchEvent | null,
       onTouchEndTime: 0,
       longPressEvent: null as TouchEvent | null,
       touchEndEvent: null as TouchEvent | null,
       onTapTime: 0,
       tapEvent: null as MouseEvent | null,
       onClickTime: 0,
       clickEvent: null as MouseEvent | null,
       onLongPressTime: 0,
     }
   },
   methods: {
     onTouchStart(e : TouchEvent) {
       this.touchStartEvent = e
       this.onTouchStartTime = Date.now()
       console.log('onTouchStart')
     },
     onTouchCancel(e : TouchEvent) {
       this.touchCancelEvent = e
       console.log('onTouchCancel')
     },
     onTouchMove(e : TouchEvent) {
       this.touchMoveEvent = e
       this.onTouchMoveTime = Date.now()
       console.log('onTouchMove')
     },
     onLongPress(e : TouchEvent) {
       this.longPressEvent = e
       this.onLongPressTime = Date.now()
       console.log('onLongPress')
     },
     onTouchEnd(e : TouchEvent) {
       this.touchEndEvent = e
       this.onTouchEndTime = Date.now()
       console.log('onTouchEnd')
     },
     onTap(e : MouseEvent) {
       this.tapEvent = e
       this.onTapTime = Date.now()
       console.log('onTap')
     },
     onClick(e : MouseEvent) {
       this.clickEvent = e
       this.onClickTime = Date.now()
       console.log('onClick')
     },
   },
 }
</script>

<style>
 .container {
   padding-bottom: 10px;
 }

 .target {
   margin: 20px 0 0 50px;
   width: 200px;
   height: 100px;
   background-color: aqua;
 }

 .title1 {
   margin-top: 15px;
   font-size: 20px;
 }

 .title2 {
   margin-top: 10px;
   font-size: 18px;
 }

 .title3 {
   margin-top: 5px;
   font-size: 16px;
 }
</style>