Vue:创建vue项目的两种方式,ref属性,props配置项,mixin混入,scoped,webStorage,自定义事件,全局事件总线,pubsub消息订阅发布,axios,插槽

创建Vue项目

前提准备

Vue环境

创建方式

  • 方式1:
  1. cmd打开终端 输入命令vue ui ,输入命令后自动开打浏览器页面

  2. 修改项目创建路径,修改路径后点击下方在此创建新项目

    在这里插入图片描述

  3. 填写项目名,同步Git按需勾选

在这里插入图片描述

  1. 预设勾选Vue2,点击创建项目即可

    在这里插入图片描述

  • 方式2:
  1. 在WebStrom工具控制台中输入命令:vue create xxxx >>> xxxx为项目名

  2. 选择使用Vue的版本(vue2)按方向键↓

    在这里插入图片描述

  3. 进入项目的根目录(项目创建完成后会有提示)

    cd xxxx    // xxxx为项目名
    
  4. 启动项目

    npm run serve
    
  5. 访问:启动后控制台会输出访问端口,点击即可访问

停止项目:Ctrl+C

项目结构

public
	favicon.ico  主页图标
	index.html 主页页面  容器的位置 #app
src
	assets 静态资源存放
		logo.png logo图标 .....
components  组件存储
	HelloWorld.vue
App.vue  汇总所有的组件
main.js  入口文件  new Vue
.gitignore  git版本管理 忽略的配置
babel.config.js
jsconfig.json
package.json   应用包的配置文件
package-lock.json 包的版本控制文件
README.md  应用描述文件
vue.config.js 项目配置文件

Vue下创建组件步骤

  1. 在src目录下components路径下,右键new创建一个Vue Component

  2. <template></template>标签中写代码,只允许有一个一级标签,通常写一个div标签在里面写所有内容

    <template>
      <div>
        <h2>学校名称:xx</h2>
        <h2>学校地址:xx</h2>
      </div>
    </template>
    
  3. 在App.vue中注册组件

    import School from "@/components/School";
    export default {
      name: 'App',
      data(){
        return{}
      },
      methods:{},
      components: {
        School
      }
    }
    

    需要使用import引入,在components配置中注册

    使用:在标签<div id="App"></div>中使用

    <!--App.vue-->
    <template>
      <div id="app">
        <School></School>   <!--可以双标签使用-->
    		<School/>						<!--也可以单标签使用-->
      </div>
    </template>
    

基本配置

配置参考文档:https://cli.vuejs.org/zh/config/

常用:

// vue.config.js
module.exports = {
  devServer: {
    port: 8083        //配置端口号
  },
  lintOnSave: false		// 关闭命名规范(自动检验命名规范过于严格,所以关闭)
}

若不配置端口号,Vue在端口不可应的情况下会自动向下延续端口号,知道找到可用的;如8080被占用,Vue会匹配8081,8082…

ref属性

  1. 用于给元素或者 组件 注册引用信息(类似id属性)
  2. 在html标签上 可以获取到真实的DOM元素,在组件标签上 可以获取到组件实例对象(vc)

案例:

<!--App.vue-->
<template>
  <div id="app">
    <h1 ref="title">{{msg}}</h1>
		<School ref="sch"></School>
    <button @click="demo">点击此按钮控制台查看ref</button>
  </div>
</template>

<script>
import School from "@/components/School";

export default {
  name: 'App',
  data(){
    return{}
  },
  methods:{},
  components: {
    School
  }
}
</script>

props配置项

让组件接收外部传入的数据,使用组件时传参,并在子组件中添加props

App.vue

<template>
  <div id="app">
    <Student name="张三" :age="21" sex="男" />       
  </div>
</template>

<script>
import Student from "@/components/Student";

export default {
  name: 'App',
  data(){
    return{}
  },
  methods:{},
  components: {
    Student
  }
}
</script>

