vue 组件开发

目录

组件认知

 组件简单使用

项目结构:

Search.vue

HelloWorld.vue 

App.vue 根组件

效果展示 

data函数return的理解 

通过 Prop 向子组件传递数据 子取父数据

理解:

简单使用:

父组件 App.vue

子组件 Search.vue

结果展示: 

单向数据流

监听子组件事件 父取子数据

理解

简单使用

代码

结果:

 父子组件的访问方式

父组件访问子组件 $refs 常用

理解

代码

展示效果

 子组件访问父组件 $parent $root

理解

 代码

结果

插槽

通过插槽分发内容

理解

简单使用 代码

具名插槽  渲染作用域 备用内容

 具名插槽 渲染作用域 代码  

备用内容 渲染作用域 代码 

 作用域插槽

理解

代码

组件之间跨级通信 Provide / Inject

理解

代码 

非响应式 

 响应式


组件认知

一个应用会以一棵嵌套的组件树的形式来组织

例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件。

层层划分 页由多组 

组件是可复用的实例,所以它们与根实例接收相同的选项,例如 datacomputedwatchmethods 以及生命周期钩子等

 组件简单使用

项目结构:

我们使用的组件是单文件组件(有一套完整的.vue内容 单独模块功能的封装)而不是字符串模板

Search.vue

<template>
  <h2>你好呀 这个是搜索框 组件</h2>
</template>

HelloWorld.vue 

<script setup>
import { ref } from 'vue'

defineProps({
  msg: String
})

const count = ref(0)
</script>

<template>
  <h1>{{ msg }}</h1>

  <p>
    Recommended IDE setup:
    <a href="https://code.visualstudio.com/" target="_blank">VS Code</a>
    +
    <a href="https://github.com/johnsoncodehk/volar" target="_blank">Volar</a>
  </p>

  <p>
    <a href="https://vitejs.dev/guide/features.html" target="_blank">
      Vite Documentation
    </a>
    |
    <a href="https://v3.vuejs.org/" target="_blank">Vue 3 Documentation</a>
  </p>

  <button type="button" @click="count++">count is: {{ count }}</button>
  <p>
    Edit
    <code>components/HelloWorld.vue</code> to test hot module replacement.
  </p>
</template>

<style scoped>
a {
  color: #42b983;
}
</style>

App.vue 根组件

<script>
//导入自己定义的组件
import SearchVue from './components/Search.vue'
import HelloWorldVue from './components/HelloWorld.vue'
export default{
  components:{
    //加载组件
    SearchVue,
    HelloWorldVue
  }
}
</script>
<template>
<!-- 使用自己定义的组件 -->
<!-- App.vue 相当于父组件 而Search.vue和HelloWorld.vue相当于子组件  -->
<SearchVue></SearchVue>
<HelloWorldVue></HelloWorldVue>
</template>
<style>
</style>

效果展示 

 

data函数return的理解 

<script>
export default{
  data(){
    //data 让子组件每次返回不同对象 防止数据污染 到其他使用的该组件的父组件
    return{
      msg:"你好呀"
    }
  }
}
</script>
<template>
  <h2>你好呀 这个是搜索框 组件</h2>
  <h3>{{msg}}</h3>
  <button @click="this.msg='HelloWorld'">改变msg</button>
</template>
<style>
</style>

对比:

<script>
const obj={
    msg:'hello',
}
export default{
  data(){

    return obj
  }
}
</script>
<template>
  <h2>你好呀 这个是搜索框 组件</h2>
  <h3>{{msg}}</h3>
  <button @click="this.msg='HelloWorld'">改变msg</button>
</template>
<style>
</style>

通过 Prop 向子组件传递数据 子取父数据

理解:

简单使用:

父组件 App.vue

<script>
//导入自己定义的组件
import SearchVue from './components/Search.vue'
export default{
  data(){
    return{
      transfer:[1,2,3,4]
    }
  },
  components:{
    //加载组件
    SearchVue
  }
}
</script>
<template>
<!--命名可随便取值(message,title) v-bind :message 绑定动态值  title 绑定静态值 -->
<SearchVue :message="transfer" title="我要向Search.vue 传递我的信息啦"></SearchVue>
</template>
<style>
</style>

子组件 Search.vue

1.以字符串数组形式列出的 props

