三. Vue组件化

1. 认识组件化

1.1 什么是组件化

人面对复杂问题的处理方式

任何一个人处理信息的逻辑能力都是有限的,所以当面对一个非常复杂的问题时我们不太可能一次性搞定一大堆的内容。

但是我们人有一种天生的能力就是将问题进行拆解。如果将一个复杂的问题拆分成很多个可以处理的小问题再将其放在整体当中,你会发现大的问题也会迎刃而解。

组件化也是类似的思想

如果我们将一个页面中所有的处理逻辑全部放在一起,处理起来就会变得非常复杂,而且不利于后续的管理以及扩展。

但如果我们将一个页面拆分成一个个小的功能块,每个功能块完成属于自己这部分独立的功能,那么之后整个页面的管理和维护就变得非常容易了。

image-20201124214310726

1.2 Vue组件化思想

组件化是Vue.js中的重要思想

它提供了一种抽象,让我们可以开发出一个个独立可复用的小组件来构造我们的应用,任何的应用都会被抽象成一颗组件树

image-20201124214641019

组件化思想的应用

有了组件化的思想,我们在之后的开发中就要充分的利用它

尽可能的将页面拆分成一个个小的、可复用的组件

这样让我们的代码更加方便组织和管理,并且扩展性也更强

2. 注册组件

2.1 注册组件的基本步骤

组件的使用分成三个步骤

  • 创建组件构造器

  • 注册组件

  • 使用组件

image-20201124215013411

三个步骤的含义

  • Vue.extend()

    • 调用 Vue.extend() 创建的是一个组件构造器
    • 通常在创建组件构造器时,传入template代表我们自定义组件的模板
    • 该模板就是在使用到组件的地方要显示的HTML代码
    • 事实上,这种写法在 Vue2.x 的文档中几乎已经看不到了,它会直接使用下面如 2.4 形式的语法糖,但是在很多资料还是会提到这种方式,而且这种方式是学习后面方式的基础
  • Vue.component()

    • 调用 Vue.component() 是将刚才的组件构造器注册为一个组件并且给它起一个组件的标签名称
    • 所以需要传递两个参数:① 注册组件的标签名 ② 组件构造器
  • 在Vue实例的作用范围内使用组件

    • 组件必须挂载在某个Vue实例下,否则它不会生效
    • 下面我使用了三次<my-cpn></my-cpn> ,而第三次其实并没有生效

image-20201124215628434

2.2 组件的作用域

全局组件

当我们通过调用 Vue.component() 注册组件时,组件的注册是全局的这意味着该组件可以在任意Vue示例下使用

局部组件

如果我们注册的组件是挂载在某个实例中,那么就是一个局部组件

image-20201124221306083

2.3 父子组件

在前面我们看到了组件树

组件和组件之间存在层级关系

而其中一种非常重要的关系就是父子组件的关系

我们来看通过代码如何组成的这种层级关系

image-20201124221953846

父子组件错误用法:以子标签的形式在Vue实例中使用

因为当子组件注册到父组件的components时,Vue会编译好父组件的模块。

该模板的内容已经决定了父组件将要渲染的HTML(相当于父组件中已经有了子组件中的内容了)。

<child-cpn></child-cpn> 是只能在父组件中被识别的,如果想要在Vue实例中使用<child-cpn></child-cpn>,则必须在Vue实例中注册child-cpn组件。

2.4 注册组件语法糖

在上面注册组件的方式,可能会有些繁琐

Vue为了简化这个过程,提供了注册的语法糖

主要是省去了调用 Vue.extend() 的步骤,而是可以直接使用一个对象来代替

语法糖注册全局组件和局部组件如下

image-20201124222436062

3. 组件其他补充

3.1 模板的分离写法

刚才我们通过语法糖简化了Vue组件的注册过程,另外还有一个地方的写法比较麻烦,就是template模块写法

如果我们能将其中的HTML分离出来写,然后挂载到对应的组件上,必然结构会变得非常清晰

Vue提供了两种方案来定义HTML模块内容:

  • 使用 <script> 标签
  • 使用 <template> 标签

image-20201124222815433

3.2 组件可以访问Vue的实例数据吗?

组件是一个单独功能模块的封装

这个模块有属于自己的HTML模板,也应该有属性自己的数据data