age前添加:是为了让Vue接管,不然子组件在运算时数字就变成了字符串拼接,如20+1变成了211,添加:后,不会出现该问题

  1. 简单声明接收

    <template>
      <div>
        <h2>学生姓名:{{name}}</h2>
        <h2>学生年龄:{{ age + 1}}</h2>
        <h2>学生性别:{{sex}}</h2>
      </div>
    </template>
    
    <script>
    export default {
      name: "Student",
      // 简单声明接收
     	props: ['name','age','sex'],
      data(){
        return {
        }
      }
    }
    </script>
    
    <style scoped>
    
    </style>
    
  2. 在接收的同时要求类型

    <template>
      <div>
        <h2>学生姓名:{{name}}</h2>
        <h2>学生年龄:{{ age + 1}}</h2>
        <h2>学生性别:{{sex}}</h2>
      </div>
    </template>
    
    <script>
    export default {
      name: "Student",
      // 在接收的同时 要求类型
      props:{
        name:String,
        age:Number,
        sex:String
      },
      data(){
        return {
        }
      }
    }
    </script>
    
    <style scoped>
    
    </style>
    
  3. 接收同时要求类型,默认值,限制必要性

    <Student name="李四"  />
    

    子组件

    <template>
      <div>
        <h2>学生姓名:{{name}}</h2>
        <h2>学生年龄:{{ age + 1}}</h2>
        <h2>学生性别:{{sex}}</h2>
      </div>
    </template>
    
    <script>
    export default {
      name: "Student",
      // 接收同时要求类型,默认值,限制必要性
      props:{
        name:{
          type:String,
          required: true   // 是否必要
        },
        age:{
          type:Number,
          default: 20   // 默认值
        },
        sex:{
          type:String,
          required: false
        }
      },
      data(){
        return {
        }
      }
    }
    </script>
    
    <style scoped>
    
    </style>
    

    组件传参值给了一个name属性,但是子组件中props中age有默认值,sex非必要,所以页面会显示姓名李四,年龄21,性别没数据且控制台也不报错

注意:props 是只读的, 如果需要改变 那么复制props中的数据 再修改

<template>
  <div>
    <h2>学生姓名:{{ name }}</h2>
    <h2>学生年龄:{{ sAge + 1 }}</h2>
    <h2>学生性别:{{ sex }}</h2>
    <button @click="sAge++">age+++</button>
  </div>
</template>

<script>
export default {
  name: "Student",
  // 接收 父组件  传递 来的数据
  // 接收的同时 要求类型  默认值 限制必要性
  props: {
    name: {
      type: String,
      required: true
    },
    age: {
      type: Number,
      default: 99
    },
    sex: {
      type: String,
      required: true 
    }
  },
  data() {
    return {
      sAge:this.age
    }
  }
}
</script>
<style scoped>
</style>

mixin混入

Vue混入提供了一种非常灵活的方式,来分发Vue组件中的可复用功能。一个混入对象可以包含任意组件选项(如data、methods、mounted等等)。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。

把多个组件的共同的配置提取到一个混入对象中

局部混入

在src创建mixin.js

export const mixin ={
    methods:{
        showName(){
            alert(this.name);
        }
    },
    mounted() {
        console.log("这是mixin的mounted")
    }
}

School组件

<template>
  <div>
    <h2>学校名称:{{name}}</h2>
    <h2>学校地址:{{address}}</h2>
    <button @click="showName">mixin混用</button>
  </div>
</template>

<script>
import {mixin} from "@/mixin";

export default {
  name: "School",
  data(){
    return {
      name:'清华大学',
      address:'北京'
    }
  },
  mixins:[mixin],      //局部混入
  /*methods:{
    showName(){
      console.log("这是组件的方法");
    }
  },
  mounted() {
    console.log("这是School组件的mounted")
  }*/
}
</script>
<style scoped>
</style>
  • 组件中的methods和mounted注掉:

    1. 点击按钮出现弹框
  • 组件中的methods和mounted未注掉:

    1. 点击按钮不会走混入的js方法,而是走组件自己的方法

      在发生冲突时(方法)会以组件优先

    2. 组件和混入对象如果含有同名的项时:

      这些项目会合并(生命周期函数)

