Vue学习笔记2--组件化开发

组件化开发

完整的基础篇笔记PDF下载,完全手打有用的话请给个赞呗Thanks♪(・ω・)ノ

官方文档内容最全

组件化思想

  • 标准
  • 分治
  • 重用
  • 组合

组件注册

全局注册

Demo–注册

Vue.component('button-counter',{
    //组件内部需要的数据
    data: function(){
        return {
            count: 0
        }
    },
    //组件的模板
    template: ''
});

使用

<button-counter>button-counter>

注意事项:

  • data必须是一个函数(形成闭包保证每个组件数据的独立性)

  • 组件模板内容必须是单个根元素

  • 组件模板内容可以使用模板字符串

     Vue.component('button-counter',{
     	data: function(){
        	return {
            	count: 0
                }
         },
         template: `
             
    `
    });
  • 命名方式

    • 短横线:推荐

    • 驼峰式:不可以在页面上直接使用驼峰式(换为对应的短横线),只可以在其他组件模板中使用驼峰式

      HelloWorld --> hello-world
      

局部注册

var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }
var ComponentC = { /* ... */ }
new Vue({
  el: '#app',
  components: {
    'component-a': ComponentA,
    'component-b': ComponentB
  }
})

注意

  • 局部注册的组件只能在其注册的父组件中使用
  • 全局组件模板中使用局部组件会报错

Vue调试工具

谷歌商店:vue-devtools

组件间的数据交互

父组件向子组件传值

Vue.component('blog-post', {
  // 子组件接收父组件的值
  props: ['postTitle'],
  template: '

{{ postTitle }}

'
})

<blog-post post-title="hello!">blog-post>

<blog-post :post-title="title">blog-post>

props支持类型

子组件向父组件传值

子组件可以直接操作父组件传过来的值

props传递数据的原则:单向数据传递

不推荐直接更改props中的数据

使用$emit自定义事件改变父组件中的数据

思路:

  • 子组件模板中绑定事件
  • 父组件中监听子组件的事件
  • 将改变逻辑放到父组件方法中
 //子组件
 Vue.component('button-counter',{
     template: `
        
`
});

页面父组件中监听对应的事件enlarge-text

<div id="app">
    <div :style='{fontSize: fontSize + "px"}'>{{msg}}div>
    <button-counter @enlarge-text="handle">button-counter>
div>

父组件中处理逻辑handle

var vm = new Vue({
    el: '#app',
    data: {
        fontSize: 10,
        msg: 'Hello World'
    },
    methods: {
        handle: function () {
            this.fontSize += 5;
        }
    }
});
子组件自定义事件携带参数
Vue.component('button-counter',{
    template: `
        
`
});

父组件中使用$event获取传值

<div id="app">
    <div :style='{fontSize: fontSize + "px"}'>{{msg}}div>
    <button-counter @enlarge-text="handle($event)">button-counter>
div>

父组件处理方法handle接收参数

handle: function (val) {
	this.fontSize += val;
}

非父子组件间的传值

使用事件中心管理组件间的通信

  • 单独的事件中心

    var eventHub = new Vue();
    
  • 监听事件和销毁事件

    eventHub.$on('add-todo',addTodo);
    eventHub.$off('add-todo');
    
  • 触发事件

    eventHub.$emit('add-todo',id);
    
Demo
  • 创建事件中心处理组件
var hub = new Vue();
  • 定义组件1:
