Vue积累
对象的hasOwnProperty
判断对象内是否有此属性
Object的hasOwnProperty()方法返回一个布尔值,判断对象是否包含特定的自身(非继承)属性。
var o = new Object();
o.prop = 'exists';
function changeO() {
o.newprop = o.prop;
delete o.prop;
}
o.hasOwnProperty('prop'); // true
changeO();
o.hasOwnProperty('prop'); // false
箭头函数
var elements = [
'Hydrogen',
'Helium',
'Lithium',
'Beryllium'
];
elements.map(function(element) {
return element.length;
}); // 返回数组:[8, 6, 7, 9]
// 1. 上面的普通函数可以改写成如下的箭头函数
elements.map((element) => {
return element.length;
}); // [8, 6, 7, 9]
// 2. 当箭头函数只有一个参数时,可以省略参数的圆括号
elements.map(element => {
return element.length;
}); // [8, 6, 7, 9]
// 3. 当箭头函数的函数体只有一个 `return` 语句时,可以省略 `return` 关键字和方法体的花括号
elements.map(element => element.length); // [8, 6, 7, 9]
// 在这个例子中,因为我们只需要 `length` 属性,所以可以使用参数解构
// 需要注意的是字符串 "length" 是我们想要获得的属性的名称,而 `lengthFooBArX` 则只是个变量名,
// 可以替换成任意合法的变量名
elements.map(({ "length": lengthFooBArX }) => lengthFooBArX); // [8, 6, 7, 9]
export const
Vuex
import * as api from '@/api/mapCommon.js';
const state = {
// 矢量图配置信息
vmapConfig: {
mapEnable:0
},
// 测量方式(测距/测面)
currMeasure: '',
// 是否全屏
isFullScreen: false
}
const mutations = {
// 获取矢量图配置信息
GET_VMAP_CONFIG (state, val) { // 参数都是从第二个开始的,第一个就是上方的 state
state.vmapConfig = val;
},
SET_CURR_MEASURE (state, val) {
state.currMeasure = val;
},
SET_FULLSCREEN_STATUS (state, val) {
state.isFullScreen = val;
},
CHANGE_FULLSCREEN_STATUS (state) {
this.commit('mapCommon/SET_FULLSCREEN_STATUS', !state.isFullScreen);
}
}
const actions = {
getVmapConfig ({ commit }) {
api.getVmapConfig().then(res => {
res = JSON.parse(res)
commit('GET_VMAP_CONFIG', res);
});
}
getPermission({ commit }, userId) {
return new Promise(async (resolve, reject) => {
getPermission(userId).then(res => {
const menuList = res.data.users[0].menuNodes
commit('SET_MENU_LIST', menuList)
resolve(menuList)
}).catch(error => {
reject()
})
})
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
mapState -> state
import { mapState } from 'vuex';
computed: {
...mapState({
currMeasure: state => state.mapCommon.currMeasure,
}),
},
this.$store.state.mapCommon.currMeasure // 可直接调用
mutations
// 标记打点
setTag () {
this.$store.commit('mapCommon/SET_CURR_MEASURE', '')
this.$emit('setTag')
},
mapActions -> actions
import { mapActions } from 'vuex'
methods: {
// 方法 1
...mapActions({
getVmapConfig: 'mapCommon/getVmapConfig', //...mapActions的方法 调用不同Module的数据必须这样写 mapCommon 这个是模块名
}),
// 方法 2
getVehicleParams () {
this.$store.dispatch('realTimeMonitor/getVehicleParams') // 直接调用得方法
}
}
this.$store.dispatch
两个方法都是传值给vuex的mutation改变state
dispatch:异步操作,数据提交至 actions ,可用于向后台提交数据
this.$store.dispatch('isLogin', true);
this.$store.commit
commit:同步操作,数据提交至 mutations ,可用于登录成功后读取用户信息写到缓存里
this.$store.commit('loginStatus', 1);
注:必须要用commit(‘SET_TOKEN’, tokenV)调用mutations里的方法,才能在store存储成功。
Mixin
import { regex } from '@/utils/validate'
export default {
data() {
return {
validErrorMsg: {
userName: '请输入1-50个字符且不包含空格 ‘ “ ;:& @',
password: '请输入8-32字符且不包含空格 ‘ “ ;:& @',
}
}
},
methods: {
/**
* @description 校验方法
* @param {Object} rule 校验规则
* @param {String} value 值
* @param {Function} callback 回调
*/
regexEpValidRules(rule, value, callback) {
if (regex[rule['validRule']].test(value)) {
callback()
} else {
callback(new Error(this.validErrorMsg[rule['validRule']]))
}
},
}
}
import mixin from '@/mixins'
export default {
mixins: [mixin],
methods: {
toggleSideBar() {
this.regexEpValidRules('app/toggleSideBar') // 可以直接用
},
}
}
组件 props
<ddd aa-bb = 'cc' />
props: {
cc:{
type: String,
default: ''
},
父组件
<alarmImages
v-if="!noImages"
:picture-str="picture"
:alarm-date="alarmDateStr"
:location-name="locationName"
/>
import alarmImages from './alarmImages.vue'
export default {
components: {
alarmImages,
},
}
子组件
<template>
<div class="alarm-images">
<div><span>{{ $t('alarm.modal.time') }}</span><span>{{ alarmDate }}</span></div>
<div class="alarm-modal-address">
<span>{{ $t('alarm.modal.address') }}</span><span>{{ locationName }}</span>
</div>
<img
v-for="item in imageList"
:key="item"
:src="item"
alt=""
class="alarm-images-item"
>
</div>
</template>
<script>
import { queryAlarms } from '@/api/alarm-process/index.js'
export default {
props: {
pictureStr:{
type: String,
default: ''
},
alarmDate: {
type: String,
default: ''
},
locationName: {
type: String,
default: ''
}
},
methods:{
changeFilter() {
console.log(this.pictureStr) // 直接在这里使用
}
}
}
</script>
Vue-cli watch监听$route
需要在有子路由的情况下 才能监听到 app 是所有路由的父路由,所以可以监听,其他的就需要该路由下有子路由才行
watch: {
$route(to) {
if (to.path.indexOf('index') != -1) {
//路由变化后重新获取帖子列表
this.$http.get('/api/communityList').then((res) => {
if (res.data.errCode === 0) {
let getRes = res.data.data.hotList
this.postList = getRes
}
})
}
}
}
this.$parent
this.$parent 可以访问到父组件 上所有的 data(){ 里的数据信息和生命周期方法,methods里的方法 }!
async/await
1.async/await场景
这是一个用同步的思维来解决异步问题的方案,当前端接口调用需要等到接口返回值以后渲染页面时。
methods: {
initChart() {
this.chart = echarts.init(document.getElementById(this.id));
fetchOverview().then(response => {
this.option.series[0].data = response.items
}).catch(error => {
console.log(error);
})
this.chart.setOption(this.option);
},
}
methods: {
async initChart() {
this.chart = echarts.init(document.getElementById(this.id));
await fetchOverview().then(response => {
this.option.series[0].data = response.items
}).catch(error => {
console.log(error);
})
this.chart.setOption(this.option);
},
}
this.$emit
子组件
<el-dialog :before-close="closeVideo" >
closeVideo() {
this.$emit('closeVideoFilterModal',value) // 第一步
},
父组件
import videoFilter from '@/components/videoFilter'
components: { voiceIntercom },
<video-filter @closeVideoFilterModal="closeVideoFilterModal" /> // 第二部 @这个
closeVideoFilterModal(value) { // 第三步 这个就是子组件绑定的时间 value为传参
this.pictureAdjustmentVisible = false
},
Vue.component 全局注册组件
// 导入组件,组件必须声明 name
import iTree from './index.vue'
// 为组件添加 install 方法,用于按需引入
iTree.install = function (Vue) {
Vue.component(iTree.name, iTree)
}
export default iTree
<iTree></iTree>
表格内动态添加操作按钮
TableBase 子组件
<template>
<el-table>
<el-table-column v-else :key="index" :prop="item.prop" :label="$t(item.label)":show-overflow-tooltip="true">
<template slot-scope="scope">
<template v-if="item.render">
<custom-cell :column="item" :row="scope.row" :render="item.render" :index="scope.$index"/>
</template>
<template v-else-if="item.slot">
<slot :name="item.slot" :row="scope.row" :index="scope.$index"/> // 这里是往表格内动态加 是显示按钮还是显示文本
</template>
<template v-else>
<span>{{ scope.row[item.prop] }}</span>
</template>
</template>
</el-table-column>
</el-table>
</template>
父组件
可以根据传入配置动态显示 复选框 或者 按钮
<table-base :table-height="'650'" :columns="columns" :list-data="listData" :total="total" :loading="loading" >
<template slot="operation" slot-scope="scope"> // 这个就是 slot 动态组件
<el-button v-if="scope.row.handleStat == 0" type="primary" size="small" @click="openAlarmModal(scope.row, 'handle')">
{{ $t('alarm.process.process') }}
</el-button>
<el-button v-else type="primary" size="small" @click="openAlarmModal(scope.row, 'view')">
{{ $t('real.time.monitor.view') }}
</el-button>
</template>
</table-base>
columns: [
{type: 'selection'},
{ prop: 'plateNo', label: this.$t('hard.disk.failure.plateNo'), width: '100px' },
{ prop: 'deviceName', label: this.$t('hard.disk.failure.deviceName'), width: '120px' },
{ prop: 'handleDate', label: this.$t('alarm.process.process.time') },
{ slot: 'operation', label: this.$t('alarm.process.operation'), width: '120px'},
],
template及template上使用v-for
<template>
<div class="root">
<template v-for="item,index in 5"> // 这个 template 标签只会渲染出来一个 div, 但是采用 div 来渲染的话就会出来很多个 div
<div>测试{{index}}</div>
</template>
</div>
</template>
<div class='root'>
<div>测试0</div>
<div>测试1</div>
<div>测试2</div>
<div>测试3</div>
<div>测试4</div>
</div>
Sass的@mixin与@include
@mixin 指令允许我们定义一个可以在整个样式表中重复使用的样式。
@include 指令可以将混入(mixin)引入到文档中。
@mixin important-text {
color: red;
font-size: 25px;
font-weight: bold;
border: 1px solid blue;
}
.danger {
@include important-text;
background-color: green;
}
向混入传递变量
/* 混入接收两个参数 */
@mixin bordered($color, $width) {
border: $width solid $color;
}
.myArticle {
@include bordered(blue, 1px); // 调用混入,并传递两个参数
}
.myNotes {
@include bordered(red, 2px); // 调用混入,并传递两个参数
}
created()与activated()
created():在创建vue对象时,当html渲染之前就触发;但是注意,全局vue.js不强制刷新或者重启时只创建一次,也就是说,created()只会触发一次;
activated():在vue对象存活的情况下,进入当前存在activated()函数的页面时,一进入页面就触发;可用于初始化页面数据等
使用<keep-alive>会将数据保留在内存中,如果要在每次进入页面的时候获取最新的数据,需要在activated阶段获取数据,承担原来created钩子中获取数据的任务。
被包含在 <keep-alive> 中创建的组件,会多出两个生命周期的钩子: activated 与 deactivated
activated:在组件被激活时调用,在组件第一次渲染时也会被调用,之后每次keep-alive激活时被调用。
deactivated:在组件被停用时调用。
注意:只有组件被 keep-alive 包裹时,这两个生命周期才会被调用,如果作为正常组件使用,是不会被调用,以及在 2.1.0 版本之后,使用 exclude 排除之后,就算被包裹在 keep-alive 中,这两个钩子依然不会被调用!另外在服务端渲染时此钩子也不会被调用的。
什么时候获取数据?
当引入keep-alive 的时候,页面第一次进入,钩子的触发顺序created-> mounted-> activated,退出时触发deactivated。当再次进入(前进或者后退)时,只触发activated。
我们知道 keep-alive 之后页面模板第一次初始化解析变成HTML片段后,再次进入就不在重新解析而是读取内存中的数据,即,只有当数据变化时,才使用VirtualDOM进行diff更新。有需要的话,页面进入的数据获取应该在activated中也放一份。数据下载完毕手动操作DOM的部分也应该在activated中执行才会生效。
所以,有需要的话,应该activated中留一份数据获取的代码,或者不要created部分,直接将created中的代码转移到activated中。
vue动态绑定class的方式
第一种:(最简单的绑定)
1.绑定单个class
html部分:
<div :class="{'active':isActive}"></div> // js部分:判断是否绑定一个active
data() {
return {
isActive: true
};
}
结果渲染为:
<div class="active"></div>
2.若要绑定多个class,需要逗号隔开就行:(这里的activeTwo加不加引号都可以,也一样都能渲染,如下)
<div class="activeOne" v-bind:class="{ activeTwo: isActive, 'activeThree': hasError }"></div>
js部分:判断是否绑定对应class
data() {
return {
isActive: true,
hasError: true
};
}
结果渲染为:
<div class="activeOne activeTwo activeThree"></div>
第二种:(绑定的数据对象)
<div :class="classObject"></div>
data: {
classObject: {
active: true,
}
}
第三种:(绑定一个返回对象的计算属性)
<div :class="classObject"></div>
export default {
data() { return { isActive: true, }; },
computed: {
classObject: function () {
return {
active: this.isActive,
}
}
}
结果渲染为:
<div class="active"></div>
第四种:(单纯数组方法)
<div :class="[activeClass, errorClass]"></div>
data() {
return {
activeClass: "active",
errorClass: "disActive"
};
},
结果渲染为:
<div class="active disActive"></div>
第五种:(数组与三元运算符结合判断选择需要的class)
<div :class="[isActive?'active':'disActive']"></div>
data() {
return {
isActive: false,
}
},
结果渲染为:
<div class="disActive"></div>
file转base64 与 base64转file
// file转base64
getBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = () => resolve(reader.result)
reader.onerror = (error) => reject(error)
})
},
// base64转file
base64ToFile(data) {
// 将base64 的图片转换成file对象上传 atob将ascii码解析成binary数据
const binary = atob(data.split(',')[1])
const mime = data.split(',')[0].match(/:(.*?);/)[1]
const array = []
for (let i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i))
}
const fileData = new Blob([new Uint8Array(array)], {
type: mime
})
const file = new File([fileData], `${new Date().getTime()}.png`, { type: mime })
return file
},
this.$set
this.$set(obj, key, value)
<script>
export default {
data() {
return {
student: {
name: '张三',
}
}
},
methods: {
setMessage() {
this.$set(this.student, 'age', 15)
console.log(this.student)
}
}
}
</script>
slot-scope
slot-scope的出现却实现了父组件调用子组件内部的数据,子组件的数据通过slot-scope属性传递到了父组件
// 作用域插槽
Vue.component("todo-list",{
inheritAttrs:false,
props:{
todos:[Array,Object]
},
template:
`<ul>
<li v-for="todo in todos" :key="todo.id" style="display: block;" >
//这里的:data=“todo”就是讲子组件todo这个数据传给了父组件
<slot :data="todo">{{todo.text}}</slot>//todo.text是默认值,父组件会把它覆盖掉
</li>
</ul>
`
});
<!--使用作用域插槽,通过slot-scope实现-->
<todo-list :todos="todos">
<template slot-scope="slotProps">
<span v-if="slotProps.data.isTrue">√</span>
{{slotProps.data.text}}
</template>
</todo-list>
JavaScript eval() 函数
eval() 函数计算或执行参数。
如果参数是表达式,则 eval() 计算表达式。如果参数是一个或多个 JavaScript 语句,则 eval() 执行这些语句。
props怎么自定义验证
props: {
num: {
default: 1,
validator: function (value) {
// 返回值为false则验证不通过,报错
return [1, 2, 3, 4, 5].indexOf(value) !== -1
}
}
}
watch的immediate属性
// 比如平时created时要请求一次数据,并且当搜索值改变,也要请求数据,我们会这么写:
created(){
this.getList()
},
watch: {
searchInputValue(){
this.getList()
}
}
// 使用immediate完全可以这么写,当它为true时,会初始执行一次
watch: {
searchInputValue: {
handler: 'getList',
immediate: true
}
}
watch监听一个对象时,如何排除某些属性的监听
下面代码是,params发生改变就重新请求数据,无论是a,b,c,d属性改变
data() {
return {
params: {
a: 1,
b: 2,
c: 3,
d: 4
},
};
},
watch: {
params: {
deep: true,
handler() {
this.getList;
},
},
}
只要a,b改变时重新请求,c,d改变时不重新请求
mounted() {
Object.keys(this.params)
.filter((_) => !["c", "d"].includes(_)) // 排除对c,d属性的监听
.forEach((_) => {
this.$watch((vm) => vm.params[_], handler, {
deep: true,
});
});
},
data() {
return {
params: {
a: 1,
b: 2,
c: 3,
d: 4
},
};
},
watch: {
params: {
deep: true,
handler() {
this.getList;
},
},
}
computed如何实现传参
// html
<div>{{ total(3) }}
// js
computed: {
total() {
return function(n) {
return n * this.num
}
},
}
Vue引入JS(JS内含this)
/config.js
export const handelOrderSource = function (value) {
const orderSourceList = {
1: this.$t('电召订单'),
2: this.$t('线下订单'),
3: this.$t('APP订单'),
}
return orderSourceList[value]
}
export const handelOrderInfo = function (value) {
const self = this
value.orderSource = handelOrderSource.call(self, value.orderSource) // 如果传参了 需要这样写 .call(this, argument)
return value
};
/aaa.vue
import { handelOrderInfo } from '../assets/js/config.js'
this.orderInfo = handelOrderInfo.call(this, this.orderInfo) // 如果传参了 需要这样写 .call(this, argument)