前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >通过修改样式调整trtccalling 视图

通过修改样式调整trtccalling 视图

原创
作者头像
良人
发布2022-03-25 16:53:49
3080
发布2022-03-25 16:53:49
举报

效果展示

切换视角
切换视角

实现分析

总体思路就是通过添加点击事件,给流播放节点动态添加样式,来实现视角切换。拿web 端 Demo来举例就是,通过点击,修改flex来实现两个dom的切换。

Demo代码位置修改

1. 添加变量

代码语言:javascript
复制
  data() {
    return {
      isRowReverse: false
    };
  },

2. 给播放div添加点击事件

代码语言:javascript
复制
    <div
          v-for="userId in meetingUserIdList"
          :key="`video-${userId}`"
          :id="`video-${userId}`"
          :class="{
            'user-video-container': true,
            'is-me': userId === loginUserInfo.userId,
          }"
          @click="isRowReverse = !isRowReverse"
        >

3. 给 video-conference-list 添加动态样式

代码语言:javascript
复制
   <div
        :class="{
          'video-conference-list': true,
          'row-rev': isRowReverse,
        }"
      >

4. 添加row-rev样式并给 video-conference-list 样式添加 justify-content 属性

代码语言:javascript
复制
.video-conference-list {
  display: flex;
  flex-direction: row;
  justify-content: center;
  margin-top: 10px;
}

.row-rev {
  flex-direction: row-reverse;
}

通过上述步骤就可以切换视角了!

总结

实现视图切换最好是通过动态修改样式来实现,不需要调佣TRTCCalling的相关api,这样可以比较快速便捷无感切换。

全文件代码

代码语言:javascript
复制
<template>
  <div class="video-call-section">
    <div class="video-call-section-header">
      Welcome
      {{ loginUserInfo && (loginUserInfo.name || loginUserInfo.userId) }}
    </div>
    <div class="video-call-section-title">视频通话</div>
    <search-user
      :callFlag="callFlag"
      :cancelFlag="cancelFlag"
      @callUser="handleCallUser"
      @cancelCallUser="handleCancelCallUser"
    ></search-user>
    <div :class="{ 'video-conference': true, 'is-show': isShowVideoCall }">
      <div class="video-conference-header">视频通话区域</div>

      <div
        :class="{
          'video-conference-list': true,
          'row-rev': isRowReverse,
        }"
      >
        <div
          v-for="userId in meetingUserIdList"
          :key="`video-${userId}`"
          :id="`video-${userId}`"
          :class="{
            'user-video-container': true,
            'is-me': userId === loginUserInfo.userId,
          }"
          @click="isRowReverse = !isRowReverse"
        >
          <div class="user-status">
            <div
              :class="{
                'user-video-status': true,
                'is-mute': isUserMute(muteVideoUserIdList, userId),
              }"
            ></div>
            <div
              :class="{
                'user-audio-status': true,
                'is-mute': isUserMute(muteAudioUserIdList, userId),
              }"
            ></div>
          </div>
          <div class="video-item-username">
            {{ userId2Name[userId] || userId }}
          </div>
        </div>
      </div>
      <div class="video-conference-action">
        <el-button class="action-btn" type="success" @click="toggleVideo">{{
          isVideoOn ? "关闭摄像头" : "打开摄像头"
        }}</el-button>

        <el-button class="action-btn" type="success" @click="toggleAudio">{{
          isAudioOn ? "关闭麦克风" : "打开麦克风"
        }}</el-button>

        <el-button class="action-btn" type="danger" @click="handleHangup"
          >挂断</el-button
        >
      </div>
    </div>
  </div>
</template>

<script>
import { mapState } from "vuex";
import SearchUser from "../search-user";
import { getUsernameByUserid } from "../../service";

