jjzjj

微信原生组件|基于小程序实现音视频通话

ZEGO即构开发者 2023-03-28 原文

1 微信小程序原生推拉流组件功能简介

本文将介绍如何使用微信小程序原生推拉流组件 <live-pusher> 和 <live-player> 进行推拉流,快速实现一个简单的实时音视频通话。

由于微信小程序原生推拉流组件使用起来比较复杂,推荐开发者使用即构封装的音视频SDK <zego-push> 和 <zego-player> 组件实现视频通话,可参考 实现视频通话

2 实现微信小程序音视频通话的前提条件

在实现基本的实时音视频功能之前,请确保:

3 即构音视频SDK实现流程

用户通过 ZEGO Express SDK 即构音视频SDK进行视频通话的基本流程为:

用户 A、B 加入房间,用户 B 预览并将音视频流推送到 ZEGO 云服务(推流),用户 A 收到用户 B 推送音视频流的通知之后,在通知中播放用户 B 的音视频流(拉流)。

3.1 配置微信小程序后台

在初始化 音视频SDK 前,需要在 微信公众平台 中进行如下配置:

  • 服务器域名配置:在“小程序后台 > 开发管理 > 开发设置 > 服务器域名”中,按照协议分类,将即构 Server 地址、LogUrl、以及用户业务需要用到的地址填到指定的“request合法域名”或“socket合法域名”中。

  • 相关功能开启:在“小程序后台 > 开发管理 > 接口设置 > 接口权限”中,打开 实时播放音视频流实时录制音视频流 功能开关。

3.2 即构音视频SDK初始化

1. 创建音视频通话界面

根据音视频场景需要,为您的项目创建音视频通话的用户界面。我们推荐您在项目中添加如下元素:

  • 本地预览窗口
  • 远端视频窗口
  • 结束按钮

小程序推流组件 <live-pusher> 中的 "video-width" 和 "video-height" 存在兼容性问题,可能会出现设置不生效的情况。

参考界面代码:

<view wx:if="{{canShow== 1}}" class="">
  <view class="containerBase">
    <live-pusher class="testpusher" 
    wx:if="{{pusher.url}}" 
    url="{{pusher.url}}"  
    mode="{{pusher.mode}}"
    autopush="{{pusher.autopush}}"
    enable-camera="{{pusher.enableCamera}}"
    enable-mic="{{pusher.enableMic}}"
    muted="{{!pusher.enableMic}}"
    enable-agc="{{pusher.enableAgc}}"
    enable-ans="{{pusher.enableAns}}"
    zoom="{{pusher.enableZoom}}"
    min-bitrate="{{pusher.minBitrate}}"
    max-bitrate="{{pusher.maxBitrate}}"
    video-width="{{pusher.videoWidth}}"
    video-height="{{pusher.videoHeight}}"
    beauty="{{pusher.beautyLevel}}"
    whiteness="{{pusher.whitenessLevel}}"
    orientation="{{pusher.videoOrientation}}"
    device-position="{{pusher.frontCamera}}"
    remote-mirror="{{pusher.enableRemoteMirror}}"
    local-mirror="{{pusher.localMirror}}"
    background-mute="{{pusher.enableBackgroundMute}}"
    audio-quality="{{pusher.audioQuality}}"
    audio-volume-type="{{pusher.audioVolumeType}}"
    audio-reverb-type="{{pusher.audioReverbType}}"
    waiting-image="{{pusher.waitingImage}}"
    beauty-style="{{pusher.beautyStyle}}"
    filter="{{pusher.filter}}"
    bindstatechange="onPushStateChange" 
    bindaudiovolumenotify="bindaudiovolumenotify"  
    bindnetstatus="onPushNetStateChange"
    waiting-image="https://storage.zego.im/downloads/pause_publish.png"></live-pusher>
      <live-player  wx:for="{{playerList}}" wx:key="streamID" id="{{item.id}}" 
      src= "{{item.url}}"
      mode= "RTC"
      autoplay= "{{item.autoplay}}"
      mute-audio= "{{item.muteAudio}}"
      mute-video= "{{item.muteVideo}}"
      orientation= "{{item.orientation}}"
      object-fit= "{{item.objectFit}}"
      min-cache= "{{item.minCache}}"
      max-cache= "{{item.maxCache}}"
      sound-mode= "{{item.soundMode}}"
      enable-recv-message= "{{item.enableRecvMessage}}"
      auto-pause-if-navigate= "{{item.autoPauseIfNavigate}}"
      auto-pause-if-open-native= "{{item.autoPauseIfOpenNative}}" enable-metadata="true" bindmetadatachange="binddatachange"  bindstatechange="onPlayStateChange" bindnetstatus="onPlayNetStateChange"></live-player>
  </view>
  <view class="index-container">
    <view class='input-container'>
      <input value="{{roomID}}" bindinput="bindKeyInput" placeholder="请输入房间 ID" placeholder-style='color: #b3b3b3; font-size: 14px;' class="room-input" />
      <text class="tip"></text>
    </view>
    <view class="button-container">
      <button bindtap="openRoom" data-role="1" data-option="videoAndAudio" hover-class="none" class="openRoom">
        加入房间(推流)
      </button>
     
      
      <button bindtap="logout" hover-class="none">退出房间</button>
    </view>
  </view>