全局混入

  1. 导入全局混入
  2. 配置混入到Vue中
<!--main.js-->
import Vue from 'vue'
import App from './App.vue'

//配置全局混入
import {mixin} from "@/mixin";

Vue.config.productionTip = false
//配置 混入到Vue
Vue.mixin(mixin)

new Vue({
  render: h => h(App),
}).$mount('#app')

plugin插件

plugin用于增加Vue,包含了install方法的一个对象,第一个参数是Vue,后续参数是使用者传入的

插件的使用步骤:

  1. 在src下新建plugin.js

    export default {
        // Vue实例,可以传多参
        install(Vue,a,b,c){
            console.log(a,b,c);
            // 过滤器
            Vue.filter('strSlice',function (){
                return value.slice(0,4)
            })
            // 混入
            Vue.mixin({
                data(){
                    return{
                        count:1024
                    }
                }
            })
            // 原型
            Vue.prototype.hello = () =>{
                console.log("hello,world");
            }
        }
    }
    
  2. main.js中配置plugin

    import Vue from 'vue'
    import App from './App.vue'
    
    //第一步:引入plugin
    import plugin from "@/plugin";
    
    Vue.config.productionTip = false
    //第二部:插件传参
    VUe.use(plugin,1,2,3)
    
    new Vue({
      render: h => h(App),
    }).$mount('#app')
    
  3. 在组件中使用插件

    <template>
      <div>
        <h2>当前count的值:{{count}}</h2>
        <h2>学生姓名:{{name | strSlice }}</h2>
        <h2>学生年龄:{{age}}</h2>
        <button @click="demo">按钮</button>
      </div>
    </template>
    
    <script>
    export default {
      name: "Student",
      data(){
        return {
          name:'测试数据张三',
          age: 18
        }
      },
      methods:{
        demo(){
          this.hello();
        }
      }
    }
    </script>
    
    <style scoped>
    </style>
    

    结果:

    控制台会输出1,2,3

    当前count值:1024 (混入起作用)

    学生姓名:测试数据 (插件中过滤器起作用)

    点击按钮:控制台输出hello,world(插件中的原型)

scoped样式

让样式在局部生效,防止冲突

  1. components目录下的组件中样式都是<style scoped></style>,添加scoped是隔离样式

  2. App.vue中的样式是<style></style>,未添加scoped是全局样式

  3. 隔离样式优先级高于全局样式

School.vue

<template>
  <div>
    <h2>学校名称:{{ name }}</h2>
    <h2>学校地址:{{ address }}</h2>
  </div>
</template>

<script>

export default {
  name: "School",
  data() {
    return {
      name: '猿究院',
      address: '太白南路'
    }
  },
  methods: {
  }
}
</script>

<style scoped>
  // 给h2标签添加属性
  h2{
    color: red;
  }
</style>

Student.vue

<template>
  <div>
    <h2>学生姓名:{{name}}</h2>
    <h2>学生年龄:{{age}}</h2>
  </div>
</template>

<script>
export default {
  name: "Student",
  data() {
    return {
      name: '张三-测试数据',
      age: 18
    }
  },
  methods: {}
}
</script>

<style scoped>
  // 给 h2标签添加样式
  h2 {
    color: pink;
  }
</style>

App.vue

<template>
  <div>
    <h2>测试数据</h2>
    <Student></Student>
    <School></School>
  </div>
</template>

<script>
import Student from "@/components/Student.vue";
import School from "@/components/School.vue";

export default {
  name: 'App',
  data() {
    return {}
  },
  methods: {},
  components: {School, Student}
}
</script>

