vue - 学习笔记

1. 初始化以及配置说明

1.1 初始化

方式一

序号说明命令
1初始化一个项目vue init webpack 项目名称
2初始化完成后不要选择使用npm下载,选择手动下载–>No,I will handle that myselfNo,I will handle that myself
3先用cd命令进入项目的路径cd 项目目录
4接着npm安装npm install
5项目测试运行npm run dev
D:\WorkSpace\webWorkSpace>vue init webpack 20200319vuerouter

? Project name 20200319vuerouter
? Project description A Vue.js project
? Author Prometheusxiao <iapetosee@163.com>
? Vue build standalone
? Install vue-router? Yes
? Use ESLint to lint your code? No
? Set up unit tests No
? Setup e2e tests with Nightwatch? No
? Should we run `npm install` for you after the project has been created? (recommended) no

D:\WorkSpace\webWorkSpace>cd 20200319vuerouter

D:\WorkSpace\webWorkSpace\20200319vuerouter>npm install

D:\WorkSpace\webWorkSpace\20200319vuerouter>npm run dev

方式二

序号说明命令
1创建一个新项目vue create 项目名
2Manually select features(手动选择项目特性)选择
3配置参考图1.1.1与图1.1.2
4试运行npm run serve

图1.1.1

Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection)
[为你的项目选择需要的特性,按下空格去选择单项,按下a去选择全部,i反选]
◉  Babel [在项目中把es6转化成所有浏览器能识别的es5代码]
◯ TypeScript [micrsoft出的一个js库,能做类型校验]
◯ Progressive Web App (PWA) Support[把网页做的更像原生app]
◉  Router [vue路由插件]
◉  Vuex [vue状态管理,vue的数据库]
◉  CSS Pre-processors [css预处理器]
◯ Linter / Formatter [js代码校验/格式化]
◯ Unit Testing [单元测试,提前找出bug]
◯ E2E Testing [end to end test 端对端测试,测试全流程]

图1.1.2

Vue CLI v4.2.3
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, Router, Vuex, CSS Pre-processors
? Use history mode for router? (Requires proper server setup for index fallback in production) No
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Less
? Where do you prefer placing config for Babel, ESLint, etc.? In package.json
? Save this as a preset for future projects? No

参考地址.

1.2 配置

1. 路由组件放在view或者pages文件夹下
2. 非路由组件放在components文件夹下
3. 路由配置命名index.js 放在router文件夹下

2. 如何引入其他库并使用

2.1 bootstrap
# 控制台
npm install bootstrap --save

# main.js
import "bootstrap/dist/css/bootstrap.css"

参考链接: vue中导入bootstrap.css

3. 路由

3.1 vue路由的简单实践
  1. 在src下创建router文件夹,并创建index.js文件;
    index.js文件的名称可以是其他,但是使用index命名在引入的时候可以少些几个字
  2. 编写要引入的路由组件
import About from '@/pages/About' //@ 代表webpack.base.conf.js中的别名设置 相当于src
import Home from '../pages/Home' //另外一种方式
import News from '../pages/News'
import Messages from '../pages/Messages'
  1. 编写src下router文件夹中的index.js文件;
    用 Vue.js + Vue Router 创建单页应用,非常简单。使用 Vue.js ,可以通过组合组件来组成应用程序,当你要把 Vue Router 添加进来,需要做的是,将组件 (components) 映射到路由 (routes),然后告诉 Vue Router 在哪里渲染它们
//引入vue
import Vue from 'vue'
//引入路由
import Router from 'vue-router';

//引入路由组件
import About from '@/pages/About' //@ 代表webpack.base.conf.js中的别名设置 相当于src
import Home from '../pages/Home' //另外一种方式
import News from '../pages/News'
import Messages from '../pages/Messages'

//使用路由器
Vue.use(Router) 
//Vue.use(Router)就可以在任何组件内通过 this.$router 访问路由器,也可以通过 this.$route 访问当前路由

