百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分类 > 正文

vue3学习11、12、13组件化开发(vue组件化开发案例)

ztj100 2024-11-12 14:22 14 浏览 0 评论

利用vue脚手架创建一个项目

vue create component_demo

可以在vscode中安装Vue VSCode Snippets插件或vue3 snippets,帮助生成一些代码片段

vbase-css

可以快速生成vue3模板

组件通信

父子组件之间通信

  • 父组件传递给子组件:通过props属性
  • 子组件传递给父组件:通过$emit触发事件

在父组件中引入组件传值

<show-message :title="title"></show-message>

子组件中在props中定义

    props: {
      title: {
        type: String,
        require: true,   //表示这个属性是必传的
        default: '123'  //默认属性
      },
      //当属性是Object型时,默认值要为一个函数.因为多个组件会引用同一个对象
      info: {
        type: Object,
        default() {
          return {name: 'juju'}
        }
      },
      //自定义验证函数
      man: {
        validator(value) {
          //这个值必须匹配下列字符串中的一个
          return ['success', 'warning', 'danger'].include(value)
        }
      }
    }

props命名 建议父组件中要传递的值采用驼峰写法

<show-message :message-info="title"></show-message>
...


data() {
    return {
        messageInfo: 'damn'
    }
}

非props的Attribute

当我们传递给一个组件某个属性,但是该属性并没有定义对应的props或者emits,就称之为非props的Aaaribute

常见的包括css,style,id属性等 例如当给子组件设置一个class属性

<show-message class="liin" :title="title"></show-message>

当组件有单个根节点时,会自动添加到根节点的attribute

<template>
  <div class="liin">
    <h2>{{ title }}</h2>
    <h2>{{ info.name }}</h2>
  </div>
</template>

如果我们不希望根组件继承attribute,可以在子组件中设置inheritAttrs: false 我们可以通过$attrs来访问所有的非props的attribute

<h2 :class="$attrs.class">{{ title }}</h2>

通过v-bind绑定所有属性 父组件

<show-message id="xixi" class="liin" :title="title"></show-message>

子组件

<h2 v-bind="$attrs">{{ title }}</h2>

子组件传递给父组件 子组件中与vue2不同的是多了个emit参数,里面存放着可能要触发的事件

  export default {
    //emits属性,里面存放着待会会触发的事件
    emits: ["add", "sub"],
    //emits的对象写法,目的是为了进行参数的验证
    emits: {
      sub: null,
      add: (name, age) => {
        if(name == 'juju') {
          return true
        }
        return false
      }
    },
    methods: {
      increament() {
        this.$emit("add","juju",18)   //后面多个参数跟着的是要传的参数
      },
      decreament() {
        this.$emit("sub")
      },
    }
  }

父组件中写法与vue2相同

<counter-operation @add="addOne" @sub="subOne"></counter-operation>

非父组件的通信

  • provide/inject
  • mitt全局事件总线
  • vuex

provide和inject

无论层级结构有多深,父组件都可以作为其所有子组件的依赖提供者; 父组件有一个provide选项来提供数据,子组件有一个inject选项来使用这些数据

在父组件中添加一个provide

    components: {
      Home
    },
    provide: {
      name: 'juju',
      age: 18
    },

在子孙组件中注入

  export default {
    inject: ["name", "age"]
  }

当然,许多情况下数据都要从data中拿并从后台请求了,此时的provide要写成函数形式

    provide() {
      return {
        name: juju,
        age: 18,
        title: this.title
      }
    },

如果后续title改变的话,inject里的值并不是响应式的,可以使用vue中的computed函数


import {computed} from 'vue'

    provide() {
      return {
        name: juju,
        age: 18,
        title: computed(() => {
          this.title
        })
      }
    },

全局事件总线mitt库

安装mitt库

npm install mitt

创建一个eventbus.js文件

import mitt from 'mitt'

const emitter = mitt();

export default emitter;

// 也可以创建多个mitt对象

测试叔侄组件之间通信 在叔组件中传递

import emmiter from '../util/eventbus.js'

    methods: {
      btnClick() {
        emmiter.emit("handle", "juju",18);  //第一个参数方法名,后面跟着的是参数
      }
    }

在侄组件的生命周期中监听

    import emitter from '../util/eventbus.js'
    created() {
      emitter.on("handle", (name,age)=> {
        console.log(name)
      })
    }

mitt事件取消

emitter.all.clear();  //全部取消监听

function onFoo(){}
emitter.on('foo', onFoo)  //监听
emitter.off('foo', onFoo)  //取消监听

插槽slot

对于不同的区域可能存放不同的内容,因此要使用slot

  • 插槽的使用过程其实是抽取共性,预留不同
  • 我们会将共同的元素,内容依然在组件内进行封装
  • 同时将不同的元素使用slot作为占位,让外部决定到底显示什么样的元素

简单插槽的使用

定义一个子组件

    <h2>组件开始</h2>
    <slot></slot>
    
    <h2>组件结束</h2>

