API:https://vue.docschina.org/v2/guide/installation.html
动画曲线函数:https://cubic-bezier.com/#.63,.11,.51,.69
<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> <!-- 1. 导入Vue的包 --> <script src="./lib/vue-2.4.0.js"></script> </head> <body> <!-- 将来 new 的Vue实例,会控制这个 元素中的所有内容 --> <!-- Vue 实例所控制的这个元素区域,就是我们的 V --> <div id="app"> <p>{{ msg }}</p> </div> <script> // 2. 创建一个Vue的实例 // 当我们导入包之后,在浏览器的内存中,就多了一个 Vue 构造函数 // 注意:我们 new 出来的这个 vm 对象,就是我们 MVVM中的 VM调度者 var vm = new Vue({ el: '#app', // 表示,当前我们 new 的这个 Vue 实例,要控制页面上的哪个区域 // 这里的 data 就是 MVVM中的 M,专门用来保存 每个页面的数据的 data: { // data 属性中,存放的是 el 中要用到的数据 msg: '欢迎学习Vue' // 通过 Vue 提供的指令,很方便的就能把数据渲染到页面上,程序员不再手动操作DOM元素了【前端的Vue之类的框架,不提倡我们去手动操作DOM元素了】 } }) </script> </body>
{{msg}}
使用插值表达式时,如果vue没有及时被加载出来(网速较慢情况),就会在页面上展现
{{msg}}
而不是具体数据信息,vue的解决方案类似Angular一样,使用属性控制器
<style> [v-cloak] { display: none; } </style> <script src="./lib/vue-2.4.0.js"></script> </head> <body> <div id="app"> <p v-cloak>+++++++{{ msg }}------</p> <p v-text="msg">+++++++--------</p> <!-- 默认v-text 是没有闪烁问题的 --> <!-- v-text 会覆盖元素中原本的内容,但是 插值表达式 只会 替换自己的这个占位符,不会把整个元素的内容清空--> </div>
解决 插值表达式 闪烁问题的指令,使用的同时别忘记添加样式:
<style> [v-cloak] { display: none; } </style>
类似于插值表达式,但是不同于插值表达式的是,使用该指令不会出现闪烁问题,而且其内指定的内容采用覆盖的方式覆盖元素内容,插值表达式不会覆盖只会替换自己占位符的内容。
插值表达式和v-text都只能在元素内插入文本,如果使用这两种方式向元素内插入子元素,需要使用v-html。
goWd(e) { // 判断触发事件的是不是动态绑定的元素 if (e.target.nodeName == "A") { this.$router.push("/wd"); } }
v-bind: 是vue中,提供的用于绑定属性的指令【属性绑定机制】,该指令会告诉vue,冒号后面的属性值里的内容是一个变量。
<div id="app"> <button title="123">点我</button> <!-- v-bind: 是vue中,提供的用于绑定属性的指令,该指令会告诉vue,冒号后面的属性值里的内容是一个变量。 --> <button v-bind:title="titl">点vue</button> <!-- 既然是变量,当然可以使用字符串拼接等操作 --> <button v-bind:title="titl.replace('Vue','vUE') + '123'">点vue</button> <!-- v-bind:提供了一种简写的方式就是直接在要绑定的元素上写: --> <button :title="titl">点vue了吗</button> </div> <script> var vm = new Vue({ el: '#app', data: { titl: '欢迎学习Vue' } }) </script>
vue像Angular一样,都不提倡使用dom操作,v-on是vue提供的事件绑定机制。在vue中,指令指定的内容为变量(属性)或者method,类似下面的直接调用alert方法,vue会去methods去寻找这个alert方法或属性,找不到就会报错
<div id="app"> <!-- 在vue的指令中会把其内内容当作属性(变量)或方法来处理,alert作为一个method并没有在vue中定义,所以点击1会报错 --> <!-- <input type="button" value="点击1" v-on:click="alert('1bc')"> --> <input type="button" value="点击2" v-on:click="click_abc"> <!-- v-on:的缩写是@ --> <input type="button" value="点击3" @click="click_abc"> </div> <script> var vm = new Vue({ el: '#app', data: { titl: '欢迎学习Vue' }, methods: { click_abc: function () { alert('abc') } } }) </script>
在这里有个问题,vue并没有那么严格的说方法一定要在methods中定义,它也可以在变量(data内属性)中定义:
<div id="app"> <!-- 在vue的指令中会把其内内容当作属性(变量)或方法来处理, alert作为一个method并没有在vue中定义,所以点击1会报错 --> <input type="button" value="点击1" v-on:click="alert('1bc')"> <input type="button" value="点击2" v-on:click="click_abc"> </div> <script> var vm = new Vue({ el: '#app', data: { titl: '欢迎学习Vue', alert:function (x) { alert(x) } }, methods: { click_abc: function () { alert('abc') } } }) </script>
不过还是不推荐这种写法,毕竟一个好的约定习惯是data内只封装数据。
1、在vm实例中,如果想要获取 data 上的数据,或者 想要调用methods 中的方法,必须通过this.数据属性名 或 this.方法名 来进行访问,这里的this就表示我们 new 出来的 vm实例对象。
2、vm实例,会监听自己身上 data 中所有数据的改变,只要数据一旦发生变化,就会自动把最新的数据从data上同步到页面中去。 [好处:程序员只需要关心数据,不需要考虑怎么渲染数据了
<div id="app"> <input type="button" value="浪起来" @click="bll"> <input type="button" value="稳住" @click="wz"> <h3>{{msg}}</h3> </div> <script> // 注意:在vm实例中,如果想要获取 data 上的数据,或者 想要调用 // methods 中的方法,必须通过this.数据属性名 或 this.方法名 来 // 进行访问,这里的this就表示我们 new 出来的 vm实例对象 var vm = new Vue({ el: '#app', data: { msg: '猥琐发育,别浪!!', inter: null }, methods: { bl() { if (this.inter != null) return; let that = this; that.inter = setInterval(function () { let start = that.msg.substring(0, 1); let end = that.msg.substring(1); that.msg = end + start; // 注意:vm实例,会监听自己身上 data 中所有数据的改变,只要数据 // 一旦发生变化,就会自动把最新的数据从data上同步到页面中去。 // [好处:程序员只需要关心数据,不需要考虑怎么渲染数据了。] }, 500); }, bll() { // 使用箭头函数解决this指向问题。箭头函数内部的this永远和箭头 // 函数外部的this保持一致。 if (this.inter != null) return; this.inter = setInterval(() => { let start = this.msg.substring(0, 1); let end = this.msg.substring(1); this.msg = end + start; // 注意:vm实例,会监听自己身上 data 中所有数据的改变,只要数据 // 一旦发生变化,就会自动把最新的数据从data上同步到页面中去。 // [好处:程序员只需要关心数据,不需要考虑怎么渲染数据了。] }, 500); }, wz() { clearInterval(this.inter); this.inter = null; } } }) </script>
v-model只能运用在表单元素中,用于双向数据绑定。注意v-bind只能用于单向数据绑定。
<div id="app"> <!-- v-bind只能用于实现数据的单向绑定,从M 自动绑定到 V,无法实现数据的双向绑定 --> <input type="text" v-bind:value="msg"> <!-- 使用 v-model 指令,可以实现 表单元素和Model中数据的双向绑定 --> <!-- 注意:v-model 只能运用在 表单元素中 --> <input type="text" v-model:value="msg"> </div> <script> var vm = new Vue({ el: '#app', data: { msg: 'Hello Vue' }, methods: {} }) </script>
<div id="app"> <ul> <!--<li v-for="value in common">{{value}}</li>--> <li v-for="(value,index) in common">索引:{{index}},值:{{value}}</li> </ul> <ul> <!--<li v-for="(k,v) in obj">键:{{v}},值:{{k}}</li>--> <!-- 在遍历对象的时候,还有可以获取索引 --> <li v-for="(k,v,i) in obj">键:{{v}},值:{{k}},索引:{{i}}</li> </ul> <ul> <!-- 如果迭代数字的话是从1开始的 --> <li v-for="num in 10">{{num}}</li> </ul> <ul> <li v-for="str in 'Hello_World'">{{str}}</li> </ul> </div> <script> var vm = new Vue({ el: '#app', data: { // 循环普通数组 common: [1, 2, 3, 4, 5], // 循环对象 obj: {maomao: '24', keke: 24, jiji: 22, mimi: 22} }, methods: {} }) </script>
使用v-for可能存在一定的问题,建议在使用v-for时指定:key
<div id="app"> <div> <label>id: <input type="text" v-model="id"> </label> <label>name: <input type="text" v-model="name"> </label> <input type="button" value="添加" @click="add"> </div> <!-- 如果不使用用:key强制绑定对象与元素唯一关联,可能会导致意想不到的问题: 例如:如果你勾选了最后一项,然后添加一组数据,会发现原来勾选的 变为了倒数第二个了! --> <!--<p v-for="mate in roommates">--> <!--<input type="checkbox">{{mate.id}}---{{mate.name}}--> <!--</p>--> <!-- 注意:在v-for遍历的时候,key 属性只能使用number或者string。 注意:key在使用的时候,必须使用 v-bind 属性绑定的形式,指定key的值。 在组件中,使用v-for循环的时候,或者在一些特殊情况中,如果 v-for有问题,必须 在使用v-for的同时,指定唯一的 字符串/数字 类型 :key 值 --> <p v-for="mate in roommates" :key="mate.id"> <input type="checkbox">{{mate.id}}---{{mate.name}} </p> </div> <script> var vm = new Vue({ el: '#app', data: { id: '', name: '', roommates: [ {id: 1, name: '毛毛'}, {id: 2, name: '吉吉'}, {id: 3, name: '可可'}, {id: 4, name: '咪咪'}, {id: 5, name: '德玛'} ] }, methods: { add() { this.roommates.unshift({ id: this.id, name: this.name }); } } }) </script>
<div id="app"> <!--<button @click="toggle">toggle</button>--> <!-- 如果事件内逻辑就一行代码,可以直接写 --> <button @click="flag=!flag">toggle</button> <!-- v-if 的特点:每次都会重新删除或创建元素 v-show 的特点:每次不会重新进行DOM的删除和创建操作,只是切换了 元素的 display:none 样式。 v-if 有较高的切换性能消耗 v-show 有较高的初始渲染消耗 如果元素涉及到频繁的切换,最好不要使用v-if,而是推荐使用v-show 如果元素可能永远也不会被显示出来被用户看到,则推荐使用v-if --> <p v-if="flag">我是v-if</p> <p v-show="flag">我是v-show</p> </div> <script> var vm = new Vue({ el: '#app', data: { flag: true }, methods: { toggle() { this.flag = !this.flag; } } }) </script>
// 注册一个名为 `v-focus` 的全局自定义指令 Vue.directive('focus', { // 当绑定的元素插入到 DOM 时调用此函数…… inserted: function (el) { // 元素调用 focus 获取焦点 el.focus() } }) //如果你想要注册一个局部指令,也可以通过设置组件的 directives 选项: directives: { focus: { // 指令定义对象 inserted: function (el) { el.focus() } } }
全局自定义指令中参数1:指令的名称,在定义的名称前面,不需要加 v- 前缀。但是在调用的时候,必须 在指令名称前 加上 v- 前缀来进行调用。
全局自定义指令中参数2:是一个对象,这个对象身上,有一些指令相关的函数,这些函数可以在特定的阶段,执行相关操作。
<div id="app"> 自定义指令自动获取焦点:<input type="text" v-focus v-color="'red'"> <!--<p v-fontSize="'40px'">哈哈哈哈,我使用了简写方式</p>--> <p v-font-size="'40px'">哈哈哈哈,我使用了简写方式</p> </div> <script> <!-- 定义全局指令 --> Vue.directive('focus', { bind: (el, binding) => { // 每当指令绑定到元素上的时候,会立即执行这个bind函数,只 // 执行一次。 // 注意在 每个 函数中,第一个参数,永远是el,表示 被绑定了指令的那个元素, // 这个el参数,是个原生的js对象。 // 在元素 刚绑定了指令的时候,还没有 插入到 DOM中去,这时候 // 调用focus方法没有作用,因为,一个元素,只有插入DOM之后,才能获取焦点 // el.focus() // 和样式相关的操作,一般都可以在bind执行 }, inserted: (el, binding) => { // 在已绑定的元素插入到父节点时调用(只能保证父 // 节点存在,不一定存在于 document 中)。 el.focus(); // 和JS行为有关的操作,最好在inserted中去执行,放置 JS行为不生效 }, update: (el, binding) => { // 当BNode更新的时候,会执行 updated,可能会触发多次 }, componentUpdated: (el, binding) => { }, unbind: (el, binding) => { } }); Vue.directive('color', { bind(el, binding) { console.log('指令名称', binding.name); console.log('指令值', binding.value); console.log('指令值(未计算过的)', binding.expression); el.style.color = binding.value; } }); // 使用简写 // 不能在自定义指令中使用驼峰命名法,要么全小写,要么使用font-size的形式 // Vue.directive('fontSize', function (el, binding) { // el.style.fontSize = parseInt(binding.value) + 'px'; // }) Vue.directive('font-size', function (el, binding) { el.style.fontSize = parseInt(binding.value) + 'px'; }); let vm = new Vue({ el: '#app', data: {}, methods: {}, directives: { focus: { // 指令名称 // 指令定义对象 inserted: function (el) { el.focus() } }, // 简写方式:表示给fontSize写两个方法bind和update,且这两个方法公用同样的方法体 // 不能在自定义指令中使用驼峰命名法,要么全小写,要么使用font-size的形式 // fontSize: function(el, binding){ // el.style.fontSize = parseInt(binding.value) + 'px'; // } 'font-size':(el,binding)=>{ el.style.fontSize = parseInt(binding.value) + 'px'; } } }) </script>
<div id="app"> <!-- 过滤器可以在两种场景中使用:双花括号插 值(mustache interpolation)和 v-bind 表达 式(后者在 2.1.0+ 版本支持) --> <!-- 类似django模板过滤 --> <p>{{ msg | StrFilter }}</p> <!-- 可以连续过滤 --> <p>{{ msg | StrFilter | blackFilter }}</p> <!-- 可以传递多个参数:1-msg,2-*,3-* --> <p>{{ msg | strictFilter({name:'毛毛'},['1',2,3]) }}</p> <!-- 使用组件内部过滤器 --> <p>{{ msg | doFilter }}</p> <!-- 还可以用于属性绑定 --> <p :title="msg | doFilter">鼠标悬停一会看看</p> </div> <script> // vue定义全局过滤器[必须在创建实例之前!!!] Vue.filter('StrFilter', (str) => { return str.replace(/大/g, '小'); }); Vue.filter('blackFilter', (str) => { return str.replace(/黑/g, '白'); }); Vue.filter('strictFilter', (str, arg1, arg2) => { console.log(arg1, arg2); return str.replace(/黑/g, '白'); }); var vm = new Vue({ el: '#app', data: { msg: '安徽省阜阳市是一个大大大的市区,里面有很多大佬和黑帮。' }, methods: {}, filters: { // 组件内部的过滤器 doFilter(str) { return str.replace(/安徽省阜阳市/g, '**省**市'); } } }); </script>
event.preventDefault() 或 event.stopPropagation()
是非常常见的需求。尽管我们可以在methods中轻松实现这点,但更好的方式是:methods只有存粹的数据逻辑,而不是去处理DOM事件细节。为了解决这个问题,vue为v-on提供了事件修饰符。修饰符是以点(.)开头的指令后缀来表示。
-
-
-
- .stop
- .prevent
- .capture
- .self
- .once
- .passive
-
-
<style> .inner { padding: 50px; margin: 2px; background-color: darkolivegreen; } </style> <script src="./lib/vue-2.4.0.js"></script> </head> <body> <div id="app"> <!-- 停止默认事件,提交/跳转等事件不再有效 --> <!--<a href="https://www.baidu.com" @click.prevent="doThis">去百度</a>--> <!-- 停止事件向上冒泡 --> <!--<div class="inner" @click="innerDivHandler"> <button @click="doThis">去百度1</button> </div> <div class="inner" @click="innerDivHandler"> <button @click.stop="doThis">去百度2</button> </div>--> <!-- 只要event.target是元素自身时,才触发处理函数 --> <!-- 也就是说,event.target 是子元素时,不触发处理函数 --> <!--<div class="inner" @click="innerDivHandler"> <button @click="doThis">去百度1</button> </div> <div class="inner" @click.self="innerDivHandler"> <button @click="doThis">去百度2</button> </div>--> <!-- 添加事件监听器,使用事件捕获模式 --> <!-- 也就是说,内部元素触发的事件先在此处处理,然后才交给内部元素进行处理 --> <!--<div @click.capture="doThis">...</div>--> <!-- 事件只会触发一次,修饰符可以链式调用 --> <!--<a href="https://www.baidu.com" @click.prevent.once="doThis">去百度</a>--> <!--<a href="https://www.baidu.com" @click.once.prevent="doThis">去百度</a>--> <!-- 滚动事件的默认行为(滚动)将立即发生, --> <!-- 而不是等待 `onScroll` 完成后才发生, --> <!-- 以防在滚动事件的处理程序中含有 `event.preventDefault()` 调用 --> <!--不要将 .passive 和 .prevent 放在一起使用,因为 --> <!-- .prevent 将被忽略,并且浏览器可能会显示一条警告。 --> <!-- 记住,.passive 会向浏览器传达的意思是,你_并不_希望阻止事件的默认行为。 --> <!--<div v-on:scroll.passive="onScroll">...</div>--> </div> <script> var vm = new Vue({ el: '#app', data: {}, methods: { doThis() { console.log('doThis'); }, innerDivHandler() { console.log('innerDivHandler'); } } }) </script>
<div id="app"> <!-- 监听按键码为13的keyup事件 --> 按键码:<input type="text" v-model="msg" @keyup.13="add"> <!-- enter为vue提供的一些常用按键别名 --> 按键别名:<input type="text" v-model="msg" @keyup.enter="add"> <!-- 使用自定义的按键别名 --> 自定义按键别名:<input type="text" v-model="msg" @keyup.f1="add"> <!-- 可以串联响应多个按键 --> 串联响应多个按键:<input type="text" v-model="msg" @keyup.up.enter="add"> <p>回车输出:{{txt}}</p> </div> <script> <!--自定义按键别名--> Vue.config.keyCodes.f1=13 let vm = new Vue({ el: '#app', data: { msg: '', txt: '' }, methods: { add() { this.txt = this.msg; } } }) </script>
仅在以下修饰符对应的按键被按下时,才会触发鼠标或键盘事件监听器:
<div id="app">
<!-- ctrl+enter触发add方法 -->
按键码:<input type="text" v-model="msg" @keyup.ctrl.enter="add">
<p>回车输出:{{txt}}</p>
</div>
<div id="app">
<!-- ctrl+enter触发add方法 -->
按键码:<input type="text" v-model="msg" @keyup.ctrl.enter="add">
<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">做一些操作</div>
<p>回车输出:{{txt}}</p>
<!--.exact 修饰符可以控制触发事件所需的系统辅助按键的准确组合。-->
<!-- 如果 Alt 键或 Shift 键与 Ctrl 键同时按下,也会触发事件 -->
<button @click.ctrl="onClick">A</button>
<!-- 只在 Ctrl 按键按下,其他按键未按下时,触发事件 -->
<button @click.ctrl.exact="onCtrlClick">A</button>
<!-- 只在没有系统辅助按键按下时,触发事件 -->
<button @click.exact="onClick">A</button>
</div>
在数据绑定中,一个常见的需求是,将数据与元素的class列表,以及元素的style内联样式的操作绑定在一起。由于它们都是属性(attribute),因此我们可以使用v-bind来处理它们:只需从表达式中计算出最终的字符串。然而,处理字符串拼接,即麻烦又容易出错。为此,在使用 v-bind 指令来处理 class 和 style 时,Vue 对此做了特别的增强。表达式除了可以是字符串,也能够是对象和数组。
<style> .red { color: red; } .italic { font-style: italic; } .thin { font-weight: 200; } .active { font-size: 50px; } </style> <script src="./lib/vue-2.4.0.js"></script> </head> <body> <div id="app"> <!--<h1 class="red italic thin active">这是一个大的H1</h1>--> <!-- 第一种使用方式,直接传递一个数组,注意:这里的class需要使用 v-bind做数据绑定 --> <!--<h1 :class="['thin','italic']">这是一个大的H1</h1>--> <!-- 在数组中使用三元表达式 --> <!--<h1 :class="['thin','italic',flag?'active':'']">这是一个大的H1</h1>--> <!-- 在数组中使用 对象 来替代三元表达式,提高代码可读性 --> <!--<h1 :class="['thin','italic',{active:flag}]">这是一个大的H1</h1>--> <!-- 在为class使用 v-bind 绑定对象的时候,对象的属性是类名,由于 对象的属性可 带引号,也可以不带引号,所以这里我没写引号;属性的值 是一个标识符 --> <h1 :class="classObj">这是一个大的H1</h1> </div> <script> var vm = new Vue({ el: '#app', data: { flag: true, classObj: {red: true, italic: true, active: false, thin: true} }, methods: {} }) </script>
<div id="app"> <!-- 由于对象中的键不允许直接使用-,所以要用引号引起来 --> <!--<h1 :style="{color:'red','font-size':'50px'}">这是一个大的H1</h1>--> <!-- 在data上直接定义,然后绑定 --> <!--<h1 :style="styleObj">这是一个大的H1</h1>--> <!-- 通过数组引用多个data上定义的样式对象 --> <h1 :style="[styleObj,style2Obj]">这是一个大的H1</h1> </div> <script> var vm = new Vue({ el: '#app', data: { styleObj: {color: 'red', 'font-size': '50px'}, style2Obj: {'font-style': 'italic'}, }, methods: {} }) </script>
组件的出现,就是为了拆分Vue实例的代码量的,能够让我们以不同的组件,来划分不同的功能模块,将来我们需要什么样的功能,就可以调用对应的组件即可;
模块化:是从代码逻辑的角度进行划分的;方便代码分层开发,保证每个功能模块的职能单一;
组件化:是从UI界面的角度进行划分的;前端的组件化,方便UI组件的重用;
<body> <div id="app"> <!-- 1.3 在页面中引用定义的组件 --> <!-- <my-com1></my-com1> --> <mycom1></mycom1> </div> <script> // 1.1 使用Vue.extend 来创建全局的Vue组件模板HTML // 通过 template 属性,指定了组件要展示的HTML结构 // var com1 = Vue.extend({ // template:'<h3>这是使用Vue.extend创建的组件</h3>' // }); // 1.2 使用Vue.component('组件的名称',创建出来的组件模板对象)生成组件 // Vue.component('myCom1',com1) // 如果使用Vue.component 定义全局组件的时候,组件名称使用了 驼峰命名,则在引用的时候,需要把大写的驼峰改为小写的字母,同时,两个单词之间,使用 - 链接 // Vue.component('myCom1',com1); // 如果不使用驼峰,则直接拿名称来使用即可; // Vue.component('mycom1',com1); // 我们其实没必要把创建组件的过程拆分两部,下面将使用一步的方式 Vue.component('mycom1',Vue.extend({ template:'<h3>这是使用Vue.extend创建的组件</h3>' })) var vm = new Vue({ el: "#app", data: { }, methods: { } }); </script>
<div id="app"> <mycom2></mycom2> </div> <script> <!-- 可以直接在定义组件时,直接写组件模板HTML --> Vue.component('mycom2',{ // 注意组件内的模板只能有一个根元素 // template:'<h2>你好,组件2</h2><span>哈哈啊哈</span>' template:'<div><h2>你好,组件2</h2><span>哈哈啊哈</span></div>' }) Vue.filter('method', (args) => { return ``; }) // 实例必须定义,因为组件依赖实例中的el元素 var vm = new Vue({ el: "#app", data: { }, methods: { } }); </script>
<template id="mytemp1"> <!-- 同样的,只能有一个根元素 --> <div> <h3>模板3的方式很方便,哈哈哈哈</h3> </div> </template> <script> <!-- 使用前两种创建方式,都不能在template里有html代码提示,第三种方式是将template抽离出来,放到被管理的app之外,然后再template中指定对应的模板,最后在app中直接引入即可 --> Vue.component('mycom3',{ template:'#mytemp1' }) var vm = new Vue({ el: "#app", data: { }, methods: { } }); </script>
<div id="app"> <mycom4> </mycom4> </div> <div id="app2"> <!-- <mycom4></mycom4> --> </div> <template id="teml4"> <h4> 哈哈我是一个私有组件 </h4> </template> <script> Vue.filter('method', (args) => { return ``; }) var vm1 = new Vue({ el: "#app", data: { }, methods: { }, filters:{}, directives:{}, components:{ mycom4:{ template:'#teml4' } }, beforeCreat() {}, created(){}, beforeMount(){}, mounted(){}, beforeUpdate(){}, updated(){}, beforeDestory(){}, destoryed(){}, afterDestory(){} }); var vm2 = new Vue({ el:"#app2" }) </script>
<div id="app"> <mycom1> </mycom1> <hr> <mycom1> </mycom1> <hr> <mycom1> </mycom1> <hr> </div> <template id="templ"> <div> <input @click="increament" name="" value="increament" type="button"> <h3> {{count}} </h3> </input> </div> </template> <script> var obj = {count:0}; // 如果data不是一个methods的话(而是一个对象obj), // 那么每次创建一个新的组件,都会像使用全局变量一样,这样导致 // 的结果就是所有的组件共用变量。 Vue.component('mycom1',{ template:"#templ", data:function(){ // return obj; // 这样写是为每个组件都开辟一块内存区域 return {count:0}; }, methods:{ increament() { this.count++; } } }) var vm = new Vue({ el: "#app", data: { }, methods: { } }); </script>
<style type="text/css"> .v-enter,.v-leave-to { opacity: 0; transform: translateX(100px); } .v-enter-active,.v-leave-active { transition: all .8s ease; } </style> </head> <body> <div id="app"> <a href="" @click.prevent="templ = 'login'">登陆</a> <a href="" @click.prevent="templ = 'register'">注册</a> <!-- 对组件使用动画,只需要使用transition包裹起来即可 --> <!-- 使用mode指定动画执行的顺序模式:先出后进 --> <transition mode="out-in"> <component :is="templ"></component> </transition> </div> <script> var vm = new Vue({ el: "#app", data: { templ:'login' }, methods: { }, components:{ login:{ template:"<h3>登陆模块</h3>" }, register:{ template:"<h3>注册模块</h3>" } } }); </script>
首先,子组件是不能直接获取父组件里的值的,要想获取值需要在组件标签中使用指令绑定一个变量,传递给子组件中,如下:
<div id="app"> <shop v-bind:parentmsg="msg"></shop> </div>
子组件shop要获得父组件里的msg,需要使用属性绑定指令绑定一个变量,将父组件里的某个变量传递给这个变量,然后:
components:{ shop:{ template:'#list', props:['parentmsg'] } }
在子组件里,通过props指定的变量引入父组件里绑定的值,注意:props是一个数组,它里面的内容即为要引入的变量名称(通过名称引入)
<body> <div id="app"> <shop v-bind:parentmsg="msg"> </shop> </div> <template id="list"> <div> <p> 从父组件里传来的数据---{{parentmsg.mm}} </p> </div> </template> <script> var vm = new Vue({ el: "#app", data: { msg:{mm:'我是父组件里的信息'} }, methods: { }, components:{ // 结论:经过演示发现,子组件中,默认无法访问到父组件中的 data 上的数据 和 methods中的方法 shop:{ template:'#list', data:()=>{ // 注意:子组件中的data数据,并不是通过 父组件传递过来的,而是子组件自身私有的,比如:子组件通过Ajax,请求回来的数据,都可以放到data身上; // data上的数据都是可写的 return { title:'abc', name:'123' } }, methods:{ }, // 注意:组件中的所有props中的数据,都是通过父组件传递给子组件的 // props上的数据都是只读的 props:['parentmsg'] // 把父组件传递过来的 parentmsg属性,先在props数组中,定义一下,这样,才能使用这个数据 } } }); </script>
不管你是传递值还是传递引用,注意:在子组件中都不允许修改父组件传递过来的值,也就是说子组件只能使用,而不能修改。
注意:子组件想要获取父组件内的数据,必须通过组件传值的方式去获取。但是对于DOM操作,子组件直接可以使用document对象去操作父组件内部的元素【挂载完毕后】,例如子组件的某元素通过click方法,获取父组件内部某个元素,此时dom已经渲染完毕,针对dom操作以及跨越了组件,和组件并无关系了。
<div id="app"> <!-- 传递子组件方法,使用v-on绑定事件的形式将父组件中的方法绑定到子组件身上 --> <!-- func为getMsg在子组件中的别名,getMsg为父组件的methods --> <shop @func="getMsg"> </shop> </div> <template id="list"> <div> <!-- 调用子组件的info方法 --> <button @click="info">点击调用父组件中的方法</button> </div> </template> <script> var vm = new Vue({ el: "#app", data: { }, methods: { getMsg(data1,data2){ console.log('我是父组件的methods' + data1 + data2); } }, components:{ shop:{ template:'#list', data:()=>{ return { title:'abc', name:'123' } }, methods:{ info(){ // 子组件可以通过通过$emit触发执行绑定到自己身上的func方法 // 如果有参数,参数直接写在方法名后 this.$emit('getMsg',123,222); } } } } }); </script>
子组件给父组件传递值,只能是被动方式传递,即某个事件触发,才能传递。子组件向父组件传递值采用了父组件给子组件传递方法的方式。
<div id="app"> <!-- 传递子组件方法,使用v-on绑定事件的形式将父组件中的方法绑定到子组件身上 --> <shop @func="getMsg"> </shop> </div> <template id="list"> <div> <button @click="info">点击调用父组件中的方法</button> </div> </template> <script> var vm = new Vue({ el: "#app", data: { childdata:null }, methods: { getMsg(data){ this.childdata = data; } }, components:{ shop:{ template:'#list', data:()=>{ return { title:'abc', name:'123' } }, methods:{ info(){ // 当子组件中的方法被调用时,会执行父组件中的方法,此时,将要传递给父组件的值通过函数的参数传递过去,在父组件中接收。 // 子组件向父组件传值只能被动的传递(有事件触发) this.$emit('func',this.title); } } } } }); </script>
<div id="app"> <!-- <p ref="ppp">我能通过ref引用到p元素</p> --> <!-- 如果ref指定的名称被多个元素占用,则只使用最后一个 --> <p ref="ppp">我能通过ref引用到p元素</p> <!-- 使用ref还可以引用组件 --> <login ref="logref"></login> </div> <template id="mytempl"> <div></div> </template> <script> var vm = new Vue({ el: '#app', data: { }, methods: { }, components:{ login:{ template:"#mytempl", data:()=>{ return { title:'哈哈哈' } } } } }); console.log(vm.$refs.ppp); console.log(vm.$refs.logref); console.log(vm.$refs.logref.title); </script>
我们的组件除了使用特殊占位符替换以外,还可以使用render渲染我们的组件,不同的是这两者就类似于v-text和插值表达式,render渲染的组件会直接覆盖容器里的所有内容,而使用占位符的形式组件只会替换占位符位置的内容。
<script src="../lib/vue-2.4.0.js"></script> </head> <body> <div id="app"> </div> <script> var login = { template:"<h1>登陆模块</h1>" } var vm = new Vue({ el: '#app', render:function(createElements) { // createElements是一个方法,调用它,能够把指定的组件模板,渲染为 html 结构 return createElements(login) // 注意:这里 return的结果,会替换页面中的el指定的那个容器 } }) </script>