后台管理系统

1,059 阅读3分钟

(一).PC端后台管理系统开发总结

(1)vue+elementui进阶之路el-table中显示图片

1、table中显示图片

2、当需要遍历图片时,不能直接使用prop绑定值

一张图片
<el-table-column label="头像">
    <template slot-scope="scope">
        <img :src="scope.row.img" width="50" height="50"/>
    </template>
</el-table-column>

多张图片
<el-table-column prop="pictures" label="描述图片">
    <template scope="scope">
        <img v-for="item in scope.row.pictures" :src="item" width="50" height="50"/>
    </template>
</el-table-colunm>


使用@change="handleStatusChange(scope.row)"这种方式进行点击事件传值
<el-table-column label="状态" align="center">     
    <template slot-scope="scope">          
        <el-switch v-model="scope.row.status" 
        active-value="0" 
        inactive-color="1" 
        @change="handleStatusChange(scope.row)">
        </el-switch>     
    </template>   
</el-table-column>

(2)上传图片

1、转成base64上传图片

<!-- 上传图片的 -->

 <input type="file" id="uploadIcon" @change="uploadImg" accept="image/*" /> 
 <el-image style="width: 100px; height: 100px" :src="dataForm.testSubjectImg"></el-image>

// 上传图片    
uploadImg: function (e) {      
    console.log(e.target.files[0]);      
// this.dataForm.file=e.target.files[0]      
    let _this = this;      
    if (!e || !window.FileReader) return; // 看支持不支持FileReader      
    let reader = new FileReader();      
    reader.readAsDataURL(e.target.files[0]);     
    reader.onloadend = function () {        
        _this.dataForm.testSubjectImg = this.result;        
        _this.dataForm.files = this.result;      
    };    
    },

2、上传图片
<!-- 上传图片 -->        
<el-form-item label="上传图片">          
<img v-if="form.image" :src="form.image" class="avatar">          
<el-upload action="#" :http-request="requestUpload" :before-upload="beforeUpload">            <el-button size="small" >              上传              <i class="el-icon-upload el-icon--right"></i>            </el-button>          </el-upload>        </el-form-item>

 // 上传预处理    
