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跨平台应用(八)基础技法(二)
这篇主要对如下内容做个解答
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
9. 调试
9.1 VConsole
9.2 Chrom / 360浏览器调试面板介绍
10. Vue 深度监听/watch函数和计算属性compute
node应用是由模块组成的,那么模块之间必然存在将数据暴露给其他模块使用,在暴露数据的时候,需要遵循两个基本规范: CommonJS 模块规范和ES6语法规范
在CommonJS 规范中,我们使用module.exports和exports来导出数据,通过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语法规范中,我们利用export和export default导出模块,import导入模块。我们先看下其用法说明
- export default表示一个模块的默认输出,所以在一个模块中,export default有且仅有一个; export表示按需导出,所以可以用多个
- 使用export向外暴露的成员,只能使用{ }的形式来接收
- 导出的时候可以通过as来设置别名
- 导出一个变量/对象,应注意导出对象或者变量时不需要使用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的服务只能被本机访问
首先我们看下从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上运行,那个代码如下
当我们clone远程代码之后,就可以通过vscode中的源代码管理器查看已经修改的部分,如图所示
1:确认代码之后,需要将代码提交到暂存区,如下图点击 + 号,暂存所有更改
2:暂存完成会后,你会发现在暂存区(STAGED CHANGES)已经保存了对应的文件
3:提交代码到本地库,输入提交信息 点击enter完成
4: 此时代码已经上传到本地仓库,这时候你需要更新下git服务器上最新代码
5:更新完之后,需要推送本次修改的代码到远端,即完成上传
1:使用Git History插件进行历史记录查看,在应用商店搜索git history,点击install即可完成安装(我这边已经安装了,所以显示为卸载)
2:安装完成之后,你可以通过右击文件打开git history,也可以点击右上角的按钮打开;这两者的区别是
前者是查看该文件的历史记录,后者是查看整个git的历史提交记录
3:我们以点击右上角的git history按钮为例查看下全部的提交记录
4:点击某一个文件会出现下图,点击对应列表项,即可查看文件内容,对比上一版本和查看该文件历史记录
如上图表示在develop分支上,有0个更新,1个本地仓库存储需要上传
点击左下角的develop处,便会弹出如图分支,选择对应分支即可
git clone 项目代码地址 代码保存位置
如: git clone http://xxxxxx/xxx.git E:/workspace/
- 打开win10的控制版本(输入控制面板进行搜索)
- 点击用户账户
- 点击管理Window凭据
- 修改新的用户名或者密码
git checkout dev_20200101
- 更新开发分支代码
git pull
- 切换到master分支
git checkout master
- 开发分支合并到master分支
git merge dev_20200101
- 推送代码到远程服务器,完成开发分支的代码合并到master分支
git push
4.9 拉取代码报错:You have not concluded your merge
1. 如果你想保留本地的修改: 中止合并->重新合并->重新拉取git merge --abort
git reset --merge
git pull
- 如果不想保留本地的修改:弃本地代码,远端版本覆盖本地版本
git fetch --all
git reset --hard origin/master
git fetch
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
相较于普通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行的代码
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
在介绍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
在我们构建项目的时候,在使用npm run test或者npm run build编译的时候,如果你使用console.log会产生
unexpected console statement
的错误的时候,这是由于你在构建项目初期使用了ESLint检查项目代码规范导致的。这时候我们又想在移动端或者PC端输入日志信息,我们可以使用如下输入方式:
window.console.log(res);
安装和使用方法
npm install vconsole //安装
watch和computed都是以Vue的依赖追踪机制为基础的,它们都试图处理这样一件事情: 当某一个数据(称它为依赖数据)发生变化的时候,所有依赖这个数据的“相关”数据“自动”发生变化, 也就是自动调用相关的函数去实现数据的变动。// 使用
var vConsole = new VConsole();
console.log(‘Hello world’);
计算属性:
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
}
}
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,中国"