<script>
export default{
  data(){
    return 
  },
  //以字符串数组形式列出的 props
  //通过props 去接收到父组件传递过来的值 
  props: ['title','message'],
}
</script>
<template>
  <h2>你好呀 这个是搜索框 组件</h2>

  <h3>这个是静态的值 {{title}}</h3>
  <h3>这个是动态的值 {{message}}</h3>
</template>
<style>
</style>

2. proos以对象的形式

<script>
export default{
  data(){
    return {
      
    }
  },
  //proos以对象的形式
  props: {
    //1.可对类型的限制
    //2.可设置默认值 父组件没有传值的时候就会使用默认值
    //3.设置是否为必传值
    //以上不满足设置要求的话都会有警告喔
    title:{
      //类型可设置为多个
      type:[String],
      default:"这个是message的默认值喔",
      required: true
    },
    message:{ 
      // 对象或数组的默认值必须从一个工厂函数返回
      type:Array,
      default(){
        return []
      }
    }
  }
}
</script>
<template>
  <h2>你好呀 这个是搜索框 组件</h2>

  <h3>这个是静态的值 {{title}}</h3>
  <h3>这个是动态的值 {{message}}</h3>
</template>
<style>
</style>

结果展示: 

 警告:

 

单向数据流

所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。

另外,每次父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告

1.这个 prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用

 2.这个 prop 以一种原始的值传入且需要进行转换。

监听子组件事件 父取子数据

理解

简单使用

代码

Search.vue

<script>
export default{
  data(){
    return {
      message:"我想要去到父组件"
    }
  },
  methods:{
    //1.在子组件中 通过 $emit来触发事件 this.$emit('自定义事件的名称','发送的事件参数')
    sendParent(){
      this.$emit('send',this.messgae)
    }
  }
}
</script>
<template>
   <button @click="sendParent">点击按钮</button>
</template>
<style>
</style>

App.vue

<script>
//导入自己定义的组件
import SearchVue from './components/Search.vue'
export default{
  data(){
    return{
      msg:""
    }
  },
  components:{
    //加载组件
    SearchVue
  },
  methods:{
    //子组件的自定义事件 会给该方法一个参数 该参数就是 this.$emit的第二个参数'发送的事件参数'
   getChildMsg(value){
    console.log(value);
    this.msg=value;
   }
  }
}
</script>
<template>
<!-- 获取子组件SearchVue的数据 通过自定义事件 -->
<!-- 2.在父组件中 通过v-on监听子组件中自定义的事件 -->
<SearchVue @send="getChildMsg"></SearchVue>
<h2>通过获取到子组件的值================{{msg}}</h2>
</template>
<style>
</style>

结果:

 父子组件的访问方式

父组件访问子组件 $refs 常用

理解

代码

vue.app

<script>
//导入自己定义的组件
import SearchVue from './components/Search.vue'
export default{
  data(){
    return{
      msg:""
    }
  },
  //钩子函数
  mounted(){
   console.log(this.$refs);
  },
  components:{
    //加载组件
    SearchVue
  }
}
</script>
<template>
<!-- 父组件访问子组件 $refs -->
<!-- ref: 用来给元素或者子组件注册引用信息 -->
<SearchVue  ref="search"></SearchVue>
<h2 ref="h2"></h2>
</template>
<style>
</style>

search.vue

<script>
export default{
  data(){
    return {
      message:"我想要去到父组件"
    }
  },
  methods:{
    //1.在子组件中 通过 $emit来触发事件 this.$emit('自定义事件的名称','发送的事件参数')
    sendParent(){
      this.message="嘻嘻";
    }
  }
}
</script>
<template>
   <button @click="sendParent">点击按钮</button>
</template>
<style>
</style>

展示效果

 

 子组件访问父组件 $parent $root

提示不太推荐使用 组件复用性高 这样使用会降低子组件的使用场景

理解

 代码

$parent $root 用法相同 就展示一个使用方法

$parent

Search.vue

<script>
export default{
  data(){
    return {
      message:"我想要去到父组件"
    }
  },
   //钩子函数
  mounted(){
    //获取父组件 信息
   console.log(this.$parent);
  }
}
</script>
<template>
</template>
<style>
</style>

App.vue