export default {
  name: "VideoCall",
  components: {
    SearchUser,
  },
  computed: {
    ...mapState({
      loginUserInfo: (state) => state.loginUserInfo,
      callStatus: (state) => state.callStatus,
      isInviter: (state) => state.isInviter,
      meetingUserIdList: (state) => state.meetingUserIdList,
      muteVideoUserIdList: (state) => state.muteVideoUserIdList,
      muteAudioUserIdList: (state) => state.muteAudioUserIdList,
    }),
  },
  data() {
    return {
      isShowVideoCall: false,
      isVideoOn: true,
      isAudioOn: true,
      userId2Name: {},
      callFlag: false,
      cancelFlag: false,
      isRowReverse: false,
    };
  },
  mounted() {
    if (this.callStatus === "connected" && !this.isInviter) {
      this.startMeeting();
      this.updateUserId2Name(this.meetingUserIdList);
    }
  },
  destroyed() {
    this.$store.commit("updateMuteVideoUserIdList", []);
    this.$store.commit("updateMuteAudioUserIdList", []);
    if (this.callStatus === "connected") {
      this.$trtcCalling.hangup();
      this.$store.commit("updateCallStatus", "idle");
    }
  },
  watch: {
    callStatus: function (newStatus, oldStatus) {
      // 作为被邀请者, 建立通话连接
      if (newStatus !== oldStatus && newStatus === "connected") {
        this.startMeeting();
        this.updateUserId2Name(this.meetingUserIdList);
      }
    },
    meetingUserIdList: function (newList, oldList) {
      if (newList !== oldList || newList.length !== oldList) {
        this.updateUserId2Name(newList);
      }
    },
  },
  methods: {
    handleCallUser: function ({ param }) {
      this.callFlag = true;
      this.$trtcCalling
        .call({
          userID: param,
          type: this.TrtcCalling.CALL_TYPE.VIDEO_CALL,
        })
        .then(() => {
          this.callFlag = false;
          this.$store.commit("userJoinMeeting", this.loginUserInfo.userId);
          this.$store.commit("updateCallStatus", "calling");
          this.$store.commit("updateIsInviter", true);
        });
    },
    handleCancelCallUser: function () {
      this.cancelFlag = true;
      this.$trtcCalling.hangup().then(() => {
        this.cancelFlag = false;
        this.$store.commit("dissolveMeeting");
        this.$store.commit("updateCallStatus", "idle");
      });
    },
    startMeeting: function () {
      if (this.meetingUserIdList.length >= 3) {
        // 多人通话
        const lastJoinUser =
          this.meetingUserIdList[this.meetingUserIdList.length - 1];
        this.$trtcCalling.startRemoteView({
          userID: lastJoinUser,
          videoViewDomID: `video-${lastJoinUser}`,
        });
        return;
      }
      this.isShowVideoCall = true;
      this.$trtcCalling.startLocalView({
        userID: this.loginUserInfo.userId,
        videoViewDomID: `video-${this.loginUserInfo.userId}`,
      });
      const otherParticipants = this.meetingUserIdList.filter(
        (userId) => userId !== this.loginUserInfo.userId
      );
      otherParticipants.forEach((userId) => {
        this.$trtcCalling.startRemoteView({
          userID: userId,
          videoViewDomID: `video-${userId}`,
        });
      });
    },
    handleHangup: function () {
      this.$trtcCalling.hangup();
      this.isShowVideoCall = false;
      this.$store.commit("updateCallStatus", "idle");
      this.$router.push("/");
    },
    toggleVideo: function () {
      this.isVideoOn = !this.isVideoOn;
      if (this.isVideoOn) {
        this.$trtcCalling.openCamera();
        const muteUserList = this.muteVideoUserIdList.filter(
          (userId) => userId !== this.loginUserInfo.userId
        );
        this.$store.commit("updateMuteVideoUserIdList", muteUserList);
      } else {
        this.$trtcCalling.closeCamera();
        const muteUserList = this.muteVideoUserIdList.concat(
          this.loginUserInfo.userId
        );
        this.$store.commit("updateMuteVideoUserIdList", muteUserList);
      }
    },
    toggleAudio: function () {
      this.isAudioOn = !this.isAudioOn;
      this.$trtcCalling.setMicMute(!this.isAudioOn);
      if (this.isAudioOn) {
        const muteUserList = this.muteAudioUserIdList.filter(
          (userId) => userId !== this.loginUserInfo.userId
        );
        this.$store.commit("updateMuteAudioUserIdList", muteUserList);
      } else {
        const muteUserList = this.muteAudioUserIdList.concat(
          this.loginUserInfo.userId
        );
        this.$store.commit("updateMuteAudioUserIdList", muteUserList);
      }
    },
    isUserMute: function (muteUserList, userId) {
      return muteUserList.indexOf(userId) !== -1;
    },
    updateUserId2Name: async function (userIdList) {
      let userId2Name = {};
      let loginUserId = this.loginUserInfo.userId;
      for (let i = 0; i < userIdList.length; i++) {
        const userId = userIdList[i];
        if (!this.userId2Name[userId]) {
          const userName = await getUsernameByUserid(userId);
          userId2Name[userId] = userName;
          if (loginUserId === userId) {
            userId2Name[userId] += "(me)";
          }
        }
      }
      this.userId2Name = {
        ...this.userId2Name,
        ...userId2Name,
      };
    },
    goto: function (path) {
      this.$router.push(path);
    },
  },
};
</script>

<style scoped>
.video-call-section {
  padding-top: 50px;
  width: 800px;
  margin: 0 auto;
}
.video-call-section-header {
  font-size: 24px;
}
.video-call-section-title {
  margin-top: 30px;
  font-size: 20px;
}
.video-conference {
  display: none;
  margin-top: 20px;
}
.video-conference.is-show {
  display: block;
}

.video-conference-list {
  display: flex;
  flex-direction: row;
  justify-content: center;
  margin-top: 10px;
}

.row-rev {
  flex-direction: row-reverse;
}
.user-video-container {
  position: relative;
  text-align: left;
  width: 360px;
  height: 240px;
  margin: 10px;
}

.user-video-status {
  position: absolute;
  right: 50px;
  bottom: 20px;
  width: 24px;
  height: 27px;
  z-index: 10;
  background-image: url("../../assets/camera-on.png");
  background-size: cover;
}
.user-video-status.is-mute {
  background-image: url("../../assets/camera-off.png");
}

.user-audio-status {
  position: absolute;
  right: 20px;
  bottom: 20px;
  width: 22px;
  height: 27px;
  z-index: 10;
  background-image: url("../../assets/mic-on.png");
  background-size: cover;
}

.user-audio-status.is-mute {
  background-image: url("../../assets/mic-off.png");
}

.video-conference-action {
  margin-top: 10px;
}

.video-item-username {
  position: absolute;
  top: 20px;
  left: 20px;
  z-index: 10;
  color: #ffffff;
}
@media screen and (max-width: 767px) {
  .video-call-section {
    width: 100%;
  }
  .video-conference-list {
    margin: 0;
    padding: 10px;
  }
  .user-video-container {
    margin: 5px;
  }
}
</style>

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 效果展示
  • 实现分析
  • Demo代码位置修改
  • 总结
  • 全文件代码
相关产品与服务
实时音视频
实时音视频(Tencent RTC)基于腾讯21年来在网络与音视频技术上的深度积累,以多人音视频通话和低延时互动直播两大场景化方案,通过腾讯云服务向开发者开放,致力于帮助开发者快速搭建低成本、低延时、高品质的音视频互动解决方案。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档