//配置路由具体映射关系
export default new Router({
  routes: [
    {
      path: '/about',
      name: 'About',
      component: About
    },
    {
      path: '/home',
      name: 'Home',
      component: Home,
      children:[
        {
          path: '/home/news',  //path中的斜杠永远代表根路径,标准写法
          name: 'News',
          component: News
        },
        {
          path: 'messages',    //path中的斜杠永远代表根路径,简单写法
          name: 'Messages',
          component: Messages
        },
        {
          path: '',            //配置默认路由 '' 就代表当前
          redirect: '/home/news'
        }
      ]
    },
    {
      path: '/',              //配置默认路由
      redirect: './home'
    }
  ]
})
  1. 配置编写好的路由index.js到vue项目中去
import Vue from 'vue'
import App from './App'

//注入配置好的路由
import router from './router'  //因为是index名称,就不用./router/index.js了

import 'bootstrap/dist/css/bootstrap.css'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,   //这个是对象默认属性名称一样是可以简写,不一样时就:router: 你自己的名称,就是import那个名字
  components: { App },
  template: '<App/>'
})
  1. 使用路由
//连接
<router-link to="****" class="list-group-item">About</router-link>
//渲染
<router-view></router-view>
3.2 保持路由组件渲染后的数据,避免切换后重置

使用keep-alive标签

    <keep-alive>
         <router-view></router-view>
    </keep-alive>
3.3 路由统一个路由组件渲染后不会再次执行mounted中方法,会导致页面不变动

解决方法增加当前路由的监听

<template>
    <div>
        详情页面 - {{$route.params.id}}
        <h4>{{data.title}}</h4>
        <p>{{data.content}}</p>
        <p style="width: 20px">{{data.id}}</p>
    </div>
</template>

<script>
    export default {
        name: "message-detail",
        mounted(){
            this.getContent();
            //路由组件创建后只执行一次后续点击不会改变数据,所以要监听这个路由组件的变动
        },
        methods:{
            getContent() {
                let id = this.$route.params.id;
                let data = this.msgs.find(element => element.id == id);
                this.data = data;
            }
        },
        data() {
            return {
                msgs:[
                    {id: 1, title: 'messages1', content: '哈哈'},
                    {id: 2, title: 'messages2', content: '嘻嘻'},
                    {id: 3, title: 'messages3', content: '兔兔'}
                ],
                data:{}
            }
        },
        watch:{
            //监听当前路由
            $route:function(newRoute){
                let id = newRoute.params.id;
                this.data = this.msgs.find(element => element.id == id);
            }
        }
    }
</script>
<style scoped>
</style>
3.4 编程式路由

route代表路由组件映射,router代表路由器

// 1. 注意不是this.$route而是this.$router!!!
// 2. this.$router.push(path): 相当于点击路由链接(可以返回到当前路由界面)
// 3. this.$router.replace(path): 用心路由替换当前路由(不可以返回当前路面界面)
// 4. this.$router.back(): 请求(返回)上一个记录路由
// 5. this.$router.go(-1): 请求(返回)上一个记录路由
methods: {
	pushShow(id){
		this.$router.push(`/home/messages/detail/${id}`);//值就是路由路径值
	},
	replaceShow(id){
	    this.$router.replace(`/home/messages/detail/${id}`);//值就是路由路径值
	}
}

4. vuex状态管理(共享数据管理)

一定注意:npm install vuex --save 不然搞个卵

4.1 vuex的简单实现
  1. 在src文件下创建store文件夹然后在创建index.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex) //声明使用

const state = {
    count: 0
}

const mutations = {
    increment(state){
        state.count+=1;
    },
    decrement(state){
        state.count-=1;
    },
    incrementIsOdd(state){
        if(state.count%2!=0){
            state.count += 1;
        }
    },
    incrementIsAsync(state){
        state.count+=1;
    }
}

const actions = {
    increment({commit}){
        commit('increment')
    },
    decrement({commit}){
        commit('decrement')
    },
    incrementIsOdd({commit}){
        commit('incrementIsOdd')
    },
    incrementIsAsync({commit}){
        setTimeout(()=>{
            commit('incrementIsAsync')
        },1000);
    }
}
const getters = {
    evenOrOdd(state){
        return state.count%2==0?"偶数":"奇数"
    }
}
/**
 *  state      : 类似vue中的data
 *  actions    : 类似vue中的methods,注意action可执行异步操作,但是mutation必须同步执行 --> 随意了
 *  mutations  :  就是actions与state的中继件,注意action可执行异步操作,但是mutation必须同步执行  --> 最好全大写
 *  getters    : 类似vue的计算属性
 */