Vue.component('test-tom', {
    data: function () {
        return {
            num: 0
        }
    },
    template: `
    
Tom : {{num}}
`
, methods:{ handle: function(){ //通过事件处理中心触发兄弟组件的事件 hub.$emit('jerry-event',1); } }, mounted() { //监听事件中心组件中的事件 hub.$on('tom-event',(val)=>{ this.num += val; }); } });
  • 定义组件2
Vue.component('test-jerry', {
    data: function () {
        return {
            num: 0
        }
    },
    template: `
    
Jerry : {{num}}
`
, methods:{ handle: function(){ //通过事件处理中心触发兄弟组件的事件 hub.$emit('tom-event',2); } }, mounted() { //监听事件中心组件中的事件 hub.$on('jerry-event',(val)=>{ this.num += val; }); } });
  • 页面使用
<div id="app">
    <test-tom>test-tom>
    <test-jerry>test-jerry>
div>

组件插槽

父组件向子组件传递内容

使用指定插槽位置

Vue.component('alert-box',{
    template: `
    
ERROR:
`
});

父组件中传递内容

<div id="app">
    <alert-box>传递的内容alert-box>
div>

默认内容在不传递内容时显示

具名插槽

组件template

<div class="container">
  <header>
    <slot name="header">slot>
  header>
  <main>
    <slot>slot>
  main>
  <footer>
    <slot name="footer">slot>
  footer>
div>

页面调用v-slot指定插入的位置,未指定的填充到未命名的插槽

template临时包裹信息,不会渲染到页面

<base-layout>
  <template v-slot:header>
    <h1>Here might be a page titleh1>
  template>

  <p>A paragraph for the main content.p>
  <p>And another one.p>

  <template v-slot:footer>
    <p>Here's some contact infop>
  template>
base-layout>

作用域插槽

  • 应用场景

    父组件对子组件的内容进行处理

子组件中使用slot指定插槽,并且指定slot的属性返回要在父组件中处理的数据

Vue.component('fruit-list',{
    //获取父组件通过属性传过来的数据
    props: ['list'],
    template: `
        
  • {{item.name}}
`
});

父组件提供数据

var vm = new Vue({
    el: '#app',
    data: {
        list: [{
            id: 1,
            name: 'apple'
        },{
            id: 2,
            name: 'banane'
        },{
            id: 3,
            name: 'orange'
        }]
    }
});

父组件页面调用子组件

  • :list=“list” 向子组件传递数据
  • v-slot=“slotProps” 用来接收子组件
  • slotProps.info 获取子组件通过属性(info)返回的数据
<div id="app">
    <fruit-list :list="list">
        <template v-slot="slotProps">
            
            <strong v-if="slotProps.info.id == 2">{{slotProps.info.name}}strong>
        template>
    fruit-list>
div>

案例:购物车


<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>选项卡title>
    
    <script src="js/vue.js">script>
    <style>
        #app{
            position: relative;
            left: 50%;
        }
        .cart{
            width: 50%;
        }
        .title{
            width: 100%;
            height: 30px;
            border: 1px solid blueviolet;
            background-color: aqua;
            text-align: center;
            font-size: large;
        }
        .cartlist{
            width: 100%;
            border: 1px outset pink;
        }
        .cartitem{
            height: 50px;
            text-align: center;
            font-size: x-large;
        }
        .itemname{
            position: relative;
            left: -70px;
        }
        .option input{
            width: 40px;
        }
        .total{
            width: 100%;
            border: 1px solid yellow;
            background-color: yellow;
            text-align: right;
        }


    style>
head>

<body>
    <div id="app">
      <my-cart>my-cart>
    div>
    <script>
        var cartTitle = {
            props: ['uname'],
            template: `
                
{{uname}}的购物车
`
} var cartList = { props: ['list'], template: `
{{item.name}}
`
, methods:{ del: function(id){ //将id传递给父组件 this.$emit('cart-del',id); }, dec: function(id){ this.$emit('cart-dec',id); }, add: function(id){ this.$emit('cart-add',id); }, changeNum: function(id,event){ this.$emit('change-num',{ id: id, num: event.target.value }) } } } var cartTotal = { props: ['list'], template: `
总价 {{total}}
`
, computed: { total: function(){ //计算商品总价 var t = 0; this.list.forEach(item=>{ t += item.price * item.num; }); return t; } }, } Vue.component('my-cart',{ data: function(){ return { uname: '张三', list: [ { id: 1, name: '小米', price: 200, num: 1 },{ id: 2, name: '小狗', price: 200, num: 2 },{ id: 3, name: '小猫', price: 200, num: 3 },{ id: 4, name: '小野猪', price: 200, num: 1 },{ id: 5, name: '小皮球', price: 200, num: 1 } ] } }, template: `
`
, components: { 'cart-title': cartTitle, 'cart-list': cartList, 'cart-total': cartTotal }, methods: { delCart: function(id){ //根据id删除列表中的数据 var index = this.list.findIndex(item=>{ return item.id = id; }); this.list.splice(index,1); }, decNum: function(id){ //减少指定商品的数量 this.list.some(item=>{ if(item.id == id){ item.num--; return true; } }); }, addNum: function(id){ //增加指定商品的数量 this.list.some(item=>{ if(item.id == id){ item.num++; return true; } }); }, changeNum: function(pojo){ //通过更改输入框更改数量 this.list.some(item=>{ if(item.id == pojo.id){ item.num += pojo.num; return true; } }); } } }); var vm = new Vue({ el: '#app', data: { }, methods: { handle: function () { } } });
script> body> html>

你可能感兴趣的:(前端)