『从零开始学小程序』媒体组件video组件

Posted starry陆离

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了『从零开始学小程序』媒体组件video组件相关的知识,希望对你有一定的参考价值。

👨‍🎓作者简介:一位喜欢写作,计科专业大三菜鸟
🏡个人主页:starry陆离
🕒首发日期:2022年9月15日星期四
如果文章有帮到你的话记得点赞👍+收藏💗支持一下哦

『从零开始学小程序』媒体组件video组件

1.简介

多媒体包括音频、视频和相机等,为了更好地在小程序中使用这些多媒体功能,微信官方也为开发者提供了一系列多媒体组件和API接口。多媒体组件如下所示:

  • video组件:视频组件
  • camera组件:相机组件
  • audio组件:音频组件
  • image组件:图片组件

video,视频组件。组件的属性可以实现视频的播放暂停,发送弹幕,获取视频所处位置等。

2.简单案例

属性类型默认值必填说明
srcstring要播放视频的资源地址,支持网络路径、本地临时路径、云文件ID

<video src="cloud://cloud1-0gq03z948cf60a2f.636c-cloud1-0gq03z948cf60a2f-1313616796/a2.mp4"></video>

3.自动循环播放

官方组件还提供了是否自动播放和是否循环播放的属性。通过设置autoplayloop的值来实现相应功能。

属性类型默认值必填说明
autoplaybooleanfalse是否自动播放
loopbooleanfalse是否循环播放
<video src="cloud://cloud1-0gq03z948cf60a2f.636c-cloud1-0gq03z948cf60a2f-1313616796/a2.mp4"
autoplay="true" loop="true"></video>

4.容器适配

可以看到我们现在的视频是有黑边的这很影响视觉体验,那么如何去掉黑边呢,可以通过object-fit属性来调整视频和video容器的大小关系。

属性类型默认值必填说明
object-fitstringcontain当视频大小与 video 容器大小不一致时,视频的表现形式

object-fit属性 有如下取值:

合法值说明
contain包含
fill填充
cover覆盖

通过使用三种取值我发现取值为fill时,视频会去通过拉伸去适配容器;而取值为cover时会等比缩放视频,然后裁剪多余的部分去适配容器

5.小窗模式

属性类型默认值必填说明
picture-in-picture-modestring/Array设置小窗模式: push, pop,空字符串或通过数组形式设置多种模式(如: [“push”, “pop”])

video 小窗支持以下三种触发模式(在组件上设置 picture-in-picture-mode 属性):

  1. push 模式,即从当前页跳转至下一页时出现小窗(页面栈push)
  2. pop 模式,即离开当前页面时触发(页面栈pop)
  3. 以上两种路由行为均触发小窗

此外,小窗还支持以下特性:

  • 小窗容器尺寸会根据原组件尺寸自动判断
  • 点击小窗,用户会被导航回小窗对应的播放器页面
  • 小窗出现后,用户可点击小窗右上角的关闭按钮或调用 context.exitPictureInPicture() 接口关闭小窗

当播放器进入小窗模式后,播放器所在页面处于 hide 状态(触发 onHide 生命周期),该页面不会被销毁。当小窗被关闭时,播放器所在页面会被 unload (触发 onUnload 生命周期)。

注意:在虚拟机上调试是无法看到小窗效果的,在手机真机上是可以的。

<!--pages/video/video.wxml-->
<video src="cloud://cloud1-0gq03z948cf60a2f.636c-cloud1-0gq03z948cf60a2f-1313616796/a2.mp4"
autoplay="true" loop="true" object-fit="cover" picture-in-picture-mode="push"></video>

<view class="container">
  <button type="primary" size="mini" bindtap="gotoPrevideo">跳转到prevideo界面</button>
  <button type="primary" size="mini" style="margin: 10px;" bindtap="gotoNextvideo">跳转到nextvideo界面</button>
</view>

6.视频弹幕案例

本案例针对video组件的实践应用场景编写了一个简单的发送视频弹幕的页面,其中使用到了播放视频相关的API函数:

可以看到我们弹幕中实现了静态的设置第几秒出现弹幕(绿色的弹幕)和按钮点击获取文本框里的文字然后输出到弹幕。

6.1wxml设计

具体怎么实现的呢,我来一一分说:首先在wxml中我们还是定义了一个video容器,并为之取了一个id(id="myVideo"),其次我们还用到了如下的属性:

属性类型默认值必填说明
danmu-listArray.弹幕列表
danmu-btnbooleanfalse是否显示弹幕按钮,只在初始化时有效,不能动态变更
enable-danmubooleanfalse是否展示弹幕,只在初始化时有效,不能动态变更

