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,中國"
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章