const store = new Vuex.Store({
    state,
    mutations,
    actions,
    getters
});
export default store;//向外默认暴露store对象
  1. 在src下中的main.js中引入暴露的store对象
import Vue from 'vue'
import App from './App'
import store from './store'
Vue.config.productionTip = false

new Vue({
  el: '#app',
  store,
  components: { App },
  template: '<App/>'
})
  1. vue中使用
    this.$store.dispatch(‘increment’) 中的这个dispatch就是指向的actions中的方法可以传参数

方式一:

<template>
    <div id="app">
        <P> click {{$store.state.count}} times,count is {{evenOrOdd}}</P>
        <button @click="increment">+</button>
        <button @click="decrement">-</button>
        <button @click="incrementIsOdd">if odd</button>
        <button @click="incrementIsAsync">async</button>
    </div>
</template>

<script>
    export default {
        name: 'App',
        computed:{
            evenOrOdd:function(){
                return this.$store.getters.evenOrOdd
            }
        },
        methods:{
            increment(){
                this.$store.dispatch('increment')
            },
            decrement(){
                this.$store.dispatch('decrement')
            },
            incrementIsOdd(){
                this.$store.dispatch('incrementIsOdd')
            },
            incrementIsAsync(){
                this.$store.dispatch('incrementIsAsync')

            }
        }
    }
</script>

<style>
</style>

方式二:

<template>
    <div id="app">
        <P> click {{count}} times,count is {{evenOrOdd2}}</P>
        <button @click="increment">+</button>
        <button @click="decrement">-</button>
        <button @click="incrementIsOdd">if odd</button>
        <button @click="incrementIsAsync">async</button>
    </div>
</template>

<script>
    import {mapState,mapActions,mapGetters} from 'vuex'
    export default {
        name: 'App',
        computed:{
            //...mapGetters(['evenOrOdd2']),
            //名字对应不上怎么办
            ...mapGetters({'evenOrOdd':'evenOrOdd2'}),
            // const getters = {
			//     evenOrOdd2(state){
			//         return state.count%2==0?"偶数":"奇数"
			//     }
			// }
            ...mapState(['count'])
        },
        methods:{
            ...mapActions(['increment','decrement','incrementIsOdd','incrementIsAsync'])
        }
    }
</script>

<style>
</style>
  1. vuex模块化
    在这里插入图片描述
    ==vuex中的store分模块管理,需要在store的index.js中引入各个模块,为了解决不同模块命名冲突的问题, 同模块的namespaced:true,之后在不同页面中引入getter、actions、mutations时,需要加上所属的模块名
    ==

  2. 使用vuex模块中的数据

export default {
        name: 'App',
        computed: {
            xx: function () {
                return this.$store.state.authentication.authenticated;
            }
        },
        mounted(){
            console.log(this.$store.state.authentication.authenticated);
            console.log(this.$store.state.layout.test);
            console.log(this.$store.state.menu.test);
        }
    }

5. vue在开发时跨域问题解决方案

5.1 方式一服务端解决方式(其实不好!!!)
	/**
     * 跨域问题过滤器
     */
    @Bean
    public FilterRegistrationBean corsFilter(){
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.addAllowedHeader("*");
        UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
        corsConfigurationSource.registerCorsConfiguration("/**",corsConfiguration);
        FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(corsConfigurationSource));
        bean.setOrder(1);//在安全过滤器之前
        return bean;
    }
5.2 vue开发用反向代理的方式(这个好)

正式环境是在一块的就没有跨域的问题了,再说还有nginx这个玩意

const proxy = require('http-proxy-middleware');//必须引入否则搞死你也不知道为什么没有效果