除此之外我们还需要定义一个文本框来获取用户输入,和一个监听按钮来发送弹幕,代码如下:

 <input bindblur="bindInputBlur" type="text" placeholder="输入弹幕内容" style="margin: 10px;"/>
 <button type="primary" size="mini" bindtap="bindSendDanmu">发送弹幕</button>

6.2VideoContext类方法

VideoContext 实例,可通过 wx.createVideoContext获取。

VideoContext 通过 id 跟一个 video 组件绑定,操作对应的video组件。(这是为什么我们要在wxml中给video容器加一个id属性)

/**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady() 
    this.videoContext=wx.createVideoContext('myVideo')
  ,

在这里我们需要用到VideoContext.sendDanmu(Object data)方法来发送弹幕

在这里我们定义两个监听函数bindInputBlurbindSendDanmu

  • bindInputBlur:用来获取用户在文本框组件上输入的文字
  • bindSendDanmu:用来监听按钮发送弹幕

如此我们就大功告成了,还是很简单的,大家可以看看动图的效果。

bindInputBlur(e)
    this.inputValue=e.detail.value;
  ,

  bindSendDanmu()
    this.videoContext.sendDanmu(
      text:this.inputValue,
      color:'#ff00ff'
    )
  ,

6.2完整代码

<!--pages/video/video.wxml-->
<video id="myVideo" src="cloud://cloud1-0gq03z948cf60a2f.636c-cloud1-0gq03z948cf60a2f-1313616796/a2.mp4"
autoplay="true" loop="true" object-fit="cover" picture-in-picture-mode="push"
danmu-btn="true" danmu-list="danmuList" enable-danmu="true"></video>

<view class="container">
  <input bindblur="bindInputBlur" type="text" placeholder="输入弹幕内容" style="margin: 10px;"/>
  <button type="primary" size="mini" bindtap="bindSendDanmu">发送弹幕</button>
  <button type="primary" size="mini" style="margin: 10px;" bindtap="gotoPrevideo">跳转到prevideo界面</button>
  <button type="primary" size="mini" style="margin: 10px;" bindtap="gotoNextvideo">跳转到nextvideo界面</button>
</view>


// pages/video/video.js
Page(

  /**
   * 页面的初始数据
   */
  inputValue:'',
  data: 
    danmuList:[
      text:'第1s出现的弹幕',color:'#ff0000',time:1,
      text:'第3s出现的弹幕',color:'#00ff00',time:3,
    ]
  ,
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady() 
    this.videoContext=wx.createVideoContext('myVideo')
  ,

  bindInputBlur(e)
    this.inputValue=e.detail.value;
  ,

  bindSendDanmu()
    this.videoContext.sendDanmu(
      text:this.inputValue,
      color:'#ff00ff'
    )
  ,

  gotoPrevideo:function()
    wx.navigateTo(
      url: '../prevideo/prevideo',
    )
  ,
  
  gotoNextvideo:function()
    wx.navigateTo(
      url: '../nextvideo/nextvideo',
    )
  

)
/* pages/video/video.wxss */
video
  width: 100%;
  height: 250px;
  border-radius: 10px;

.container
  display: flex;
  text-align: center;
  justify-items: center;
  vertical-align: center;

7.小试牛刀

从零开始手写Tomcat的教程14节----服务器组件(Server)和服务组件(Service)

从零开始手写Tomcat的教程14节----服务器组件Server和服务组件Service



服务器组件

public interface Server 


    // ------------------------------------------------------------- Properties


    /**
     * Return descriptive information about this Server implementation and
     * the corresponding version number, in the format
     * <code>&lt;description&gt;/&lt;version&gt;</code>.
     */
    public String getInfo();


    /**
     * Return the global naming resources.
     */
    public NamingResources getGlobalNamingResources();


    /**
     * Set the global naming resources.
     * 
     * @param namingResources The new global naming resources
     */
    public void setGlobalNamingResources
        (NamingResources globalNamingResources);


    /**
     * Return the port number we listen to for shutdown commands.
     */
    public int getPort();


    /**
     * Set the port number we listen to for shutdown commands.
     *
     * @param port The new port number
     */
    public void setPort(int port);


    /**
     * Return the shutdown command string we are waiting for.
     */
    public String getShutdown();


    /**
     * Set the shutdown command we are waiting for.
     *
     * @param shutdown The new shutdown command
     */
    public void setShutdown(String shutdown);


    // --------------------------------------------------------- Public Methods


    /**
     * Add a new Service to the set of defined Services.
     *
     * @param service The Service to be added
     */
    public void addService(Service service);


    /**
     * Wait until a proper shutdown command is received, then return.
     */
    public void await();


    /**
     * Return the specified Service (if it exists); otherwise return
     * <code>null</code>.
     *
     * @param name Name of the Service to be returned
     */
    public Service findService(String name);


    /**
     * Return the set of Services defined within this Server.
     */
    public Service[] findServices();


    /**
     * Remove the specified Service from the set associated from this
     * Server.
     *
     * @param service The Service to be removed
     */
    public void removeService(Service service);

    /**
     * Invoke a pre-startup initialization. This is used to allow connectors
     * to bind to restricted ports under Unix operating environments.
     *
     * @exception LifecycleException If this server was already initialized.
     */
    public void initialize()
    throws LifecycleException;



StandardServer类


initialize方法

    /**
     * Invoke a pre-startup initialization. This is used to allow connectors
     * to bind to restricted ports under Unix operating environments.
     */
    public void initialize()
    throws LifecycleException 
        if (initialized)
            throw new LifecycleException (
                sm.getString("standardServer.initialize.initialized"));
        initialized = true;

        // Initialize our defined Services
        for (int i = 0; i < services.length; i++) 
            services[i].initialize();
        
    


start方法

    public void start() throws LifecycleException 

        // Validate and update our current component state
        if (started)
            throw new LifecycleException
                (sm.getString("standardServer.start.started"));

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);

        lifecycle.fireLifecycleEvent(START_EVENT, null);
        started = true;

        // Start our defined Services
        synchronized (services) 
            for (int i = 0; i < services.length; i++) 
                if (services[i] instanceof Lifecycle)
                    ((Lifecycle) services[i]).start();
            
        

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);

    


stop方法

    public void stop() throws LifecycleException 

        // Validate and update our current component state
        if (!started)
            throw new LifecycleException
                (sm.getString("standardServer.stop.notStarted"));

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);

        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
        started = false;

        // Stop our defined Services
        for (int i = 0; i < services.length; i++) 
            if (services[i] instanceof Lifecycle)
                ((Lifecycle) services[i]).stop();
        

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);

    


await方法

    public void await() 

        // Set up a server socket to wait on
        ServerSocket serverSocket = null;
        try 
            serverSocket =
                new ServerSocket(port, 1,
                                 InetAddress.getByName("127.0.0.1"));
         catch (IOException e) 
            System.err.println("StandardServer.await: create[" + port
                               + "]: " + e);
            e.printStackTrace();
            System.exit(1);
        

        // Loop waiting for a connection and a valid command
        while (true) 

            // Wait for the next connection
            Socket socket = null;
            InputStream stream = null;
            try 
                socket = serverSocket.accept();
                socket.setSoTimeout(10 * 1000);  // Ten seconds
                stream = socket.getInputStream();
             catch (AccessControlException ace) 
                System.err.println("StandardServer.accept security exception: "
                                   + ace.getMessage());
                continue;
             catch (IOException e) 
                System.err.println("StandardServer.await: accept: " + e);
                e.printStackTrace();
                System.exit(1);
            

            // Read a set of characters from the socket
            StringBuffer command = new StringBuffer();
            int expected = 1024; // Cut off to avoid DoS attack
            while (expected < shutdown.length()) 
                if (random == null)
                    random = new Random(System.currentTimeMillis());
                expected += (random.nextInt() % 1024);
            
            while (expected > 0) 
                int ch = -1;
                try 
                    ch = stream.read();
                 catch (IOException e) 
                    System.err.println("StandardServer.await: read: " + e);
                    e.printStackTrace();
                    ch = -1;
                
                if (ch < 32)  // Control character or EOF terminates loop
                    break;
                command.append((char) ch);
                expected--;
            

            // Close the socket now that we are done with it
            try 
                socket.close();
             catch (IOException e) 
                ;
            

            // Match against our command string
            boolean match = command.toString().equals(shutdown);
            if (match) 
                break;
             else
                System.err.println("StandardServer.await: Invalid command '" +
                                   command.toString() + "' received");

        

        // Close the server socket and return
        try 
            serverSocket.close();
         catch (IOException e) 
            ;
        

    


Service接口

public interface Service 


    // ------------------------------------------------------------- Properties


    /**
     * Return the <code>Container</code> that handles requests for all
     * <code>Connectors</code> associated with this Service.
     */
    public Container getContainer();


    /**
     * Set the <code>Container</code> that handles requests for all
     * <code>Connectors</code> associated with this Service.
     *
     * @param container The new Container
     */
    public void setContainer(Container container);


    /**
     * Return descriptive information about this Service implementation and
     * the corresponding version number, in the format
     * <code>&lt;description&gt;/&lt;version&gt;</code>.
     */
    public String getInfo();


    /**
     * Return the name of this Service.
     */
    public String getName();


    /**
     * Set the name of this Service.
     *
     * @param name The new service name
     */
    public void setName(String name);


    /**
     * Return the <code>Server</code> with which we are associated (if any).
     */
    public Server getServer();


    /**
     * Set the <code>Server</code> with which we are associated (if any).
     *
     * @param server The server that owns this Service
     */
    public void setServer(Server server);

    
    // --------------------------------------------------------- Public Methods


    /**
     * Add a new Connector to the set of defined Connectors, and associate it
     * with this Service's Container.
     *
     * @param connector The Connector to be added
     */
    public void addConnector(Connector connector);


    /**
     * Find and return the set of Connectors associated with this Service.
     */
    public Connector[] findConnectors();


    /**
     * Remove the specified Connector from the set associated from this
     * Service.  The removed Connector will also be disassociated from our
     * Container.
     *
     * @param connector The Connector to be removed
     */
    public void removeConnector(Connector connector);

    /**
     * Invoke a pre-startup initialization. This is used to allow connectors
     * to bind to restricted ports under Unix operating environments.
     *
     * @exception LifecycleException If this server was already initialized.
     */
    public void initialize()
    throws LifecycleException;



StandardService类


Connector和Container

    public void setContainer(Container container) 

        Container oldContainer = this.container;
        if ((oldContainer != null) && (oldContainer instanceof Engine))
            ((Engine) oldContainer).setService(null);
        this.container = container;
        if ((this.container != null) && (this.container instanceof Engine))
            ((Engine) this.container).setService(this);
        if (started && (this.container != null) &&
                (this.container instanceof Lifecycle)) 
            try 
                ((Lifecycle) this.container).start();
             catch (LifecycleException e) 
                ;
            
        
        synchronized (connectors) 
            for (int i = 0; i < connectors.length; i++)
                connectors[i].setContainer(this.container);
        
        if (started && (oldContainer != null) &&
            (oldContainer instanceof Lifecycle)) 
            try 
                ((Lifecycle) oldContainer).stop();
             catch (LifecycleException e) 
                ;
            
        

        // Report this property change to interested listeners
        support.firePropertyChange("container", oldContainer, this.container);

    

   public void addConnector(Connector connector) 

        synchronized (connectors) 
            connector.setContainer(this.container);
            connector.setService(this);
            Connector results[] = new Connector[connectors.length + 1];
            System.arraycopy(connectors, 0, results, 0, connectors.length);
            results[connectors.length] = connector;
            connectors = results;

            if (initialized) 
                try 
                    connector.initialize();
                 catch (LifecycleException e) 
                    e.printStackTrace(System.err);
                
            

            if (started && (connector instanceof Lifecycle)) 
                try 
                    ((Lifecycle) connector).start();
                 catch (LifecycleException e) 
                    ;
                
            

            // Report this property change to interested listeners
            support.firePropertyChange("connector", null, connector);
        

    

   public void removeConnector(Connector connector) 

        synchronized (connectors) 
            int j = -1;
            for (int i = 0; i < connectors.length; i++) 
                if (connector == connectors[i]) 
                    j = i;
                    break;
                
            
            if (j < 0)
                return;
            if (started && (connectors[j] instanceof Lifecycle)) 
                try 
                    ((Lifecycle) connectors[j]).stop();
                 catch (LifecycleException e) 
                    ;
                
            
            connectors[j].setContainer(null);
            connector.setService(null);
            int k = 0;
            Connector results[] = new Connector[connectors.length - 1];
            for (int i = 0; i < connectors.length; i++) 
                if (i != j)
                    results[k++] = connectors[i];
            
            connectors = results;

            // Report this property change to interested listeners
            support.firePropertyChange("connector", connector, null);
        

    

与生命周期有关的方法

    public void initialize()
    throws LifecycleException 
        if (initialized)
            throw new LifecycleException (
                sm.getString("standardService.initialize.initialized"));
        initialized = true;

        // Initialize our defined Connectors
        synchronized (connectors) 
                以上是关于『从零开始学小程序』媒体组件video组件的主要内容,如果未能解决你的问题,请参考以下文章

跳出小程序 video组件 卡顿黑屏全屏等坑

从零学习微信小程序—— 常用组件

从零学习微信小程序—— 常用组件

微信小程序之video组件与cover-view组件和cover-image组件灵活应用

自己的微信小程序学习笔记——从零开始新建项目

自己的微信小程序学习笔记——从零开始新建项目