组件中的数据是保存在哪里呢?顶层的Vue实例中吗?

  • 如下测试发现不能并不能访问,而且即使可以访问,如果将所有的数据都放在Vue实例中Vue实例就会变的非常臃肿
  • 结论:组件并不能直接访问Vue实例中的data,Vue组件应该有自己保存数据的地方

image-20201124223920656

3.3 组件数据的存放

组件自己的数据存放在哪里呢?

组件对象也有一个data属性(当然也可以有methods等属性,下面我们有用到)

只是这个data属性必须是一个函数

而且这个函数返回一个对象,对象内部保存着数据

image-20201124223817597

为什么data在组件中必须是一个函数呢?

首先,如果不是一个函数Vue直接就会报错

其次,原因是在于Vue让每个组件对象都返回一个新的对象。因为如果是同一个对象的,组件在多次使用后会相互影响

image-20201124224212074

4. 父子组件通信

4.1 父子组件通信理解

之前我们提到了子组件是不能引用父组件或者Vue实例的数据的

但是,在开发中往往一些数据确实需要从上层传递到下层:

  • 比如在一个页面中我们从服务器请求到了很多的数据

  • 其中一部分数据并非是我们整个页面的大组件来展示的,而是需要下面的子组件进行展示

  • 这个时候并不会让子组件再次发送一个网络请求,而是直接让 大组件(父组件) 将数据传递给 小组件(子组件)

  • 如何进行父子组件间的通信呢?Vue官方提到

    • 通过 props 向子组件传递数据
    • 通过 事件 向父组件发送消息

image-20201124225224780

在下面的代码中,我直接将Vue实例当做父组件并且其中包含子组件来简化代码

真实的开发中,Vue实例和子组件的通信和父组件和子组件的通信过程是一样的

4.2 父组件向子组件传递数据 - props

基本用法

在组件中,使用选项props来声明需要从父级接收到的数据

props的值有两种方式

  • 字符串数组,数组中的字符串就是传递时的名称
  • 对象,对象可以设置传递时的类型,也可以设置默认值等

我们先来看一个最简单的props传递

image-20201124225501375

props数据验证

在前面我们的props选项是使用一个数组

除了数组之外我们也可以使用对象,当需要对props进行类型等验证时就需要对象写法了

验证支持如下数据类型

  • String
  • Number
  • Boolean
  • Array
  • Object
  • Date
  • Function
  • Symbol

image-20201124225932450

当我们有自定义构造函数时,验证也支持自定义的类型

image-20201124225823411

4.4 子组件向父组件传递数据或事件 - $emit()

自定义事件

props用于父组件向子组件传递数据,还有一种比较常见的是子组件传递数据或事件到父组件中我们应该如何处理呢?这个时候我们需要使用自定义事件来完成

什么时候需要自定义事件?

当子组件需要向父组件传递数据时,就要用到自定义事件了

我们之前学习的v-on不仅仅可以用于监听DOM事件,也可以用于组件间的自定义事件

自定义事件的流程

在子组件中,通过$emit()来触发事件

在父组件中,通过v-on来监听子组件事件

我们来看一个简单的例子:

  • 我们之前做过一个两个按钮 +1-1 ,点击后修改 counter
  • 我们整个操作的过程还是在子组件中完成,但是之后的展示交给父组件
  • 这样我们就需要将子组件中的 counter,传给父组件的某个属性比如 total

image-20201124230536738

