vue使用echarts报错Error in mounted hook: “TypeError: this.dom.getContext is not a function”

  • 解决
    • 一开始是this.$refs.dom获取节点的,后面使用在<el-row>标签上就不可以,所以如果使用this.$refs进行echarts的初始化操作会报错,就使用原生dom获取节点后初始化即可

elementUI 日期选择器在vue-admin中设置中文显示

  • 方法

    • main.js文件当中

      1
      2
      3
      // import locale from 'element-ui/lib/locale/lang/en' // lang i18n 注释掉
      import locale from 'element-ui/lib/locale/lang/zh-CN' //添加
      Vue.use(ElementUI, { locale });//添加
  • 设置前

  • 设置后

moment日期插件输出格式错误

  • 之前输出console.log(moment().format("yyyy-MM-dd"));
  • 原来是字母问题,改为大写就可以了
  • 之后改为console.log(moment().format("YYYY-MM-DD"));

moment获取本周-本月

  • 获取本周
    • moment().day(1)即可设置为星期一
    • moment().day(1).format('YYYY-MM-DD');//输出本周星期一的日期也就是2022/05/09
    • moment().day(7)即可设置为星期天
    • moment().day(7).format("YYYY-MM-DD");//输出本周星期一的日期也就是2022/05/15
  • 获取本月1日
    • moment().startOf('month')即可获取本月一日
    • moment().startOf('month').format("YYYY-MM-DD")//输出本月1日也就是 2022-05-01
  • 获取本月结尾
    • moment().endOf('month')即可获取本月最后一天的日期
    • moment().endOf('month').format("YYYY-MM-DD")//输出本月最后一天,也就是 2022-05-31
  • 获取本日
    • moment().startOf('day')

明明组件是复用的,为什么echarts图表只显示一个?

  • 如图,只有左边有,为什么会这样子?

  • 解决

    • 原来初始化的时候获取dom是document.querySelector(xxxx)改为this.$refs.xxxx即可

    如图

    • 成功解决

      成功解决

支付的轮询

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//开始轮询
if(!this.timer){
this.timer = setInterval(async () => {
let result = await this.$API.queryPayStatus(this.orderNo)
if(result.code == 200){
//说明支付成功了
//清除定时器
clearInterval(this.timer);
//置空timer
this.timer = null;
//更改支付状态记录表
this.payStatu = result.code;
//关闭信息弹窗
this.$msgbox.close();
//跳转路由
this.$router.push("/paysuccess");
}
}, 2000);
}

流程图

轮询支付流程图

数组去重

  • set构造函数去重
1
2
3
4
5
6
7
8
9
10
11
12
13
<script>
var tempArray = [1,2,3,4,5,5,6,7];
//转化为set
var tempSet = new Set(tempArray);
//set转换回来数组 - 方法1
var tempAfterArray1 = [...tempSet];
///set转换回来数组 - 方法2
var tempAfterArray2 = Array.from(tempSet);
//[1, 2, 3, 4, 5, 6, 7]
console.log(tempAfterArray1);
//[1, 2, 3, 4, 5, 6, 7]
console.log(tempAfterArray2);
</script>
  • 普通方法(这里就说一个~)

filterindexOf结合,filter为真的时候才会返回,indexOf如果找到第一个会停止寻找

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
var tempArray = [1, 2, 5, 5, 6, 6, 7];

//item为当前遍历的项
//index为当前遍历项的索引
var a = tempArray.filter((item, index) => {
return tempArray.indexOf(item) == index;
})
//[1, 2, 5, 6, 7]
console.log(a);

//遍历过程
item = 1,index=0
tempArray.indexOf(item) 返回 0
return 0 == 0 ;//为true,存储'1'

item = 2,index=1
tempArray.indexOf(item) 返回 1
return 1 == 1 ;//为true,存储'2'


item = 5,index=2
tempArray.indexOf(item) 返回 2
return 2 == 2 ;//为true,存储'5'

item = 5,index=3
tempArray.indexOf(item) 返回 2
return 2 == 3 ;//为false,不存储


item = 6,index=4
tempArray.indexOf(item) 返回 4
return 4 == 4 ;//为true,存储'6'

item = 6,index=5
tempArray.indexOf(item) 返回 4
return 4 == 5 ;//为false,不存储

item = 7,index=6
tempArray.indexOf(item) 返回 6
return 6 == 6 ;//为true,存储'7'

element-ui当中<el-table></el-table>索引自定义

