封装 avm 组件经验分享

 avm.js 是一个跨端开发框架,AVM(Application-View-Model)前端组件化开发模式基于标准Web Components组件化思想,提供包含虚拟DOM和Runtime的编程框架avm.js以及多端统一编译工具,完全兼容Web Components标准,同时兼容Vue和React语法糖编写代码,编译工具将Vue和React相关语法糖编译转换为avm.js代码。

有Vue和React 开发经验的很容易上手。

1. 组件的定义和引用:

     1.1 使用stml定义一个组件 / 页面

stml组件兼容Vue单文件组件(SFC)规范,使用语义化的Html模板及对象化js风格定义组件或页面。stml最终被编译为JS组件 / 页面,渲染到不同终端。

定义组件:

// api-test.stml:
<template>  
    <view class='header'>
        <text>{this.data.title}</text>
    </view>  
</template>  
<script>
    export default {  
        name: 'api-test',
        data(){
            return {
                title: 'Hello APP'
            }
        }
    }
</script>
<style scoped>
    .header{
        height: 45px;
    }
</style>

  1.2 组件引用:

// app-index.stml:

<template>  
    <view class="app">  
        <img src="./assets/logo.png" />  
        <api-test></api-test> 
    </view>  
</template>
<script>
    import './components/api-test.stml'  
    
    export default {  
        name: 'app-index',  
        data: function () {  
            return {
                title: 'Hello APP'
            }
        }  
    }  
</script>  
<style>  
    .app {   
        text-align: center;  
        margin-top: 60px;  
    }  
</style>

2. 向子组件传值

向子组件传值采用 props 的方式,这里以一个示例来进行说明。

定义子组件,在 props 里面注册一个 title 属性:

// api-test.stml:

<template>
    <text>{title}</text>
</template>
<script>
    export default {
        name:'api-test',
        props:{
            title: String
        }
    }
</script>

这里定义的title属性类型为String,属性类型包括 String、Number、Boolean、Array、Object、Function等。

     2.1 在其它页面使用子组件时传递静态值:

// app-index.stml:

<template>  
    <view>  
        <api-test title="Hello App!"></api-test> 
    </view>  
</template>
<script>
    import './components/api-test.stml'  
    
    export default {  
        name: 'app-index'
    }  
</script>

     2.2 通过数据绑定传递动态值:

// app-index.stml:

<template>
    <view>
        <api-test v-bind:title="msg"></api-test>
    </view>
</template>
<script>
    import './components/api-test.stml'  
    
    export default {
        name: 'app-index',
        data() {
            return {
              msg: 'Hello App!'
          }
        }
    }
</script>

传递静态值时只能传递字符串类型数据,通过数据绑定的方式则可以传递任意类型的数据。

3. 监听子组件事件

监听子组件事件和监听普通事件类似,如:

// api-index.stml:

<template>
    <view>
        <api-test onresult="onGetResult"></api-test>
    </view>
</template>
<script>
    import './components/api-test.stml'  
    
    export default {
        name: 'app-index',
        methods: {
            onGetResult(e){
                console.log(e.detail.msg);
            }
        }
    }
</script>

以上示例中监听了子组件的result事件,子组件里面通过fire方法来触发监听的事件:

// app-test.stml:

<template>
    <text onclick="onclick">Hello App!</text>
</template>
<script>
    export default {
        name:'api-test',
        methods:{
            onclick(){
                let detail = {msg:'Hi'};
                this.fire('result', detail);
            }
        }
    }
</script>

fire方法有两个参数,第一个参数为事件名称,第二个参数为要传递的自定义数据,在父组件监听方法里面通过e.detail获取传递的数据。

// api-index.stml:

methods: {
  onGetResult(e){
      console.log(e.detail.msg);
  }
}

4.  声网组件实例

了解了以上组件的规则和用法,就可以封装自己的组件了 。下面看一个基于agoraRtc声网模块,实现1对1语音通话的组件实例:

<template>
	<view class="agorartc-call-voice_page">
		<safe-area></safe-area>
		<view class="agorartc-call-voice_list" v-for="(item,index) in userList">
			<view class="agorartc-call-voice_userinfo">
				<image class="agorartc-call-voice_userinfo-image" thumbnail='false'
					style="width: 64px; height: 64px; margin-right:10px" src={{item.userimg }}></image>
				<text class="agorartc-call-voice_userinfo-text">{{item.username }}</text>
			</view>
			<view class="agorartc-call-voice_callimg">
				<image @click="fnstart_voice_call(item.userid)" thumbnail='false' style="width: 50px; height: 50px"
					src="../../image/voice-call.png"></image>
			</view>
		</view>
		<view class="agorartc-call-voice_connected" v-if="connected">
			<image class="agorartc-call-voice_voice" thumbnail='false' style="width: 200px;"
				src="../../image/video-voice.gif"></image>
			<image class="agorartc-call-voice_hangup" @click="fnhangup()" thumbnail='false'
				style="width: 64px; height: 64px;" src="../../image/video-hangup.png"></image>
		</view>
	</view>
</template>
<script>
export default {
	name: 'agorartc-call-voice',
	props: {
		channel: String,
		userList: Array,
		rtcAppId: String
	},

	installed() {
		this.fnishasper_mic();
	},
	data() {
		return {
			connected: false
		};
	},
	methods: {
		fnishasper_mic(_userid) {
			var resultList = api.hasPermission({
				list: ["microphone"]
			});
			if (resultList[0].granted) {

			} else {
				api.toast({
					msg: "需要启用麦克风权限"
				});
				api.requestPermission({
					list: ["microphone"]
				}, res => {
					if (res.list[0].granted) {

					}
				});
			}
		},
		fnstart_voice_call(_userid) {
			this.fnrtc_init();
			this.fnerr_listener();
			this.fnjoin_channel(_userid);
		},
		fnrtc_init() {
			console.log('初始化');
			var agoraRtc = api.require('agoraRtc');
			agoraRtc.init({
				appId: this.props.rtcAppId
			});
		},
		fnjoin_channel(_userid) {
			console.log('121:---' + _userid);
			this.data.connected = true;
			var agoraRtc = api.require('agoraRtc');
			agoraRtc.joinChannelSuccessListener(function (ret) {
				console.log(ret.uid + 'uid------');
			});

			agoraRtc.remoteUserJoinedListener((ret) => {
				console.log(ret.uid + 'remoteUserJoinedListener------');
				if (ret.uid) {
					this.data.connected = true;
				}
			});
			// 多人语音通话 ,需设置角色为主播 
			agoraRtc.setClientRole({
				role: 1
			}, function (ret) {
				if (ret.code == 0) {
					//success
					console.log('设置主播模式成功')
				}
			});

			agoraRtc.enableAudio((ret) => {
				if (ret.code == 0) {
					//success
					console.log('开启音频成功---' + this.props.channel);
					agoraRtc.joinChannel({
						channel: this.props.channel,
						uid: _userid
					}, function (ret) {
						if (ret.code == 0) {
							console.log('加入频道成功');
						}
					});
				}
			});

			agoraRtc.remoteUserOfflineListener((ret) => {
				api.toast({
					msg: '对方已挂断'
				})
				this.fnhangup();
			});
		},
		fnerr_listener() {
			var agoraRtc = api.require('agoraRtc');
			agoraRtc.errorListener(function (ret) {
				if (ret.errorCode == 0) {
					var agoraRtc = api.require('agoraRtc');
					agoraRtc.leaveChannel(function (ret) {
						if (ret.code == 0) { //success
						}
					});
					api.toast({
						msg: '通话出错!'
					});
				}
			});
		},
		fnhangup() {
			var agoraRtc = api.require('agoraRtc');
			agoraRtc.leaveChannel(function (ret) {
				if (ret.code == 0) {
					//success
				}
			});
			this.data.connected = false;
		}
	}
};
</script>
<style>
.agorartc-call-voice_page {
	height: 100%;
	width: 100%;
	background-color: #fff;
}

.agorartc-call-voice_list {
	height: 64px;
	width: 100%;
	display: flex;
	flex-direction: row;
	flex-wrap: nowrap;
	justify-content: flex-start;
	margin-bottom: 10px;
}

.agorartc-call-voice_userinfo {
	display: flex;
	flex-direction: row;
	flex-wrap: nowrap;
	justify-content: flex-start;
	align-items: center;
	padding-left: 20px;
}

.agorartc-call-voice_callimg {
	display: flex;
	flex-direction: row;
	flex-wrap: nowrap;
	justify-content: flex-end;
	align-items: center;
	flex-grow: 2;
	padding-right: 20px;
}

.agorartc-call-voice_connected {
	position: absolute;
	top: 0;
	left: 0;
	background-color: #fff;
	width: 100%;
	height: 100%;
	display: flex;
	flex-direction: column;
	justify-content: space-around;
	align-items: center;
}

.agorartc-call-voice_hangup {
	margin-top: 30px;
}
</style>

avm.js 默认使用 flex 弹性盒子布局,实现UI时,应充分利用 flex 弹性布局原理进行布局。而实现声网语音通话的核心逻辑很简单:两个用户加入同一个频道即可 。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值