Electron + Vue跨平台应用(九)基础技法(三)

Electron + Vue + Vscode构建跨平台应用(一)知识点补充
Electron + Vue + Vscode构建跨平台应用(二)Electron + Vue环境搭建
Electron + Vue + Vscode构建跨平台应用(三)利用webpack搭建vue项目
Electron + Vue + Vscode构建跨平台应用(四)利用Electron-Vue构建Vue应用详解
Electron + Vue + Vscode构建跨平台应用(五)Electron-Vue项目源码分析
Electron + Vue跨平台应用(六)效果还不错的登录页面
Electron + Vue跨平台应用(七)基础技法(一)
Electron + Vue跨平台应用(八)基础技法(二)

  这篇主要对如下内容做个解答

1. 导出模块属性/方法

2. 配置config/index.js中host为0.0.0.0或者localhost的区别

3. Vue项目结构分析
  3.1. build/webpack.dev.conf.js
  3.2. process.env

4. vscode中利用git更新,上传等操作
  4.1 上传
  4.2 更新
  4.3 查看历史记录
  4.4 git的一些图标说明
  4.5 切换分支
  4.6 clone到指定目录
  4.7 windows10上VsCode如何更改Git账户
  4.8 开发分支合并到master分支
  4.9 拉取代码报错:You have not concluded your merge

5. 在vue项目中如何自动切换开发/生成RUL

6. 如何引入外部js文件(非ES6标准/ES6标准通用)

7. npm包管理器中qs模块

8. HTML5中video理解/自动/全屏播放

9. 调试
  9.1 VConsole
  9.2 Chrom / 360浏览器调试面板介绍

10. Vue 深度监听/watch函数和计算属性compute

11. btoa 和 atob 函数的作用


1. 导出模块属性/方法

   node应用是由模块组成的,那么模块之间必然存在将数据暴露给其他模块使用,在暴露数据的时候,需要遵循两个基本规范: CommonJS 模块规范和ES6语法规范

  在CommonJS 规范中,我们使用module.exportsexports来导出数据,通过require来引入数据,在查看源码的时候,我们经常看到这种方式来导入和导出数据;
  在CommonJS 规范中每一个文件就是一个模块,我的理解是相当于java class,那么在这个文件(类)中定义的属性/方法是私有的,类似java的private属性,那么我们就会已module来代表当前文件(类),在这个module里面有一个exports属性,这个exports就相当于对外暴露的接口,当需要对外暴露数据的时候,只需要把对应的数据添加到exports属性上即可;当其他模块需要使用另一个模块数据的时候,可以通过require方法用于加载模块,require方法返回一个对象,通过该对象就可以读取暴露的数据,如

var comJs = require('./sample.js')
vat  xValue = comJs.x

第2行,通过comJs对象获取暴露的x属性

  在ES6语法规范中,我们利用exportexport default导出模块,import导入模块。我们先看下其用法说明

  1. export default表示一个模块的默认输出,所以在一个模块中,export default有且仅有一个; export表示按需导出,所以可以用多个
  2. 使用export向外暴露的成员,只能使用{ }的形式来接收
  3. 导出的时候可以通过as来设置别名
  4. 导出一个变量/对象,应注意导出对象或者变量时不需要使用let或者var来定义,导出对象或者变量时需要注意使用{},如果写为export user则会报错

列举一些常用的导出的例子

// 导出自定义函数
export function add (a, b) {
  return a + b
}

// 导出一个变量/对象,
const user = {name: '1', schole: '1'}
export {user}

// 通过别名的方式来导出
const world = {city: ''}
export {world as earth}

// 定义变量,export defalut来导出
const filterByName = name => {
  if (name.length > 0) {
    let temp = [{name: '5', schoole: '5'}]
    return temp
  }
  return null
}
export default{
  filterByName
}

再列举一些常见的import用法

import xxx  from 'xxx'
import person, {title, content as content1} from './xxx'

2. 配置config/index.js中host为0.0.0.0或者localhost的区别

   首先我们先弄明白config/index.js下host或者port这两个属性的作用是什么

        // Various Dev Server settings
        host: '0.0.0.0', // can be overwritten by process.env.HOST
        port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined

当我们执行npm run dev的时候,会得到下图的提示
在这里插入图片描述
这里的localhost就是index.js文件中的host,后面的端口号就是index.js中的port,当然如果index.js中设定的端口号如8080被占用,则会使用一个新的端口号

   那host为0.0.0.0或者localhost到底有什么区别?我们先说下host为0.0.0.0的含义

0.0.0.0的配置代表本机的所有ip地址,这样做的目的是在同一个局域网下,别的浏览器也可以访问你运行的项目。
举个例子:你配置vue-li项目的config/index.js文件中的host为0.0.0.0,当你运行你的项目之后,别的协同开发的同学就可以在自己的电脑上看到你的项目效果了

此处我们应该注意:关闭掉你的防火墙

   localhost: 他的含义就是绑定到localhost的服务只能被本机访问

3. Vue项目结构分析

  3.1 build/webpack.dev.conf.js

首先我们看下从npm run dev命令说起,他是执行package.json里面的dev命令

"dev": "webpack-dev-server --inline --config build/webpack.dev.conf.js",

从上面的代码我们可以分析出,他会编译webpack.dev.conf.js,那么我们打开它看下(截取部分代码)

const http = require('http'),
    httpProxy = require('http-proxy')
let internalIPAdress, proxyPort
proxyPort = 8000
httpProxy
    .createProxyServer({
        target: `http://${config.dev.host}:${config.dev.port}`
    })
    .listen(proxyPort) // See (†)

const HOST = process.env.HOST
const PORT = process.env.PORT && Number(process.env.PORT)

const devWebpackConfig = merge(baseWebpackConfig, {
    module: {
        rules: utils.styleLoaders({
            sourceMap: config.dev.cssSourceMap,
            usePostCSS: true
        })
    },
    // cheap-module-eval-source-map is faster for development
    devtool: config.dev.devtool,

    // these devServer options should be customized in /config/index.js
    devServer: {
        clientLogLevel: 'warning',
        historyApiFallback: {
            rewrites: [
                {
                    from: /.*/,
                    to: path.posix.join(
                        config.dev.assetsPublicPath,
                        'index.html'
                    )
                }
            ]
        },
        hot: true,
        contentBase: false, // since we use CopyWebpackPlugin.
        compress: true,
        host: HOST || config.dev.host,
        port: PORT || config.dev.port,
        open: config.dev.autoOpenBrowser,
        overlay: config.dev.errorOverlay
            ? {
                warnings: false,
                errors: true
            }
            : false,
        publicPath: config.dev.assetsPublicPath,
        proxy: config.dev.proxyTable,
        headers: {
            'Access-Control-Allow-Origin': '*'
        },
        quiet: true, // necessary for FriendlyErrorsPlugin
        watchOptions: {
            poll: config.dev.poll
        }
    },
   plugins: [
        new DashboardPlugin(),
        new webpack.DefinePlugin({
            'process.env': require('../config/dev.env'),
            __DEV__: true
        }),
        new webpack.HotModuleReplacementPlugin(),
        new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
        new webpack.NoEmitOnErrorsPlugin(),
        // https://github.com/ampedandwired/html-webpack-plugin
        new HtmlWebpackPlugin({
            filename: 'index.html',
            template: `${config.dev.folder}/index.html`,
            inject: true,
            isDev: true
        }),    

module.exports = new Promise((resolve, reject) => {
  portfinder.basePort = process.env.PORT || config.dev.port
  portfinder.getPort((err, port) => {
    if (err) {
      reject(err)
    } else {
      // publish the new Port, necessary for e2e tests
      process.env.PORT = port
      // add port to devServer config
      devWebpackConfig.devServer.port = port

      // Add FriendlyErrorsPlugin
      devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
        compilationSuccessInfo: {
          messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
        },
        onErrors: config.dev.notifyOnErrors
        ? utils.createNotifierCallback()
        : undefined
      }))

      resolve(devWebpackConfig)
    }
  })
})

