Vue脚手架开发入门

Vue脚手架开发入门

安装脚手架及初始化项目

略过

后续使用的项目就是新搭建的一个项目

组件间的通信

父传子

查看《Vue初始化项目加载逻辑》这篇文章即可
父组件
Vue脚手架开发入门_第1张图片
子组件
Vue脚手架开发入门_第2张图片

子传父

场景:例如你的购物车,里面有很多商品,每个商品是一个小组件,每个组件都有价钱这个元素,每个组件之间是不清楚其他小组件的价钱的,我现在要算总价,购物车总价是在购物车这个大组件里的,那我现在要把每个小组件的价钱这个值传给购物车这个大组件中来

我们举例子就用新建项目的HelloWorld即可,将一些其他乱七八糟的删除掉

子组件的操作

<template>
  <div class="hello">
    <!--点击按钮,触发方法,方法里有自定义事件-->
    <button @click="handler">按钮</button>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  data(){
    return{
      childCount:0 //没有特殊含义,只是用来标识这个值来自于子类,见名知意,后续将这个值传给父组件
    }
  },
  methods:{
    handler(){
      this.childCount++
      this.$emit('child-count-change',this.childCount)  //子传父,需要通过自定义事件来处理,这里就是自定义事件设置,通过this.$emit()来触发自定义事件
      //第一个参数,我们先随便编造一个事件,就叫child-count-change
      //第二个参数,就是事件要传入的数据
      //总结一下,就是只要一触发child-count-change事件,就会将this.childCount传入进去
      //那这个时间由谁来做一个响应的处理呢,就需要去父组件里进行一个监听
    }
  }
}
</script>

<style scoped>
h3 {
  margin: 40px 0 0;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>

父组件的操作

<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png">
    <HelloWorld 
    msg="Welcome to Your Vue.js App"
    @child-count-change="handlerFather" 
    ></HelloWorld>
    <!--1、这里的@child-count-change,就是我们在子组件里的自定义实践,绑定到了handlerFather这个方法上,在methods里实现-->
    <p>父组件中接受的插值是: {{childData}}</p>
    <!--3、用来展示从子组件传递过来的值,只是方便观察-->
  </div>
</template>

<script>
import HelloWorld from '@/components/HelloWorld.vue'

export default {
  name: 'HomeView',
  data(){
    return{
      childData: 0  //2、定义一个响应式数据,之后用来承接子组件传过来的值
    }
  },
  components: {
    HelloWorld
  },
  methods:{
    //4、还记得我们在子组件里将childCount这个值传进来了
    handlerFather(childCount){
        this.childData=childCount  //5、将子组件传进来的值复制给父组件的响应式数据,按常理这里一定是更复杂的操作,例如求和等等,这样写只是为了方便而已
    }
  }
}
</script>

结果展示

按钮是子组件的,文案是父组件的
Vue脚手架开发入门_第3张图片

组件插槽

比如说现在helloworld组件里只有一个按钮了,是它的核心功能,但是比如说我们想要每次在使用这个组件的时候,有不一样的呈现的话

默认插槽

子组件原来的样子

<template>
  <div class="hello">
    <button @click="handler">按钮</button>
  </div>
</template>

父组件的内容

<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png">
    <HelloWorld 
    msg="Welcome to Your Vue.js App"
    @child-count-change="handlerFather" 
    ></HelloWorld>
    <p>{{childData}}</p>
    <!--1、多写几个helloworld组件,想要展示有所不同,像下面再双标签中间写的内容就是给插槽的内容,可以在子组件中规定你给插槽的内容在哪里去展示-->
    <HelloWorld>这是默认内容1</HelloWorld>
    <HelloWorld>这是默认内容2</HelloWorld>
    <HelloWorld>这是默认内容3</HelloWorld>    
    <HelloWorld></HelloWorld>    

  </div>
</template>

<script>
import HelloWorld from '@/components/HelloWorld.vue'

export default {
  name: 'HomeView',
  data(){
    return{
      childData: 0  
    }
  },
  components: {
    HelloWorld
  },
  methods:{
    
    handlerFather(childCount){
        this.childData=childCount  
    }
  }
}
</script>


现在页面成这个样子了
Vue脚手架开发入门_第4张图片

接下来在子组件中定义插槽的内容

<template>
  <div class="hello">
    <!--1、比如我想要将父组件传进来的值放在前面,这个slot并不是一个真正的标签,如果父组件给值了,那就展示父组件的值,没给值,那就展示我们给的默认的-->
    <slot>基础的默认内容</slot>
    <button @click="handler">按钮</button>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  data(){
    return{
      childCount:0 
    }
  },
  methods:{
    handler(){
      this.childCount++
      this.$emit('child-count-change',this.childCount)  
    }
  }
}
</script>

<style scoped>
h3 {
  margin: 40px 0 0;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>

Vue脚手架开发入门_第5张图片
比props的方式更简单,还可以将“这是默认内容”写成html

插槽的意义

除了比prop更方便之外,还意味着子组件的一部分区域是开放给父组件的,而不是全部由子组件定义,更灵活

具名插槽

默认插槽有一个问题,那就是就这一个,如果有多个插槽呢,我们怎么区别从父组件传来的值,是展示在子组件的哪个插槽呢,这就需要具名插槽

子组件的变化

<template>
  <div class="hello">
    <slot>基础的默认内容</slot>
    <button @click="handler">按钮</button>
    <!--新建一个插槽,但是插槽带了一个name属性,并且给一个默认值是:footer的默认内容-->
    <slot name="footer">footer的默认内容</slot>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  data(){
    return{
      childCount:0 
    }
  },
  methods:{
    handler(){
      this.childCount++
      this.$emit('child-count-change',this.childCount)  
    }
  }
}
</script>

<style scoped>
h3 {
  margin: 40px 0 0;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>

父组件的变化

<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png">
    <HelloWorld 
    msg="Welcome to Your Vue.js App"
    @child-count-change="handlerFather" 
    ></HelloWorld>
    <p>{{childData}}</p>
    <HelloWorld>这是默认内容1</HelloWorld>
    <HelloWorld>这是默认内容2</HelloWorld>
    <HelloWorld>这是默认内容3</HelloWorld>    
    <HelloWorld></HelloWorld>    
    <!--新建一个子组件,通过template标签,里面的v-slot:footer(或者#footer也可以)来将标签里的内容绑定给子组件名为footer的插槽,而不是其他插槽-->
    <HelloWorld>
      <template v-slot:footer>这是专门给子组件footer插槽的内容</template>
    </HelloWorld>
    <!--或者,将v-slot:替换成#-->
    <HelloWorld>
      <template #footer>这是专门给子组件footer插槽的内容2</template>
    </HelloWorld>
  </div>
</template>

<script>
import HelloWorld from '@/components/HelloWorld.vue'

export default {
  name: 'HomeView',
  data(){
    return{
      childData: 0  
    }
  },
  components: {
    HelloWorld
  },
  methods:{
    
    handlerFather(childCount){
        this.childData=childCount  
    }
  }
}
</script>

Vue脚手架开发入门_第6张图片

在父组件中通过插槽使用子组件的数据

<template>
  <div class="hello">
    <slot>基础的默认内容</slot>
    <button @click="handler">按钮</button>
    <slot name="footer" >footer的默认内容</slot>
  </div>
</template>

就以上面这个子组件的插槽来说,这个插槽是属于子组件的而不是父组件的,如果父组件要使用子组件的数据的话,就需要使用作用域插槽方式来做一个设置

子组件

<template>
  <div class="hello">
    <slot>基础的默认内容</slot>
    <button @click="handler">按钮</button>
    <!--现在我们在子组件的插槽中,绑定了一个响应式数据-->
    <slot name="footer" :childCount="childCount">footer的默认内容</slot>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  data(){
    return{
      childCount:0 
    }
  },
  methods:{
    handler(){
      this.childCount++
      this.$emit('child-count-change',this.childCount)  
    }
  }
}
</script>

<style scoped>
h3 {
  margin: 40px 0 0;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>

父组件

<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png">
    <HelloWorld 
    msg="Welcome to Your Vue.js App"
    @child-count-change="handlerFather" 
    ></HelloWorld>
    <p>{{childData}}</p>
    <!-- 我们通过 #footer="dataObj"的方式,获取了从子组件传进来的值,并重命名为dataObj,这个值,定义了就一定要使用,要不然会报错的-->
    <!-- 虽然子组件传进来的看起来是一个值,其实是一个对象 -->
    <HelloWorld>
      <template #footer="dataObj">这是专门给子组件footer插槽的内容{{dataObj }}</template>
    </HelloWorld>
  </div>
</template>

<script>
import HelloWorld from '@/components/HelloWorld.vue'

export default {
  name: 'HomeView',
  data(){
    return{
      childData: 0  
    }
  },
  components: {
    HelloWorld
  },
  methods:{
    
    handlerFather(childCount){
        this.childData=childCount  
    }
  }
}
</script>

Vue脚手架开发入门_第7张图片
你看,传进来的是
{ “childCount”: 0 }
而不是一个值
0
如果只想用某一个值的话

父组件

<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png">
    <HelloWorld 
    msg="Welcome to Your Vue.js App"
    @child-count-change="handlerFather" 
    ></HelloWorld>
    <p>{{childData}}</p>
    <!-- 我们通过 dataObj.字段名的方式来获取某一个值-->
    <HelloWorld>
      <template #footer="dataObj">这是专门给子组件footer插槽的内容{{dataObj.childCount }}</template>
    </HelloWorld>
    <!-- 或者,直接在绑定的时候就绑定其中的某一个字段 -->
    <HelloWorld>
      <template #footer="{childCount}">这是专门给子组件footer插槽的内容二{{childCount }}</template>
    </HelloWorld>  
  </div>
</template>

<script>
import HelloWorld from '@/components/HelloWorld.vue'

export default {
  name: 'HomeView',
  data(){
    return{
      childData: 0  
    }
  },
  components: {
    HelloWorld
  },
  methods:{
    
    handlerFather(childCount){
        this.childData=childCount  
    }
  }
}
</script>

Vue脚手架开发入门_第8张图片

你可能感兴趣的:(Vue,vue.js,前端,javascript)