在父组件中使用

    <my-slot-cpn>
      <button>我是按钮</button>
    </my-slot-cpn>

此时中间部分可以展示按钮或者图片或者组件,vue会将内容替换到slot的位置

具名插槽的使用

插槽的默认使用 如果子组件是这样的

  <div>
    <h2>组件开始</h2>
    <slot>
      <i>我是默认内容</i>
    </slot>

    <h2>组件结束</h2>
  </div>

父组件

    <my-slot-cpn>
    </my-slot-cpn>

则显示默认内容

具名插槽

在子组件中编写有name属性的插槽

<template>
  <div class="nav-bar">
    <div class="left">
      <slot name="left"></slot>
    </div>
    <div class="center">
      <slot name="center"></slot>
    </div>
    <div class="right">
      <slot name="right"></slot>
    </div>
  </div>
</template>

在父组件中用template v-slot方式分配元素至对于的slot内

    <!-- 具名插槽的使用 -->
    <nar-bar>
      <template v-slot:left>
        <button>左边按钮</button>
      </template>
      //等价于
       <template #left>
        <button>左边按钮</button>
      </template>
      <template v-slot:center>
        <h2>我是标题</h2>
      </template>
      <template v-slot:right>
        <i>右边的元素</i>
      </template>
    </nar-bar>

效果

如果名字是不定的话,template应该这么写

      <template v-slot:[name]>
        <i>右边的元素</i>
      </template>

作用域插槽

即子组件中的slot属性,可以传给父组件 子组件

<template>
  <div>
    <template v-for="(item,index) in names" :key="item">
      <slot :item="item" :index="index"></slot>
    </template>
  </div>
</template>

父组件通过v-slot取得

  <show-names>
    <template v-slot="slotProps">
      <button>{{slotProps.item}}-{{ slotProps.index }}</button>
    </template>
  </show-names>
  //是下面的简写,v-slot后跟插槽名字
    <show-names>
    <template v-slot:default="slotProps">
      <button>{{slotProps.item}}-{{ slotProps.index }}</button>
    </template>
  </show-names>

当只有默认插槽时,可以使用独占默认插槽写法

    <show-names v-slot="slotProps">
      <button>{{slotProps.item}}-{{ slotProps.index }}</button>
  </show-names>

动态组件的实现

根据不同的场景,去渲染不同的组件。以前基本都使用v-if去判断从而渲染不同的组件。但是当组件很多的时候,组件会显得很臃肿。此时可以考虑采用动态组件去实现。

动态组件是使用component组件,通过特殊的attribute is来实现。 例如

<component is="hello-world"></component>

此时就会渲染HelloWorld组件

动态组件传递参数

<component is="hello-world" name="juju" :age="18" @helloClick="handleClick"></component>

此时在helloworld组件可以用props接收,同时动态组件可以接受子组件的点击事件

keep-alive

默认情况下,切换组件会被销毁,再次回来会重新创建组件。此时,在开发中某些情况我们希望继续保持组件的状态,而不是销毁掉,这时我们可以使用一个内置组件:keep-alive。

<keep-alive>
    <component is="hello-world" name="juju" :age="18" @helloClick="handleClick"></component>
<keep-alive>

keep-alive有一些属性,

  • include.[string|regexp|array]只有名称匹配的组件会被缓存。
  • exclude[string|regexp|array]任何匹配的组件都不会会被缓存。
  • max[number|string]最多可以缓存多少组件实例,一旦达到这个数字,那么缓存组件中最近没有被访问的实例会被销毁


include是根据组件的name属性来进行适配,因此有时需要给组件加上name属性

  export default {
    name: 'about',
   }

webpack分包

正常打包的话会将所有资源打包到一个app.js文件中,采用webpack分包方式会将利用分包的资源打包到一个chunk文件中,需要时再去加载,可以优化首屏渲染。

//通过import函数导如的模块,后续webpack对其进行打包的时候就会进行分包的操作
import('./utils/math').then(res => {console.log(sum(10,20))})

异步组件

同时vue3提供一个函数可以使打包后的组件成为一个单独的文件夹,加快首屏渲染速度 defineAsyncComponent接受两种类型的参数: 类型一:工厂函数,该工厂函数需要返回一个promise对象 类型二:接受一个对象类型,对异步函数进行配置

import {defineAsyncComponent} from 'vue'
const AsyncHello = defineAsyncComponent(() => import('./components/HelloWorld.vue'))

一般开发中使用路由懒加载比较多

获取元素和refs

在某些情况下,我们组件想要直接获取到元素对象或者子组件实例 在vue开发中我们不推荐dom操作的,这个时候,可以给元素或者组件绑定以恶搞ref的attribute属性

<h2 ref="title">哈哈哈哈哈哈</h2>


    mounted() {
      console.log(this.$refs.title)
    },

打印结果