关键在于为type='index'的绑定:index="自定义函数"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<template>
<div>
<el-table :data="objects" border>
<el-table-column
align="center"
width="80"
type="index"
:index="indexMethod"
label="索引">
</el-table-column>
<el-table-column prop="prop" label="工作地址"> </el-table-column>
</el-table>
</div>
</template>

<script>
export default {
name: "",
data() {
return {
objects: [
{
ID: "1",
JobTitle: "Front Desk Coordinator",
EmailAddress: "Sofie_Jennson149@deons.tech",
FirstNameLastName: "Sofie Jennson",
},
{
ID: "2",
JobTitle: "Global Logistics Supervisor",
EmailAddress: "Wade_Gallacher1821@elnee.tech",
FirstNameLastName: "Wade Gallacher",
},
],
};
},
methods: {
//自定义索引,转化为0001,0002,0003的这种
indexMethod(index) {
//转字符串
index = index.toString();
while (index.length < 4) {
index = "0" + index;
}
return index;
},
},
};
</script>

<style lang="less" scoped>
</style>

效果

element-ui当中<el-table></el-table>索引自定义

el-table-column使用插槽并将数据绑定在v-model为什么可以实现双向绑定影响到原来数据

当初学的时候很懵懵懂懂,觉得既然把数据传递给了组件去显示,那应该影响不到原来的数据呢,为什么还会影响到原来数据

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<template>
<div>
<el-table :data="attrForm" border>
<el-table-column prop="EmailAddress" label="邮箱地址">
<template slot-scope="{ row }">
<!-- 为什么可以实现用户输入后data当中的数据也改变? -->
<el-input v-model="row.EmailAddress"></el-input>
</template>
</el-table-column>
</el-table>
</div>
</template>

<script>
export default {
name: "",
data() {
return {
attrForm: [
{
ID: "1",
JobTitle: "Front Desk Coordinator",
EmailAddress: "Sofie_Jennson149@deons.tech",
FirstNameLastName: "Sofie Jennson",
},
{
ID: "2",
JobTitle: "Global Logistics Supervisor",
EmailAddress: "Wade_Gallacher1821@elnee.tech",
FirstNameLastName: "Wade Gallacher",
},
],
};
},
};
</script>

当初的疑问

原因

因为element-ui当中,是按照列来传递数据的,也就是当element-ui遍历attrForm的时候,会将当前遍历项目传递给每一个<el-table-column>,所以为什么输入框当中输入的数据会影响到data

  • 首先是v-model的原因
  • 其次就是传递的是引用数据类型使用指向同一个数据

差不多这样子图过程吧

数组哪些方法的使用不会影响数组的响应式?

1
2
3
4
5
6
7
push()
pop()
shift()
unshift()
splice()
sort()
reverse()

再加上一个整体替换也不会

比如data当中的a数组是响应式的,整体替换,this.a = b;(b也为一个数组),也不会影响数组的响应式

获取输入框的焦点

1
this.$refs.xxx.focus();获取焦点

el-dialog的显示隐藏的控制

<el-dialog></el-dialog>是支持.sync的写法的,比如<el-dialog :visible.sync="xxxx"></el-dialog>
由这个xxx来决定这个dialog是否是显示还是隐藏

el-form当中的el-form-item占据一行问题

el-form-item添加下属性label-width:"80px"或者80px自己改为其他的即可

前后效果

顺带一提

<el-input>改为输入框设置type="textarea"再添加下row="4"即可多行输入

type="textarea"

可以使用混入mixin解决export default过长

混入,说简单就是将一个东西和另外一个东西混合在一起,注意是混合,不是替换!,比如我在一个文件里面有方法A,我混入在另外一个文件夹里面,那么另外一个文件夹就可以使用A了

使用:

  • 引入要混入的对象
  • 配置对象添加mixins:[],数组当中填写引入的混入对象的名称即可

例子:

com.js(可以看到,和组件传入的配置对象基本一样)

1
2
3
4
5
6
7
8
9
10
11
12
export default {
data() {
return {
address:"地球村"
}
},
methods: {
sayOther(){
console.log("回收装备,没区别");
}
},
}

Home.vue(混入使用com.js)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<template>
<div></div>
</template>

<script>
import com from "@/other/com.js";
export default {
name: "",
mixins:[com],
data() {
return {
name: "李白",
};
},
mounted(){
//调用自己的方法
this.show();
//调用混入其中的方法
this.sayOther();
console.log(this.name);//李白
console.log(this.address);//地球村
},
methods: {
show() {
console.log("大家好,我叫" + this.name);
},
},
};
</script>