module.exports = {
    devServer: {
        proxy: {
            '/api':{
                target: 'http://localhost:8888',//代理地址,这里设置的地址会代替axios中设置的baseURL
                changeOrigin: true,// 如果接口跨域,需要进行这个参数配置
                 //必须是pathRewrite不是这个冒牌的pathRequiresRewrite!!!!!
                pathRewrite: {
                    '^/api': '/'
                }
            }
        }
    }
}

6 基础知识

6.1 监听
watch:{
	   searchDate:{
	       deep: true,//开启深度监听
	       handler: (newV,oldV) => {
	           
	       }
	   },
	   searchDate:(newV,oldV) => {
	       
	   }
},

7. 我的核心组件

7.1 分页组件
<template>
    <div>
        <div style="text-align: right">
            <el-pagination v-on:size-change="handleSizeChange"
                           v-on:current-change="handleCurrentChange"
                           :current-page="currentPageComponent"
                           :page-sizes="[10,20, 50, 100, 200]"
                           :page-size="pageSizeComponent"
                           layout="total, sizes, prev, pager, next, jumper"
                           :total="total">
            </el-pagination>
        </div>
    </div>
</template>

<script>
    export default {
        name: "page-paging",
        props: {
            total: {
                type: Number,
                default: 0,
                required: true,
                validator: function (value) {
                    return value >= 0
                }
            },
            currentPage: {
                type: Number,
                default: 1,
                required: true,
                validator: function (value) {
                    return value >= 0
                }
            },
            pageSize: {
                type: Number,
                default: 10,
                required: true,
                validator: function (value) {
                    return value >= 0
                }
            }
        },
        mounted(){
            this.currentPageComponent = this.currentPage;
            this.pageSizeComponent = this.pageSize;
        },
        methods: {
            handleSizeChange(val) {
                this.pageSizeComponent = val ;
                this.$emit('pageComponentChange',this.currentPageComponent,val);
            },
            handleCurrentChange(val) {
                this.currentPageComponent = val ;
                this.$emit('pageComponentChange',val,this.pageSizeComponent);
            }
        },
        data() {
            return {
                currentPageComponent:1,
                pageSizeComponent:10
            }
        }
    }
</script>

<style scoped>
</style>

调用

<template>
    <div>
        <paging :total="total" :currentPage="currentPage" :pageSize="pageSize" @pageComponentChange="pageChange(arguments)"></paging>
    </div>
</template>

<script>
    import paging from '@/components/page/paging.vue'
    export default {
        name: "a",
        components:{
            paging
        },
        methods: {
            pageChange(pageInfo){
                this.currentPage = pageInfo[0];
                this.pageSize = pageInfo[1];
                this.getData()
            },
        },
        data() {
            return {
                total: 0,
                currentPage:1,
                pageSize:10 ,
            }
        }
    }
</script>

<style scoped>
</style>
7.2 文件展示组件
<template>
    <div>
        <!-- append-to-body 嵌套dialog 必须指定这个为true 否则会出现遮罩层显示问题-->
        <!--:destroy-on-close="true" 必须添加这个销毁这个el-dialog 否则 视频流将继续播放!!!很总要-->
        <el-dialog :visible.sync="showDialog" :close-on-click-modal="true" :close-on-press-escape="true" :before-close="cancelDialog" :destroy-on-close="true" top="6%" width="70%" :append-to-body="true">
            <div v-if="boxNum === 1" style="text-align: center">
                <el-image style="height: 100%"  :src="url" ></el-image>
            </div>
            <div v-if="boxNum === 2" style="text-align: center">
                <audio id="audiobox" :src="url" autoplay controls loop></audio><!--muted 属性静音-->
            </div>
            <div v-if="boxNum === 3" style="text-align: center">
                <video id="videobox" :src="url" style="height: 100%"  controls loop><!--muted 属性静音-->
                </video>
            </div>
        </el-dialog>
    </div>
</template>