</view>
<view class="settings">
  <button wx:if="{{canShow==0}}" open-type="openSetting" bindopensetting="settingCallback">
    授权使用摄像头和麦克风
  </button>
</view>

2. 创建音视频SDK引擎

创建 ZegoExpressEngine 引擎实例,将申请到的 AppID 传入参数 “appID”,将获取到的 Server 地址传入参数 “server”。

// 初始化实例
zg = new ZegoExpressEngine(appID, server);

如果需要注册回调,开发者可根据实际需要,实现 ZegoEvent 中的某些方法,创建引擎后可通过调用 on 接口设置回调。

zg.on('roomStateUpdate', (roomID, state, errorCode, extendedData) => {
    if (state == 'DISCONNECTED') {
        // 与房间断开了连接
	// ...
    }

    if (state == 'CONNECTING') {
        // 与房间尝试连接中
	// ...
    }

    if (state == 'CONNECTED') {
        // 与房间连接成功
	// ...
    }
})

3.3 登录音视频房间

1. 获取房间登录 Token

登录房间需要用于验证身份的 Token,获取方式请参考 用户权限控制。如需快速调试,建议使用控制台生成的临时 Token,生成临时 Token 的具体操作请参考 控制台 - 项目管理

2. 登录音视频房间

您可以调用 SDK 的 loginRoom 接口,传入房间 ID 参数 “roomID”、“token” 和用户参数 “user”,登录房间。您可通过监听 roomStateUpdate 回调实时监控自己在本房间内的连接状态,具体请参考 4.1 常见通知回调 中的“4.1.1 我在房间内的连接状态变化通知”。

roomID 和 user 的参数由您本地生成,但是需要满足以下条件:

  • 同一个 AppID 内,需保证 “roomID” 全局唯一。
  • 同一个 AppID 内,需保证 “userID” 全局唯一,建议开发者将 “userID” 与自己业务的账号系统进行关联。

为避免错过任何通知,您需要在登录房间前先设置所有的监听回调(如房间状态、用户状态、流状态、推拉流状态等),具体请参考 4.1 常见通知回调

// 登录房间,成功则返回 true
const result = await zg.loginRoom(roomID, token, {userID, userName});

3.4 将自己的音视频流推送到 ZEGO 即构音视频云

3.4.1 初始化小程序组件实例

调用 initContext 接口初始化小程序组件。

小程序组件中用于存储推流属性 pusher 和拉流属性列表 playerList 两个字段需要传给 SDK,SDK 后续将通过传入的两个字段对相应的推拉流作状态及视图更新处理。

