首页 前端知识 vue后台的一个项目遇到的一些问题和解决办法的记录

vue后台的一个项目遇到的一些问题和解决办法的记录

2024-03-26 08:03:52 前端知识 前端哥 47 116 我要收藏
vue使用echarts报错Error in mounted hook: “TypeError: this.dom.getContext is not a function”
  • 解决
    • 一开始是this. r e f s . d o m 获 取 节 点 的 , 后 面 使 用 在 ‘ < e l − r o w > ‘ 标 签 上 就 不 可 以 , 所 以 如 果 使 用 t h i s . refs.dom获取节点的,后面使用在`<el-row>`标签上就不可以,所以如果使用this. refs.dom,使<elrow>,使this.refs进行echarts的初始化操作会报错,就使用原生dom获取节点后初始化即可
elementUI 日期选择器在vue-admin中设置中文显示
  • 方法

    • main.js文件当中

      // 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即可

    如图

    • 成功解决

      成功解决

支付的轮询

代码

//开始轮询
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构造函数去重
<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如果找到第一个会停止寻找

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="自定义函数"

<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-column使用插槽并将数据绑定在v-model为什么可以实现双向绑定影响到原来数据

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

例子

<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的原因
  • 其次就是传递的是引用数据类型使用指向同一个数据

差不多这样子图过程吧

数组哪些方法的使用不会影响数组的响应式?
push()
pop()
shift()
unshift()
splice()
sort()
reverse()

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

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

获取输入框的焦点
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(可以看到,和组件传入的配置对象基本一样)

export default {
    data() {
        return {
            address:"地球村"
        }
    },
    methods: {
        sayOther(){
            console.log("回收装备,没区别");
        }
    },
}

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

<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不支持
<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>
解构赋值 { } 和 [ ]
  • { } 不多说

  • [ ] 按顺序解构赋值

    let[,attr] = "v-on:text".split(":");
    console.log(attr);//输出text
    
vue-router配置对象当中的scrollBehavior

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

const router = new VueRouter({
    mode: "history",
    routes,
    //每次路由切换的时候,就将滚动条滚动到最顶端
    scrollBehavior(to, from, savedPosition){
        return {x:0,y:0}
    }
})
getters当中要用一个||[] ||{} 的用处
  • 因为有些项目需要从后台发送请求来渲染页面,但是这些数据因为网络延迟的问题肯定不能及时到达,所以就需要在到达之前使用[]或者{}(依据返回数据是数组还是对象来选择),来进行填充,不然你一个空字符串去参与遍历(比如v-for)那肯定会报错的
  • 再者,有人会说getters的事情和我组件有什么关系,一个是仓库,一个是组件,还是有关系的,(因为组件调用了mapGetters来获取仓库的数据),当数据不存在的时候或者遍历一个不可以遍历的数据的时候,就会报错(虽然报错后数据显示依旧正常,是因为后期数据返回,重新渲染了~)(这叫假报错)
  • 所以有时候为了避免假报错,就需要使用||[] ||{}

比如这个

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 默认的格式请求体中的数据会以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当中

// 也就是先导入封装所有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()来注册全局组件的~

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方法全局注册

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
直接就一个监视回调函数
<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>

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

  data() {
    return {
      eat:{
          vegetable:"西红柿",
          meat:"牛肉"
      }
    };
  },
  watch: {
    // 监视eat对象当中meat值的变化
    'eat.meat'(newValue, oldValue) {
      console.log("值发生了变化");
    },
  },
书写配置项(比如是否深度监视)

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

<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

转载请注明出处或者链接地址:https://www.qianduange.cn//article/4167.html
标签
评论
会员中心 联系我 留言建议 回顶部
复制成功!