<script>
    export default {
        name: "img-audio-video-file",
        methods: {
            show: function (url) {
                this.url = url;
                let png = this.url.lastIndexOf(".png");
                let jpg = this.url.lastIndexOf(".jpg");
                let jpeg = this.url.lastIndexOf(".jpeg");
                if(png > -1 || jpg > -1 || jpeg > -1){
                    this.boxNum = 1;
                    this.showDialog = true;
                    return;
                }
                let mp4 = this.url.lastIndexOf(".mp4");
                if(mp4 > -1){
                    this.boxNum = 3;
                    this.showDialog = true;
                    return;
                }
                let mp3 = this.url.lastIndexOf(".mp3");
                if(mp3 > -1){
                    this.boxNum = 2;
                    this.showDialog = true;
                    return;
                }
                window.open(url, "_blank");
            },
            cancelDialog(){
                console.log("img-audio-video-file cancelDialog");
                if(this.boxNum === 3){
                    let videobox = document.getElementById("videobox");
                    if(videobox){
                        videobox.pause();
                    }
                }
                if(this.boxNum === 2){
                    let audiobox = document.getElementById("audiobox");
                    if(audiobox){
                        audiobox.pause();
                    }
                }
                this.showDialog = false;
            }
        },
        beforeDestroy() {
            console.log("img-audio-video-file beforeDestroy");
            if(this.boxNum === 3){
                let videobox = document.getElementById("videobox");
                if(videobox){
                    videobox.pause();
                }
            }
            if(this.boxNum === 2){
                let audiobox = document.getElementById("audiobox");
                if(audiobox){
                    audiobox.pause();
                }
            }
        },
        data() {
            return {
                boxNum:1,
                showDialog: false,
                url:''
            }
        }
    }
</script>

<style scoped>

</style>

调用

<template>
    <div>
        <iavf ref="iavfbox"></iavf>
    </div>
</template>

<script>
    import iavf from '@/components/media/img-audio-video-file.vue'
    export default {
        name: "a",
        components:{
            iavf
        },
        methods: {
            showFile(url){
                this.$refs['iavfbox'].show(url)
            }
        }
    }
</script>

<style scoped>
</style>
7.3 文件上传组件
<template>
    <div v-loading.fullscreen.lock="loading" v-cloak>
        <div style="text-align: left">
            <el-upload
                    multiple
                    ref="uploadFile"
                    :action="uploadUrl"
                    :headers="importHeaders"
                    :auto-upload="false"
                    :limit="fileMax"
                    :file-list="fileListFJ"
                    :on-exceed="handleOnExceed"
                    :before-upload="checkFile"
                    :on-success="successFile"
                    :on-remove="removeFile"
                    :on-preview="showFile">
                <!-- :on-preview="lookFile" 查看上传了的文件-->
                <!-- 多选文件 multiple -->
                <el-button slot="trigger" size="small" type="primary">选取文件</el-button>
                <el-button style="margin-left: 10px;" size="small" type="success" @click="submitFile">上传到服务器
                </el-button>
                <div><p style="font-size: x-small;color: #999999">注:允许上传{{fileMax}}个文件,允许格式是{{filePermit}}!</p></div>
            </el-upload>
        </div>
        <iavf ref="iavfbox"></iavf>
    </div>
</template>

