README.md 7.3 KB
Newer Older
D
DCloud_LXH 已提交
1
# UVUE DOM
D
DCloud_LXH 已提交
2 3 4

App-uvue的每个页面,在内存中都有一个 DOM(文档对象模型)。它和浏览器的 [DOM规范](https://www.w3.org/DOM/?spm=a2c7j.-zh-docs-api-weex-variable.0.0.2a5537c6FrgbYp) 类似。

DCloud-yyl's avatar
DCloud-yyl 已提交
5
DOM 是页面元素内容的结构数据。DOM 模型用一个逻辑树来表示一个页面文档,树的每个分支的终点都是一个节点,每个节点都对应一个节点对象(UniElement)。
D
DCloud_LXH 已提交
6 7 8 9 10

实际上 app-uvue 的template、数据绑定,在底层调用的也是 DOM API。

在浏览器中,开发者一旦跳过vue框架直接操作dom,vue框架将无法管理相应dom,开发者需要注意两端的冲突。

DCloud-yyl's avatar
DCloud-yyl 已提交
11
在 App 端,为了减少冲突,目前不支持通过 DOM API 创建和删除 DOM 树中的元素。只支持获取元素UniElement。
D
DCloud_LXH 已提交
12

DCloud-yyl's avatar
DCloud-yyl 已提交
13 14
> 低版本使用过 INode 对象,从HBuilderX 3.91开始统一为 Element 对象,不再推荐使用 INode  
> HBuilderX4.0开始统一调整为 UniElement 对象,不再推荐使用 Element 和 INode  
D
DCloud_LXH 已提交
15 16 17 18 19 20 21 22


## 使用场景
通常情况下,使用 uvue 框架的数据绑定来操作更新页面组件就可以。但有2个场景,需要使用 DOM API。

1. 跟手动效

	响应触屏事件更新组件的位置,要想不掉帧,需要保证16毫秒绘制一帧。
D
DCloud_LXH 已提交
23

D
DCloud_LXH 已提交
24
	uvue的data更新,有一套diff机制,每次触发data更新,会多几毫秒的耗时。
D
DCloud_LXH 已提交
25

D
DCloud_LXH 已提交
26 27 28 29
	此时推荐通过 DOM API 跳过 vue 框架直接操作组件的样式。

2. Draw API

DCloud-yyl's avatar
DCloud-yyl 已提交
30
	Android和iOS的原生view,有一些底层的高性能绘制能力,这些API的调用,需要先获取到 UniElement 对象,然后再调用其方法。
D
DCloud_LXH 已提交
31 32 33 34

[性能](../performance.md)章节,对这2个场景有详细的阐述。


D
DCloud_LXH 已提交
35
## DOM元素对象@getDomNode
D
DCloud_LXH 已提交
36

DCloud-yyl's avatar
DCloud-yyl 已提交
37
在操作DOM元素对象前,需要先获取 `UniElement` 对象,可通过 `uni.getElementById``this.$refs` 获取。
D
DCloud_LXH 已提交
38

D
DCloud_LXH 已提交
39
### 通过uni.getElementById获取DOM元素
D
DCloud_LXH 已提交
40

D
DCloud_LXH 已提交
41
app-uvue 页面中可以为页面元素节点设置 id 属性,然后通过 [uni.getElementById](../api/get-element.md#getelementbyid) 获取 DOM 元素对象。
D
DCloud_LXH 已提交
42

W
补提  
wanganxp 已提交
43 44
但注意这个方法只能获取栈顶页面的element。如需绑定调用的页面,需使用下方的[this.$refs](#refs)

D
DCloud_LXH 已提交
45 46 47 48 49 50 51 52 53 54 55 56 57 58
首先需要为组件设置 id 属性值:
```vue
<!-- id 属性值为 myView,后续可以通过此值查找 -->
<view id="myView" class="container">
    <text>Hello World</text>
</view>
```

在页面`onReady` 后(太早组件可能没有创建),通过 `uni.getElementById` 获取。如果长期使用,可以保存在vue的 data 中。
```ts
  export default {
    data() {
      return {
        color: 'red',
DCloud-yyl's avatar
DCloud-yyl 已提交
59
        myView: null as UniElement | null
D
DCloud_LXH 已提交
60 61 62
      }
    },
    onReady() {
D
DCloud_LXH 已提交
63
        // 获取组件对象并保存在 this.myView 中
D
DCloud_LXH 已提交
64 65 66 67 68
        this.myView = uni.getElementById('myView');
    },
}
```

W
补提  
wanganxp 已提交
69
### 通过this.$refs获取DOM元素@refs
D
DCloud_LXH 已提交
70
app-uvue页面中可以通过 vue 框架中的组件实例对象 [this.$refs](https://uniapp.dcloud.net.cn/tutorial/vue3-api.html#%E5%AE%9E%E4%BE%8B-property) 获取 DOM 元素对象。
D
DCloud_LXH 已提交
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85

首先需要为组件设置 ref 属性值,它类似于id:
```vue
<!-- ref 属性值为 myView,后续可以通过此值查找 -->
<view ref="myView" class="container">
    <text>Hello World</text>
</view>
```

在页面`onReady` 后(太早组件可能没有创建),通过 `this.$refs` 获取。如果长期使用,可以保存在vue的 data 中。
```ts
  export default {
    data() {
      return {
        color: 'red',
DCloud-yyl's avatar
DCloud-yyl 已提交
86
        myView: null as UniElement | null
D
DCloud_LXH 已提交
87 88 89
      }
    },
    onReady() {
D
DCloud_LXH 已提交
90
        // 获取组件对象并保存在 this.myView 中
DCloud-yyl's avatar
DCloud-yyl 已提交
91
        this.myView = this.$refs['myView'] as UniElement;  //需要使用 as 转换
D
DCloud_LXH 已提交
92 93 94 95 96
    },
}
```

### 操作DOM元素对象
DCloud-yyl's avatar
DCloud-yyl 已提交
97
获取DOM元素对象Elment后,可通过其属性或方法操作组件,完整API参考[UniElement对象文档](unielement.md)
D
DCloud_LXH 已提交
98

DCloud-yyl's avatar
DCloud-yyl 已提交
99
如通过UniElement对象的 style 属性更新组件的样式:
D
DCloud_LXH 已提交
100 101 102 103
```ts
this.myView?.style?.setProperty('background-color', 'red');
```

D
DCloud_LXH 已提交
104 105 106
### 示例
以下是完整的操作示例:
```vue
D
DCloud_LXH 已提交
107 108 109 110 111 112 113
<template>
  <!-- #ifdef APP -->
  <scroll-view style="flex:1;align-items: center;">
  <!-- #endif -->
    <view id="myView" ref="myView" class="container">
      <text>Hello World</text>
    </view>
DCloud-yyl's avatar
DCloud-yyl 已提交
114
    <button @tap="updateElement">操作UniElement</button>
D
DCloud_LXH 已提交
115 116 117 118 119 120 121 122 123 124
  <!-- #ifdef APP -->
  </scroll-view>
  <!-- #endif -->
</template>

<script>
  export default {
    data() {
      return {
        color: 'red',
DCloud-yyl's avatar
DCloud-yyl 已提交
125
        myView: null as UniElement | null
D
DCloud_LXH 已提交
126 127 128 129 130 131
      }
    },
    onLoad() {
    },
    onReady() {
      this.myView = uni.getElementById('myView');       //通过uni.getElementById获取
DCloud-yyl's avatar
DCloud-yyl 已提交
132
      //this.myView = this.$refs['myView'] as UniElement;  //通过this.$refs获取,需要使用 as 转换
D
DCloud_LXH 已提交
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
    },
    methods: {
      updateElement() {
        this.color = 'red' == this.color ? 'blue' : 'red';
        this.myView?.style?.setProperty('background-color', this.color);
      }
    },
  }
</script>

<style>
  .container {
    align-items: center;
    justify-content: center;
    background-color: aquamarine;
    width: 100%;
    height: 200px;
  }
</style>

```

>以上例子仅为演示DOM API的使用,实际上点击按钮修改背景色这种简单场景,使用数据绑定更简单,class绑定到一个data上,动态修改data即可。


D
DCloud_LXH 已提交
158
## 通过DrawableContext绘制View
D
DCloud_LXH 已提交
159 160 161 162 163

uni-app x 在 app 端提供 DrawableContext 绘制内容到 uvue 页面的`view`标签上。可用于绘制文本、形状等内容。

### 获取 DrawableContext 对象

DCloud-yyl's avatar
DCloud-yyl 已提交
164
DrawableContext 可通过节点对象(UniElement)的`getDrawableContext()`方法获取
D
DCloud_LXH 已提交
165 166 167 168 169 170 171 172 173

```vue
<template>
	<view ref="drawable" style="width: 750rpx;height: 750rpx;">
	</view>
</template>
<script>
	export default {
		onReady() {
DCloud-yyl's avatar
DCloud-yyl 已提交
174
			var ctx = (this.$refs['drawable'] as UniElement).getDrawableContext()
D
DCloud_LXH 已提交
175 176 177 178 179 180 181 182 183 184 185 186 187
		}
	}
</script>
```

### 绘制内容

通过 DrawableContext 提供的 API 绘制文本、形状等内容

```ts
<script>
	export default {
		onReady() {
DCloud-yyl's avatar
DCloud-yyl 已提交
188
			var ctx = (this.$refs['drawable'] as UniElement).getDrawableContext()
D
DCloud_LXH 已提交
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
			ctx.moveTo(50, 40);
			ctx.lineTo(200, 40);
			ctx.stroke();
		}
	}
</script>
```

### 更新到画布

DrawableContext 在调用 API 之后不会主动更新到画布上,需要主动调用`update()`方法更新。

```ts
<script>
	export default {
		onReady() {
DCloud-yyl's avatar
DCloud-yyl 已提交
205
			var ctx = (this.$refs['drawable'] as UniElement).getDrawableContext()
D
DCloud_LXH 已提交
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
			ctx.moveTo(50, 40);
			ctx.lineTo(200, 40);
			ctx.stroke();
			ctx.update()
		}
	}
</script>
```

### 清除画布内容

如果清除已经绘制的内容重新绘制,需要调用`reset()`方法清除内容再进行绘制。

```vue
<template>
	<view ref="drawable" style="width: 750rpx;height: 750rpx;" @click="drawable">
	</view>
</template>
<script>
	export default {
		data(){
			return {
				change:false
			}
		},
		onReady() {
			this.drawable()
		},
		methods:{
			drawable(){
DCloud-yyl's avatar
DCloud-yyl 已提交
236
				var ctx = (this.$refs['drawable'] as UniElement).getDrawableContext()
D
DCloud_LXH 已提交
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
				ctx.reset();
				if(this.change) {
					ctx.strokeStyle = "#33ff0000"
					ctx.lineWidth = 10
				}
				this.change = !this.change
				ctx.moveTo(50, 40);
				ctx.lineTo(200, 40);
				ctx.stroke();
				ctx.update()
			}
		}
	}
</script>
```

Q
qiang 已提交
253 254
## 注意事项

DCloud-yyl's avatar
DCloud-yyl 已提交
255
由于排版和渲染是异步的的,在修改 DOM 后,立刻使用 DOM 的同步接口获取 DOM 状态可能获取到的是排版之前的,如果需要及时准确的获取到排版之后的 DOM 状态需要使用 [uni.createSelectorQuery](../api/nodes-info.md)