<script>
//导入自己定义的组件
import SearchVue from './components/Search.vue'
export default{
  data(){
    return{
      msg:"父组件信息"
    }
  },
  components:{
    //加载组件
    SearchVue
  },
}
</script>
<template>
<SearchVue></SearchVue>
</template>
<style>
</style>

结果

插槽

通过插槽分发内容

理解

简单使用 代码

App.vue

<script>
//导入自己定义的组件
import SearchVue from './components/Search.vue'
export default{
  data(){
    return{
      msg:""
    }
  },
  components:{
    //加载组件
    SearchVue
  }
}
</script>
<template>
<SearchVue> <button>我是子组件插槽按钮</button></SearchVue>

</template>
<style>
</style>

Search.vue

<script>
export default{
  data(){
    return {
      message:""
    }
  }
}
</script>
<template>
   <h2>下面要使用插槽了</h2>
   <!-- <slot> 作为我们想要插入内容的占位符 -->
   <slot></slot>
</template>
<style>
</style>

 结果展示

具名插槽  渲染作用域 备用内容

具名插槽: 

<slot> 元素有一个特殊的 attribute:name。通过它可以为不同的插槽分配独立的 ID,也就能够以此来决定内容应该渲染到什么地方

一个不带 name 的 <slot> 出口会带有隐含的名字“default”

渲染作用域:

该插槽可以访问与模板其余部分相同的实例 property (即相同的“作用域”)。

官网 理解:父组件中用到的插槽中添加的内容 属于父组件 子组件使用不了

父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。

备用内容:

有时为一个插槽指定备用 (也就是默认的) 内容是很有用的,它只会在没有提供内容的时候被渲染。

 具名插槽 渲染作用域 代码  

Search.vue

<script>
export default{
  data(){
    return {
      msg:"子组件信息"
    }
  }
}
</script>
<template>
   <h2>下面要使用插槽了</h2>
   <!-- <slot> 作为我们想要插入内容的占位符 -->
   <slot name="left"></slot>
   <div></div>
   <slot name="right"></slot>
</template>
<style>
</style>

App.vue

<script>
//导入自己定义的组件
import SearchVue from './components/Search.vue'
export default{
  data(){
    return{
      msg:"父组件信息"
    }
  },
  components:{
    //加载组件
    SearchVue
  }
}
</script>
<template>
<!-- 如果有多个值 可同时放入组件进行替换 一起作为替换元素 -->
<!-- v-slot 只能添加在<template>上 -->
<SearchVue> 
  <template v-slot:left><button>我是子组件左插槽按钮</button>
  <!-- 父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的 -->
  <h2>{{msg}}</h2>
  </template>
  <template v-slot:right><button>我是子组件右插槽按钮</button></template>
  </SearchVue>

</template>
<style>
</style>

结果

备用内容 渲染作用域 代码 

Search.vue

<script>
export default{
  data(){
    return {
      msg:"子组件信息"
    }
  }
}
</script>
<template>
   <slot><button>我是备用按钮 父组件要是没有的话 我就存在了</button></slot>

</template>
<style>
</style>

App.vue 

<script>
export default{
  data(){
    return {
      msg:"子组件信息"
    }
  }
}
</script>
<template>
  <!-- 备用内容 会在没有提供内容的时候被渲染 -->
   <slot><button>我是备用按钮 父组件要是没有的话 我就存在了</button>
   {{msg}}
   </slot>

</template>
<style>
</style>

结果

 作用域插槽

理解

父组件替换插槽的标签 但是数据由子组件来提供

代码

Search.vue

<script>
export default{
  data(){
    return {
      msg:"子组件信息",
      list:["菠萝","香蕉","苹果","哈密瓜","西瓜"],
      thing:"(*^_^*)"
    }
  }
}
</script>
<template>
   <!-- 绑定子组件 数据 -->
   <slot :thing="thing" :msg="msg"></slot>

   <slot name="Uselist" :list="list" ></slot>

</template>
<style>
</style>

App.vue