<style >
h2{
  color: orange;
}
</style>
  • School、Student、App都给h2标签添加了样式

    测试数据:橘色(App.vue 的全局样式)

    学生组件数据:粉色

    学校组件数据:红色

  • 若给School和Student组件样式的scoped去掉,所有样式变为最后使用的样式,即所有字体都是School的样式,字体都为红色

webStorage

  • sessionStorage:基于会话
  • localStorage:基于本地
 <template>
  <div>
    <button @click="saveData">保存数据</button>
    <button @click="readData">读取数据</button>
    <button @click="deleteData">删除数据</button>
    <button @click="deleteAll">清除数据</button>
  </div>
</template>

<script>

export default {
  name: 'App',
  data() {
    return {}
  },
  methods: {
    saveData(){
      sessionStorage.setItem("msg","sessionStorage");
    },
    readData(){
      console.log(sessionStorage.getItem("msg"))
    },
    deleteData(){
      sessionStorage.removeItem("msg");
    },
    deleteAll(){
      sessionStorage.clear();
    }
  },
  components: {}
}
</script>

<style>
</style>

自定义事件

是一种组件之间的通信方式;用于子组件 ----> 父组件

自定义事件实现步骤:

  1. 创建子组件,在App.vue中注册使用
  2. 给子组件标签添加ref属性
  3. 父组件中绑定自定义事件,编写回调函数
  4. 子组件中触发自定义事件
  5. 解绑自定义事件:
    • 解绑单个:this.$off(‘xxx’);
    • 解绑多个:this.$off([‘demo’]);
    • 解绑全部:this.$off();

父组件App.vue

<template>
  <div>
    <Student :getStudentName="getStudentName"></Student>
    <Student @demo="demo"></Student>
    <Student ref="student"></Student>
  </div>
</template>

<script>
import Student from "@/components/Student.vue";

export default {
  name: 'App',
  data() {
    return {}
  },
  methods: {
    getStudentName(name) {
      console.log("收到了Student组件的传递的数据:", name);
    },
    demo(value){
      console.log("收到了数据:",value)
    }
  },
  mounted() {
    //自定义事件 名称为demo  回调函数为 demo(value)
    this.$refs.student.$on("demo",this.demo);
  },
  components: {Student}
}
</script>

<style>
</style>

子组件Student.vue

<template>
  <div>
    <h2>学生姓名:{{ name }}</h2>
    <h2>学生性别:{{ sex }}</h2>
    <button @click="sendStudentName">传递学生姓名</button>
    <button @click="off">销毁自定义事件</button>
  </div>
</template>

<script>
export default {
  name: "Student",
  props: ['getStudentName'],
  data() {
    return {
      name: '张三',
      sex: '男'
    }
  },
  methods: {
    sendStudentName() {
      // props 子  ---> 父 传值
      // this.getStudentName(this.name);
      //触发自定义事件 传值
      this.$emit('demo',this.name);
    },
    off(){
      // 解绑 一个自定义事件
      // this.$off('demo');
      //解绑 多个自定义事件
      // this.$off(['demo']);
      //解绑 所有自定义事件
      this.$off();
    }
  }
}
</script>

<style scoped>
</style>

全局事件总线

可以在任意组件之间进行通信