4.5 父子传参与双向绑定结合的案例
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <cpn 
        :snum1="num1" 
        :snum2="num2" 
        @num1-exchange="setNum1" 
        @num2-exchange="setNum2"
        ></cpn>
    </div>

    <template id="temp1">
        <!-- 1.下面的写法是有问题的,我们应该避免在子组件中直接修改props中的值
            <div>
                <span>props: {{snum1}}</span>
                <input type="text" v-model="sNum1">
                <hr>
                <span>props: {{snum2}}</span>
                <input type="text" v-model="sNum2">
            </div> 
         -->
       
        <!-- 2.这种方式双向绑定是可行的,但是我们想在input变化时同时父组件的num值也发生变化,怎么实现呢?
            <div>
                <span>props: {{snum1}}</span>
                <span>data: {{number1}}</span>
                <input type="text" v-model="number1">
                <hr>
                <span>props: {{snum2}}</span>
                <span>data: {{number2}}</span>
                <input type="text" v-model="number2">
            </div> 
        -->

        <!-- 
            3. v-model包含两个操作即:value与@input,我们可以通过分解v-model来绑定事件,从而实现双向绑定子传父的功能
        -->
        <div>
            <span>props: {{snum1}}</span>
            <span>data: {{number1}}</span>
            <input type="text" :value="number1" @input="number1Input">
            <hr>
            <span>props: {{snum2}}</span>
            <span>data: {{number2}}</span>
            <input type="text" :value="number2" @input="number2Input">
        </div> 

        <!-- 
            4. 我们也可以通过watch属性来实现,后面会讲watch
        -->
    </template>

    <script>
        const vue = new Vue({
            el: '#app',data() {
                return {
                    num1: '',num2: ''
                }
            },methods: {
                setNum1(val) {
                    this.num1 = val;
                    console.log(this.num1);
                },setNum2(val) {
                    this.num2 = val;
                }
            },components: {
                cpn: {
                    template: temp1,props: {
                        snum1: {
                            type: String,default: () => { return '' }
                        },snum2: {
                            type: String,default: () => { return '' }
                        }
                    },data(){
                        return {
                            number1: this.sNum1,number2: this.sNum2
                        }
                    },methods: {
                        number1Input(event){
                            this.number1 = event.target.value;
                            this.$emit('num1-exchange',this.number1);
                        },number2Input(event){
                            this.number2 = event.target.value;
                            this.$emit('num2-exchange',this.number2);
                        }
                    }
                }
            }
        })
    </script>
</body>

</html>
4.6 父子组件的直接访问方式 - $children或$refs  /  $parent

理解

有时候我们需要父组件直接访问子组件,子组件直接访问父组件,或者是子组件访问根组件

  • 父组件访问子组件:使用$children$refs

  • 子组件访问父组件:使用$parent

$children

this.$children是一个数组类型,它包含所有子组件对象

我们这里通过一个遍历,取出所有子组件的message状态

image-20201124231839032

$refs

$children的缺陷

通过 $children 访问子组件时,是一个数组类型,访问其中的子组件必须通过索引值

但是当子组件过多,我们需要拿到其中一个时往往不能确定它的索引值,甚至还可能会发生变化

有时候我们想明确获取其中一个特定的组件,这个时候就可以使用$refs

$refs的使用

$refsref指令 通常是一起使用的

首先我们通过 ref 给某一个子组件绑定一个特定的ID

其次通过 this.$refs.ID 就可以访问到该组件了

image-20201124232844530

$parent

如果我们想在子组件中直接访问父组件,可以通过$parent

注意

尽管在Vue开发中,我们允许通过$parent来访问父组件,但是在真实开发中尽量不要这样做

子组件应该尽量避免直接访问父组件的数据,因为这样耦合度太高了
如果我们将子组件放在另外一个组件之内,很可能该父组件没有对应的属性,往往会引起问题

另外更不好做的是通过$parent直接修改父组件的状态,那么父组件中的状态将变得飘忽不定,很不利于我的调试和维护

image-20201124233250766

5. 非父子组件通信

5.1 理解

刚才我们讨论的都是父子组件间的通信,那如果是非父子关系呢?

非父子组件关系包括多个层级的组件,也包括兄弟组件的关系

Vue1.x的时候,可以通过 $dispatch$broadcast完成,但是在 Vue2.x都被取消了

  • $dispatch用于向上级派发事件

  • $broadcast用于向下级广播事件

Vue2.x 中,有一种方案是通过中央事件总线,也就是一个中介来完成

  • 但是这种方案和直接使用 Vuex 的状态管理方案还是逊色很多
  • 并且 Vuex 提供了更多好用的功能,所以这里我们暂且不讨论这种方案,后续我们专门学习 Vuex 的状态管理
5.2 中央事件总线
5.3 Vuex状态管理(后面专门讲)

6. 插槽slot

6.1 编译作用域

在真正学习插槽之前我们需要先理解一个概念:编译作用域

官方对于编译的作用域解析比较简单,我们自己来通过一个例子来理解这个概念

我们来考虑下面的代码是否最终是可以渲染出来的:

  • <my-cpn v-show="isShow"></my-cpn>中,我们使用了 isShow属性

  • isShow属性包含在组件中,也包含在Vue实例中