<script>
    import iavf from '@/components/media/img-audio-video-file.vue'
    export default {
        name: "upload-file",
        components:{
            iavf
        },
        created(){
            this.importHeaders = {
                Authorization:this.authenticated
            }
        },
        mounted(){
            this.initFile(this.files);
        },
        props: {
            //已经存在的文件数组
            fileList: {
                type: String,
                default:null
            },
            //最大允许上传的文件数量
            fileMax: {
                type: Number,
                default: 1,
                required: true,
                validator: function (value) {
                    return value >= 0
                }
            },
            //格式校验
            filePermit: {
                type: String,
                default: 'JPG,JPEG,PNG,TXT,XLSX,XLS,DOCX,DOC,PPT,POTX,POTM,PPA,POT,PPSX,PPTX,MP4'
            }
        },
        computed: {
            authenticated() {
                return this.$store.getters['authentication/getAuthenticated'];
            },
            baseUrl() {
                return this.$store.getters['authentication/getBaseUrl'];
            },
            baseFileUrl() {
                return this.$store.getters['authentication/getBaseFileUrl'];
            },
            files(){
                return this.fileList;
            }
        },
        methods: {
            initFile(files){
                this.fileListFJ = [];
                this.fileResult = [];
                if(files && files.length>0){
                    this.$axios({
                        url:`/api/file/getByIds`,
                        method: 'POST',
                        data:{
                            fileIds:files
                        }
                    }).then(respanse => {
                        let data = respanse.data.data.data;
                        if(data){
                            for(let i=0;i<data.length;i++){
                                let dataFile = data[i];
                                let file = {
                                    name:dataFile.originalName,
                                    url:this.baseFileUrl+"user/"+dataFile.id,
                                    status:"success"
                                };
                                this.fileListFJ.push(file);
                                this.fileResult.push(dataFile.id)
                            }
                        }
                    }).catch(error => {
                        this.$message({ showClose: true, message: '查询错误,请检查网络后重试', duration:1500});
                    });
                }
            },
            checkFile: function (file) {
                //文件检查
                if(file.name){
                    let checkPermit = this.filePermit;
                    let index = file.name.lastIndexOf(".");
                    let len = file.name.length;
                    let suffix = file.name.substring(index+1,len);
                    if(suffix){
                        let check = checkPermit.indexOf(suffix.toUpperCase())>-1?true:false;
                        if(!check){
                            this.$message.error('上传的文件不合法!');
                        }
                        return check;
                    } else {
                        this.$message.error('请选择上传的文件!');
                        return false;
                    }
                } else {
                    this.$message.error('请选择上传的文件!');
                    return false;
                }
            },
            handleOnExceed(){
                this.$message({ type: 'warning',showClose: true, message: "超出最大允许上传的文件数量!", duration:1500});
            },
            successFile: function (response, file, fileList) {
                let id = response.data.data[0];
                if(id){
                    this.fileResult.push(id);
                }
            },
            removeFile(file, fileList) {
                //新上传的文件--> 新的有response但是没有url
                let index = -1;
                let id = null;
                if(file.response){
                    id = file.response.data.data[0];
                    index = this.fileResult.findIndex(item => item === id);
                }
                //旧的已经存在的文件 --> 有url但是包含了请求域名
                let url = file.url;
                if(url){
                    id = url.replace(this.baseFileUrl+"user/","");
                    index = this.fileResult.findIndex(item => item === id);
                }
                if(index > -1){
                    this.fileResult.splice(index,1);
                }
                this.deleteFile(id);
                //没有上传的文件 --> 不用处理因为本身没有调用successFile所有fileResult中是没有数据的
            },
            submitFile() {
                this.$refs.uploadFile.submit(); //提交文件
            },
            deleteFile(id){
                if(id !=null ){
                    this.loading = true;
                    this.$axios({
                        url:`/api/file/delete`,
                        method: 'POST',
                        data: {
                            id:id
                        }
                    }).then(respanse => {
                        this.$message({ showClose: true, message: respanse.data.msg==null?"删除成功": respanse.data.msg, duration:1500});
                        this.loading = false;
                    }).catch(error => {
                        this.loading = false;
                        this.$message({ showClose: true, message: '查询错误,请检查网络后重试', duration:1500});
                    });
                }
            },
            showFile(file){
                let url = file.url;
                if(url != null){
                    this.$refs['iavfbox'].show(url);
                    return;
                }
                let resUrl = file.response.data.data[0];;
                if(resUrl != null){
                    this.$refs['iavfbox'].show(this.baseFileUrl+"user/"+resUrl);
                    return;
                }
                this.$message({ showClose: true, message: '文件没有上传', duration:1500});
            },
            updateFiles(){
                if(this.fileResult.length>0){
                    this.$emit('updateFiles',this.fileResult.join(","));
                } else {
                    this.$emit('updateFiles',"");
                }
            }
        },
        watch:{
            files:{
                deep: true,
                handler:function (newVla) {
                    this.initFile(newVla);
                }
            },
            fileResult:{
                deep:true,
                handler:function (newVal) {
                    //监听数据的变化更新父组件数据
                    this.updateFiles();
                }
            }
        },
        data() {
            return {
                loading: false,
                importHeaders:'',
                uploadUrl:'/api/file/add',
                fileListFJ:[],//初始化文件列表
                fileResult:[],//文件上传返回值
            }
        }
    }
