Vue组件基础

一、Vue组件概念

组件是可复用的 Vue 实例,且带有一个名字,例如:

  Vue.component("input-content", {
            data: function () {
                return {
                    message: ""
                }
            },
            template: `<div>
                    <input type="text" v-model="message">
                    <p>输入的值为{{message}}</p>
                  </div>`
        });

在这个例子中,组件的名字是:input-content, 可以通过new Vue 创建的 Vue 根实例中,把这个组件作为自定义元素来使用

<div id="app">
        <input-content></input-content>
    </div>

因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。

二、Vue组件组织

为了能在模板中使用,这些组件必须先注册以便 Vue 能够识别。这里有两种组件的注册类型:全局注册和局部注册。全局注册的组件可以用在其被注册之后的任何 (通过 new Vue) 新创建的 Vue 根实例,也包括其组件树中的所有子组件的模板中。

三、组件传值

组件传值主要有父组件向子组件传值子组件向父组件传值

  • 父组件向子组件传值:通过prop向子组件传递数据

举例说明:

<body>
    <div id="app">
        <input-content :content="message"></input-content>

    </div>
    <script src="js/vue.js"></script>
    <script>
        Vue.component("input-content", {
            props: ["content"],
            data: function () {
                return {
                    content: ""
                }
            },
            template: `<div>
                    <p>父组件传过来的值为:{{content}}</p>
                  </div>`
        });
        const vm = new Vue({
            el: '#app',
            data: {
                message: 56
            }
        });
    </script>
</body>F

上面这段代码定义了父组件中的message的值通过props向子组件<input-content></input-content>传入,具体步骤如下。

  • 第一步 :子组件首先定义一个props选项,表示已经准备好接收来自父组件中message数据。
  • 第二步:子组件准备接受数据的时候就在标签里说明一下我要接收的是父组件的message数据,也就是上面代码中的<input-content :content="message"></input-content>,这样父组件中的message数据就传给子组件了。这里传值的时候注意了,如果传的是对象或者数组就必须绑定才能接收到,如果是静态数值就不需要绑定

  • 子组件向父组件传值,用一个书籍管理来举例
书籍

上面是效果图,思路是这样的,输入书籍的信息后,在表格里显示出来,这里运用Vue组件传值的思路,将书籍信息的输入框作为子组件,显示的表格作为父组件,也可以反着来,输入框作为父组件。表格作为子组件,这里主要为练习子组件向父组件传值。

  • 首先布局用bootstrap,就不做过多介绍
  • 接下来是绑定数据,就是将输入的书籍信息作为一个数组传给父组件显示出来
    1.首先定义子组件,将表单作为template模版写入子组件中
Vue.component("book-list", {
        data: function () {
            return {
            }
        },
        template: `
             <form action=""> 
                    <div class="form-group">
                        <label for="exampleInputEmail1">书名</label>
                        <input type="text" class="form-control" id="exampleInputEmail1">
                    </div>
                    <div class="form-group">
                        <label for="exampleInputPassword1">作者</label>
                        <input type="text" class="form-control" id="exampleInputPassword1">
                    </div>
                    <div class="form-group">
                        <label for="exampleInputPassword1">价格</label>
                        <input type="text" class="form-control" id="exampleInputPassword1">
                    </div>
                    <div class="form-group">
                        <label for="exampleInputPassword1">数量</label>
                        <input type="text" class="form-control" id="exampleInputPassword1">
                    </div>
                    <button type="button" class="btn btn-default" @click="addbook">添加书籍</button>
                </form>
                `,
    });

