vue组件三要素

props参数
slot定制插槽
event自定义事件

一、props:数据父组件传入子组件

 props: {
    // 基础类型检测 (`null` 意思是任何类型都可以)
    propA: Number,
    // 多种类型
    propB: [String, Number],
    // 必传且是字符串
    propC: {
      type: String,
      required: true
    },
    // 数字,有默认值
    propD: {
      type: Number,
      default: 100
    },
    // 数组/对象的默认值应当由一个工厂函数返回
    propE: {
      type: Object,
      default: function () {
        return { message: 'hello' }
      }
    },
    // 自定义验证函数
    propF: {
      validator: function (value) {
        return value > 10
      }
    }
  }
复制代码

对于通过 props 传入的参数,不建议对其进行操作,因为会同时修改父组件里面的数据 // vue2.5已经针对 props 做出优化,这个问题已经不存在了 如果一定需要有这样的操作,可以这么写:

let copyData = JSON.parse(JSON.stringify(this.data))
复制代码

为什么不直接写 let myData = this.data 呢? 因为直接赋值,对于对象和数组而言只是浅拷贝,指向的是同一个内存地址,其中一个改变另一个也会改变。而通过 JSON颠倒转换之后,实现了深拷贝,则可以互不影响。

二、子组件触发父组件事件

在通用组件中,通常会需要有各种事件,比如复选框的 change 事件,或者组件中某个按钮的 click 事件,有时子组件需要触发一个事件,并传递给父组件

// 子组件方法:触发父组件方法,并传递参数data到父组件
handleSubmit(data){
    this.$emit('submitToParent', data)
}
复制代码
// 父组件调用子组件
<child-component @submitToParent="parentSubmit"></child-component>
... ...
// 父组件中被触发的方法,接受到子组件传来的参数
parentSubmit(data){
    // 父组件的逻辑处理
}
复制代码

父组件中的逻辑要放在父组件处理,子组件基于父组件的数据做的逻辑放在子组件中处理; 这样既降低了耦合性,也保证了各自的数据不被污染。

三、记得留一个 slot

**一个通用组件,往往不能够完美的适应所有应用场景 所以在封装组件的时候,只需要完成组件 80% 的功能,剩下的 20% 让父组件通过 solt 解决
**
在某些场景中,右侧的按钮是 “处理” 和 “委托”。在另外的场景中,按钮需要换成 “查看” 或者 “删除” 在封装组件的时候,就不用写按钮,只需要在合适的位置留一个 slot,将按钮的位置留出来,然后在父组件写入按钮

子组件
<div class="child-btn">
    <!-- 具名插槽 -->
    <slot name="button"></slot>
    <!-- 匿名插槽(每个组件只能有一个) -->
    <slot><slot>
</div>
 
父组件
<child>
    <!-- 对应子组件中button的插槽 -->
    <button slot="button">slot按钮</button>
</child>
复制代码

开发通用组件的时候,只要不是独立性很高的组件,建议都留一个 slot,即使还没想好用来干什么。

再来个例子:

开发过程中,常常需要在子组件内添加新的内容,这时候可以在子组件内部留一个或者多个插口

然后在调用这个子组件的时候加入内容

添加的内容就会分发到对应的 slot 中

slot 中还可以作为一个作用域,在子组件中定义变量,然后在父组件中自定义渲染的方式 子组件:

关于slot的用法还可查看添加链接描述

四、Vuex:巧用但不要滥用

子组件向子组件传递数据

Vue 没有直接子对子传参的方法,建议将需要传递数据的子组件,都合并为一个组件。如果一定需要子对子传参,可以先从传到父组件,再传到子组件。 父子组件之间是通过 props 和 自定义事件来传参,非父子组件通常会采用 Vuex 传参 Vuex设计初衷是用来管理组件状态,也可以用于复杂组件的参数传递

但是 Vuex 的虽然可以用来传参,但并不推荐;因为 Vuex 类似于一个全局变量,会一直占用内存 在写入数据庞大的 state 的时候,就会产生内存泄露(人是活的,不能因为事物有弊端就不使用,合理利用即可)。 Tips: 当页面刷新的时候,Vuex 会初始化,同时也会丢失编辑过的数据 如果刷新页面时需要保留数据,可以通过 url 或者 sessionstorage 保存 id,然后 ajax 请求数据

五、组件的css:合理运用 scoped 控制样式作用域

在编写组件的时候,可以在 style 标签中添加 scoped,让标签中的样式只对当前组件生效 但是一味的使用 scoped,肯定会产生大量的重复代码 所以在开发的时候,应该避免在组件中写样式 当全局样式写好之后,再针对每个组件,通过 scoped 属性添加组件样式

六、动态组件

Vue 还可以将多个子组件,都挂载在同一个位置,通过变量来切换组件,实现 tab 菜单这样的效果
在这里插入图片描述

这样的功能可以通过路由 vue-router 实现,但路由更适合较大的组件而且 url 会有相应的改变 Vue 自身保留的 元素,可以将组件动态绑定到 is 特性上,从而很方便的实现动态组件切换
在这里插入图片描述
在这里插入图片描述

上例中,当 tabView 的值改变,component 就会渲染对应的组件,和路由的效果十分类似,但是地址栏并没有发生改变,但这样一来,每次切换组件都会重新渲染,无法保留组件上的数据。这时可以使用 ** keep-alive ** 将组件保留在内存中,避免重新渲染

 <keep-alive>
          <component :is="componentName"
            :vehicleId="vehicleId"
            :groupIds="groupIds"
            ref="componentRef"
            :option="option"
            :tableDatas="tableDatas" />
        </keep-alive>
import statistics from "@/views/workManagement/components/statistics";
componentName: "statistics",

七、递归组件

当组件拥有 name 属性的时候,就可以在它的模板内递归的调用自己,这在开发树形组件的时候十分有效
在这里插入图片描述
上面是一个子组件,定义了 name 为 simple03,然后在模板中调用自身,结合 v-for 实现递归 为了防止出现死循环,在调用自身的时候,加入了 v-if 作为判定条件 父组件中调用的时候,需要通过 props 传入一个 tree:
在这里插入图片描述在这里插入图片描述

子组件改变父组件的数据

在vue2.0之后的版本中,不允许子组件直接改变父组件的数据,在1.0的版本中可以这样操作的,但是往往项目需求需要改变父组件的数据,那我们如何变通呢?
当我们把父元素的数据给子组件时,要传一个非基础类型,即传递对象or数组,子组件通过访问对象中的属性操作数据,因为对象和数组是传引用,所以在子组件中修改的时候,父组件也会同步改变,

// 父组件要props传递给子组件的数据
myData:{
    info:'父组件信息'
}

// 子组件
 <template id="tpl">
    <div>
        <button @click="change">change</button>
        <p>{{data.info}}</p>
    </div>
</template>
... 省略部分无关代码 ...
props:['data'],
methods:{
    change(){
        this.data.info = 'change info'
    }
}

当子组件点击change按钮改变数据的时候,父组件也会同步改变
如果不想影响父组件的值,我们也可以用文章开头讲的JSON颠倒转换的方式,在mounted方法中进行深拷贝,在data中初始化数据时用另一个变量作为承载,这样才承载变量改变,就不会影响父组件该变量的值了。

转载于https://juejin.cn/post/6844903833898844174

Logo

基于 Vue 的企业级 UI 组件库和中后台系统解决方案,为数万开发者服务。

更多推荐