</script>

<style scoped>
</style>

调用

<template>
    <div>
        <!--fileList 已经存在的文件id,逗号分割-->
        <!--filePermit 合法文件格式-->
        <!-- 最大允许文件数量-->
        <uploadfile :fileList="文件id逗号分割的" :fileMax="9" :filePermit="'JPG,JPEG,PNG,MP4'" @updateFiles="updateFiles(arguments)" ></uploadfile>
    </div>
</template>

<script>
    import uploadfile from '@/components/file/upload-file.vue'
    export default {
        name: "a",
        components:{
            uploadfile
        },
        methods: {
            updateFiles(value){
                let fileResult = value[0];//返回的文件id,逗号分割的
            }
        }
    }
</script>

<style scoped>
</style>

ERROR 重要问题记录

1. 在style scoped中修改element-ui的el-transfer穿梭框宽度无效问题
/*
	这样修改有效
*/
<style>
    .el-transfer-panel {
        width: 599.9px;
    }
</style>
/*
	这样修改无效
*/
<style scoped>
    .el-transfer-panel {
        width: 599.9px;
    }
</style>

因为第三方组件的样式是在别的文件中引进的,加了scoped限制之后写的样式只能在本文件中起作用,是没办法覆盖第三方组件自带的样式的,所以要去掉

2. 初始化错误

放在mounted中Error in callback for immediate watcher "height"错误要放到created生命周期中

3. 解决 el-tab 没有滚动条问题

height:879px;overflow-y:auto;overflow-x:hidden;

 <el-tab-pane label="入库信息" name="inventory" style="height:879px;overflow-y:auto;overflow-x:hidden;">
 </el-tab-pane>
4. vue路由错误vue-router.esm.js Uncaught (in promise)

Vue-router 报NavigationDuplicated的可能解决方案
出现这个问题,控制台会报 [NavigationDuplicated {_name: “NavigationDuplicated”, name: “NavigationDuplicated”}]。其原因在于Vue-router在3.1之后把$router.push()方法改为了Promise。所以假如没有回调函数,错误信息就会交给全局的路由错误处理,因此就会报上述的错误。

如果你仔细观察并复现了多次错误你会发现,vue-router是先报了一个Uncaught (in promise)的错误(因为push没加回调),然后再点击路由的时候才会触发NavigationDuplicated的错误(路由出现的错误,全局错误处理打印了出来)。

解决方案
方案1
固定vue-router版本到3.0.7以下。这个方案没什么说的,就是简单粗暴,没有任何理由。但是你能确保以后不升级vue-router吗?

方案2
禁止全局路由错误处理打印,这个也是vue-router开发者给出的解决方案:

import Router from 'vue-router'

const originalPush = Router.prototype.push
Router.prototype.push = function push(location, onResolve, onReject) {
  if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject)
  return originalPush.call(this, location).catch(err => err)
}

把这段代码放在引入vue-router之后就行,一般在main.js里,如果你的路由单独抽取出来了,那可能在其他的路由文件中。

方案3(高成本高收益)
vue-router的开发者也给出了解决方法,你需要为每个router.push增加回调函数。

router.push('/location').catch(err => {err})

对于我们来说这个解决方案的成本可能很高,但是是值得的。在vue-router 3.1版本之前的push调用时不会返回任何信息,假如push之后路由出现了问题也不会有任何的错误信息。如果你使用方案1固定了vue-router的版本,那么以后的项目需要路由的回调时你根本无从下手。

方案4
如果你使用了Element-UI,并且方案2无法解决你的问题。那么你只能用方案1来固定你的vue-router版本了。这是因为Element-UI的el-menu在重复点击路由的时候报的错误,而且这个错误是Element-UI内部的路由问题,你无法通过方案2和3去解决。只能选择暂时不升级Vue-router。

好消息是Element-UI已经有了解决方案,预计在2.13.0版本会解决这个问题。

本段来源 https://www.cnblogs.com/rever/p/11577322.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值