同级组件之间通信实现步骤:

  1. 在main.js中配置

    import Vue from 'vue'
    import App from './App.vue'
    
    Vue.config.productionTip = false
    
    new Vue({
      render: h => h(App),
      beforeCreate() {
        Vue.prototype.$bus = this;//.$bus --->给原型定义一个对象  this指向Vue实例
      }
    }).$mount('#app')
    

    绑定后,此时的$bus就是Vue实例对象

  2. 在App.vue中注册子组件

    <template>
      <div id="app">
        <School/>
        <Student/>
      </div>
    </template>
    
    <script>
    import School from "@/components/School";
    import Student from "@/components/Student";
    export default {
      name: 'App',
      data(){
        return{}
      },
      methods:{},
      mounted() {},
      components: {Student, School}
    }
    </script>
    
  3. 确定接受数据组件,eg:school组件为接受数据组件

    <template>
      <div>
        <h2>学校名称:{{ name }}</h2>
        <h2>学校地址:{{ address }}</h2>
      </div>
    </template>
    
    <script>
    export default {
      name: "School",
      data() {
        return {
          name: '清华大学',
          address: '北京'
        }
      },
      methods: {
        demo(value){
          console.log("school组件收到了数据:",value)
        }
      },
      mounted() {
        this.$bus.$on('demo',this.demo)
        // school 自己没有$bus属性,向上找到prototype父类原型,是一个公共的区域
        // 在其上绑定一个自定义事件,创建回调函数
      },
      beforeDestroy() {
        this.$bus.$off("demo")
        // 在销毁VUe销毁之前,解绑自定义事件
      }
    }
    </script>
    
    <style scoped>
    </style>
    

    school组件自己没有$bus属性,向上找到prototype父类原型,是一个公共的区域

  4. 发送数据组件,eg:Student

    <template>
      <div>
          <h2>学生姓名:{{name}}</h2>
          <h2>学生年龄:{{age}}</h2>
          <button @click="sendStuName">点击传参给School</button>
      </div>
    </template>
    
    <script>
    export default {
      name: "Student",
      data() {
        return {
          name: '张三',
          age: 18
        }
      },
      methods: {
        sendStuName(){
          this.$bus.$emit('demo',this.name)
        }
      }
    }
    </script>
    <style scoped>
    </style>
    

    在发送数据组件中创建方法,触发自定义事件

pubsub消息订阅与发布

pubsub是组件之间的通信方式 任意组件之间

  1. 安装pubsub:在控制台中根目录下安装第三方插件:pubsub,命令如下

    官方文档:https://github.com/mroderick/PubSubJS

    npm install pubsub-js
    

    查看是否安装成功:打开package.json查看dependencies是否由pubsub

  2. 消息订阅方,订阅消息(数据接收方),eg:school

    步骤:

    1. 引入pubsub: import pubsub from ‘pubsub-js’
    2. 发起一个订阅,并编写回调函数
    3. 不用的时候取消订阅
    <template>
      <div>
        <h2>学校名称:{{ name }}</h2>
        <h2>学校地址:{{ address }}</h2>
      </div>
    </template>
    
    <script>
    // 引入pubsub 
    import pubsub from 'pubsub-js';
    
    export default {
      name: "School",
      data() {
        return {
          name: '清华大学',
          address: '北京'
        }
      },
      methods: { 
        // 回调函数  @param1:订阅名称(即demo)  @param2:接受的数据
        demo(pub,value){
          console.log("订阅者School:",pub,value)
        }
      },
      mounted() {
        // 发起订阅  (订阅名称,回调函数)
        this.pubID = pubsub.subscribe('demo',this.demo);
      },
      beforeDestroy() {
        // 取消订阅
        pubsub.unsubscribe(this.pubID);
      }
    }
    </script>
    
    <style scoped>
    </style>
    
  3. 消息发布方,发布消息(数据发送方),eg:student

    步骤:

    1. 导入pubsub: import pubsub from ‘pubsub-js’
    2. 定义方法触发订阅
    <template>
      <div>
          <h2>学生姓名:{{name}}</h2>
          <h2>学生年龄:{{age}}</h2>
          <button @click="sendStuName">点击传参给School</button>
      </div>
    </template>
    
    <script>
     // 引入pubsub 
    import pubsub from "pubsub-js";
    
    export default {
      name: "Student",
      data() {
        return {
          name: '张三',
          age: 18
        }
      },
      methods: {
        sendStuName(){
          // 发布消息('订阅名称',传递的数据)
          pubsub.publish('demo',this.name);
        }
      }
    }
    </script>
    
    <style scoped>
    </style>
    
  4. App.vue中注册组件

    <template>
      <div id="app">
        <School/>
        <Student/>
      </div>
    </template>
    
    <script>
    import School from "@/components/School";
    import Student from "@/components/Student";
    export default {
      name: 'App',
      data(){
        return{}
      },
      methods:{},
      mounted() {},
      components: {Student, School}
    }
    </script>
    