watch和$nextTick结合使用

  • watch只能监视数据的变化,而因为数据变化导致的dom更新是否已经完成watch并不知道(相当于你数据一发生变化,我就执行你设置的回调函数)
  • 而如果我们希望等待dom更新完成后在执行回调,我们就需要结合$nextTick使用
  • $nextTick意思是等待下一次DOM更新后在执行回调
  • 比如说轮播图,如果我们轮播图数据发生了变化,watch监视到了,如果我们立马执行操作使得轮播图重新绘制生成,那么肯定是不行的,因为dom都没有生成,轮播图怎么重新获取dom进行生成,所以我们就可以在里面添加$nextTick等下次DOM更新完成后执行即可
  • 顺带一提: watch支持异步请求,并且支持深度监视,computed不支持
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.js"></script>
<div id="app">
<p ref="title">{{name}}</p>
</div>
<script>
var vm = new Vue({
data: {
name: 'tom'
}
}).$mount('#app');
vm.name = "汤姆";
//设置新名字后立马输出里面的文本,发现输出的依旧是'tom',而不是'汤姆'
//因为dom还没有更新完成
console.log(vm.$refs.title.textContent); // tom

//下一次dom更新完成后输出,发送输出的是'汤姆'了
vm.$nextTick(()=>{
console.log(vm.$refs.title.textContent); // tom
})
</script>

解构赋值 { } 和 [ ]

  • { }不多说

  • [ ] 按顺序解构赋值

    1
    2
    let[,attr] = "v-on:text".split(":");
    console.log(attr);//输出text

vue-router配置对象当中的scrollBehavior

可以使得切换路由的时候,路由滚动条可以滚动到我们想滚动的位置

1
2
3
4
5
6
7
8
const router = new VueRouter({
mode: "history",
routes,
//每次路由切换的时候,就将滚动条滚动到最顶端
scrollBehavior(to, from, savedPosition){
return {x:0,y:0}
}
})

getters当中要用一个||[] ||{} 的用处

  • 因为有些项目需要从后台发送请求来渲染页面,但是这些数据因为网络延迟的问题肯定不能及时到达,所以就需要在到达之前使用[]或者{}(依据返回数据是数组还是对象来选择),来进行填充,不然你一个空字符串去参与遍历(比如v-for)那肯定会报错的
  • 再者,有人会说getters的事情和我组件有什么关系,一个是仓库,一个是组件,还是有关系的,(因为组件调用了mapGetters来获取仓库的数据),当数据不存在的时候或者遍历一个不可以遍历的数据的时候,就会报错(虽然报错后数据显示依旧正常,是因为后期数据返回,重新渲染了~)(这叫假报错)
  • 所以有时候为了避免假报错,就需要使用||[] ||{}

比如这个

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const getters = {
// 面包屑
categoryView(state){
return state.skuDetailInfo.categoryView||{};
},
// 商品详情
skuInfo(state){
return state.skuDetailInfo.skuInfo||{};
},
// 商品售卖属性
spuSaleAttrList(state){
return state.skuDetailInfo.spuSaleAttrList||[]
}
}
  • 还有就是有时候我们多层嵌套读取数据,比如a.b.c通过a读取b,又通过b读取c,假如读取到b的时候,b是undefined,那么在读取c就会报错,所以这个时候就可以考虑使用||[] 或者 ||{}

localStorage.getItem();如果获取不到指定的key,返回的是null不是返回undefined

axios的请求头(Content-Type)

1
2
3
4
5
6
7
8
// 1 默认的格式请求体中的数据会以json字符串的形式发送到后端(默认)
'Content-Type: application/json '

// 2 请求体中的数据会以普通表单形式(键值对)发送到后端
'Content-Type: application/x-www-form-urlencoded'

// 3 它会将请求体的数据处理为一条消息,以标签为单元,用分隔符分开。既可以上传键值对,也可以上传文件
'Content-Type: multipart/form-data'

注意:

jQuery当中的$.post默认请求头(Content-Type)为 application/x-www-form-urlencoded; charset=UTF-8

当不使用vuex的时候,我们可以把接口请求函数全部封装在对象当中并挂载Vue原型上

如:在main.js当中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 也就是先导入封装所有ajax请求的api.js
import * as API from "@/api.js"
// 挂载到vue原型上,和全局事件总线挂载一样
// 都是在vue生命周期的beforeCreate挂载
new Vue({
...
beforeCreate(){
//全局事件总线
//Vue.prototype.$bus = this;
//ajax请求
Vue.prototype.$API = API;
},
...
})

Vue注册全局注册的二种方式

  • Vue.use()

main.js文件(主入口文件)使用Vue.use方法全局注册

其实element-ui官方也是使用Vue.use()来注册全局组件的~

