var login = Vue.extend({ template: '<h1>登录</h1>' }); Vue.component('login', login);
案例:
<div id="app"> <!-- 如果要使用组件,直接,把组件的名称,以 HTML 标签的形式,引入到页面中,即可 --> <mycom1></mycom1> </div>
<script> // 1.1 使用 Vue.extend 来创建全局的Vue组件 // var com1 = Vue.extend({ // template: '<h3>这是使用 Vue.extend 创建的组件</h3>' // 通过 template 属性,指定了组件要展示的HTML结构 // }) // 1.2 使用 Vue.component('组件的名称', 创建出来的组件模板对象) // Vue.component('myCom1', com1) // 如果使用 Vue.component 定义全局组件的时候,组件名称使用了 驼峰命名,则在引用组件的时候,需要把 大写的驼峰改为小写的字母,同时,两个单词之前,使用 - 链接; // 如果不使用驼峰,则直接拿名称来使用即可; // Vue.component('mycom1', com1) // Vue.component 第一个参数:组件的名称,将来在引用组件的时候,就是一个 标签形式 来引入 它的 // 第二个参数: Vue.extend 创建的组件 ,其中 template 就是组件将来要展示的HTML内容 Vue.component('mycom1', Vue.extend({ template: '<h3>这是使用 Vue.extend 创建的组件</h3>' })); // 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: {}, methods: {} }); </script>
直接使用 Vue.component 方法
Vue.component('register', { template: '<h1>注册</h1>' });
案例部分代码
将模板字符串,定义到script标签中
<script id="tmpl" type="x-template"> <div><a href="#">登录</a> | <a href="#">注册</a></div> </script>
同时需要使用Vue.component来定义组件
Vue.component('account', { template: '#tmpl' });
<div id="app"> <mydemo3></mydemo3> </div> <!-- 在 被控制的 #app 外面,使用 template 元素,定义组件的HTML模板结构 --> <template id="demo"> <div> <h3>这是使用全局组件创建的第三种方式</h3> </div> </template> <script src="lib/vue-2.4.0.js"></script> <script> Vue.component("mydemo3", { template: "#demo" }); var vm = new Vue({ el: "#app", data: {}, methods: {} }) </script>
注意: 组件中的DOM结构,有且只能有唯一的根元素(Root Element)来进行包裹
定义私有组件
<template id="tmpl2"> <h1>这是私有的 login 组件</h1> </template> <div id="app2"> <login></login> </div> <script> var vm2 = new Vue({ el: '#app2', data: {}, methods: {}, filters: {}, directives: {}, components: { // 定义实例内部私有组件的 login: { template: '#tmpl2' } } }) </script>
1.
Vue.component('account', { template: '#tmpl', data() { return { msg: '大家好!' } }, methods:{ login(){ alert('点击了登录按钮'); } } });
<!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>Document</title> <script src="./lib/vue-2.4.0.js"></script> </head> <body> <div id="app"> <mycom1></mycom1> </div> <script> // 1. 组件可以有自己的 data 数据 // 2. 组件的 data 和 实例的 data 有点不一样,实例中的 data 可以为一个对象,但是 组件中的 data 必须是一个方法 // 3. 组件中的 data 除了必须为一个方法之外,这个方法内部,还必须返回一个对象才行; // 4. 组件中 的data 数据,使用方式,和实例中的 data 使用方式完全一样!!! Vue.component('mycom1', { template: '<h1>这是全局组件 --- {{msg}}</h1>', data: function () { return { msg: '这是组件的中data定义的数据' } } }) // 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: {}, methods: {} }); </script> </body> </html>
2.
1.通过计数器案例演示:
<!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>Document</title> <script src="./lib/vue-2.4.0.js"></script> </head> <body> <div id="app"> <counter></counter> <hr> <counter></counter> <hr> <counter></counter> </div> <template id="tmpl"> <div> <input type="button" value="+1" @click="increment"> <h3>{{count}}</h3> </div> </template> <script> var dataObj = { count: 0 } // 这是一个计数器的组件, 身上有个按钮,每当点击按钮,让 data 中的 count 值 +1 Vue.component('counter', { template: '#tmpl', data: function () { // return dataObj return { count: 0 } }, methods: { increment() { this.count++ } } }) // 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: {}, methods: {} }); </script> </body> </html>
使用flag标识符结合v-if和v-else切换组件
<!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>Document</title> <script src="./lib/vue-2.4.0.js"></script> </head> <body> <div id="app"> <a href="" @click.prevent="flag=false">登录</a> <a href="" @click.prevent="flag=true">注册</a> <login v-if="flag"></login> <register v-else="flag"></register> </div> <script> Vue.component('login', { template: '<h3>登录组件</h3>' }) Vue.component('register', { template: '<h3>注册组件</h3>' }) // 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: { flag: false }, methods: {} }); </script> </body> </html>
使用is属性来切换不停的子组件,并添加动画
1.组件实例定义方式
// 登录组件 const login = Vue.extend({ template: `<div> <h3>登录组件</h3> </div>` }); Vue.component('login', login); // 注册组件 const register = Vue.extend({ template: `<div> <h3>注册组件</h3> </div>` }); Vue.component('register', register); // 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: { comName: 'login' }, methods: {} });
2.使用component标签,来引用组件并通过:is属性来指定要加载的组件
<div id="app"> <a href="#" @click.prevent="comName='login'">登录</a> <a href="#" @click.prevent="comName='register'">注册</a> <hr> <transition mode="out-in"> <component :is="comName"></component> </transition> </div>
3.添加切换样式
<style> .v-enter, .v-leave-to { opacity: 0; transform: translateX(30px); } .v-enter-active, .v-leave-active { position: absolute; transition: all 0.3s ease; } h3{ margin: 0; } </style>
<script> // 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: { msg: '这是父组件中的消息' }, components: { son: { template: '<h1>这是子组件 --- {{finfo}}</h1>', props: ['finfo'] } } }); </script>
2.使用v-bind或者简化指令,将数据传递到子组件中
<div id="app"> <son :finfo="msg"></son> </div>
1.原理:父组件将方法的引用,传递到子组件内部,子组件在内部调用父组件传递过来的方法,同时把要发送给父组件的数据,在调用方法的时候当作参数传递进去
2.
<son @func="getMsg"></son>
3.
<div id="app"> <!-- 引用父组件 --> <son @func="getMsg"></son> <!-- 组件模板定义 --> <script type="x-template" id="son"> <div> <input type="button" value="向父组件传值" @click="sendMsg" /> </div> </script> </div> <script> // 子组件的定义方式 Vue.component('son', { template: '#son', // 组件模板Id methods: { sendMsg() { // 按钮的点击事件 this.$emit('func', 'OK'); // 调用父组件传递过来的方法,同时把数据传递出去 } } }); // 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: {}, methods: { getMsg(val){ // 子组件中,通过 this.$emit() 实际调用的方法,在此进行定义 alert(val); } } }); </script>
<!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>Document</title> <script src="./lib/vue-2.4.0.js"></script> </head> <body> <div id="app"> <!-- 父组件向子组件 传递 方法,使用的是 事件绑定机制; v-on, 当我们自定义了 一个 事件属性之后,那么,子组件就能够,通过某些方式,来调用 传递进去的 这个 方法了 --> <com2 @func="show"></com2> </div> <template id="tmpl"> <div> <h1>这是 子组件</h1> <input type="button" value="这是子组件中的按钮 - 点击它,触发 父组件传递过来的 func 方法" @click="myclick"> </div> </template> <script> // 定义了一个字面量类型的 组件模板对象 var com2 = { template: '#tmpl', // 通过指定了一个 Id, 表示 说,要去加载 这个指定Id的 template 元素中的内容,当作 组件的HTML结构 data() { return { sonmsg: { name: '小头儿子', age: 6 } } }, methods: { myclick() { // 当点击子组件的按钮的时候,如何 拿到 父组件传递过来的 func 方法,并调用这个方法??? // emit 英文原意: 是触发,调用、发射的意思 // this.$emit('func123', 123, 456) this.$emit('func', this.sonmsg) } } } // 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: { datamsgFormSon: null }, methods: { show(data) { // console.log('调用了父组件身上的 show 方法: --- ' + data) // console.log(data); this.datamsgFormSon = data } }, components: { com2 // com2: com2 } }); </script> </body> </html>
目标:主要练习父子组件之间传值
<!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>Document</title> <script src="./lib/vue-2.4.0.js"></script> <link rel="stylesheet" href="./lib/bootstrap-3.3.7.css"> </head> <body> <div id="app"> <cmt-box @func="loadComments"></cmt-box> <ul class="list-group"> <li class="list-group-item" v-for="item in list" :key="item.id"> <span class="badge">评论人: {{ item.user }}</span> {{ item.content }} </li> </ul> </div> <template id="tmpl"> <div> <div class="form-group"> <label>评论人:</label> <input type="text" class="form-control" v-model="user"> </div> <div class="form-group"> <label>评论内容:</label> <textarea class="form-control" v-model="content"></textarea> </div> <div class="form-group"> <input type="button" value="发表评论" class="btn btn-primary" @click="postComment"> </div> </div> </template> <script> var commentBox = { data() { return { user: '', content: '' } }, template: '#tmpl', methods: { postComment() { // 分析:发表评论的业务逻辑 // 1. 评论数据存到哪里去??? 存放到了 localStorage 中 localStorage.setItem('cmts', '') // 2. 先组织出一个最新的评论数据对象 // 3. 想办法,把 第二步中,得到的评论对象,保存到 localStorage 中: // 3.1 localStorage 只支持存放字符串数据, 要先调用 JSON.stringify // 3.2 在保存 最新的 评论数据之前,要先从 localStorage 获取到之前的评论数据(string), 转换为 一个 数组对象, 然后,把最新的评论, push 到这个数组 // 3.3 如果获取到的 localStorage 中的 评论字符串,为空不存在, 则 可以 返回一个 '[]' 让 JSON.parse 去转换 // 3.4 把 最新的 评论列表数组,再次调用 JSON.stringify 转为 数组字符串,然后调用 localStorage.setItem() var comment = { id: Date.now(), user: this.user, content: this.content } // 从 localStorage 中获取所有的评论 var list = JSON.parse(localStorage.getItem('cmts') || '[]') list.unshift(comment) // 重新保存最新的 评论数据 localStorage.setItem('cmts', JSON.stringify(list)) this.user = this.content = '' // this.loadComments() // ????? this.$emit('func') } } } // 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: { list: [ { id: Date.now(), user: '李白', content: '天生我材必有用' }, { id: Date.now(), user: '江小白', content: '劝君更尽一杯酒' }, { id: Date.now(), user: '小马', content: '我姓马, 风吹草低见牛羊的马' } ] }, beforeCreate(){ // 注意:这里不能调用 loadComments 方法,因为在执行这个钩子函数的时候,data 和 methods 都还没有被初始化好 }, created(){ this.loadComments() }, methods: { loadComments() { // 从本地的 localStorage 中,加载评论列表 var list = JSON.parse(localStorage.getItem('cmts') || '[]') this.list = list } }, components: { 'cmt-box': commentBox } }); </script> </body> </html>
使用ref获取DOM元素和组件
<div id="app"> <div> <input type="button" value="获取元素内容" @click="getElement" /> <!-- 使用 ref 获取元素 --> <h1 ref="myh1">这是一个大大的H1</h1> <hr> <!-- 使用 ref 获取子组件 --> <my-com ref="mycom"></my-com> </div> </div> <script> Vue.component('my-com', { template: '<h5>这是一个子组件</h5>', data() { return { name: '子组件' } } }); // 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: {}, methods: { getElement() { // 通过 this.$refs 来获取元素 console.log(this.$refs.myh1.innerText); // 通过 this.$refs 来获取组件 console.log(this.$refs.mycom.name); } } }); </script>
----The End