vue3学习11、12、13组件化开发

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

lua 复制代码
vue create component_demo

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

vbase-css

可以快速生成vue3模板

组件通信

父子组件之间通信

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

在父组件中引入组件传值

ruby 复制代码
<show-message :title="title"></show-message>

子组件中在props中定义

javascript 复制代码
    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命名 建议父组件中要传递的值采用驼峰写法

ruby 复制代码
<show-message :message-info="title"></show-message>
...


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

非props的Attribute

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

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

ruby 复制代码
<show-message class="liin" :title="title"></show-message>

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

xml 复制代码
<template>
  <div class="liin">
    <h2>{{ title }}</h2>
    <h2>{{ info.name }}</h2>
  </div>
</template>

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

css 复制代码
<h2 :class="$attrs.class">{{ title }}</h2>

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

ruby 复制代码
<show-message id="xixi" class="liin" :title="title"></show-message>

子组件

bash 复制代码
<h2 v-bind="$attrs">{{ title }}</h2>

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

javascript 复制代码
  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相同

ini 复制代码
<counter-operation @add="addOne" @sub="subOne"></counter-operation>

非父组件的通信

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

provide和inject

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

在父组件中添加一个provide

css 复制代码
    components: {
      Home
    },
    provide: {
      name: 'juju',
      age: 18
    },

在子孙组件中注入

arduino 复制代码
  export default {
    inject: ["name", "age"]
  }

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

javascript 复制代码
    provide() {
      return {
        name: juju,
        age: 18,
        title: this.title
      }
    },

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

javascript 复制代码
import {computed} from 'vue'

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

全局事件总线mitt库

安装mitt库

npm install mitt

创建一个eventbus.js文件

javascript 复制代码
import mitt from 'mitt'

const emitter = mitt();

export default emitter;

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

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

javascript 复制代码
import emmiter from '../util/eventbus.js'

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

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

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

mitt事件取消

csharp 复制代码
emitter.all.clear();  //全部取消监听

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

插槽slot

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

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

简单插槽的使用

定义一个子组件

xml 复制代码
    <h2>组件开始</h2>
    <slot></slot>
    
    <h2>组件结束</h2>

在父组件中使用

xml 复制代码
    <my-slot-cpn>
      <button>我是按钮</button>
    </my-slot-cpn>

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

具名插槽的使用

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

xml 复制代码
  <div>
    <h2>组件开始</h2>
    <slot>
      <i>我是默认内容</i>
    </slot>

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

父组件

perl 复制代码
    <my-slot-cpn>
    </my-slot-cpn>

则显示默认内容

具名插槽

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

xml 复制代码
<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内

xml 复制代码
    <!-- 具名插槽的使用 -->
    <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应该这么写

xml 复制代码
      <template v-slot:[name]>
        <i>右边的元素</i>
      </template>

作用域插槽

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

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

父组件通过v-slot取得

xml 复制代码
  <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>

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

xml 复制代码
    <show-names v-slot="slotProps">
      <button>{{slotProps.item}}-{{ slotProps.index }}</button>
  </show-names>

动态组件的实现

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

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

ini 复制代码
<component is="hello-world"></component>

此时就会渲染HelloWorld组件

动态组件传递参数

ini 复制代码
<component is="hello-world" name="juju" :age="18" @helloClick="handleClick"></component>

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

keep-alive

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

xml 复制代码
<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属性

arduino 复制代码
  export default {
    name: 'about',
   }

webpack分包

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

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

异步组件

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

javascript 复制代码
import {defineAsyncComponent} from 'vue'
const AsyncHello = defineAsyncComponent(() => import('./components/HelloWorld.vue'))

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

获取元素和refs

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

javascript 复制代码
<h2 ref="title">哈哈哈哈哈哈</h2>


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

打印结果

对于组件来说,调用this.refs.xx可以获取组件实例,取得data中的数据或调用一些方法。 同时,可以在子组件中采用this. <math xmlns="http://www.w3.org/1998/Math/MathML"> p a r e n t 取得父组件实例以及 parent取得父组件实例以及 </math>parent取得父组件实例以及root获取根组件

组件的生命周期

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

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

组件的v-model

ruby 复制代码
    //组件绑定v-model与下列的等价
    <hy-input v-model="title"></hy-input>
    <!-- <hy-input :modelValue="title" @update:model-value="title = $event"></hy-input> -->
xml 复制代码
<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里

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

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

ini 复制代码
<hy-input v-model="title" v-model:why="why"></hy-input>
相关推荐
学习使我快乐0113 分钟前
JS进阶 3——深入面向对象、原型
开发语言·前端·javascript
bobostudio199514 分钟前
TypeScript 设计模式之【策略模式】
前端·javascript·设计模式·typescript·策略模式
黄尚圈圈1 小时前
Vue 中引入 ECharts 的详细步骤与示例
前端·vue.js·echarts
浮华似水2 小时前
简洁之道 - React Hook Form
前端
正小安4 小时前
如何在微信小程序中实现分包加载和预下载
前端·微信小程序·小程序
_.Switch6 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一路向前的月光6 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   6 小时前
vite学习教程06、vite.config.js配置
前端·vite配置·端口设置·本地开发
长路 ㅤ   6 小时前
vue-live2d看板娘集成方案设计使用教程
前端·javascript·vue.js·live2d
Fan_web6 小时前
jQuery——事件委托
开发语言·前端·javascript·css·jquery