1
2
3
4
5
6
7
8
9
10
11
12
13
import Vue from 'vue'
import App from './App.vue'
//引入element-ui组件
import ElementUI from "element-ui"
import "element-ui/lib/theme-chalk/index.css"
Vue.use(ElementUI);

Vue.config.productionTip = false

new Vue({
render: h => h(App),
}).$mount('#app')

  • Vue.component()

一般我们用Vue.componet()比较多,因为使用Vue.use()注册全局组件使用起来麻烦点,element-ui看起来使用简单是因为内部封装好了

  • Vue.componet(参数1,参数2)
    • 参数1:注册的组件名
    • 参数2:注册的组件

main.js文件(主入口文件)使用Vue.component方法全局注册

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import Vue from 'vue'
import App from './App.vue'
//引入自定义组件
import MyButton from '@/components/MyButton'

//全局组成element-ui组件
//参数1: 注册的组件名字为 'MyButton'
//参数2: 注册的组件为 MyButton
Vue.component('MyButton',MyButton);

//或者如果组件配置了name属性,可以直接使用组件的name当中的值
//Vue.component(MyButton.name,MyButton);

new Vue({
render: h => h(App),
}).$mount('#app')

Vue当中的watch

直接就一个监视回调函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<template>
<div>
<button @click="name = '我是渣渣辉'">这是按钮</button>
<span>{{ name }}</span>
</div>
</template>

<script>
export default {
name: "MyButton",
data() {
return {
name: "李白",
};
},
watch: {
// 监视name值的变化
name(newValue, oldValue) {
console.log("值发生了变化");
},
//代码等同于
// name: {
// handler(newValue, oldValue) {
// console.log("值发生了变化");
// },
// },
},
};
</script>

<style lang="less" scoped>
</style>

如果需要监视对象当中某一个值的变化的话,就需要用到这种形式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
data() {
return {
eat:{
vegetable:"西红柿",
meat:"牛肉"
}
};
},
watch: {
// 监视eat对象当中meat值的变化
'eat.meat'(newValue, oldValue) {
console.log("值发生了变化");
},
},
书写配置项(比如是否深度监视)

如果我们想监视一个对象当中所有值的变化,包括内部对象的值的变化,我们不可以一个个去书写监听回调吧?我们可以使用配置项当中的deep

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<template>
<div>
<button @click="eat.meat = '和牛'">改变肉类</button><br/>
<button @click="eat.vegetable = '青菜'">改变蔬菜</button><br/>
<button @click="eat.other.fruit = '苹果'">改变水果</button><br/>
<span>{{ eat.meat }}</span> <br/>
<span>{{ eat.vegetable }}</span><br/>
<span>{{ eat.other.fruit }}</span><br/>
</div>
</template>

<script>
export default {
name: "MyButton",
data() {
return {
eat: {
vegetable: "西红柿",
meat: "牛肉",
other: {
fruit: "草莓",
},
},
};
},
watch: {
//深度监听eat当中值的变化,嵌套多少层都会监听到
eat: {
deep: true,
handler() {
console.log("值发生了变化");
},
},
},
};
</script>

<style lang="less" scoped>
</style>

npm run build:prod 或者 npm run build:stage

  • npm run build:prod: 构建生产环境
    • 打包的时候会读取.env.development文件的,所以不需要前缀可以编辑下这个文件
  • npm run build:stage: 构建测试环境
    • 打包的时候会读取.env.production文件的,所以不需要前缀可以编辑下这个文件

npm run build:prod 或者 npm run build:stage

解决:

vue_project\src\router\index.js 路由主入口文件当中添加如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

const originalPush = VueRouter.prototype.push
//解决重复提交相同链接报错
VueRouter.prototype.push = function push(location, onResolve, onReject) {
if (onResolve || onReject)
return originalPush.call(this, location, onResolve, onReject)
return originalPush.call(this, location).catch((err) => {
if (VueRouter.isNavigationFailure(err)) {
// resolve err
return err
}
// rethrow error
return Promise.reject(err)
})
}
const originalReplace = VueRouter.prototype.replace
VueRouter.prototype.replace = function replace(location, onResolve, onReject) {
if (onResolve || onReject){
//回调函数里面会用到this的指向,所以就要使用call
return originalReplace.call(this, location, onResolve, onReject)
}
return originalReplace.call(this, location).catch((err) => {
if (VueRouter.isNavigationFailure(err)) {
//如果为相同链接引发的错误,返回错误原因,promise状态为resolve
// resolve err
return err
}
// rethrow error
return Promise.reject(err)
})
}