第1行,利用require引入http组件,进行http通讯
第2行,引入http-proxy组件,当跨域通讯的时候,会利用http-proxy组件进行处理
第6行,创建http代理server
第14行,通过merge方法将webpack.base.conf.js里面的配置和webpack.dev.conf.js里面的配置进行整合
第25行,这里就是我们创建server的地方,host指向 HOST || config.dev.host,这里的config.dev.host就是config/index.js中的dev.host,port指向PORT || config.dev.port,这里的config.dev.port就是config/index.js中的dev.port;所以通过设置config/index.js中的host和port就可以指定server的host和端口。即产生了如下效果
在这里插入图片描述
第51行,为本地server设置代码,其代理配置指向config.dev.proxyTable,所以我们通过设置config/index.js中的proxyTable即可做跨域处理
第53行,为本地server设置Access-Control-Allow-Origin’: ‘*’,这样做的目的是当我们设置host为0.0.0.0的时候,其他机器就能访问本机项目了,这样做就解决了跨域的问题
第70行,当我们执行npm run dev命令之后,你会发现在dist目录下有如下两个文件
在这里插入图片描述
这里的index.html的生成就是通过HtmlWebpackPlugin生成的
第72行,设置生成index.html生成的路径
第78行,设置basePort的值,这个变量代表开启服务的时候最小的端口值
第79行,通过getPort方法获取到一个可运行的端口好
第84行,设置当前node.js进程中当前环境下的端口
第86行,设置启动cli server的端口号
第91行,就是我们通过执行npm run dev之后打印的信息
在这里插入图片描述
  所以在开发中运行npm run dev之后端口号总是随意变化怎么办?
通过上面的分析,我们只要在第84行指定端口号为你所希望的就好,比如你想让服务端在端口为8999上运行,那个代码如下
在这里插入图片描述

  3.2 process.env

我们在查看源码的时候,经常会看到process.env这样的代码,那这里的process代表什么,process.env.PORT的值代表什么?   process是进程的意思,其是一个全局变量,它代表当前 Node.js 进程的信息并对其进行控制。 作为一个全局变量,在使用的时候,无需使用 require()。那么理解process.env.PORT就比较简单了,他代表的时候当前Node.js进程当前环境中的端口,至于这个端口是多少,我们就不用太纠结了

4. vscode中利用git更新,上传等操作

  4.1 上传

   当我们clone远程代码之后,就可以通过vscode中的源代码管理器查看已经修改的部分,如图所示
在这里插入图片描述
1:确认代码之后,需要将代码提交到暂存区,如下图点击 + 号,暂存所有更改
在这里插入图片描述
2:暂存完成会后,你会发现在暂存区(STAGED CHANGES)已经保存了对应的文件
在这里插入图片描述
3:提交代码到本地库,输入提交信息 点击enter完成
在这里插入图片描述
4: 此时代码已经上传到本地仓库,这时候你需要更新下git服务器上最新代码
在这里插入图片描述
5:更新完之后,需要推送本次修改的代码到远端,即完成上传
在这里插入图片描述

  4.2 更新

参看上一步

  4.3 查看历史记录

  1:使用Git History插件进行历史记录查看,在应用商店搜索git history,点击install即可完成安装(我这边已经安装了,所以显示为卸载)
在这里插入图片描述
  2:安装完成之后,你可以通过右击文件打开git history,也可以点击右上角的按钮打开;这两者的区别是
前者是查看该文件的历史记录,后者是查看整个git的历史提交记录
在这里插入图片描述
  3:我们以点击右上角的git history按钮为例查看下全部的提交记录
在这里插入图片描述
  4:点击某一个文件会出现下图,点击对应列表项,即可查看文件内容,对比上一版本和查看该文件历史记录
在这里插入图片描述

  4.4 git一些图标的说明

在这里插入图片描述
如上图表示在develop分支上,有0个更新,1个本地仓库存储需要上传

  4.5 切换分支

点击左下角的develop处,便会弹出如图分支,选择对应分支即可
在这里插入图片描述

  4.6 clone到指定目录

   git clone 项目代码地址 代码保存位置
如: git clone http://xxxxxx/xxx.git E:/workspace/

  4.7 windows10上VsCode如何更改Git账户

   起初通过VsCode配置git之后,会要求你输入用户名和密码,但是如果你修改了Git的用户名或者密码,再次clone或者提交就会提示认证失败,而此时又不弹出修改账户对话框,解决方法如下   
  1. 打开win10的控制版本(输入控制面板进行搜索)
    在这里插入图片描述
  2. 点击用户账户
    在这里插入图片描述
  3. 点击管理Window凭据
    在这里插入图片描述
  4. 修改新的用户名或者密码
    在这里插入图片描述

  4.8 开发分支合并到master分支

 1. 切换到自己的开发分支
git checkout dev_20200101
  1. 更新开发分支代码
git pull
  1. 切换到master分支
git checkout master
  1. 开发分支合并到master分支
git merge dev_20200101
  1. 推送代码到远程服务器,完成开发分支的代码合并到master分支
git push

  4.9 拉取代码报错:You have not concluded your merge

1. 如果你想保留本地的修改: 中止合并->重新合并->重新拉取
git merge --abort
git reset --merge
git pull
  1. 如果不想保留本地的修改:弃本地代码,远端版本覆盖本地版本
git fetch --all
git reset --hard origin/master
git fetch

5. 在vue项目中如何自动切换开发/生成RUL

  npm run dev 和 npm run build执行的脚本是不一样的,
  npm run dev执行build/webpack.dev.conf.js完成开发模式下的打包
  npm run build执行node build/build.js完成生产环境模式下的打包,

这两者最大的区别就是
npm run dev模式下,process.env.NODE_ENV = ‘dev’
npm run dev模式下process.env.NODE_ENV = ‘production’

所以快捷切换URL代码如下

const devUrl = 'https://www.baidu.com/'
const proUrl = 'https://www.aiqiyi.com'
let url = ‘’
process.env.NODE_ENV === 'development' ? url = devUrl : url = proUrl 

6. 如何引入外部JS(非ES6标准/ES6标准通用)

   相较于普通javascript,我们可以在通过
document.createElement('script')

的方式创建一个script标签,然后指定src的位置即可,具体代码如下(该方法我封装在Tools.js文件中)

  // 加载外部js
  loadScript (src, attributes = {}) {
    return new Promise((resolve, reject) => {
      const vds = document.createElement('script')
      vds.type = 'text/javascript'
      vds.async = true
      vds.src = src
      vds.onload = () => {
        resolve()
      }
      vds.onerror = err => {
        reject(err)
      }
      if (attributes && typeof attributes === 'object') {
        for (let key in attributes) {
          vds.setAttribute(key, attributes[key])
        }
      }
      var s = document.getElementsByTagName('script')[0]
      s.parentNode.insertBefore(vds, s)
    })
  }

第6行,表示该外部js文件为异步引用,这样是为了加速DOM的渲染(html会按照顺序来加载并执行脚本,在脚本加载&执行的过程中,会阻塞后续的DOM渲染。)
第7行,指定外部js文件位置
第9行,如果加载成功,通过promise执行resolve成功方法
第12行,如果加载失败,通过promise执行reject失败方法
第20行,将该外部js作为第一个script标签,优先加载

然后我们通过如下代码引入即可

  mounted () {
    Tools.loadScript('./static/js/xxx.js')
      .then(() => {
      })
      .catch(() => {
      })
  },

第4行,如果加载xxx.js成功则执行对应的方法,反之则执行第6行的代码

7. npm包管理器中qs模块

  QS模块可以将URL解析成对象,也可以将对象 序列化成URL的形式,以&进行拼接
他默认安装在npm包里面,所以在使用的时候只要require就好
  举例说明:将URL解析成对象
const Qs = require('qs')
let url = 'http://baidu.com?where=1&page=2'
Qs.parse(url);

其输出为

