Vue-router插件使用

单页面原理

   Vue是单页面开发,即页面不刷新。

   页面不刷新,而又要根据用户选择完成内容的更新该怎么做?Vue中采用锚点来完成。

   如访问http://127.0.0.1#/index就是主页,而访问http://127.0.0.1#/home就是家目录。

   手动分析url组成与处理视图的切换非常麻烦,所以Vue提供插件Vue-router,它能够根据用户在地址栏中输入的不同链接展示不同的内容,十分的方便。

Vue-router

   打开Vue.js官网,在生态系统中找到vue-router

  

image-20201117151741748

   然后根据它的官方文档进行安装即可:

  

image-20201117152118071

   文档链接

示例演示

   使用<router-view>当作组件的显示容器。

   使用<router-link>与属性toVue切换显示的组件。

   注意查看下图中url的变化,它确实没有刷新。

  

vuerouter

<body>

<div id="app">
    <router-view></router-view>
</div>

<script src="./vue.js"></script>
<script src="./vue-router.js"></script>
<script>
    // 第一步:书写组件
    const index = {
        template: `
        <div>
            <h1>欢迎访问主页</h1>
            <router-link to="/settings">设置</router-link>
            <router-link to="/backend">后台</router-link>
        </div>
        `
    }

    const backend = {
        template: `
        <div>
            <h1>欢迎访问后台</h1>
            <router-link to="/">访问主页</router-link>
        </div>
        `
    }

    const settings = {
        template: `
        <div>
            <h1>欢迎访问个人设置页面</h1>
            <router-link to="/">访问主页</router-link>
        </div>
        `
    }

    // 第二步:配置路由
    // 根据资源请求来展示或隐藏对应的组件
    const routes = [
        // 主页,/
        {path: "/",component: index},{path: "/backend",component: backend},{path: "/settings",component: settings},]

    // 第三步:实例化路由对象
    // {routes:routes}
    const router = new VueRouter({routes,})

    // 第四步:根组件中添加路由信息
    // {router:router}
    const app = new Vue({
        el: "#app",router,})
</script>
</body>

参数相关

参数传递

   在很多情况下,我们都需要用户的请求地址携带一些参数,然后通过这个参数再进行查询。

   比如查询某一本书时,地址栏通常是这样的:

#/book/2

   而且很有可能在今后的<router-link>以及methods中都要使用这个参数,如何操作?

{path: "/book/:id(\\d+)",component: book},// 转义 \d+

我该如何从Template里拿到参数:{{ $route.params }}

我该如何从Methods里拿到参数:this.$route.params

   示例如下:

  

vuerouter参数

<body>

<div id="app">
    <router-view></router-view>
</div>