2.在data里定义四个对象,分别与书籍信息的四个属性绑定

 Vue.component("book-list", {
        props: ["books"],
        data: function () {
            return {
                name: "",            //与书名绑定
                author: "",            //与作者绑定
                price: "",            //与价格绑定
                number: "",            //与数量绑定
            }
        },
        template: `
             <form action=""> 
                    <div class="form-group">
                        <label for="exampleInputEmail1">书名</label>
                        <input type="text" class="form-control" id="exampleInputEmail1" v-model.lazy="name">`
                    </div>
                    <div class="form-group">
                        <label for="exampleInputPassword1">作者</label>
                        <input type="text" class="form-control" id="exampleInputPassword1" v-model.lazy="author">
                    </div>
                    <div class="form-group">
                        <label for="exampleInputPassword1">价格</label>
                        <input type="text" class="form-control" id="exampleInputPassword1" v-model.lazy.number="price">
                    </div>
                    <div class="form-group">
                        <label for="exampleInputPassword1">数量</label>
                        <input type="text" class="form-control" id="exampleInputPassword1" v-model.lazy.number="number">
                    </div>
                    <button type="button" class="btn btn-default" @click="addbook">添加书籍</button>
                </form>
                    `,
    });
  • 将书籍信息添加到定义的一个books数组中去
    1 .由于books数组在父组件中,这里就步入正题了,子组件向父组件传值。先定义一个book对象,来装绑定的书籍信息
    methods: {
            addbook: function () {
                const book = {
                    name: this.name,
                    author: this.author,
                    price: this.price,
                    number: this.number
                };
            },
        },

2.那么这个book对象要如何传到父组件中去呢,这里用到监听子组件事件$emit方法,就好比是一个人给另一个人寄东西,寄东西需要啥?有要寄去的东西,有寄东西的方式,还要有对方的地址。这里就当是把书籍信息book寄到books数组中去,寄的东西有了,那么我怎么寄?选什么快递?$emit方法就好比是快递。这个快递有啥?是不是有寄的东西,有地址。this.$emit("book", book);第一个book就相当于是地址,第二个book相当于是要寄的东西。快递送到了我要怎么去通知父组件?这个时候就用到了<book-list @book="addbook"></book-list>。就说在某某快递来取东西,这个时候父组件就知道了东西寄到了。那么book对象传到了,就到了下一步。
3.将book添加到books数组中

 data: {
            books: [],
        },
 methods: {
            addbook: function (book) {
                this.books.push(book);
            }
        }

4.在父组件中用v-for方法遍历books数组

           <tr v-for="(content,index) in books">
                    <td>{{index+1}}</td>
                    <td>{{content.name}}</td>
                    <td>{{content.author}}</td>
                    <td><input type="number" name="" id="" v-model.number="content.price"></td>
                    <td><input type="number" name="" id="" v-model.number="content.number"></td>
                    <td><button @click="delebook">删除</button></td>
                </tr>

这个时候就实现了添加书籍信息显示在列表中这一基本功能。但是会发现这本书没有编号,一开始的想法是用数组下标来作为编号,这时就出现了一个问题,当删除一本书的时候,就会把后面的编号打乱,就没有达到给一本书编号的的基本功能,解决方法是用获取当前数组的长度作为书的编号,添加一本书数组的长度就加1,再把当前数组长度作为当前书籍的编号,所以再删除一本书的时候就不会对书的编号产生影响
5.获取数组长度作为书籍编号,但是数组定义在了父元素上,所以就用props属性来给子元素传值,然后再回传给父元素作为书籍的编号。这里props属性的运用就不做过多介绍了。
6.源码:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>书籍管理</title>
    <link rel="stylesheet" href="css/bootstrap.css">
    <style>
        input {
            width: 55px;
        }
    </style>
</head>

<body>
    <div id="app">
        <div class="container">
            <h3>书籍管理系统</h3>
            <table class="table table-striped table-bordered">
                <tr>
                    <th>序号</th>
                    <th>编号</th>
                    <th>名称</th>
                    <th>作者</th>
                    <th>价格</th>
                    <th>数量</th>
                    <th>操作</th>
                </tr>
                <tr v-for="(content,index) in books">
                    <td>{{index+1}}</td>
                    <td>{{content.id}}</td>
                    <td>{{content.name}}</td>
                    <td>{{content.author}}</td>
                    <td><input type="number" name="" id="" v-model.number="content.price"></td>
                    <td><input type="number" name="" id="" v-model.number="content.number"></td>
                    <td><button @click="delebook">删除</button></td>
                </tr>
                <tr>
                    <td>总价格:{{allprice}}</td>
                </tr>
            </table>
            <div>
                <h4>添加书籍</h4>
                <book-list @book="addbook" :books="books"></book-list>
            </div>
        </div>
    </div>
</body>
<script src="js/jquery-3.4.1.js"></script>
<script src="js/bootstrap.js"></script>
<script src="js/vue.js"></script>
<script>

    Vue.component("book-list", {
        props: ["books"],
        data: function () {
            return {
                name: "",
                author: "",
                price: "",
                number: "",
            }
        },
        template: `
             <form action=""> 
                    <div class="form-group">
                        <label for="exampleInputEmail1">书名</label>
                        <input type="text" class="form-control" id="exampleInputEmail1" v-model.lazy="name">
                    </div>
                    <div class="form-group">
                        <label for="exampleInputPassword1">作者</label>
                        <input type="text" class="form-control" id="exampleInputPassword1" v-model.lazy="author">
                    </div>
                    <div class="form-group">
                        <label for="exampleInputPassword1">价格</label>
                        <input type="text" class="form-control" id="exampleInputPassword1" v-model.lazy.number="price">
                    </div>
                    <div class="form-group">
                        <label for="exampleInputPassword1">数量</label>
                        <input type="text" class="form-control" id="exampleInputPassword1" v-model.lazy.number="number">
                    </div>
                    <button type="button" class="btn btn-default" @click="addbook">添加书籍</button>
                </form>
                `,
        methods: {
            addbook: function () {
                const book = {
                    id: this.books.length + 1,
                    name: this.name,
                    author: this.author,
                    price: this.price,
                    number: this.number
                };
                this.$emit("book", book);
            },
        },
    });
    // --------------------------------------------------------------------------------------
    const vm = new Vue({
        el: "#app",
        data: {
            books: [],
        },
        methods: {
            addbook: function (book) {
                this.books.push(book);
            },
            //删除书籍功能
            delebook: function (index) {
                this.books.splice(index, 1);
            }
        },
        computed: {
            //计算当前书籍的总价
            allprice: function () {
                let totalprice = 0;
                let books = this.books;
                books.forEach(function (book) {
                    totalprice = totalprice + book.price * book.number;
                });
                return totalprice;
            }
        },
    });
</script>

</html>
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容

  • 组件是可复用的Vue实例,且带有一个名字。我们可以在一个通过new Vue创建的Vue根实例中,把这个组件作为自定...
    oWSQo阅读 325评论 0 0
  • 祭出demo 基础示例 组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data、...
    rainbowboy阅读 850评论 0 50
  • 组件是可复用的 Vue 实例,且带有一个名字:在这个例子中是 。我们可以在一个通过 new Vue 创建的 Vu...
    波克比阅读 169评论 0 0
  • 定义组件 Vue.component props 接受父组件的传值 props也可以接受一个对象 在组件上用v-f...
    豆浆的铲屎官阅读 244评论 0 0
  • 作为中国最火的两位脱口秀演员,李诞和池子都说自己想当作家,李诞至今都不愿意承认自己是个脱口秀演员。 作为《脱口秀大...
    网易王三三阅读 2,199评论 5 25