axios

axios:Vue中的请求,官方文档:https://github.com/axios/axios,本质上是对原生XMLHttpRequest的封装,可用于浏览器和nodejs的HTTP客户端

使用步骤:

  1. 安装axios:

    npm isntall axios
    
  2. 引入axios:import axios from “axios”;

  3. axios可以请求的方法:

    • get:获取数据,请求指定的信息,返回实体对象
    <template>
      <div>
      </div>
    </template>
    
    <script>
    import axios from "axios";
    
    export default {
      name: 'App',
      data() {
        return {}
      },
      methods: {},
      mounted() {
        axios.get('/user?ID=12345')
            .then((response) => {
              console.log("请求成功", response);
            })
            .catch((error) => {
              console.log("请求失败", error);
            })
            .finally(() => {
                  console.log("释放资源");
                }
            )
      },
      components: {}
    }
    </script>
    

    案例:

    <template>
      <div>
      </div>
    </template>
    
    <script>
    import axios from "axios";
    
    export default {
      name: 'App',
      data() {
        return {}
      },
      methods: {},
      mounted() {
        axios.get("/api1/getTeaGrowerData") // /api1   在config.js中配置
            .then(response=>{
                  console.log("请求成功", response.data);
            },
            error=>{
              console.log("请求失败", error);
            });
      },
      components: {}
    }
    </script>
    
    • post:向指定资源提交数据(例如表单提交或文件上传)
    <template>
      <div>
      </div>
    </template>
    
    <script>
    import axios from "axios";
    
    export default {
      name: 'App',
      data() {
        return {}
      },
      methods: {},
      mounted() {
        axios({
          url: '',
          method: 'post',
          headers: {'content-type': 'application/x-www-form-urlencoded'},
          // 声明传参方式:from表单
          data: {}
        }).then(response => {
              console.log("请求成功", response.data);
            },
            error => {
              console.log("请求失败", error);
            });
      },
      components: {}
    }
    </script>
    
    • put:更新数据,从客户端向服务器传送的数据取代指定的文档的内容
    • patch:更新数据,是对put方法的补充,用来对已知资源进行局部更新
    • delete:请求服务器删除指定的数据
  4. vue.config.js配置,跨域处理
    在前端处理跨域问题

    module.exports = {
        lintOnSave: false,
        devServer: {
            port: 8083,
            //开始代理服务 方式1:
            // proxy:"http://localhost:8081/"
          	// 方式2:
            proxy: {
                '/api1': {
                    target: 'http://localhost:8081/',
                    pathRewrite: {'^/api1': '/garden/' },  // 路径替换
                    // ws: true,// 用于支持webSocket 默认值为 true
                    changeOrigin: true // 控制头部请求中的host值  启用跨域处理
                },
                '/api2': {
                    target: 'http://localhost:8082/',
                    // ws: true,// 用于支持webSocket 默认值为 true
                    changeOrigin: true // 控制头部请求中的host值
                }
            }
        },
    }
    

    target:填写需要访问的url地址

    pathRewrite:路径替换,{‘^/api1’:‘/graden/’}会将第一个参替换成第二个参数,拼到url中

    ws:用于支持webSocket 默认值为 true

    changeOrigin:启用跨域处理,控制头部请求中的host值

axios案例