<script src="./vue.js"></script>
<script src="./vue-router.js"></script>
<script>
    // 第一步:书写组件
    const index = {
        template: `
          <div>
              <h1>主页</h1>
              <input type="text" v-model="book_id" placeholder="输入要查询的图书编号">
              <router-link :to="'/book/'+book_id">查询图书</router-link>
          </div>
        `,data() {
            return {
                book_id: 0,};
        }
    }

    const book = {
        // 在模板以及方法中,你都可以拿到查询的参数
        template: `
          <div>
              <p>我该如何从Template里拿到参数:{{ $route.params }}</p>
              <p>我该如何从Methods里拿到参数:{{ show() }}</p>
              <p v-for="item in books" v-if="item.id==$route.params.id">你查询的图书是:{{ item }}</p>
          </div>
        `,data() {
            return {
                books: [
                    {id: 1,name: "红楼梦",author: "曹雪芹",price: 199,},{id: 2,name: "西游记",author: "吴承恩",price: 179,{id: 3,name: "三国演义",author: "罗贯中",price: 158,{id: 4,name: "水浒传",author: "施耐庵",price: 128,]
            }
        },methods:{
            show(){
                return this.$route.params
            }
        }
    }

    // 第二步:配置路由
    const routes = [
        // 主页,/
        {path: "/",{path: "/book/:id(\\d+)",// 转义 \d+
    ]

    // 第三步:实例化路由对象
    // {routes:routes}
    const router = new VueRouter({routes,})
</script>
</body>

默认参数

   根据RestAPI规范,如果没有携带参数则代表查询所有。

   如果按照上面的示例,直接不带参数进行请求路由将匹配不上,所以我们还需要做一个查询所有的功能。

   其实对上面路由进行改进即可,设置为默认参数:

{path: "/book/:id?",// ?代表可以有也可以没有

   示例如下:

  

vuerouter默认参数

<body>

<div id="app">
    <router-view></router-view>
</div>

<!--查询模板-->
<template id="result">
    <div>
        <table border="1" :style="{borderCollapse:'collapse'}">
            <caption :style="{border:'1px solid #000',fontSize:'1.2rem'}">查询结果</caption>
            <thead>
            <tr>
                <th>编号</th>
                <th>名称</th>
                <th>作者</th>
                <th>价格</th>
            </tr>
            </thead>
            
            <!-- 查询一本 -->
            <tbody v-if="$route.params.id">
            <tr v-for="item in books" v-if="item.id == $route.params.id">
                <td>{{ item.id }}</td>
                <td>{{ item.name }}</td>
                <td>{{ item.author }}</td>
                <td>{{ item.price }}</td>
            </tr>
            </tbody>
            
            <!-- 查询所有 -->
            <tbody v-else>
            <tr v-for="item in books">
                <td>{{ item.id }}</td>
                <td>{{ item.name }}</td>
                <td>{{ item.author }}</td>
                <td>{{ item.price }}</td>
            </tr>
            </tbody>
        </table>
    </div>
</template>

<script src="./vue.js"></script>
<script src="./vue-router.js"></script>
<script>
    // 第一步:书写组件
    const index = {
        template: `
          <div>
          <h1>主页</h1>
          <input type="text" v-model="book_id" placeholder="输入要查询的图书编号">
          <router-link :to="'/book/'+book_id">查询单个图书</router-link>
          <router-link to="/book/">查询所有图书</router-link>
          </div>
        `,};
        }
    }

    const book = {
        // 在模板以及方法中,你都可以拿到查询的参数
        template: `#result`,}

    // 第二步:配置路由
    const routes = [
        // 主页,/
        {path: "/",{path: "/book/:id?",// 转义 \d+,?可以有也可以没有
    ]

    // 第三步:实例化路由对象
    // {routes:routes}
    const router = new VueRouter({routes,})
    
</script>
</body>

路由别名

路由name

   为每一个路由匹配规则添加name属性,使其更方便的在模板以及Js代码中进行跳转:

   如下所示:

    const routes = [
        {path: "/",component: index,name: "index"},component: book,name: "query_book"},]

router-link

   模板中使用router-link与路由的别名name进行跳转时,格式如下:

<!-- 有参数就传递,没有就不传递。注意在to前添加: -->
<router-link :to="{name:'query_book',params:{id:书籍编号}}">查询</router-link>

$route.push

   Js代码中使用跳转时要用到this.$router.push()这个方法,如下所示:

// 模板中的按钮
<button @click="func(书籍编号)">查看详情</button>

// js
func(bookId){
	// 使用url拼接跳转
    let url = {path:"/book/"+bookId};
    // 使用别名进行跳转跳转:
    // {name:'book_query',params:{id:id}}
    this.$router.push(url);  // 使用$router.push(url)进行跳转
}

视图布局

视图嵌套

   一个大的组件中可以包含很多小的组件。

   如下所示,有一个school组件,在school组件中你可以查看到当前的teacherclasses

   当然teacherclasses也都是两个组件。

   换而言之,我在school组件中点击查看教师或者班级,我并不希望他跳转到新的页面而是在当前页面的其他位置进行显示其他组件就可以使用路由嵌套。

<div id="app">
	<!-- 第一层,展示学校 -->
    <router-view></router-view>
</div>

# 子组件中的关键代码
 <router-view></router-view>
 
# 路由中的代码,第一层的路由匹配第一层的router-view,第二层的路由就在第二层的router-view中显示
 path: "/school",component: school,name: "school",children: [
     {path: "/school/teacher",component: teacher,name: "teacher"},{path: "/school/classes",component: classes,name: "classes"},]

  

vuerouter嵌套

<body>

<div id="app">
	<!-- 第一层,展示学校 -->
    <router-view></router-view>
</div>


<script src="./vue.js"></script>
<script src="./vue-router.js"></script>
<script>
    // 第一步:书写组件
    const school = {
        template: `
        <div>
            <h1>欢迎来到大肥羊学校</h1>
            <router-link :to="{name:'classes'}">查看班级</router-link>
            <router-link :to="{name:'teacher'}">查看老师</router-link>
            <!-- 第二层,展示班级或者教师 -->
            <router-view></router-view>
        </div>
        `
    }

    const teacher = {
        template: `
          <div>
            <ul>
              <li v-for="item in teacherMessage">{{item.id}}-{{item.name}}</li>
            </ul>
          </div>
        `,data() {
            return {
                teacherMessage: [
                    {id: 1,name: "王老师",name: "张老师",name: "李老师",]
            }
        }
    }


    const classes = {
        template: `
          <div>
              <ul>
                <li v-for="item in classMessage">{{item.id}}-{{item.name}}</li>
              </ul>
          </div>
        `,data() {
            return {
                classMessage: [
                    {id: 1,name: "一年级一班",name: "一年级二班",name: "一年级三班",]
            }
        }
    }

    // 第二步:配置路由
    const routes = [
        {
            path: "/school",children: [
                {path: "/school/teacher",]
        },})

</script>
</body>

嵌套的问题

   当页面发生变化,如#school/classes跳转到#school/teacherschool组件将会产生复用。

   这代表school的组件声明周期钩子函数不会被重复调用,就可能造成数据更新不及时的问题。

   举一个例子,上述示例中的school欢迎语是欢迎来到大肥羊学校,如果它是钩子函数created()从后端获取的数据,在用户查看#school/classes后跳转到#school/teacher这个时间点中间后端数据发生了改变,变成了欢迎来到小肥羊学校,由于组件复用问题不会再次执行created(),则代表用户依旧看到的是欢迎来到大肥羊学校。如下所示,我们只有手动更新标语才能执行更新,这显然是不符合常理的:

  

vuerouter嵌套问题

<body>

<div id="app">
    <router-view></router-view>
</div>

<script src="./vue.js"></script>
<script src="./vue-router.js"></script>
<script>

    // 假设是从后端抓取数据
    let schoolTitle = "欢迎来到大肥羊学校";

    // 5s后发生改变
    setTimeout(() => {
        schoolTitle = "欢迎来到小肥羊学校";
    },5000);

    // 第一步:书写组件
    const school = {
        template: `
        <div>
            <h1>{{ title }}</h1>
            <router-link :to="{name:'classes'}">查看班级</router-link>
            <router-link :to="{name:'teacher'}">查看老师</router-link>
            <p><button @click="updateTitle">更新新的标语</button></p>
            <router-view></router-view>
        </div>
        `,data(){
            return {
                title : "",}
        },created(){
            // 假设发送异步请求
            console.log("school钩子函数触发了...")
            this.title = schoolTitle;
        },methods:{
            updateTitle(){
                this.title = schoolTitle;
            }
        }
    }

    const teacher = {
        template: `
          <div>
            <h3>老师太多了,显示不过来...</h3>
          </div>
        `,}


    const classes = {
        template: `
          <div>
            <h3>班级太多了,显示不过来...</h3>
          </div>
        `,}

    // 第二步:配置路由
    const routes = [
        {
            path: "/school",})

</script>
</body>

解决问题

   如果想解决组件复用钩子函数不执行的问题,我们可以使用watch来监听$route对象,也就是使用watch来监听地址栏变化,当发生变化时就重新获取数据。

   或者使用 2.2 中引入的 beforeRouteUpdate 导航守卫,解决思路如下图所示:

  

image-20201117180236494

  

vuerouter嵌套问题解决

   代码如下,使用watch进行解决:

    const school = {
		template:"...",created(){
            // 假设发送异步请求
            this.getTitle();
        },methods:{
            getTitle(){
                // 从后端获取数据
                this.title = schoolTitle;
            }
        },watch:{
            $route(to,from){
                // to 要跳转的页面
                // from 从那个页面进行跳转
                this.getTitle();
            }
        }
    }

   使用导航守卫进行解决的代码如下:

    // 第一步:书写组件
    const school = {
    	template:"...",beforeRouteUpdate (to,from,next) {
            this.getTitle();
        }
    }

命名视图

   命名视图就是说可以在一个页面上,使用多个<router-view>,相较于路由嵌套的层级关系,它是一种扁平化的设计。

   如,头部导航栏,左侧菜单栏,右边内容块三个组件,都显示在一个页面上,就可以使用命名视图。

   核心代码如下:

# 根组件模板
<div id="app">
    <!-- 这里只放个人主页 -->
    <router-view></router-view>
    <router-view name="menu"></router-view>
    <router-view name="show"></router-view>
</div>
   

# Js配置路由,/代表根目录。有三个视图,router-view
path: "/",components: {
    default: header,// 如果 view-router没有name属性,则用default
    menu: menu,show: show,}

  

image-20201117194355773

 <style>
        *{
            padding: 0;
            margin: 0;
            box-sizing: border-box;
        }
        header{
            height: 45px;
            display: flex;
            justify-content: space-evenly;
            background-color: #ddd;
            align-items: center;
        }
        body>div>div:nth-child(2){
            display: inline-flex;
            width: 15%;
            border: 1px solid #ddd;
            height: 1000px;
        }
        menu>ul{
            list-style-type: none;
            display: inline-flex;
            flex-flow: column;
            
        }
        menu>ul>li{
            margin: 10px 0 0 10px;
        }
        body>div>div:last-child{
            display: inline-flex;
            justify-content: center;
            border: 1px solid #ddd;
            width: 70%;
            height: 1000px;
        }

    </style>

<body>
    <div id="app">
        <!-- 这里只放个人主页 -->
        <router-view></router-view>
        <router-view name="menu"></router-view>
        <router-view name="show"></router-view>
    </div>
   
    <!-- 头部组件 -->
    <template id="header">
        <div>
            <header><span>首页</span><span>新闻</span><span>关注</span><span>链接</span></header>
        </div>
    </template>

    <!-- 左侧菜单 -->
    <template id="menu">
        <div>
            <menu>
                <ul>
                    <li>最新</li>
                    <li>最热</li>
                    <li>最多评论</li>
                </ul>
            </menu>
        </div>
    </template>

    <!-- 内容区域 -->
    <template id="show">
        <div>
            <section>
                <h1>内容区域</h1>
            </section>
        </div>
    </template>

    <script src="vue.js"></script>
    <script src="vue-router.js"></script>
    <script>

        // 第一步:书写组件
        const header = {
            template: "#header",}

        const menu = {
            template: "#menu",}

        const show = {
            template: "#show",}

        // 第二步:配置路由
        const routes = [
            {
                // 当你访问主页时,有三个组件扁平显示
                path: "/",components: {
                    default: header,// 如果 view-router没有name属性,则用default
                    menu: menu,}
            }

        ]

        // 第三步:实例化路由对象
        const router = new VueRouter({
            routes,// es6新语法
        })


        // 第四步:根组件中添加路由信息 
        const app = new Vue({
            el: "#app",});

    </script>
</body>

重定向

redirect

   当你访问一个页面时,可以重定向至另一个页面,如下示例,使用redirect进行重定向。

   访问/doc,重定向到/help中。但是地址栏中显示的还是/help

const routes = [
    // 当用户访问doc时,将会跳转到help中,地址栏中显示是help
    { path: "/help",component: help,name: "help"},{ path: "/doc",redirect: { name: "help" } }
]

alias

   如果你使用alias参数进行匹配,就方便许多了,并且地址栏中显示的是用户输入的值,但是当输入的路径不存在,则不会显示:

  

Vue的路由重定向alias参数

const routes = [
    // 用户输入在alias中的所有路径,都会交给help组件进行处理
    { path: "/help",name: "help",alias: ["/doc","/doc.html","/help.html"] },]

history模式

   如果你的url中不想有#号的锚点,可开启history模式。

   同时你还需要在后端做相应的配置,参见官方文档:

   点我

切换动画

   相信现在你已经对单页面开发有所了解,单页面开发说白了就是根据url请求的#后的参数不停的更换要显示的组件。

   所以我们可以为这一切换过程加上过渡动画,你可以在其他子组件模板中添加<transition>标签,并自己书写css类或者引用第三方库。

   如下所示:

  

Vue的路由动画

   我这里是单独给每个子组件加的动画:

        // 书写组件
        const index = {
            template:
             `
            <transition enter-active-class="animate__animated  animate__bounce">
                <h1>wecome to index</h1>
            </transition>
            `,}

        const backend = {
            template:             `
            <transition enter-active-class="animate__animated  animate__bounce">
                <h1>wecome to backend</h1>
            </transition>
            `,}

   如想了解更多,请参考官方文档。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


https://segmentfault.com/a/1190000022018995 https://www.jianshu.com/p/8c3599dda094 vuex教程中,有这样一句话和这样一段代码: 实践中,我们会经常用到 ES2015 的参数解构来简化代码(特别是我们需要调用commi
ES6 (ECMAScript 6)中的模块是一个包含 JavaScript 代码的文件,在这个模块中所有的变量都对其他模块是不可见的,除非我们导出它。 ES6的模块系统大致分为导出(export)和导入(import)两个模块。 1、模块导出(export) 可以 导出 所有的最外层 函数 、 类
from https://mp.weixin.qq.com/s/-rc1lYYlsfx-wR4mQmIIQQ Vue知识点汇总(含Vue3) 一、Vue 基础 1. Vue的基本原理 当一个Vue实例创建时,Vue会遍历data中的属性,用 Object.defineProperty(vue3.0使
D:\Temp&gt;npm init vite@latest vue3study --template vuenpm ERR! code ETIMEDOUTnpm ERR! errno ETIMEDOUTnpm ERR! network request to https://registry.np
文章浏览阅读1.2k次。最近自己从零撸起的甘特图组件需要子组件的滚动条同步滚动这就涉及到子组件之间的互相通信,通过 消息总线可以达到我们的需求 ,首先建立一个标志位,拖动左边滚动条的时候,右边的滚动条事件不处理,反之拖动右边滚动条时,左边的滚动条事件不做处理,建立一个公共的变量用于两者的互斥store.jsimport Vue from 'vue'export let store = Vue.observable({ scrollFlag: true})export let mutations =.._vue 能不能同时有两个滚动事件
文章浏览阅读3.3k次,点赞3次,收藏16次。静默打印是什么?简单来说就是不需要用户点击"打印",自动去打印,但是使用浏览器web打印不可避免的要弹出以下画面面对这种问题也只能用"富客户端"技术来解决,在浏览器的沙盒安全模型中无法做到,那么只能使用插件的技术,这个我们就不自己花力气去做了,我找来了 lodop 这个免费的打印组件,功能还是挺强大的,下载下图的发行包解压后安装下图两个exe如果你的系统是64位的,可以安装install_lodop64.exe上图的LodopFuncs.js 是客户端要使用的核心库文件..._this.$getlodop().then((lodop) =>{
文章浏览阅读1.7k次。个人觉得大屏展示其实很简单,噱头多过技术含量,下面使用了 DataV (不是阿里的那个DataV哈,具体链接在这里)开发了一个大屏展示,使用了css flex弹性布局,使用了DataV的一些比较酷炫的边框(SVG写的),基本上功能没有全部完成,但是模子已经刻出来了,只是后端推送的内容没有全部写出来前端<template> <dv-full-screen-container class="screen-container"> <div class="ti_用signalr做一个简单的实时大屏显示
文章浏览阅读3.4k次,点赞3次,收藏10次。【说明】导入的Excel 字体颜色和背景色只能识别【标准色】,别的如"主题颜色",exceljs 解析出来不是颜色值。导入的样式包括字体,字号,列宽,合并单元格,【部分能识别】的背景色,文字颜色。导入到 x-data-spreadsheet 如下图。原Excel样式如下。_x-data-spreadsheet
文章浏览阅读1.7k次。之前参考某文章把 router-view 放在 el-tab-pane 外面都不起作用,问题根本不是出在 el-tab-pane,而是v-for 里面有多个route-view , keep-alive 时 tab 并未销毁掉,而是缓存隐藏了起来。需要把 router-view 的 name 与路由的 index.js 名称对应起来。之前参照很多文章修改试图修正这个问题,结果都徒劳,终于让我找到。我做了如下修改,主页面 main.vue。_el-tab-pane 后面接router-view
文章浏览阅读533次。今天在一台虚拟机上面运行老项目,报各种类型上图的错误提示,一开始还以为是less的问题,结果一个个装完还是报错,后面又说webpack, webpack cli有问题,头有点大了,google 一下,发现一个命令。讨论这个命令的文章,可以了解一下。运行以后终于出现了期待已久的。_npm install 忽略依赖
文章浏览阅读8k次,点赞3次,收藏12次。从这篇文章得到启发先定义一个组件从外部接收Template,然后在组件里调用<template > <div ref="markedContent"></div></template><script>import Vue from 'vue/dist/vue.esm.js'export default { name: 'wf-marked-content', props: ['content'], mounte.._vue components 动态传入模板
文章浏览阅读5.4k次。参考上一篇知识开发的一个功能,制作一个打印模板的管理模块,如下(就是保存froala编辑后的html文本,其中包括Vue的Template,这样我们可以利用Vue的模板的优势来动态绑定一些数据源进行HTML的打印,基本上跟过去水晶报表做一个模板再绑定数据源的方法异曲同工)在 main.js 里引用 froala 组件// Import and use Vue Froala lib.import VueFroala from 'vue-froala-wysiwyg'// 引入 Fr.._vue设计网页打印模板
文章浏览阅读992次。计划是这样,公司的项目一直在持续改动,安装包总是需要频繁生成新的,由此我想到了"持续集成"!有自动化工具不用,岂不可惜?这周的主要时间就用来学习CruiseControl.Net全面实现持续集成_怎么在vue的 script部分使用 eldigloa
文章浏览阅读1.2k次。其实Element UI 只用了文字提示的 el-tooltip 组件,不喜欢可以去掉,不记得是从哪拿到的原始代码,我给加了高亮渐变显示,图标,和拖拽时只能拖拽图标的位置,效果如上图,可以水平方向拖动,也可以垂直方向拖动。样式是less写的,css写嵌套样式太繁琐了。拿来主义,改造有理!下面贴代码<template> <div ref="splitPane" class="split-pane" :class="direction" :"{ fl..._element ui拉条样式
文章浏览阅读953次,点赞2次,收藏2次。接上一篇,这次加入的是从x-speadsheet导出Excel,并且带有x-speadsheet中的样式,重点关注 exportExcel 这个方法,我加入了 tinycolor 这个库用来翻译颜色值,值得注意的是, exceljs的颜色值是 argb 不是 rgba,一定不要弄混了a 是代表的透明度放在最前面_x-data-spreadsheet 导出
文章浏览阅读5.5k次,点赞2次,收藏21次。尝试了两个连线库 jsplumb 和 leadline ,其实两个库都很强大,但是基于个人使用的习惯,决定还是用 leadline ,在Vue 下我使用它的一个包装库 leader-line-vue 下面是上图的连接线示例代码,连接线很轻松的就实现了一个渐变效果..._vue 连线
文章浏览阅读4.2k次,点赞2次,收藏5次。首先官网推荐的安装方法没有生成dist文件,导致样式表等这些文件并没有生成npm install element-plus --save以上方法是有问题的,如果不幸执行了上面的命令,那么先执行卸载npm uninstall element-plus删除 main.js文件对element ui的引用,输入以下命令vue add element-plus..._elementui3.0
文章浏览阅读3.1k次。如上图,下面贴代码<template> <div> <el-date-picker size="large" style ="width:120px" v-model="selectYear" format="yyyy 年" value-format="yyyy" type="year" :clearable = "false" placeholder="选择年">.._vue多选周
文章浏览阅读1.8k次,点赞6次,收藏6次。经过 2021年的一个春节,从年前到现在,大致撸出一个 甘特图,进度条是用SVG画的,使用了几个工具库 (interactjs 用来处理拖拽和修改尺寸,snap.svg 用来处理 svg 的dom 操作,moment.js用来处理时间的操作),其他没有依赖任何的UI组件,目前初见雏形,还比较粗糙,后面会不断更新源码地址点击期间也摸索了怎么把vs code的项目上传到 GitHub 上面进行源代码的管理,基本上是参考的这篇文章做的..._vue gantt demo
文章浏览阅读2.1k次。接上两篇vue 下使用 exceljs + x-spreadsheet 带样式导入Excelvue 下使用 exceljs + x-spreadsheet 带样式导出Excel下面封装好一个组件调用组件的页面效果如图,目前“导出Json”还没有做_x-spreadsheet导入导出