beforeUpload(file) {      
    if (file.type.indexOf("image/") == -1) {        
        this.msgError("文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。");      
}       // 
else {      
//   const reader = new FileReader();     
//   reader.readAsDataURL(file);     
//   reader.onload = () => {      //     
// console.log(reader.result)      //     
this.form.image = reader.result;      //     
this.form.file=reader.result;      //   
};      // }    },    
// 覆盖默认的上传行为    
requestUpload(e) {      
console.log(e)      
let formdata=new FormData()      
formdata.append('avatarfile',e.file)      
uploadImage(formdata).then(response => {          
console.log(response)          
if(response.code===200){            
this.newImage=response.imgUrl;            
this.form.image= process.env.VUE_APP_BASE_API + response.imgUrl          
}        
});    
},



<el-row :gutter="20">     
     <el-col :span="1.5"> 选择文件 </el-col>      
        <el-col :span="1.5">        
            <el-upload action="#" :limit="1" :show-file-list="false" :on-change="handleChange">          
                <el-button size="mini" type="primary">上传文件</el-button>        
            </el-upload>      
        </el-col>      
            <el-col :span="8">        
                <span>{{ name }}</span>      
            </el-col>      
            <el-col :span="6" class="fl_btn">        
                <el-button size="mini" type="primary" @click="upLoadImg">上传</el-button>      
            </el-col>    
</el-row>

// 上传   
handleChange(img) {      
    this.name = img.name;      
    this.formData = img.raw;      
    console.log(img);    
},    
// 上传图片    
upLoadImg() {      
    var formData = new window.FormData();      
    formData.append("file", this.formData);      
    formData.append("type", this.type);      
    formData.append("uid", this.uid);      
    console.log(formData);      
    uploadImage(formData).then((res) => {        
        console.log(res);        
        if (res.code == 200) {          //   
            this.$emit("upload", res.data.fileUrl);          
            this.name = "未选择文件";          
            this.getImgList();          
            this.msgSuccess("上传成功");        
        } else {          
            this.msgError("失败");        
        }      });    },

(3).element-ui样式调整

1.vue使用elementUI form表单label样式修改

(1)删除style标签中的scoped属性

(2)在对应el-form-item的label属性中加入class样式

<el-form-item label="用户名" class="item"> 
    <el-input v-model="ruleForm.username" placeholder="请输入用户名" maxlength="10"></el-input> 
</el-form-item>

(3)审查元素,找到label对应的class

如:.el-form-item__label 添加如下样式代码

.item .el-form-item__label{
    color: wheat;
}

(4)父子组件传值

1.父组件:  :color="color"

2.子组件接受值   

props:{
    color:{
        type:String,
        default:""
    }
}

3.在页面中显示

v-bind:style="{color:color}"

(5) VUE兄弟组件之间传值,Vue.prototype.bus=new Vue(),this.bus.$on的使用方法

1.在main.js中添加一个bus实例

Vue.prototype.bus=new Vue();

2.分享按钮  加点击事件;把这个true值传给组件二

<a href="#"
    class="wap-zl-share"
    @click="share1">
</a>
<script>
export default {
  data () {
    return {
      'iscancle': true
    }
  },
  methods: {
    sharecl () {
      this.bus.$emit('sharecl', this.iscancle)
      // console.log(this.iscancle)
    }
  },
}
</script>

3。默认组件二的分享组件为隐藏;组件二分享组件接受一传过来的值;点击取消按钮iscancle改为false

<div class="wapshare"
       v-show="iscancle">
       我是分享内容
       <p class="share_cancle"
         @click="cancle">取消</p>
</div>
<script>
export default {
  data () {
    return {
      'iscancle': false,
    }
  },
  created () {
    this.bus.$on('sharecl', iscancle => {
      this.iscancle = iscancle
    })
  },
  methods: {
    cancle () {
      this.iscancle = false
      // console.log(iscancle)
    }
  },
}
</script>

(6)更改table中分页的样式

可以添加多个

<style lang="scss" scoped>

</style>

<style lang='scss'>
.pagination-container{
    background:none !important;
    color:#fff;
    .el-pagination{
        .el-pagination__total{
            color:#fff !important;
        }
        .el-pagination__jump{
            color:#fff !important;
        }
    }

}
</style>

(7)父子组件中显示

父组件

<base-header :title="title" :color="color"></base-header>

子组件

<span v-bind:style="{color:color}">{{title}}</span>

props:{
    title:{
        type:String,
        default:''
    },
    color:{
        type:String,
        defalt:''
    }
}

(8)VUE中监听路由参数的变化

当传值到下一页判断下一页内容显示问题时,使用string类型判断,如果使用Boolean类型传值到下一页的话会自动转类型

this.$router.push({
    path:'/proccess/examine',
    query:{isSee:"0"}
})

当值不同时,判断是否一样,如果不一样的时候就赋值新的值

watch:{
    $route(to,from){
        if(to.query.isSee!==from.query.isSee){
            this.isSee=this.$route.query.isSee
        }
    }
}

(9)el-form嵌套在table

<el-form :model="fromData" ref="from">
    <el-table :data="fromData.domain" border size="larget">
        <el-table-coloumn label="开始放假时间">
            <template slot-scope="scope">
                <el-form-item 
                :prop="'domains.'+scope.$index+'.startTime'"
                :rules="fromDataRules.startTime"
                >
                    <el-picker
                        type="date"                        
                        v-model="scope.row.startTime"
                    ></el-picker>
                </el-form-item>
            </template>
        </el-table-column>
        <el-table-coloumn label="结束放假时间">            <template slot-scope="scope">
                <el-form-item 
                :prop="'domains.'+scope.$index+'.endTime'"
                :rules="fromDataRules.endTime"
                >
                    <el-picker
                        type="date"                        
                        v-model="scope.row.endTime"
                    ></el-picker>
                </el-form-item>
            </template>
        </el-table-column>
    </el-table>
</el-form>



fromDataRules:{
    startTime:[
        {required:true,message:'请输入开始时间',trigger:'blur'}
    ]
}

data(){
    return{
        数组中时间判断,使用@change事件拿到索引值进行判断
    }
}

(9)上传和下载功能

<el-form-item prop="stddspfile">
    <el-upload
     v-model="form.stddspfile"
     action="#"
     :http-request="requestUpload"
     :show-file-list="false"
    >
   <el-button type="primary">上传</el-button>
</el-upload></el-form-item>

requestUpload(e){
   let formdata=new FormData()
   formdata.append('file',e.file)
   //调取接口
   uploadImg(formdata).then(res=>{})进行处理
}


下载功能是先调下载接口
const baseURL = process.env.VUE_APP_BASE_API
export function download(fileName){
    window.loacation.href=baseURL+'/common/download?fileName='+encodeURL(fileName)+'&delete='+true;
}

(10)当使用本地缓存存Boolean类型时,localStorage.getItem('isshow')

eval(localStorage.getItem('isshow').toLowerCse())

(11)vue如何监听浏览器刷新事件

在created、mounted 都行啊。window.addEventListener('beforeunload', e => {    localStorage.setItem("store",JSON.stringify(this.$store.state))});

(12)typeof 与instanceof的区别

js是一个弱类型的语言,所以一般想知道当前变量是哪一种类型必须判断类型,都知道判断类型的两种方式:typeof、instanceof。它们各有缺点:typeof适用于基础数据类型判断,引用类型判断都是object。instanceof判断一个实例是否属于某种类型,但严重存在原型继承,所以判断最好在两个对象之间。

tyeof

typeof是一个一元运算,放在一个运算数之前,运算数可以是任意类型。它返回值是一个字符串,该字符串说明运算数的类型。typeof可以用来检测给定变量的数据类型。

var a = [34,4,3,54],
b = 34,
c = 'adsfas',
d = function(){console.log('我是函数')},
e = true,
f = null,
g;
console.log(typeof(a));//object
console.log(typeof(b));//number
console.log(typeof(c));//string
console.log(typeof(d));//function
console.log(typeof(e));//boolean
console.log(typeof(f));//object
console.log(typeof(g));//undefined

但是你可能会发现,typeof在判断null,array,object以及函数实例(new +函数)时,得到的都是object(其实都是原型继承)。这使得在判断这些数据类型的时候,得不到真的数据类型。由此引出instanceof

instanceof

instanceof运算符用来判断一个构造函数的prototype属性所指向的对象是否存在另外一个要检测对象的原型链上。通常来讲,使用 instanceof 就是判断一个实例是否属于某种类型。 a instanceof b:判断a是否为b的实例,可以用于继承关系中 b是c的父对象,a是c的实例,a instanceof b 与 a instanceof c 结果均为true [] instanceof Object // true [] instanceof Array // true 因为Array也是Object的实例对象,由于原型继承造成这种情况 

在这里插入图片描述

instanceof 只能处理两个对象是否属于的实例关系

(三)sass加载不出来,如下图所示,以及解决办法

1. 错误代码:原因是sass-loader版本过高导致的

Module build failed: TypeError [ERR_INVALID_ARG_TYPE]: 
The "path" argument must be of type string. Received type undefined

解决方案:重装低版本sass-loader

npm uninstall sass-loader
npm install --save-dev sass-loader@7.3.1

2.node-sass的安装,以及出现的问题及解决方法

node-sass是一个项目依赖,在一个项目中在使用sass语法的时候,必须通过sass-loader来解析sass,从而sass语法变成浏览器能够识别的css语法,而node-sass模块就是对sass-node的支持模块,如果不安装node-sass,sass-loader就不能正常工作。

安装sass时经常出错的解决办法:

npm install -g cnpm --registry=https://registry.npm.taobao.org (安装淘宝镜像)
cnpm install node-sass --save (使用淘宝镜像安装node-sass

原本以为安装好淘宝镜像之后就可以成功安装node-sass,但是visual studio code终端又出现了 “cnpm - 解决“cnpm:无法加载文件C:*******,因为在此系统上禁止运行脚本……(等有关信息)”

这次我们可以在win10搜索框中输入Windows PowerShell,然后选择管理员身份运行(记得是要管理员身份,要不然就出错)

然后在输入命令:set-ExecutionPolicy RemoteSigned,然后修改权限为A,最后最后通过 get-ExecutionPolicy 查看当前的状态,如下图显示就是成功了

接着回到visual studio code的终端,运行npm install node-sass --save,问题就就解决了。

3.前端启动项目的时候报错,最好的做法就是

1.安装cnpm
2.把该项目文件夹下的node_modules彻底删掉,必须彻底
3.然后cnpm install(安装依赖包)   cnpm run dev(运行)

(四)element-ui表单重置函数resetFields()使用注意事项

<el-form :model="queryParams" ref="queryForm">

//封装
export function resetForm(refName){
   if(this.$refs[refName]){
       this.$refs[refName].resetFields();
}

在main.js中引入
import {resetForm} from '路径'

全局方法挂载
Vue.prototype.resetForm=resetForm;

在需要的页面
this.resetForm("传入节点")



(五)字符串拼接+es6字符串拼接

"' + userIds + '"

es6拼接
`${userIds}`

(六)vue-treeselect的使用

实现:
(1)首先安装包 "@riophae/vue-treeselect"2)在要用的vue页面上引入
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
(3)注册组件
components: { Treeselect }


7、转类型

// 转换字符串,undefined,null等转化为""

export function praseStrEmpty(str) {

if (!str || str == "undefined" || str == "null") {

return "";

}

return str;

}

8、全局组件挂载

1、引入
import RightToolbar from '@/components/RightToolbar'
2、全局组件挂载
Vue.component('RightToolbar',RightToolbar)
3、在页面中引用
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
4、v-show="showSearch"

9、vue-router中routeroute和router

1、$route对象(当前路由信息对象)

表示当前激活的路由的状态信息,包含了当前URL解析得到的信息,还有URL匹配到的route records(路由记录)

路由信息对象:即$router会被注入每个组件中,可以利用它进行一些信息的获取

$route.path  //字符串,对应当前路由的路径,如"/foo/bar"
$route.params  //一个key/value对象,包含了动态片段和全匹配片段,如果没有路由参数
,就是一个空对象
$route.query    //一个key/value对象,表示URL查询参数
                //对于路径/foo?user=1,则有$route.query.user==1
                //如果没有查询参数,则是个空对象
$route.hash     //
$route.fullPath  //完成解析后的URL,查询参数和hash的完整路径
$route.matched   //数组,包含当前匹配的路径中所包含的所有片段所对应的配置参数对象
$route.name      //当前路径名称
$route.meta      //路由元信息

10、Vue组件component创建及使用

Vue提供了component,来展示对应名称的组件

component是一个占位符,:is属性可以用来指定要展示的组件名称

使用component占位符来展示组件
注意:is是绑定的属性,需要在实例的data中绑定,组件的名称是字符串
其中  他还提供了mode属性来切换动画的先进先出的问题

11、vue.js如何根据后台返回来的图片进行图片下载

在左下方进行下载图片

//HTML
<el-table-column label="文件名称" prop="fileName">   
    <template slot-scope="scope">     
        <a @click="downLoadImg(scope.row)">{{ scope.row.fileName }}</a>   
    </template> 
</el-table-column>

// 下载图片    
downLoadImg(row) {      
    var that = this;      
    downloadBlob(row.filePath, row.fileName);    
},



function download(href, name) {    
    let eleLink = document.createElement("a");    
    eleLink.download = name;    
    eleLink.href = href;    e
    leLink.click();    
    eleLink.remove();}
    function downloadBlob(url, name) {    
        let image = new Image();    
        image.setAttribute("crossOrigin", "anonymous");    
image.src = url;    image.onload = () => {        let canvas = document.createElement("canvas");        canvas.width = image.width;        canvas.height = image.height;        let ctx = canvas.getContext("2d");        ctx.drawImage(image, 0, 0, image.width, image.height);        canvas.toBlob((blob) => {            let url = URL.createObjectURL(blob);            download(url, name);            // 用完释放URL对象            URL.revokeObjectURL(url);        });    };}export {    download,    downloadBlob}

然后就可以下载了

12、点击预览放大图片

<template>  <!-- 过渡动画 -->  <transition name="fade">    <div class="img-view" @click="bigImg" v-if="show===true">      <!-- 遮罩层 -->      <div class="img-layer"></div>      <div class="img">        <img :src="imgSrc" />      </div>    </div>    </transition></template><script>export default {  props: ["imgSrc", "show"],  methods: {    bigImg() {      // 发送事件      this.$emit("clickit", { show: false });    },  },};</script><style scoped>body,html {  width: 100%;  height: 100%;}/*动画*/.fade-enter-active,.fade-leave-active {    transition: all .2s linear;    transform: translate3D(0, 0, 0);}.fade-enter,.fade-leave-active {    transform: translate3D(100%, 0, 0);}.img-view {  position: fixed;  top: 0;  left: 0;  right: 0;  bottom: 0;  width: 100%;  height: 100%;  z-index: 3000;}/*遮罩层样式*/.img-view .img-layer {  position: fixed;  z-index: 1999;  top: 0;  left: 0;  right: 0;  bottom: 0;  background: rgba(0, 0, 0, 0.7);  width: 100%;  height: 100%;  overflow: hidden;}.img-view .img {  /* width: 80%; */  display: block;  position: absolute;  left: 50%;  top: 50%;  transform: translate(-50%, -50%);  z-index: 3001;}/*不限制图片大小,实现居中*/.img-view .img img {  max-width: 100%;  height: 100%;}</style>

<large-img :imgSrc="imgSrc" :show="show" @clickit="clickit"></large-img>

// 预览handleSeeInfo(row) {   this.imgSrc = row.filePath;   this.show = true;},
/**预览图片 */clickit(thing) {   this.show = thing.show;},

13.如何实现高性能的在线PDF预览

用户需要在我们可站点上在线查看 PDF 文件,并且查看时,用户可以对 PDF 文件的进行旋转、缩放、跳转到指定页码等操作。

  • 使用 iframe、embed、object 标签直接加载

采用此方案,只需要直接将 PDF 的在线地址设置为标签的 src 属性

  • 使用第三方库 PDF.js 加载

PDF内容分票加载

如何让用户快速打开内容,减少等待时间。由于现有方案都是将pdf文件内容全部下载完成之后才开始渲染,如果文件比较大的时候,用户第一次打卡时就可能需要等待很长时间。()可以不下载全部的文件内容就开始渲染

因为用户不可能一眼看到所有的 PDF 内容,每次只能看到屏幕显示范围内的几页。所以我们可以将可视范围内的PDF 页面内容优先下载并展示,可视范围外的我们根据用户浏览的实际位置按需下载和渲染。这样就可以减少第一次打开时用户的等待时间了。(类似与数据分页、图片懒加载的思想,目的是提高首屏性能。)

我们需要跟后端约定好PDF文件分片之后的数据格式。加入分片的大小为5(即每次请求5页内容)

{
   "startPage":1,//分片的开始页码
    "endPage":5,//分片结束页码
    "totalPage":100,//pdf总页码数
    "url":"http://test.com/asset/fhdf82372837283.pdf" // 分片内容下载地址
}

pdf上传与预览

<div class="importPDF">    <el-dialog      title="PDF数据导入"      :visible.sync = showDataImportDialog      center      width="35%" style="left: 10%">      <div>        <label style="font-weight: bold;margin-right: 10px;">文      件:</label>        <el-input v-model="fileName" size="mini" style="width:52%; margin-left: 18px"></el-input>        <el-upload          class="upload-demo"          ref="upload"          action="/pdf/upload"          :show-file-list="false"          :before-upload="beforeUpload">          <el-button slot="trigger" size="mini" type="danger">选取文件</el-button>        </el-upload>         <el-form ref="pdfForm"  :model="pdfForm" >           <el-form-item label="公告类型" style="margin-top: 10px">             <el-select class="formItem" size="mini" placeholder="请选择公告类型" v-model="pdfForm.announcementType">               <el-option v-for="item in announcementTypeOptions"                          :key="item.value"                          :label="item.label"                          :value="item.value"></el-option>             </el-select>           </el-form-item>           <el-form-item label="文件级别"  style="margin-top: -20px">             <el-select class="formItem" size="mini" placeholder="请选择文件级别" v-model="pdfForm.fileLevel">               <el-option v-for="item in fileLevelOptions"                          :key="item.value"                          :label="item.label"                          :value="item.value"></el-option>             </el-select>           </el-form-item>         </el-form>        <div style="margin-top: 10px">备注:仅限上传一个PDF文件</div>      </div>      <div slot="footer" style="text-align: center;">        <el-button size="mini" @click="viewfile">预览</el-button>        <el-button size="mini" type="primary" @click="upLoadpdf()">上传</el-button>        <el-button size="mini" @click="showDataImportDialog = false">取 消</el-button>      </div>    </el-dialog>  </div>

//上传PDF文件之前      beforeUpload(file){        console.log("文件", file);        this.file = file;        this.fileName = file.name;        // this.fileSize = file.size;        const extension = file.name.split('.').slice(-1) == 'pdf'        if (!extension) {          this.$message.warning('上传模板只能是pdf格式!')          return        }        let reader = new FileReader();        reader.readAsDataURL(file);        let that = this;        reader.onload = function() {          that.fileData = reader.result;        };        return false; // 返回false不会自动上传      },      //预览文件      viewfile(){        console.log("viewFile");        var win = window.open();        win.document.write(          '<body style="margin:0px;"><object data="' +          this.fileData +          '" type="application/pdf" width="100%" height="100%"><iframe src="' +          this.fileData +          '" scrolling="no" width="100%" height="100%" frameborder="0" ></iframe></object></body>'        );        // win.document.write(        //   '<body style="margin:0px;"><iframe src="' +        //     this.fileData +        //     '" scrolling="no" width="100%" height="100%" frameborder="0" ></iframe></body>'        // );      },      //上传文件按钮      upLoadpdf(){        if(this.fileName === ''){          this.$message.warning('请选择要上传的文件!');          return false        }        if(this.pdfForm.announcementType === ''){          this.$message.warning('请选择公告类型');          return false        }        if(this.pdfForm.fileLevel === ''){          this.$message.warning('请选择公告级别');          return false        }            //后端需要三个参数file、announcementType、fileLevel,用fileFormData包起来防止           // 出现 headers:  'multipart/form-data'等错误          // 若后端只需一个参数  添加          //  let requestConfig = {          //headers: {           // 'Content-Type': 'multipart/form-data'          //},        //}        //this.axios.post('/market/upload',formData,requestConfig).then((res)=>                     let fileFormData = new FormData();            fileFormData.append("file", this.file);            fileFormData.append('announcementType',this.pdfForm.announcementType)            fileFormData.append('fileLevel',this.pdfForm.fileLevel)            this.axios.post('/admin/uploadUserFile',fileFormData).then(res =>{              if (res.data.status===1){                this.$message({                  message:res.data.msg,                  type:'success',                  duration: 3000,                });                this.showDataImportDialog=false              }else{                this.messageLabel = this.$message({                  message:res.data.msg,                  type:'error',                  showClose:true,                  duration:0,                });              }            })      }

14.文件大小转换,字节转换成K  M  G  T单位

// 计算文件大小函数(保留两位小数),Size为字节大小// size:初始文件大小function getfilesize(size) {  if (!size) return "";  var num = 1024.0; //byte  if (size < num) return size + "B";  if (size < Math.pow(num, 2)) return (size / num).toFixed(2) + "K"; //kb  if (size < Math.pow(num, 3))    return (size / Math.pow(num, 2)).toFixed(2) + "M"; //M  if (size < Math.pow(num, 4))    return (size / Math.pow(num, 3)).toFixed(2) + "G"; //G  return (size / Math.pow(num, 4)).toFixed(2) + "T"; //T}//Math.pow(x,y) //返回 x 的 y 次幂的值//NumberObject.toFixed(num) //可把 Number 四舍五入为指定小数位数的数字

14.Vue实现PC端分辨率自适应

方案:

lib-flexible + px2remLoader
lib-flexible:阿里可伸缩布局方案
px2rem-loader:px转rem

安装依赖

npm install px2rem-loader -D
npm install lib-flexible -S

引入依赖

在main.js引入lib-flexible

import 'lib-flexible'

px转换成rem

vue-loader的options和其他样式文件loader最终都是由build/utils.js里的方法生成的,我们只需在cssLoader后再加上一个px2remLoader即可,px2rem-loader的remUnit选项意思是1rem=多少像素,结合lib-flexible的方案,我们将px2remLoader的options.remUinit设置成设计稿宽度的1/10,这里假设设计稿宽为1920px

15.elementUI里面的el-input框有时候无法输入的问题

最近发现项目中需要输入内容的时候,input框有时候会无法输入进去

发现elementUI中@input事件可以拿到当前输入的值,

问题找到了,视图没有更新的问题

解决方法 this.$forceUpdate()

16.vue强制更新$forceUpdate()的使用及原理

调用强制更新方法this.$forceUpdate()会更新视图和数据,触发updated生命周期。

<button @click="reload()">强制更新</button>

updated(){
      console.log("更新了");
  },
  methods:{
      reload(){
          this.$forceUpdate();
      }
  }