zg.initContext({
     wxContext: this,
     pushAtr: "pusher", // 对象名,对象属性与 live-pusher 中的属性为映射关系
     playAtr: "playerList" // 对象名,对象属性与 live-player 中的属性为映射关系
})

即构音视频SDK 在内部会对推拉流实例进行操作以及视图更新,开发者无需保存推拉流实例和调用小程序 setData 接口更新视图,避免与 SDK 发生冲突。后续可通过 getPusherInstancegetPlayerInstance 接口获取推拉流实例。

3.4.2 创建对应业务场景的 WXML

根据您的业务场景需求,编写 WXML 文件,创建推拉流组件 <live-pusher> 和 <live-player>。

  • <live-pusher> 组件用于小程序的实时推送音视频流功能。
  • <live-player> 组件用户小程序的实时播放音视频流功能。

WXML 的具体含义与用法请参考微信官网文档中的介绍 WXML

WXML 中的 pusher 与 playerList,必须与初始化小程序组件 initContext 中定义的这两个字段属性名保持一致,后续 SDK 调用推拉流接口之后才能正确地进行状态及视图更新。

bindstatechange 表示播放状态变化事件;bindaudiovolumenotify 表示播放音量大小通知;bindnetstatus 表示网络状态通知。

<live-pusher class="testpusher" 
    wx:if="{{pusher.url}}" 
    url="{{pusher.url}}"  
    mode="{{pusher.mode}}"
    autopush="{{pusher.autopush}}"
    enable-camera="{{pusher.enableCamera}}"
    enable-mic="{{pusher.enableMic}}"
    muted="{{!pusher.enableMic}}"
    enable-agc="{{pusher.enableAgc}}"
    enable-ans="{{pusher.enableAns}}"
    enable-ear-monitor="{{pusher.enableEarMonitor}}"
    auto-focus="{{pusher.enableAutoFocus}}"
    zoom="{{pusher.enableZoom}}"
    min-bitrate="{{pusher.minBitrate}}"
    max-bitrate="{{pusher.maxBitrate}}"
    video-width="{{pusher.videoWidth}}"
    video-height="{{pusher.videoHeight}}"
    beauty="{{pusher.beautyLevel}}"
    whiteness="{{pusher.whitenessLevel}}"
    orientation="{{pusher.videoOrientation}}"
    aspect="{{pusher.videoAspect}}"
    device-position="{{pusher.frontCamera}}"
    remote-mirror="{{pusher.enableRemoteMirror}}"
    local-mirror="{{pusher.localMirror}}"
    background-mute="{{pusher.enableBackgroundMute}}"
    audio-quality="{{pusher.audioQuality}}"
    audio-volume-type="{{pusher.audioVolumeType}}"
    audio-reverb-type="{{pusher.audioReverbType}}"
    waiting-image="{{pusher.waitingImage}}"
    beauty-style="{{pusher.beautyStyle}}"
    filter="{{pusher.filter}}"
    bindstatechange="onPushStateChange" 
    bindaudiovolumenotify="bindaudiovolumenotify"  
    bindnetstatus="onPushNetStateChange"
    waiting-image="https://storage.zego.im/downloads/pause_publish.png">
</live-pusher>
<live-player  wx:for="{{playerList}}" wx:key="streamID" id="{{item.id}}" 
      src= "{{item.url}}"
      mode= "RTC"
      autoplay= "{{item.autoplay}}"
      mute-audio= "{{item.muteAudio}}"
      mute-video= "{{item.muteVideo}}"
      orientation= "{{item.orientation}}"
      object-fit= "{{item.objectFit}}"
      min-cache= "{{item.minCache}}"
      max-cache= "{{item.maxCache}}"
      sound-mode= "{{item.soundMode}}"
      enable-recv-message= "{{item.enableRecvMessage}}"
      auto-pause-if-navigate= "{{item.autoPauseIfNavigate}}"
      auto-pause-if-open-native= "{{item.autoPauseIfOpenNative}}" enable-metadata="true" bindmetadatachange="binddatachange"  bindstatechange="onPlayStateChange" bindnetstatus="onPlayNetStateChange">