Github的用户查询

  1. vue.config.js配置代理服务器

    module.exports = {
      lintOnSave: false,
      devServer: {
        port: 8083,
        proxy:{
          '/api1':{
            target:'https://api.github.com/',
            pathRewrite:{'^/api1':'//'},
            changeOrigin:true
          }
        }
      }
    }
    
  2. main.js中配置全局事件总线

    import Vue from 'vue'
    import App from './App.vue'
    
    Vue.config.productionTip = false
    
    new Vue({
      render: h => h(App),
      beforeCreate() {
        Vue.prototype.$bus=this;
      }
    }).$mount('#app')
    
    
  3. Search组件,用于搜索请求接口

    <template>
      <section>
        <h1>GitHub用户搜索</h1>
        <input type="text" placeholder="请输入搜索内容(英文)" v-model="keyWord" />
        &nbsp;
        <button @click="getUsers">点击搜索</button>
      </section>
    </template>
    
    <script>
    import axios from "axios";
    
    export default {
      name: "Search",
      data(){
        return{
          keyWord: ''
        }
      },
      methods:{
        getUsers() {
          this.$bus.$emit('updateListData',{isLoading:true,errMsg:'',users:[],isFirst:true})
          axios.get(`/api1/search/users?q=${this.keyWord}`)
          .then(res=>{
            console.log(res.data)
            this.$bus.$emit('updateListData',{isLoading:false,errMsg:'',users:res.data.items,isFirst:false})
          },error=>{
            console.log('发生异常',error)
            this.$bus.$emit('updateListData',{isLoading:true,errMsg:error.message,users:[],isFirst:false})
          })
        }
      }
    }
    </script>
    
  4. List组件,用于接收Search传递的数据,并展示数据

    <template>
      <div class="row">
        <div class="card" v-for="user in info.users" :key="user.id" v-show="info.users.length">
          <a :href="user.html_url" target="_blank">
            <img :src="user.avatar_url" style="width: 100px;"/>
          </a>
          <h4 class="care-title">{{ user.login }}</h4>
        </div>
    
        <h1 v-if="info.isFirst">欢迎使用查询</h1>
        <h1 v-show="info.isLoading">欢迎使用查询</h1>
        <h1 v-show="info.errMsg">{{ info.errMsg }}</h1>
      </div>
    </template>
    
    <script>
    export default {
      name: "List",
      data() {
        return {
          info: {
            isFirst: true,
            isLoading: true,
            errMsg: '',
            users: []
          }
        }
      },
      mounted() {
        this.$bus.$on('updateListData',(data)=>{
          this.info = {...this.info,...data}
        })
      },
      beforeDestroy() {
        this.$bus.$off('updateListData')
      }
    }
    </script>
    
    <style scoped>
    .card {
      float: left;
      width: 31%;
      padding: .75rem;
      margin-bottom: 2rem;
      border: 1px solid #efefef;
      text-align: center;
    }
    
    .card  img {
      margin-bottom: .75rem;
      border-radius: 100%;
    }
    </style>
    
  5. App.vue中注册组件

    <template>
      <div id="app">
        <Search/>
        <List/>
      </div>
    </template>
    
    <script>
    
    import Search from "@/components/Search";
    import List from "@/components/List";
    export default {
      name: 'App',
      components: {
        List,
        Search
      }
    }
    </script>
    

插槽

Vue中的插槽(slot)是一种用于在组件中插入内容的机制。它允许我们在组件的模板中定义一些占位符,然后在使用该组件时,可以将具体的内容插入到这些占位符中。

默认插槽