<script>
//导入自己定义的组件
import SearchVue from './components/Search.vue'
export default{
  data(){
    return{
      msg:"父组件信息"
    }
  },
  components:{
    //加载组件
    SearchVue
  }
}
</script>
<template>
<!-- 如果有多个值 可同时放入组件进行替换 一起作为替换元素 -->
<!-- v-slot 只能添加在<template>上 -->
<SearchVue> 
  <!-- 作用域插槽:父组件替换插槽的标签 但是数据由子组件来提供 -->
  <!-- 包含所有插槽 prop的对象命名为 slotProps 命名 随意 -->
  <template v-slot:default="sloProps">
  <h2>{{sloProps}}</h2>
  <h2>{{sloProps.msg}}</h2>
  </template>
  </SearchVue>
  <br/>
  <!-- 无序序列表 -->
  <SearchVue>
    <template v-slot:Uselist="fruitList">
     <ul>
      <li v-for="item in fruitList.list" :key="item">
       {{item}}
      </li>
     </ul>
    </template>
  </SearchVue>
  <br/>
<!-- 有序列表 -->
  <SearchVue>
    <template v-slot:Uselist="fruitList">
     <ol>
      <li v-for="item in fruitList.list" :key="item">
       {{item}}
      </li>
     </ol>
    </template>
  </SearchVue>
</template>
<style>
</style>

结果

组件之间跨级通信 Provide / Inject

无论组件层次结构有多深,父组件都可以作为其所有子组件的依赖提供者。这个特性有两个部分:父组件有一个 provide 选项来提供数据,子组件有一个 inject 选项来开始使用这些数据。

理解

 

 

代码 

App.vue

<script>
//导入自己定义的组件
import NavigationBarVue from './components/NavigationBar.vue'
export default{
  data(){
    return{
      message:"根组件"
    }
  },
  components:{
    //加载组件
    NavigationBarVue
  }
}
</script>
<template>
<NavigationBarVue></NavigationBarVue>
</template>
<style>
</style>

Search.vue

<template>
  <InputVue></InputVue>
</template>

<script>
import InputVue from './Input.vue'
export default {
      data(){
    return{
      message:"父组件"
    }
  },
  components:{
    //加载组件
    InputVue
  }
}
</script>

<style>

</style>

非响应式 

默认情况下,provide/inject 绑定并不是响应式的

如果我们更改了 祖先组件 的数据,这个变化并不会反映在 inject 的 子组件 property 中。

NavigationBar.vue

<template>
  <h2>祖先组件========>{{message}}</h2>
  <br/>
  <button @click="this.message='你好呀'">改变message按钮</button>
  <br/>
  <SearchVue></SearchVue>
</template>

<script>
import SearchVue from './Search.vue'
export default {
    data(){
    return{
      message:"hello"
    }
  },
//   provide:{msg:"Hello"} 这样使用不可传入组件实例属性 所以简单写一下用法
//可访问组件实例的属性 函数方法
  provide(){
    return{
        //非响应式 访问
        msg:this.message
    }
  },
   components:{
    //加载组件
    SearchVue
  }
}
</script>

<style>

</style>

Input.vue

<script>
export default{
  data(){
    return {
      message:"子组件"
    }
  },
  inject:['msg']
}
</script>
<template>
<h2>子组件=====>{{msg}}</h2>
</template>
<style>
</style>

展示

点按钮前

 点按钮后

 响应式

NavigationBar.vue

<template>
  <h2>祖先组件========>函数{{message}}  对象{{obj.msg}}</h2>
  <br/>
  <button @click="this.message='你好呀'">改变message按钮</button>
  <button @click="this.obj.msg='你也好呀'">改变obj.msg按钮</button>
  <br/>
  <SearchVue></SearchVue>
</template>

<script>
import SearchVue from './Search.vue'
export default {
    data(){
    return{
      message:"hello",
      obj:{
        msg:"hi"
      }
    }
  },
//   provide:{msg:"Hello"} 这样使用不可传入组件实例属性 所以简单写一下用法
//可访问组件实例的属性 函数方法
  provide(){
    return{
        //函数返回响应式数据
        msg:() => this.message,
        //响应式对象方式
        obj:this.obj
    }
  },
   components:{
    //加载组件
    SearchVue
  }
}
</script>

<style>

</style>

Input.vue

<script>
export default{
  data(){
    return {
      message:"子组件"
    }
  },
  inject:['msg','obj'],
  computed:{
    newMsg(){
     return this.msg()
    }
  }
}
</script>
<template>
<h2>子组件=====>函数{{newMsg}} 对象{{obj.msg}}</h2>
</template>
<style>
</style>

结果

点按钮前

 

点按钮后

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

新生代农民工-小王八

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值