对于组件来说,调用this.refs.xx可以获取组件实例,取得data中的数据或调用一些方法。 同时,可以在子组件中采用this.parent取得父组件实例以及parent取得父组件实例以及parent取得父组件实例以及root获取根组件

组件的生命周期

  • beforecreated
  • created
  • beforemounted
  • mounted
  • beforeUpdate
  • updated
  • beforeUnmount
  • unmounted

对于有缓存的组件来说,再次进入时,我们是不会执行created或者mounted等生命周期的,这时我们可以使用activated和deactiveated这两个生命周期钩子函数来监听。

组件的v-model

    //组件绑定v-model与下列的等价
    <hy-input v-model="title"></hy-input>
    <!-- <hy-input :modelValue="title" @update:model-value="title = $event"></hy-input> -->
<template>
  <div>
    <button @click="btnClick">input按钮</button>
    {{ modelValue }}
  </div>
</template>

<script>
  export default {
    props: {
      modelValue: String
    },
    emits: ["update:modelValue"],
    methods: {
      btnClick() {
        this.$emit("update:modelValue", '嘿嘿')
      }
    }
  }
</script>

$event为update:model-value事件传出来的参数

如果子组件中有input可以实现v-model绑定计算属性的操作,因为不能绑定到props里

    <input v-model="value" />
    
    ...
    computed: {
      value: {
        get(){
          return this.modelValue
        },
        set(value) {
          this.$emit("update:modelValue", value)
        }
      }
    },  

绑定多个v-model,后面加名字,此时why为子组件prop的值

<hy-input v-model="title" v-model:why="why"></hy-input>

相关推荐

告别手动操作:一键多工作表合并的实用方法

通常情况下,我们需要将同一工作簿内不同工作表中的数据进行合并处理。如何快速有效地完成这些数据的整合呢?这主要取决于需要合并的源数据的结构。...

【MySQL技术专题】「优化技术系列」常用SQL的优化方案和技术思路

概述前面我们介绍了MySQL中怎么样通过索引来优化查询。日常开发中,除了使用查询外,我们还会使用一些其他的常用SQL,比如INSERT、GROUPBY等。对于这些SQL语句,我们该怎么样进行优化呢...

9.7寸视网膜屏原道M9i双系统安装教程

泡泡网平板电脑频道4月17日原道M9i采用Win8安卓双系统,对于喜欢折腾的朋友来说,刷机成了一件难事,那么原道M9i如何刷机呢?下面通过详细地图文,介绍原道M9i的刷机操作过程,在刷机的过程中,要...

如何做好分布式任务调度——Scheduler 的一些探索

作者:张宇轩,章逸,曾丹初识Scheduler找准定位:分布式任务调度平台...

mysqldump备份操作大全及相关参数详解

mysqldump简介mysqldump是用于转储MySQL数据库的实用程序,通常我们用来迁移和备份数据库;它自带的功能参数非常多,文中列举出几乎所有常用的导出操作方法,在文章末尾将所有的参数详细说明...

大厂面试冲刺,Java“实战”问题三连,你碰到了哪个?

推荐学习...

亿级分库分表,如何丝滑扩容、如何双写灰度

以下是基于亿级分库分表丝滑扩容与双写灰度设计方案,结合架构图与核心流程说明:一、总体设计目标...

MYSQL表设计规范(mysql表设计原则)

日常工作总结,不是通用规范一、表设计库名、表名、字段名必须使用小写字母,“_”分割。...

怎么解决MySQL中的Duplicate entry错误?

在使用MySQL数据库时,我们经常会遇到Duplicateentry错误,这是由于插入或更新数据时出现了重复的唯一键值。这种错误可能会导致数据的不一致性和完整性问题。为了解决这个问题,我们可以采取以...

高并发下如何防重?(高并发如何防止重复)

前言最近测试给我提了一个bug,说我之前提供的一个批量复制商品的接口,产生了重复的商品数据。...

性能压测数据告诉你MySQL和MariaDB该怎么选

1.压测环境为了尽可能的客观公正,本次选择同一物理机上的两台虚拟机,一台用作数据库服务器,一台用作运行压测工具mysqlslap,操作系统均为UbuntuServer22.04LTS。...

屠龙之技 --sql注入 不值得浪费超过十天 实战中sqlmap--lv 3通杀全国

MySQL小结发表于2020-09-21分类于知识整理阅读次数:本文字数:67k阅读时长≈1:01...

破防了,谁懂啊家人们:记一次 mysql 问题排查

作者:温粥一、前言谁懂啊家人们,作为一名java开发,原来以为mysql这东西,写写CRUD,不是有手就行吗;你说DDL啊,不就是设计个表结构,搞几个索引吗。...

SpringBoot系列Mybatis之批量插入的几种姿势

...

MySQL 之 Performance Schema(mysql安装及配置超详细教程)

MySQL之PerformanceSchema介绍PerformanceSchema提供了在数据库运行时实时检查MySQL服务器的内部执行情况的方法,通过监视MySQL服务器的事件来实现监视内...

取消回复欢迎 发表评论: