Vue.js详谈组件化

Vue.js详谈组件化

前面已经总结过:

vue入门

vue常用指令总结

在大型应用开发的时候,页面可以划分成很多部分。往往不同的页面,也会有相同的部分。例如可能会有相同的头部导航

但是如果每个页面都独自开发,这无疑增加了我们开发的成本。所以我们会把页面的不同部分拆分成独立的组件,然后在不同页面就可以共享这些组件,避免重复开发

在vue里,所有的vue实例都是组件

全局组件

我们通过Vue的component方法来定义一个全局组件

定义一个组件如下:

<!-- development version, includes helpful console warnings -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script type="text/javascript">
    // 定义全局组件,两个参数:1,组件名称。2,组件参数
    Vue.component("counter",{
        template:'<button v-on:click="count++">你点了我 {{ count }} 次,我记住了.</button>',
        data(){
            return {
                count:0
            }
        }
    })
    var app = new Vue({
        el:"#app"
    })
</script>

html代码:

<body>
<div id="app">
  <!--使用定义好的全局组件-->
  <counter></counter>
</div>
</body>

效果:

在任何地方你都可以放置这个组件,只要你带着唯一的组件名,本例中参数名就为counter

  • 组件其实也是一个Vue实例,因此它在定义时也会接收:data、methods、生命周期函数
  • 不同的是组件不会与页面的元素绑定,否则就无法复用了,因此没有el属性
  • 但是组件渲染需要html模板,所以增加了template属性,值就是HTML模板
  • 全局组件定义完毕,任何vue实例都可以直接在HTML中通过组件名称来使用组件了。
  • data必须是一个函数,不再是一个对象

组件复用

<div id="app">
    <!--使用定义好的全局组件-->
    <counter></counter>
    <counter></counter>
    <counter></counter>
</div>

局部组件

一旦全局注册,就意味着即便以后你不再使用这个组件,它依然会随着Vue的加载而加载,这样会造成网页加载速度延迟

因此,对于一些并不频繁使用的组件,我们会采用局部注册

我们先在外部定义一个对象,结构与创建组件时传递的第二个参数一致:

const counter = {
    template:'<button v-on:click="count++">你点了我 {{ count }} 次,我记住了.</button>',
    data(){
        return {
            count:0
        }
    }
};

然后在Vue实例中使用它:

var app = new Vue({
    el:"#app",
    components:{
        counter:counter // 将定义的对象注册为组件
    }
})
  • components就是当前vue对象子组件集合
    • key就是子组件名称
    • 其值就是组件对象名
  • 效果与刚才的全局注册是类似的,不同的是,这个counter组件只能在当前的Vue实例中使用

组件通信

通常一个单页应用会以一棵嵌套的组件树的形式来组织:

  • 页面首先分成了顶部导航、左侧内容区、右侧边栏三部分
  • 左侧内容区又分为上下两个组件
  • 右侧边栏中又包含了3个子组件

各个组件之间以嵌套的关系组合在一起,那么这个时候不可避免的会有组件间通信的需求

props(父向子传递)

  1. 父组件使用子组件时,自定义属性(属性名任意,属性值为要传递的数据
  2. 子组件通过props接收父组件数据,通过自定义属性的属性名

**例子:**父组件使用子组件,并自定义了title属性:

<body>
<div id="app">
  <h1>打个招呼:</h1>
  <!--父组件使用子组件,同时传递title属性,本例中子组件会对title做渲染-->
  <introduce title="大家好,我是Junsir"/>
</div>
</body>

<!-- development version, includes helpful console warnings -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script type="text/javascript">

  Vue.component("introduce",{
    //
    template:'<<h2>{{title}}</h2>',  // 直接使用props接收到的属性来渲染页面
    props:['title'] //使用props来接收一个父组件传递的属性

  })
  var app = new Vue({
    el:"#app"
  })
</script>

props验证

我们定义一个子组件,并接收复杂数据:

    const myList = {
        template: '\
        <ul>\
        	<li v-for="item in items" :key="item.id">{{item.id}} : {{item.name}}</li>\
        </ul>\
        ',
        props: { //接收item对象
            items: {
                type: Array,
                default: [],
                required: true
            }
        }
    };
  • 这个子组件可以对 items 进行迭代,并输出到页面。
  • props:定义需要从父组件中接收的属性
  • items:是要接收的属性名称
  • type:限定父组件传递来的必须是数组
  • default:默认值
  • required:是否必须

当 prop 验证失败的时候,Vue 将会产生一个控制台的警告

例子

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
  <h2>课程:</h2>
  <!-- 使用子组件的同时,传递属性,这里使用了v-bind,指向了父组件自己的属性lessons -->
  <my-list :items="lessons"/>
</div>
</body>

<!-- development version, includes helpful console warnings -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script type="text/javascript">
  //定义子组件
  const myList = {
    //渲染模板
    template: '\
        <ul>\
        	<li v-for="item in items" :key="item.id">{{item.id}} : {{item.name}}</li>\
        </ul>\
        ',
    props: { //接收item对象
      items: {
        type: Array,  //接收数组
        default: [], //props验证
        required: true //props验证
      }
    }
  };

  var app = new Vue({
    el:"#app",
    components:{
      myList // 子组件 当key和value一样时,可以只写一个
    },
    data:{
      lessons:[
        {id:1, name: 'java'},
        {id:2, name: '操作系统'},
        {id:3, name: '数据结构'},
      ]
    }
  })
</script>
</html>

type类型可以有:String Number Boolean Array Object Date Function Symbol

动态静态传递

给 prop 传入一个静态的值:

<introduce title="大家好,我Junsir"/>

给 prop 传入一个动态的值: (通过v-bind从数据模型中,获取title的值)

<introduce :title="title"/>

静态传递时,我们传入的值都是字符串类型的,但实际上任何类型的值都可以传给一个 props

子向父通信(semit)

子组件接收到父组件属性后,默认是不允许修改的。怎么办?

既然只有父组件能修改,那么加和减的操作一定是放在父组件:

但是,点击按钮是在子组件中,那就是说需要子组件来调用父组件的函数,怎么做?

我们可以通过v-on指令将父组件的函数绑定到子组件上:

<div id="app">
  <h2>num: {{num}}</h2>
  <counter :count="num" @inc="increment" @dec="decrement"></counter>
</div>

在子组件中定义函数,函数的具体实现调用父组件的实现,并在子组件中调用这些函数。当子组件中按钮被点击时,调用绑定的函数:

        
	Vue.component("counter", {
            template:'\
                <div>\
                    <button @click="plus">加</button>  \
                    <button @click="reduce">减</button>  \
                </div>',
            props:['count'],
            methods:{
                      //vue提供了一个内置的this.$emit()函数,用来调用父组件绑定的函数
                plus(){
                    this.$emit("inc");
                },
                reduce(){
                    this.$emit("dec");
                }
            }
        })
        
    var app = new Vue({
    el:"#app",
    data:{
      num:0
    },
    methods:{ // 父组件中定义操作num的方法——加与减
      increment(){
        this.num++;
      },
      decrement(){
        this.num--;
      }
    }
  })

效果:

原创文章 197 获赞 142 访问量 6万+

猜你喜欢

转载自blog.csdn.net/JunSIrhl/article/details/105799370