</live-player>

3.4.3 推送音视频流到 ZEGO 即构音视频云

必须完成初始化小程序组件实例和创建业务场景的 WXML 之后,才能调用 SDK 接口创建推流和拉流实例。

用户调用 SDK 的 createPusher 接口创建推流实例,并通过调用实例对象上的 start 接口,传入流 ID 参数 “streamID”。您可通过监听 publisherStateUpdate 回调知晓推流是否成功,具体请参考 4.1 常见通知回调 中的“4.1.4 用户推送音视频流的状态通知”。

“streamID” 由您本地生成,但是需要保证:

  • 同一个 AppID 下,“streamID” 全局唯一。如果同一个 AppID 下,不同用户各推了一条 “streamID” 相同的流,后推流的用户推流失败。
  • “streamID” 长度不超过 256 字节的字符串。仅支持数字,英文字符和 “~”,“!”,“@”,“$”,“%”,“^”,“&”,“*”,“(”,“)”,“_”,“+”,“=”,“-”,“`”,“;”,“’”,“,”,“.”,“<”,“>”,“/”,“\”。
// 推流方登录房间成功后触发推流
 const pusher = zg.createPusher();
 pusher.start("streamID_xxx");

3.5 拉取其他用户的音视频

进行视频通话时,我们需要拉取到其他用户的音视频。

用户先调用 getPlayerInstance接口,根据传入的流 ID 参数 “streamID”,获取 streamID 对应的拉流实例,然后通过调用拉流实例对象的 play 接口开始拉流。您可通过监听 playerStateUpdate 回调知晓是否成功拉取音视频,具体请参考 4.1 常见通知回调 中的“4.1.5 用户拉取音视频流的状态通知”。

远端用户推送的 “streamID” 可以从 roomStreamUpdate 回调中获得,具体回调设置请参考 4.1 常见通知回调 中的“4.1.3 房间内流状态变更的通知”。

// 在 SDK 的回调 roomStreamUpdate 中获取拉流 streamID
// 当用户加入或离开房间时,该事件被触发
zg.on("roomStreamUpdate", (roomID, updateType, streamList) => {
    console.log("roomStreamUpdate", roomID, updateType, streamList);
    if (updateType === "ADD") {
        streamList.forEach(i => {
              zg.getPlayerInstance(i.streamID).play();
        })
    } else {
       streamList.forEach(i => {
              zg.getPlayerInstance(i.streamID).stop();
       })
    }
});

4 小程序音视频通话的常用功能

4.1 常见音视频房间通知回调

4.1.1 我在房间内的连接状态变化通知

roomStateUpdate:本地调用 loginRoom 加入房间时,您可通过监听该回调实时监控自己在本房间内的连接状态。

用户可以在回调中根据不同状态处理业务逻辑。

zg.on('roomStateUpdate', (roomID, state, errorCode, extendedData) => {
    if (state == 'DISCONNECTED') {
        // 与房间断开了连接
	// ...
    }

    if (state == 'CONNECTING') {
        // 与房间尝试连接中
	// ...
    }

    if (state == 'CONNECTED') {
        // 与房间连接成功
	// ...
    }
})

4.1.2 其他用户进出房间的通知

roomUserUpdate:同一房间内的其他用户进出房间时,您可通过此回调收到通知。登录房间后,当房间内有用户新增或删除时,SDK 会通过该回调通知。

只有调用 loginRoom 接口登录房间时传入 ZegoRoomConfig 配置,且 “userUpdate” 参数取值为 “true” 时,用户才能收到 roomUserUpdate 回调。

// 用户状态更新回调
zg.on('roomUserUpdate', (roomID, updateType, userList) => {
    console.warn(
        `roomUserUpdate: room ${roomID}, user ${updateType === 'ADD' ? 'added' : 'left'} `,
        JSON.stringify(userList),
    );
});

4.1.3 房间内流状态变更的通知

roomStreamUpdate:流状态更新回调。登录房间后,当房间内有用户新推送或删除音视频流时,SDK 会通过该回调通知。

// 流状态更新回调
zg.on('roomStreamUpdate', async (roomID, updateType, streamList, extendedData) => {
    if (updateType == 'ADD') {
        // 流新增,开始拉流
    } else if (updateType == 'DELETE') {
        // 流删除,停止拉流
    }
});

4.1.4 用户推送音视频流的状态通知

  • 推流状态事件

微信小程序会在 <live-pusher> 的 bindstatechange 绑定的方法中通知出推流状态事件,开发者需要:

a. 在 bindstatechange 绑定的回调函数中,调用 SDK 的 updatePlayerState 接口将推流状态事件透传给 SDK。

b. 在 SDK 的 publisherStateUpdate 回调中处理推流的开始、失败状态。

// live-pusher 绑定推流事件
onPushStateChange(e) {
    // 透传推流事件给 SDK
    zg.updatePlayerState(this.data.publishStreamID, e);
},

// 推流后,服务器主动推过来的,流状态更新
// NO_PUBLISH:未推流状态,PUBLISH_REQUESTING:正在请求推流状态,PUBLISHING:正在推流状态
// state: "PUBLISHING" | "NO_PUBLISH" | "PUBLISH_REQUESTING";
zg.on("publisherStateUpdate", (result) => {
    console.log("publishStateUpdate", result.state);
});
  • 推流网络事件

微信小程序会在 <live-pusher> 的 bindnetstatus 绑定的方法中通知出推流网络事件,开发者需要在对应的小程序回调中,调用 SDK 的 updatePlayerNetStatus 接口将推流网络事件透传给 SDK。

// live-pusher 绑定网络状态事件
onPushNetStateChange(e) {
    //透传网络状态事件给 SDK
    zg.updatePlayerNetStatus(this.data.publishStreamID, e);
},


// SDK 推流网络质量回调
zg.on("publishQualityUpdate", (streamID, publishStats) => {
    console.log("publishQualityUpdate", streamID, publishStats);
});

4.1.5 用户拉取音视频流的状态通知

  • 拉流状态事件

微信小程序会在 <live-player> 的 bindstatechange 绑定的方法中通知出拉流状态事件,开发者需要:

a. 在 bindstatechange 绑定的回调函数中,调用 SDK 的 updatePlayerState 接口将拉流状态事件透传给 SDK。

b. 在 SDK 提供的 playerStateUpdate 回调中处理拉流的开始或失败状态。

// live-player 绑定的拉流事件
onPlayStateChange(e) {
    // 透传拉流事件给 SDK
    zg.updatePlayerState(e.currentTarget.id, e);
},

// 服务器主动推过来的流的播放状态
// 视频播放状态通知;state: "NO_PLAY" | "PLAY_REQUESTING" | "PLAYING";
zg.on("playerStateUpdate", (result) => {
    console.log("playStateUpdate", result.state);
});
  • 拉流网络事件

微信小程序会在 <live-player> 的 bindnetstatus 绑定的方法中通知出拉流网络事件,开发者需要在对应的小程序回调中,调用 SDK 的 updatePlayerNetStatus 接口将推流网络事件透传给 SDK。

// live-player 绑定网络状态事件
onPlayNetStateChange(e) {
    // 透传网络状态事件给 SDK
    zg.updatePlayerNetStatus(playStreamID, e);
},

// SDK 拉流网络质量回调
zg.on("playQualityUpdate", (playStreamID, playStats) => {
    console.log("playQualityUpdate", playStreamID, playStats);
});

4.2 停止fang jian音视频通话

4.2.1 停止推送/拉取音视频流

1. 停止推流

调用 SDK 的 getPusherInstance 接口获取推流实例,并调用推流实例的 stop 方法停止推流。

// 停止推流
zg.getPusherInstance().stop();

2. 停止拉流

调用 SDK 的 getPlayerInstance 接口获取拉流实例,并调用推流实例的 stop 方法停止拉流。

// 停止拉流
zg.getPlayerInstance(streamID).stop();

4.2.2 退出房间

调用 SDK 的 logoutRoom 接口退出房间。

zg.logoutRoom(roomID);

5 调试视频通话功能

在真机中运行项目,运行成功后,可以看到本端视频画面。

为方便体验,ZEGO 提供了一个 Web 端调试示例 ,在该页面下,输入相同的 AppID、RoomID,输入一个不同的 UserID,即可加入同一房间与真机设备互通。当成功开始音视频通话时,可以听到远端的音频,看到远端的视频画面。

6 视频通话 API 调用时序

整个推拉流过程的 API 调用时序可参考下图:

有关微信原生组件|基于小程序实现音视频通话的更多相关文章

  1. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  2. 叮咚买菜基于 Apache Doris 统一 OLAP 引擎的应用实践 - 2

    导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵

  3. 华为OD机试用Python实现 -【明明的随机数】 2023Q1A - 2

    华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o

  4. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  5. MIMO-OFDM无线通信技术及MATLAB实现(1)无线信道:传播和衰落 - 2

     MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO

  6. 微信小程序通过字典表匹配对应数据 - 2

    前言一般来说,前端根据后台返回code码展示对应内容只需要在前台判断code值展示对应的内容即可,但要是匹配的code码比较多或者多个页面用到时,为了便于后期维护,后台就会使用字典表让前端匹配,下面我将在微信小程序中通过wxs的方法实现这个操作。为什么要使用wxs?{{method(a,b)}}可以看到,上述代码是一个调用方法传值的操作,在vue中很常见,多用于数据之间的转换,但由于微信小程序诸多限制的原因,你并不能优雅的这样操作,可能有人会说,为什么不用if判断实现呢?但是if判断的局限性在于如果存在数据量过大时,大量重复性操作和if判断会让你的代码显得异常冗余。wxswxs相当于是一个独立

  7. 计算机毕业设计ssm+vue基本微信小程序的小学生兴趣延时班预约小程序 - 2

    项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU

  8. 微信小程序开发入门与实战(Behaviors使用) - 2

    @作者:SYFStrive @博客首页:HomePage📜:微信小程序📌:个人社区(欢迎大佬们加入)👉:社区链接🔗📌:觉得文章不错可以点点关注👉:专栏连接🔗💃:感谢支持,学累了可以先看小段由小胖给大家带来的街舞👉微信小程序(🔥)目录自定义组件-behaviors    1、什么是behaviors    2、behaviors的工作方式    3、创建behavior    4、导入并使用behavior    5、behavior中所有可用的节点    6、同名字段的覆盖和组合规则总结最后自定义组件-behaviors    1、什么是behaviorsbehaviors是小程序中,用于实现

  9. kvm虚拟机安装centos7基于ubuntu20.04系统 - 2

    需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc

  10. 动漫制作技巧如何制作动漫视频 - 2

    动漫制作技巧是很多新人想了解的问题,今天小编就来解答与大家分享一下动漫制作流程,为了帮助有兴趣的同学理解,大多数人会选择动漫培训机构,那么今天小编就带大家来看看动漫制作要掌握哪些技巧?一、动漫作品首先完成草图设计和原型制作。设计草图要有目的、有对象、有步骤、要形象、要简单、符合实际。设计图要一致性,以保证制作的顺利进行。二、原型制作是根据设计图纸和制作材料,可以是手绘也可以是3d软件创建。在此步骤中,要注意的问题是色彩和平面布局。三、动漫制作制作完成后,加工成型。完成不同的表现形式后,就要对设计稿进行加工处理,使加工的难易度降低,并得到一些基本准确的概念,以便于后续的大样、准确的尺寸制定。四、

随机推荐