答案:最终可以渲染出来,也就是使用的是Vue实例的属性。为什么呢?

  • 官方给出了一条准则:父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译
  • 而我们在使用 <my-cpn v-show="isShow"></my-cpn> 的时候,整个组件的使用过程是相当于在父组件中出现的
  • 那么他的作用域就是父组件,使用的属性也是属于父组件的属性
  • 因此 isShow使用的是Vue实例中的属性,而不是子组件的属性

image-20201124234313056

6.2 为什么使用slot

slot翻译为插槽

在生活中很多地方都有插槽,电脑的USB插槽,插板当中的电源插槽

插槽的目的是让我们原来的设备具备更多的扩展性

比如电脑的USB我们可以插入U盘、硬盘、手机、音响、键盘、鼠标等

组件的插槽

组件的插槽也是为了让我们封装的组件更加具有扩展性

让使用者可以决定组件内部的一些内容到底展示什么

例子:移动网站中的导航栏

  • 移动开发中,几乎每个页面都有导航栏

  • 导航栏我们必然会封装成一个插件,比如nav-bar组件

  • 一旦有了这个组件,我们就可以在多个页面中复用了

  • 但是,每个页面的导航是一样的吗?No,我以京东M站为例

image-20201124234612254

6.3 如何在封装组件时正确使用slot

如何去封装京东M站导航栏这类的组件呢?

它们也很多区别,但是也有很多共性

如果我们每一个单独去封装一个组件显然不合适:比如每个页面都返回,这部分内容我们就要重复去封装

但是如果我们封装成一个好像也不合理:有些左侧是菜单,有些是返回,有些中间是搜索,有些是文字等

如何封装合适呢?抽取共性,保留不同

  • 最好的封装方式就是将共性抽取到组件中,将不同暴露为插槽

  • 一旦我们预留了插槽,就可以让使用者根据自己的需求,决定插槽中插入什么内容

  • 是搜索框,还是文字,还是菜单。由调用者自己来决定

  • 这就是为什么我们要学习组件中的插槽slot的原因

6.4 slot基本使用

了解了为什么用slot,我们再来谈谈如何使用slot?

  • 在子组件中,使用特殊的元素 <slot> 就可以为子组件开启一个插槽。

  • 该插槽插入什么内容取决于父组件如何使用。

我们通过一个简单的例子,来给子组件定义一个插槽

  • <slot> 中的内容表示,如果没有在该组件中插入任何其他内容,就默认显示该内容
  • 有了这个插槽后,父组件如何使用呢?

image-20201128135942587

6.5 具名插槽slot

当子组件的功能复杂时,子组件的插槽可能并非是一个

比如我们封装一个导航栏的子组件,可能就需要三个插槽,分别代表左边、中间、右边。、

那么,外面在给插槽插入内容时,如何区分插入的是哪一个呢?

这个时候,我们就需要给插槽起一个名字

image-20201128135942587

如何使用具名插槽呢?

非常简单,只要给slot元素一个name属性即可

<slot name='myslot'></slot>

我们来给出一个案例:

这里我们先不对导航组件做非常复杂的封装,先了解具名插槽的用法。

image-20201128140254483

6.6 作用域插槽

作用域插槽是slot一个比较难理解的点,而且官方文档说的又有点不清晰。

这里,我们用一句话对其做一个总结,然后我们在后续的案例中来体会:父组件替换插槽的标签,但是内容由子组件来提供。

我们先提一个需求

子组件中包括一组数据,比如:pLanguages: ['JavaScript','Python','Swift','Go','C++']

需要在多个界面进行展示:

  • 某些界面是以水平方向一一展示的,
  • 某些界面是以列表形式展示的,
  • 某些界面直接展示一个数组

内容在子组件,希望父组件告诉我们如何展示,怎么办呢

  • 利用slot作用域插槽就可以了

我们来看看子组件的定义:

image-20201128140613312

在父组件使用我们的子组件时,从子组件中拿到数据

我们通过 <template slot-scope="slotProps"> 获取到 slotProps 属性

注:
① 在 vue2.5.x 以下必须使用template标签,之后的版本也可以使用其他任意标签了
① 这里的 :data并不是定义死的,也可以使用其他任意名字 :xx

再通过 slotProps.data 就可以获取到刚才我们传入的data了

image-20201128140707214

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 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导入导出