{http://baidu.com?where: "1", page: "2"}

这样我们就可以通过解析结构获取其中的key字段了

  举例说明:将对象 序列化成URL的形式,以&进行拼接

const Qs = require('qs');
let obj = {
      where: 1,
      page: 2
    }
Qs.stringify(obj);

其输出为

where=1&page=2

8. HTML5中video理解/自动/全屏播放

  在介绍video之前我们先说下同层播放,其含义是不脱离文档流,在video元素的上方可以显示其他元素;同层页面内播放是标准的视频播放形态; 而在未设置为同层页面播放的时候,video的播放的接管者为系统自身,他会已一个新的页面/全屏/来播放视频;

下面两个代码将说明非同层播放效果同层播放效果

//   未加同层播放的video,其播放效果被系统接管,效果是在浏览器和微信浏览器都是新起一个页面,全屏展示
<div class="video">
     <video
       id="myVideo"
       :src="videoUrl"
       :key="keyUrl"
       preload="auto">
    </video>
</div>
//   加了同层播放的video, 其播放效果在浏览器上会在当前页面全屏播放,但不是新起一个页面,所以无法返回;在微信浏览器的效果和未加同层播放效果一样,但是在手机其他浏览器上虽然效果同未加同层播放效果,但是在返回之后,video元素会显示在页面上层

<div class="video">
     <video
       id="myVideo"
       :src="videoUrl"
       :key="keyUrl"
       x5-video-player-type="h5-page"
       preload="auto">
    </video>
</div>

  在看下内联播放:内联播放指的是视频在文档流中直接进行播放,不会弹出新的播放窗口的方式,我的理解是内联播放是在IOS上的专业说法,而同层播放是在Android上的专业说法,其是由腾讯H5同层播放器接入规范引入的

  关于Video元素,一般我们会着重在android和ios上进行适配,ios因为其封闭性,在适配上还是比较方便的;但是android上,我们就需要考虑多种浏览器的处理方法了;这里我们有腾讯浏览器(TBS),webkit内核浏览器,在微信内打开网页的视频播放效果等等

  先看下HTML5中Video元素的主要属性和API

属性1:fullscreenElement 该属性返回当前处于全屏模式的DOM元素。
属性2:fullscreenEnabled 该属性返回当前 document 是否进入了可以请求全屏模式的状态。
方法1:requestFullscreen() 请求进入全屏模式。
方法2:exitFullscreen() 退出全屏模式。
事件1:fullscreenchange 进入/退出全屏模式切换时会触发。
事件2:fullscreenerror 进入/退出全屏模式失败时会触发             

  再看下在HTML5中Video元素设置object-fit属性的用法

object-fit属性类似background-position,来的作用主要用来设置video元素封面(poster)的展示效果,其有如下几个值,

fill: 中文释义“填充”。默认值。替换内容拉伸填满整个content box, 不保证保持原有的比例。
contain: 中文释义“包含”。保持原有尺寸比例。保证替换内容尺寸一定可以在容器里面放得下。因此,此参数可能会在容器内留下空白。
cover: 中文释义“覆盖”。保持原有尺寸比例。保证替换内容尺寸一定大于容器尺寸,宽度和高度至少有一个和容器一致。因此,此参数可能会让替换内容(如图片)部分区域不可见。
none: 中文释义“无”。保持原有尺寸比例。同时保持替换内容原始尺寸大小。
scale-down: 中文释义“降低”。就好像依次设置了none或contain, 最终呈现的是尺寸比较小的那个

   接着我们在看下在IOS中常见的属性

airplay: 用于控制ios的airplay设备,一般设置为true

x-webkit-airplay: 用于控制ios的airplay设备,一般设置为true,这是一种兼容性表达

playsinline: 内联播放属性,布尔属性,不需要赋值(存在即是true)

webkit-playsinline: 内联播放属性,布尔属性,不需要赋值(存在即是true),这是一种兼容性表达

   然后还有在腾讯浏览器(TBS)中常见的属性设置,

x5-video-player-type: 在video标签中添加x5-video-player-type:h5-page属性来控制网页内部同层播放,可以在视频上方显示html元素

x5-video-player-fullscreen: 视频播放时将会进入到全屏模式,X5内核视频默认播放形态,用户点击视频区域后开始进入全屏播放,视频区域内的所有事件行为会由X5内核视频组件全权托管。视频层级最高,会遮挡所在区域所有html元素。(仅使用于安卓微信、手机QQ等非安卓QQ浏览器的X5内核场景)

x5-video-orientation : 声明播放器支持的方向,可选值: landscape 横屏, portraint竖屏,默认值:portraint

x5videoenterfullscreen: 进入全屏通知,我们可以通过JS监听事件

						myVideo.addEventListener("x5videoenterfullscreen", function(){
							
							alert("player enterfullscreen");
										
						})

x5videoexitfullscreen: 退出全屏的通知

更详细的我们可以参考TBS的文档

   最后说下我们最终需要实现的效果:在微信/Android/IOS上点击视频,全屏自动播放视频,当退出全屏的时候,可以暂停视频播放并将video元素至于页面底层,效果如下:点击下方的播放按钮进入到播放页面

在这里插入图片描述
通过我们有三种做法:

1:通过浏览器加载视频地址
2: 通过调用requestFullscreen方法进入全屏
3:通过在页面下方加载一个全屏的video组件

先看下方法一:

这个方法比较简单,直接指定浏览器为MP4地址即可

window.location.href = '.............mp4'

这个方案的优点: 简单,实在简单。一行代码;
那这个方案的确认也很明显
1:在微信内部并不是百分百能够播放,甚至无法加载
2:在外部浏览器中,我们无法控制视频的播放,视频的播放就交由浏览器处理,是否全屏会根据视频源的大小来由系统决定

再看方法二:

<!--全屏自动播放视频-->
<template>
  <div class="tab-video">
    <div class="video-img"></div>
    <div class="video-play" @click="playFullScreen()"></div>
    <div class="video-time">01:30</div>
    <div class="video-sum">
      <video
        id="myVideo"
        :src="videoUrl"
        preload="auto"
        x-webkit-airplay="allow"
        x5-video-player-type="h5"
        x5-video-player-fullscreen="false"
        x5-video-orientation="portraint"
        @fullscreenchange="changeFull"
        @webkitfullscreenchange="changeFull"
        @mozfullscreenchange="changeFull"
        style="object-fit: contain;"
      ></video>
    </div>
  </div>
</template>
<script>
export default {
  components: {},
  data () {
    return {
      videoUrl: '填写你自己的视频地址',
      isfull: false
    }
  },
  methods: {
    playFullScreen () {
      setTimeout(() => {
        const videoObj = document.getElementById('myVideo')
        videoObj.setAttribute('src', this.videoUrl)
        videoObj.play()
        if (videoObj.requestFullscreen) {
          videoObj.requestFullscreen()
        } else if (videoObj.webkitRequestFullScreen) {
          if (navigator.userAgent.indexOf('UCBrowser') > -1) {
            window.open(this.videoUrl)
          } else {
            videoObj.webkitRequestFullScreen()
          }
        } else if (videoObj.mozRequestFullScreen) {
          videoObj.mozRequestFullScreen()
        } else if (videoObj.msRequestFullscreen) {
          videoObj.msRequestFullscreen()
        } else {
          videoObj.webkitEnterFullscreen()
        }
        videoObj.play()
      }, 600)
    },
    changeFull () {
      if (this.isfull) {
        setTimeout(() => {
          const videoObj = document.getElementById('myVideo')
          videoObj.pause()
          if (videoObj.exitFullscreen) {
            videoObj.exitFullscreen()
          } else if (videoObj.mozCancelFullScreen) {
            videoObj.mozCancelFullScreen()
          } else if (videoObj.webkitCancelFullScreen) {
            videoObj.webkitCancelFullScreen()
          }
          this.videoUrl = ''
        }, 100)
      }
      this.isfull = !this.isfull
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style>
.tab-video {
  position: relative;
  background-color: #000;
  width: 16.72rem;
  height: 9rem;
  border-radius: 0.32rem;
  margin: 0 auto;
}
.video-time {
  width: 1.25rem;
  height: 0.44rem;
  position: absolute;
  z-index: 101;
  right: 0.8rem;
  bottom: 0.2rem;
  font-size: 0.26rem;
  color: #fff;
  line-height: 0.44rem;
  text-align: center;
  background-size: 100%;
}
.video-play {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 5rem;
  height: 5rem;
  margin-left: -2.65rem;
  margin-top: -1.65rem;
  z-index: 200;
  background-image: url("../assets/play.png");
  background-repeat: no-repeat;
  background-size: 100%;
}
.video-img {
  position: absolute;
  top: 0;
  left: 0;
  width: 16.72rem;
  height: 9rem;
  border-radius: 0.32rem;
  background-size: 6.72rem 3.98rem;
  z-index: 99;
  background-image: url("../assets/f_bg.jpg");
  background-repeat: no-repeat;
  background-size: 100%;
}
.video-sum {
  position: absolute;
  width: 5.08rem;
  height: 3.34rem;
  border-radius: 0.32rem;
  left: 5.7rem;
  top: 0.96rem;
}
video {
  width: 5.08rem;
  height: 3.34rem;
  border-radius: 0.32rem;
}
</style>

这个方法实现的好处是,即使我们可以在页面下方创建一个1*1的video元素,但是你会发现webkitRequestFullScreen()这个方法并没有将视频进入到全屏模式

最后看下方法三:

最后如果你想实现在某个区域内不脱离文档流的播放效果,如下图图一,点击播放按钮,就在页面区域内部播放(如图二)
在这里插入图片描述

在这里插入图片描述
此时你可以将这个video修改成和屏幕固定大小,这样播放起来就可以全屏了,但是这个方案的缺点也比较明显:无论视频的大小,视频都将竖屏,并且居中播放

<template>
  <div class="tab-video">
    <div class="video-img" v-show="!showVideo"></div>
    <div class="video-play" @click="plaVideo()" v-show="!showVideo"></div>
    <div class="video-time" v-show="!showVideo">01:30</div>
    <div class="video-sum" v-show="showVideo">
      <video
        id="myVideo"
        :src="videoUrl"
        preload="auto"
        autoplay
        style="object-fit: fill;"
      ></video>
    </div>
  </div>
</template>
<script>
export default {
  components: {},
  data () {
    return {
      videoUrl: '填写你mp4的地址',
      isfull: false,
      showVideo: false
    }
  },
  methods: {
    plaVideo () {
      this.showVideo = true
      setTimeout(() => {
        const videoObj = document.getElementById('myVideo')
        videoObj.play()
      }, 600)
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style>
.tab-video {
  position: relative;
  background-color: #000;
  width: 16.72rem;
  height: 9rem;
  border-radius: 0.32rem;
  margin: 0 auto;
}
.video-time {
  width: 1.25rem;
  height: 0.44rem;
  position: absolute;
  z-index: 101;
  right: 0.8rem;
  bottom: 0.2rem;
  font-size: 0.26rem;
  color: #fff;
  line-height: 0.44rem;
  text-align: center;
  background-size: 100%;
}
.video-play {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 5rem;
  height: 5rem;
  margin-left: -2.65rem;
  margin-top: -1.65rem;
  z-index: 200;
  background-image: url("../assets/play.png");
  background-repeat: no-repeat;
  background-size: 100%;
}
.video-img {
  position: absolute;
  top: 0;
  left: 0;
  width: 16.72rem;
  height: 9rem;
  border-radius: 0.32rem;
  background-size: 6.72rem 3.98rem;
  z-index: 99;
  background-image: url("../assets/f_bg.jpg");
  background-repeat: no-repeat;
  background-size: 100%;
}
.video-sum {
  position: absolute;
  width: 17.08rem;
  height: 9.34rem;
  border-radius: 0.32rem;
}
video {
  width: 17.08rem;
  height: 9.34rem;
  border-radius: 0.32rem;
}
</style>

至于其他效果,比如你想解决在微信打开自动全屏的问题,可以在github上参考这个工程
alilmq

9. 调试

  9.1 VConsole

  vconsole的使用主要是方便我们在手机上调试页面的,通过点击右下角的console按钮,就可以在手机上查看页面输出信息了。

在这里插入图片描述

   在我们构建项目的时候,在使用npm run test或者npm run build编译的时候,如果你使用console.log会产生

unexpected console statement

的错误的时候,这是由于你在构建项目初期使用了ESLint检查项目代码规范导致的。这时候我们又想在移动端或者PC端输入日志信息,我们可以使用如下输入方式:

window.console.log(res);

   安装和使用方法

npm install vconsole //安装

// 使用
var vConsole = new VConsole();
console.log(‘Hello world’);

  9.2 Chrom /360浏览器调试面板介绍

10. Vue Watch和Compute

   watch和computed都是以Vue的依赖追踪机制为基础的,它们都试图处理这样一件事情: 当某一个数据(称它为依赖数据)发生变化的时候,所有依赖这个数据的“相关”数据“自动”发生变化, 也就是自动调用相关的函数去实现数据的变动。

   计算属性:
   1. 计算属性默认只有 getter, 写法上通过一个函数的方式来定义, 当然也可以自己定义 setter
  computed: {
	    // 计算属性的 getter
	    lowerCaseMessage: function () {
	      // `this` 指向 vm 实例
	      return this.message.toLowerCase()
	    },
    }

   2. 计算属性也可以自定义get 和 setter, 如下当我们对 fullName重新赋值的时候, set方法就会被调用.

  computed: {
    // 计算属性的 自定义get 和 setter, 当我们对 fullName重新赋值的时候, set方法就会被调用
    fullName: {
      // getter
      get: function () {
        return this.message
      },
      // setter
      set: function (newValue) {
        var names = newValue.split(' ')
        this.message = names[0]
      }
    }
  },

   watch
   这是一种监听方法 用于检测某个值是否方法变化,这种写法当值第一次绑定的时候,不会执行监听函数,只有值发生改变才会执行

watch: {
	    // 如果 `message` 发生改变,这个函数就会运行
	    message: function (newMessage, oldMessage) {
	      console.log('**监听函数被调用**')
	    },
    }

   上面的代码我们需要第一次绑定的时候是不会执行的,只有当值发生变化才会执行;如果需要立即执行,则需要用到immediate属性
immediate表示在watch中首次绑定的时候,是否执行handler,值为true则表示在watch中声明的时候,就立即执行handler方法,值为false,则和一般使用watch一样,在数据发生变化的时候才执行handler。

  watch: {
	    // 第一次绑定playVideoTitle` handler函数就会运行
	    // 监听的数据后面写成对象形式,包含handler方法和immediate,
	    // 上面的函数其实就是在写这个handler方法;
	    playVideoTitle: {
	      handler (newTitle, oldTitle) {
	        console.log('**监听函数立即被调用**')
	      },
	      immediate: true
	    },
    }
    

   watch方法同样可以对一个对象进行监听,此时就需要使用deep属性,设置deep: true 此时会给watchObject的所有属性都加上这个监听器,
  当对象属性较多时,每个属性值的变化都会执行handler。

  watch: {
    watchObject: {
      handler (newTitle, oldTitle) {
        console.log('**监听对象函数立即被调用**')
      },
      deep: true,
      immediate: true
    },
    }

如果只想监听对象中的某一个属性,则使用字符串的形式监听对象属性,如此处只监听name属性是否发生了变化

watch {
	    'watchObject.name': {
	      handler (newTitle, oldTitle) {
	        console.log('**监听对象函数立即被调用**')
	      },
	      deep: true,
	      immediate: true
	    }
    }

11. btoa 和 atob 函数的作用

   btoa 函数用于将字符转为base64编码格式    atob 函数用于将base64编码格式的字符进行转码

同时在使用btoa函数的时候,如果字符串中包含中文字符,则会抛出如下异常

The string to be encoded contains characters outside of the Latin1 range.

此时我们需要使用如下方法进行编码和解码

var str = "China,中国";

window.btoa(window.encodeURIComponent(str))
//"Q2hpbmElRUYlQkMlOEMlRTQlQjglQUQlRTUlOUIlQkQ="

window.decodeURIComponent(window.atob('Q2hpbmElRUYlQkMlOEMlRTQlQjglQUQlRTUlOUIlQkQ='))
//"China,中国"
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章