实现步骤

  1. 创建插槽组件

    <template>
      <div class="category">
        <h3>{{title}}分类</h3>
        <slot></slot>     // 插槽(插槽相当于是挖了个坑儿)
      </div>
    </template>
    
    <script>
    export default {
      name: "Category",
      props:['title']
    }
    </script>
    
    <style scoped>
    .category {
      background-color: aqua;
      width: 200px;
      height: 300px;
    }
    h3{
      text-align: center;
      background-color: orange;
    }
    img{
      width: 100%;
    }
    </style>
    
  2. App.vue中使用插槽

    <template>
      <div id="app" class="cont">
        <Category title="美食">
          <img src="./assets/头像.jpg">
        </Category>
        <Category title="影视">
          <h4>电影</h4>
        </Category>
        <Category title="游戏">
          <ul>
            <li v-for="(game,index) in games" :key="index">
              {{game}}
            </li>
          </ul>
        </Category>
      </div>
    </template>
    
    <script>
    import Category from "@/components/Category";
    export default {
      name: 'App',
      data(){
        return{
          games:['猪猪侠','喜羊羊','菠萝吹雪']
        }
      },
      components:{
        Category
      }
    }
    </script>
    
    <style scoped>
      .cont{
        display: flex;
        justify-content: space-around;
      }
    </style>
    

默认插槽缺点:插槽内的布局统一

具名插槽

解决了默认插槽布局统一的缺点

  1. 插槽组件

    <template>
      <div class="category">
        <h3>{{title}}分类</h3>
        <slot name="center"></slot>      // 具名插槽
        <slot name="footer"></slot>			 // 具名插槽
      </div>
    </template>
    
    <script>
    export default {
      name: "Category",
      props:['title']
    }
    </script>
    
    <style scoped>
    .category {
      background-color: aqua;
      width: 200px;
      height: 300px;
    }
    h3{
      text-align: center;
      background-color: orange;
    }
    img{
      width: 100%;
    }
    </style>
    
  2. App.vue

    <template>
      <div id="app" class="cont">
        <Category title="美食">
          <img slot="footer" src="./assets/头像.jpg">
          <a href="#" slot="center" >点击跳转</a>
        </Category>
        <Category title="影视">
          <h4 slot="footer" >电影</h4>
          <img slot="center"  src="./assets/logo.png">
        </Category>
        <Category title="游戏">
          <img src="./assets/logo.png" slot="footer" >
          <ul slot="center">
            <li v-for="(game,index) in games" :key="index">
              {{game}}
            </li>
          </ul>
        </Category>
      </div>
    </template>
    
    <script>
    import Category from "@/components/Category";
    export default {
      name: 'App',
      data(){
        return{
          games:['猪猪侠','喜羊羊','菠萝吹雪']
        }
      },
      components:{
        Category
      }
    }
    </script>
    
    <style scoped>
      .cont{
        display: flex;
        justify-content: space-around;
      }
    </style>
    

具名插槽缺点:数据在父组件App.vue中,

作用域插槽

解决具名插槽数据在父组件中

  1. 插槽组件

    <template>
      <div class="category">
        <h3>{{title}}分类</h3>
        <slot :games="games"></slot>  <!--作用域插槽-->
      </div>
    </template>
    
    <script>
    export default {
      name: "Category",
      data(){
        return{
          games:['猪猪侠','喜羊羊','菠萝吹雪']
        }
      },
      props:['title']
    }
    </script>
    
    <style scoped>
    .category {
      background-color: aqua;
      width: 200px;
      height: 300px;
    }
    h3{
      text-align: center;
      background-color: orange;
    }
    img{
      width: 100%;
    }
    </style>
    
  2. App.vue组件

    <template>
      <div id="app" class="cont">
        <Category title="游戏">
          <!-- template标签scope属性接收子组件传过来的数据 -->
          <template scope="obj">
            <ul>
              <li v-for="(g,index) in obj.games" :key="index" >
                {{g}}
              </li>
            </ul>
          </template>
        </Category>
      </div>
    </template>
    
    <script>
    
    import Category from "@/components/Category";
    export default {
      name: 'App',
      data(){
        return{
        }
      },
      components:{
        Category
      }
    }
    </script>
    
    <style scoped>
      .cont{
        display: flex;
        justify-content: space-around;
      }
    </style>
    
  • 25
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

CodeMonkey-D

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

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

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

打赏作者

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

抵扣说明:

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

余额充值