一、创建简单vue实例
<!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>hello world</title><!-- 引入vue.js文件创建vue实例 --><script src='./vue.js'></script>
</head><body><div id="app">{{content}}</div><!-- <div>{{content}}</div> --><script>// var dom = document.getElementById('app');// dom.innerHTML = "Hello World!"// setTimeout(function(){// dom.innerHtml='bye world'// },2000)var app = new Vue({el: '#app',data: {content: 'hello world!'}})setTimeout(function () {app.$data.content = 'bye world!'}, 2000)</script>
</body></html>
二、实现todoList
1.通过简单vue实例
<!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>todo list</title><script src='./vue.js'></script>
</head><body><div id="app"><input type='text' v-model="inputValue" /><button v-on:click="handleBtnClick">提交</button><ul><!-- <li>第一课的内容</li><li>第二课的内容</li> --><li v-for="item in list">{{item}}</li></ul></div><script>var app = new Vue({el: '#app',data: {list: [],inputValue:''},methods: {handleBtnClick: function () {// alert('click')this.list.push(this.inputValue);this.inputValue=''}}})</script>
</body></html>
2.通过jquery
<!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>todoList Jquery</title><script src='./jquery.js'></script>
</head><body><div><input id="input" type='text' /><button id="btn">提交</button><ul id="list"></ul></div><script>function Page() {}$.extend(Page.prototype, {init: function () {this.bindEvents()},bindEvents: function () {var btn = $('#btn');// proxy方法 会改变handleBtnClick方法的this指向,使其一直是指向这个page实例btn.on('click', $.proxy(this.handleBtnClick, this))},handleBtnClick: function () {// alert('123')var inputElem = $("#input");// 获取Input框的内容var inputValue = inputElem.val();// 将其添加到ul里面var ulElem = $("#list");ulElem.append('<li>' + inputValue + '</li>');// input框内容再置空inputElem.val('');}})var page = new Page();page.init();</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>todo list</title><script src='./vue.js'></script>
</head><body><div id="app"><input type='text' v-model="inputValue" /><button v-on:click="handleBtnClick">提交</button><ul><li v-for="item in list">{{item}}</li><!-- <todo-item v-bind:content="item" v-for="item in list"></todo-item> --></ul></div><script>// 全局组件// Vue.component("TodoItem",{// template:"<li>todo item</li>"// })// Vue.component("TodoItem",{// props:['content'],// template:"<li>{{content}}</li>"// })// 局部组件// var TodoItem = {// props: ['content'],// template: "<li>{{content}}</li>"// }var app = new Vue({el: '#app',components: { TodoItem: TodoItem },data: {list: [],inputValue: ''},methods: {handleBtnClick: function () {// alert('click')this.list.push(this.inputValue);this.inputValue = ''}}})</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>todo list</title><script src='./vue.js'></script>
</head><body><div id="root"><input type='text' v-model="inputValue" /><button v-on:click="handleBtnClick">提交</button><ul><todo-item v-bind:content="item" v-bind:key="index" v-for="(item,index) in list" v-on:delete="handleItemDelete(index)"></todo-item></ul></div><script>// 局部组件var TodoItem = {props: ['content','index'],template: "<li v-on:click='handleItemClick'>{{content}}</li>",methods: {handleItemClick: function () {this.$emit("delete",this.index);}}}var app = new Vue({el: '#root',components: { TodoItem: TodoItem },data: {list: [],inputValue: ''},methods: {handleBtnClick: function () {// alert('click')this.list.push(this.inputValue);this.inputValue = ''},handleItemDelete: function (index) {// alert('delete')this.list.splice(index,1)}}})</script>
</body></html>
四、两种创建vue实例
<!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>hello world</title><script src='./vue.js'></script>
</head><body><div id="root" @click="handleCLick">{{message}}<item></item></div><script>// 全局组件Vue.component(),不用在父组件当中components中再注册Vue.component("item",{template:"<p>hello item</p>"})// 根实例var vm = new Vue({el: "#root",data: {message: "hello world!"},methods: {handleCLick: function () {alert('hello world!');}}// props computed watch})</script>
</body></html>
五、vue实例生命周期
<!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><script src='./vue.js'></script>
</head><body><div id="app">111111</div><script>// 生命周期函数就是vue实例在某个"时间点"会"自动执行"的函数// 注意生命周期钩子没有定义在methods里面// 下面一共8个生命周期钩子,其实vue源码当中是11个,点击vue官网的学习->API// activated() deactivated() errorCaptured() 在后面的学习当中会给演示说明var vm = new Vue({el: "#app",template: "<div>{{test}}</div>",data: {test: "hello world!"},beforeCreate: function () {console.log("beforeCreate");},created: function () {console.log("created")},// 接着会询问是否有el选项// 然后询问有无template选项// 有template,就把模板内容直接渲染// 无template,就把el接管的dom标签的全部内容当做模板template来进行渲染 // 在渲染之前,也就是在模板和数据相结合之前的一瞬间,会执行beforeMount函数beforeMount: function () {console.log(this.$el);console.log("beforeMount");// alert("beforeMount");},// beforeMount执行后,模板和数据结合后生成的vue实例当中的dom元素会挂载(显示)到页面之上// vue实例挂载之后,会执行mounted()mounted: function () {//上面的和这行的$el反映出mounted执行后页面才渲染完毕// 这里的$el才打印出模板template中的内容console.log(this.$el);console.log("mounted");},// 下面有两个beforeDestroy()和destroyed()// 但是到页面刷新后发现并没有执行,那么它们什么时候会被执行呢?// 答:只有当vm.$destroy()方法被调用执行之后才会触发这两个生命周期钩子// 组件即将被销毁时 beforeDestroybeforeDestroy: function () {console.log("beforeDestroy");},// 组件被完全销毁后 destroyed destroyed: function () {console.log("destroyed");},// 下面有两个beforeUpdate()和updated()// 但是到页面刷新后发现并没有执行,那么它们什么时候会被执行呢?// 答:只有当数据发生改变之后才会触发这两个生命周期钩子// 打开控制台 vm.test="zhangsan" 或 vm.$data.$test="zhangsan"// 数据发生改变但还没重新渲染之前 beforeUpdatebeforeUpdate: function () {console.log("beforeUpdate");},// 重新渲染之后 updatedupdated: function () {console.log("updated");},})</script>
</body></html>
六、vue模板语法
<!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><script src='./vue.js'></script>
</head><body><div id="app"><div>{{name+" Lee"}}</div><div v-text="name+' Lee'"></div><div v-html="name+' Lee'"></div></div><script>var vm = new Vue({el: "#app",data: {name: "Dell"}})</script>
</body></html>
七、计算属性computed、方法method、侦听器watch
<!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><script src='./vue.js'></script>
</head><body><div id="app"><!--冗余的 插值表达式 --><!-- {{firstName+" "+lastName}} --><!--1 计算属性computed --><!-- {{fullName}} --><!--2 方法methods --><!-- {{fullName()}} --><!--3 侦听器watch -->{{fullName}} {{age}}</div><script>var vm = new Vue({el: "#app",data: {firstName: "Dell",lastName: "Lee",// 下面这样会数据冗余fullName: "Dell Lee",age: 28},// computed watch methods 若三者都可实现某种功能,推荐使用computed// 侦听器(有缓存,只要侦听的变量所依赖的不变化,就不执行,用缓存)// 即watch与computed很类似都有缓存机制,但是推荐computed// watch: {// firstName: function () {// console.log("计算了一次firstName");// this.fullName = this.firstName + " " + this.lastName;// },// lastName: function () {// console.log("计算了一次lastName");// this.fullName = this.firstName + " " + this.lastName;// }// },// 方法(无缓存特点,只要页面渲染一次,方法就会重新执行一次)// 测试:vm.lastname="liu" 会打印“计算了一次”// 测试:vm.age=27 也会打印“计算了一次”// methods: {// fullName: function () {// console.log("计算了一次");// return this.firstName + " " + this.lastName;// }// }// 计算属性(内置缓存的特点:若计算属性依赖的值没有发生变化,就不会执行)// 测试:vm.age=27 不会打印“计算了一次”// 测试:vm.lastname="liu" 会打印“计算了一次”// computed: {// fullName: function () {// console.log("计算了一次");// return this.firstName + " " + this.lastName;// }// }})</script>
</body></html>
八、计算属性setter-getter
<!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>计算属性-setter+getter</title><script src='./vue.js'></script>
</head><body><div id="app">{{fullName}}</div><script>var vm = new Vue({el: "#app",data: {firstName: "Dell",lastName: "Lee"},computed: {// fullName: function () {// return this.firstName + " " + this.lastName;// }fullName: {get: function () {return this.firstName + " " + this.lastName;},set: function (value) {// console.log(value);var arr = value.split(" ");// 因为firstName和lastName重新赋值了,所以执行set()后会引起上面的get()的执行this.firstName = arr[0];this.lastName = arr[1];}}}})</script>
</body></html>
九、vue样式绑定
<!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><script src='./vue.js'></script><style>.activated {color: red;}</style>
</head><body><div id="app"><!-- class 对象--><!-- 样式和数据的一个绑定,我们把这个叫做class的对象绑定 --><!-- :class="{activated:isActivated}" --><!-- class 数组--> <!-- 可绑定多个样式名 --><!-- :class="[activated,activatedOne]" --><!-- style 对象--><!-- :style="styleObj" --><!-- style 数组 除此之外其他代码同上面style 对象形式--><!-- :style="[styleObj]" --><!-- style 数组(可以放多个对象 --><!-- :style="[styleObj,{fontSize:'20px'}]" --><div :style="[styleObj, {fontSize:'20px'}]" @click="handleDivClick">hello world</div></div><script>var vm = new Vue({el: "#app",data: {// isActivated:false// activated: '',// activatedOne:"activated-one",styleObj: {color: "black"}},methods: {handleDivClick: function () {// class :class="{activated:isActivated}"// this.isActivated = !this.isActivated;// class :class="[activated]"// this.activated = this.activated === "activated" ? "" : "activated";// stylethis.styleObj.color = this.styleObj.color === "black" ? "red" : "black";}}})</script>
</body></html>
十、vue条件渲染 v-if v-show
<!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><script src='./vue.js'></script>
</head><body><div id="app"><!-- v-if和v-show --><!-- v-if 直接不挂载,不存在页面dom之上 --><!-- v-show 是不显示 display:none --><!-- v-show的性能较高,因为不会频繁移除dom --><!-- <div v-if="show" data-test="v-if">{{message}}</div><div v-if="show" data-test="v-if">{{message}}</div> --><!-- v-if和v-else --><!-- v-else不必绑定变量,但这两个指令所在的标签必须紧贴使用,中间不可放其他标签,比如放一个<span></span> --><!-- 有你没我,有我没你,dom树上只挂载其中一个 --><!-- <div v-if="show">{{message}}</div><div v-else>bye world</div> --><!-- v-if和v-else-if和v-else --><!-- 注意这三者也是有紧贴着使用 --><!-- <div v-if="show==='a'">This is A</div><div v-else-if="show==='b'">This is B</div><div v-else>This is Others</div> --><!-- 简单例子 --><!-- 问题:vue的虚拟dom机制会尽量复用页面上的dom --><!-- 比如下面如果<input/>,在切换用户名和邮箱名的时候,Input框会复用,即内容不会清空 --><!-- 解决方案,给<input key="" /> 这样vue会知道是唯一元素,就不会复用它--><!-- <div v-if="show">用户名:<input key="userName"/></div><div v-else>邮箱名:<input key="emailName"/></div> --></div><script>var vm = new Vue({el: "#app",data: {show:false,// show: 'a',message: "hello world!"}})</script>
</body></html>
十一、vue列表渲染 v-for
<!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><script src='./vue.js'></script>
</head><body><div id="app"><!-- 数组的循环 --><!-- <div v-for="item in list"></div> --><!-- 更推荐用of这个语法 --> <!-- 为了提高循环性能,推荐给每一个循环项加上唯一的key值--><!-- 但是key不推荐用这里的index,推荐使用后端返回的id标识,即item.id --><!-- <div v-for="(item,index) of list":key="item.id">{{item.text}}---{{index}}</div> --><!-- template 占位符 在sources中不显示这个标签,即并不会渲染到页面之上 --><!-- 需要一个新的标签包裹使其只循环一次但是又不想用div--><!-- <template v-for="(item,index) of list"><div>{{item.text}}---{{index}}</div><span>{{item.text}}---{{index}}</span></template> --><!-- 对象的循环 --><!-- vm.userInfo.name="Dell Lee" 操作已有的key值 数据变 页面变--><!-- vm.userInfo.address="Beijing" 操作没有的key值 数据变 页面不变--><!-- 如何解决这种问题,想添加新的Key值? --><!-- 答:和上面数组一样的方法,改变对象的引用。 vm.userInfo={新对象新的Key和value值} --><!-- 但其实还有set方法,见下一节内容 --><div v-for="(item,key,index) of userInfo">{{item}}---{{key}}---{{index}}</div></div><script>var vm = new Vue({el: "#app",// vm.list.push({id:"26419",text:"try"}) 成功 数据变 页面变// vm.list[4]={id:"26419",text:"try"} 失败 数据变 页面不变// 注意:我们不能通过下标方式来操作数组,只能通过vue提供的七种数组变异方法来操作数组// 数组尾部添加删除push pop// 数组头部添加删除shift unshift// 截取splice 排序sort 取反reverse// 除了上面七种方法,可以有别的方法吗?// 答:改变数组的引用地址,即直接给List赋值 vm.list=[新数组]// 还可以用set方法,见下一节内容// data: {// list: [{// id:"1628640",// text:"hello"// },{// id:"6924155",// text:"Dell"// },{// id:"0174746",// text:"Lee"// }]// }// 对象data:{userInfo:{name:"Dell",age:28,gender:"male",salary:"secret"}}})</script>
</body></html>
十二、vue-set
<!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>vue-set</title><script src='./vue.js'></script>
</head><body><div id="app"><!-- 对象 --><!-- <div v-for="(item,key,index) of userInfo">{{item}}---{{key}}---{{index}}</div> --><!-- 数组 --><div v-for="(item,index) of userInfo">{{item}}---{{index}}</div></div><script>// 对象// set即是全局方法,也是实例方法// 全局方法// Vue.set(vm.userInfo,"address","Beijing")// 实例方法// vm.$set(vm.userInfo,"address","Beijing")// 数组// 全局方法 Vue.set(vm.userInfo,2,10)// 实例方法 vm.$set(vm.userInfo,3,100)// 改数组(数据变,页面变)// (1) 七种变异方法 (2) 改变引用地址 (3)set// 改对象(数据变,页面变)// (1) 改变引用地址 (2)setvar vm = new Vue({el: "#app",data: {// userInfo: {// name: "Dell",// age: 28,// gender: "male",// salary: "secret"// }userInfo:[1,2,3,4]}})</script>
</body></html>
十三、事件绑定 v-on、@click
<!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><script src='./vue.js'></script>
</head><body><div id="app"><!-- @click="handleClick()"这样写会触发点击事件,但是获取不到事件对象e,可写成@click="handleClick($event)" --><!--写法1 <button @click="handleClick($event)">Button</button> --><!--写法2 <button @click="handleClick">Button</button> --><!--写法1加括号,可以传参 @click="handleClick($event,1,2,3)" --><!-- <button @click="handleClick($event,1,2,3)">Button</button> --><!-- "/abc" 为提交form表单后的跳转地址 --><!-- 为阻止这个默认跳转的行为,可在handleClick()函数内写上e.preventDefault(); --><!-- 当然也可这样 <form action="/abc" @click.prevent> 便可实现完全一致的功能--><!-- 这是vue提供的修饰符,上面也可写成 @click.prevent="handleClick" --><!-- <form action="/abc" @click.prevent><input type="submit" /></form> --><!-- 这样的基础事件修饰符还有很多,如下 --><!-- 普通修饰符 --><!-- @click.prevent 阻止默认行为 e.preventDefault()--><!-- @click.stop 阻止事件冒泡 e.stopPropagation()--><!-- @click.self 只有e.target=e.currentTarget的时候才会执行。即只有触发元素和绑定元素一致时才会触发事件执行--><!-- @click.once 只执行一次事件 --><!-- @click.capture 事件冒泡——>事件捕获规则,当然是父和子元素都加上.capture --><!-- @click.stop 点击子元素时,若父元素也监听同样事件,将 不会冒泡到父元素身上--><!-- @click.self 只有点击标签自身的时候才会触发点击事件。点击其子元素时不触发。点击父元素也不触发。--><!-- @click.capture 按道理是按事件冒泡,由子到父的顺序,先触发子的事件再触发父的事件。 --><!-- 若加上capture的话,就事件捕获,即由父到子的顺序,先触发父的事件再触发子的事件 --><!-- <div @click.capture="handle">love<div @click.capture="handleClick">hello world</div></div> --><!-- 按键修饰符 --><!-- @keydown.enter 只有点击enter键时候才会执行后面的函数 --><!-- @keydown.esc @keydown.tab @keydown.delete 等等 --><!-- <input @keydown.enter="handleKeyDown" /> --><!-- 系统修饰符 --><!-- 和按键修饰符差不多,有四个 --><!-- @keydown.ctrl --><!-- @keydown.alt --><!-- @keydown.shift --><!-- @keydown.meta 有些特殊键盘有这个键--><!-- 即要想执行后面的函数,关按键是不够的,还需要按下对应的系统键 --><!-- <input @keydown.shift="handleKeyDown" /> --><!-- 鼠标修饰符 --><!-- @click.right 监听鼠标右键的点击事件 --><!-- @click.left 监听鼠标左键的点击事件 --><!-- @click.middle 监听鼠标中键的点击事件 --><!-- <div @click.right="handleMouseClick">click</div> --></div><script>var vm = new Vue({el: "#app",methods: {handleClick: function (e) {console.log("儿子");},handle: function (e) {console.log("爸爸");},handleKeyDown:function(e){console.log(e.target.value)},handleMouseClick:function(e){console.log("right")}}})</script>
</body></html>
十四、表单绑定v-model
<!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><script src='./vue.js'></script>
</head><body><!-- 表单绑定主要是指 v-model --><!-- v-model不仅可以用于 <input>标签还可以 --><div id="app"><!-- <input v-model="value" type="text"> --><!-- <textarea v-model="value"></textarea> --><!-- <input v-model="value" type="checkbox"> --><!-- <input v-model="value" type="radio" value="test"> --><!-- select v-model的value值优先选择option里的value(1,2,3),没有value才选择innerHtml(A,B,C) --><!-- <select v-model="value"><option disabled>----请选择-----</option> 这个是为了更好的用户体验<option value="1">A</option><option value="2">B</option><option value="3">C</option></select> --><!-- {{value}} --><!-- 表单修饰符 --><!-- <input type="text" v-model.lazy="value" /> --><!-- <input type="text" v-model.number="value" /> --><!-- <input type="text" v-model.trim="value" /> --><!-- v-model.number 不加时,123也会判断为string类型,加了之后会把能转换为number类型的都转换为number类型再输出 --><!-- v-model.lazy 当输入框失焦的时候才输出 --><!-- v-model.trim 去首尾空格修饰符后才输出 -->{{value}}</div><script>var vm = new Vue({el: "#app",data:{value:""},watch:{value:function(){console.log(typeof this.value)}}})</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>组件细节点</title><script src='./vue.js'></script>
</head><body><div id="root"><!-- 知识点1 用is解决h5标签上的一些小bug--><!-- 因为tbody里面只能接<tr> --><!-- 因为ul里面只能接<li> --><!-- 因为ol里面只能接<li> --><!-- 因为select里面只能接<option> --><!-- 故以上的都用 is属性来接所设置的子组件名字 --><!-- <table><tbody><tr is="row"></tr><tr is="row"></tr><tr is="row"></tr></tbody></table><table><ul><li is="row"></li><li is="row"></li><li is="row"></li></ul></table><table><ol><li is="row"></li><li is="row"></li><li is="row"></li></ol></table><select><option is="row"></option><option is="row"></option><option is="row"></option></select> --><!-- 知识点2 子组件当中定义data,data必须是一个返回对象的函数。只有在根组件实例中,data才可以是一个对象--><!-- <table><tbody><tr is="row"></tr><tr is="row"></tr><tr is="row"></tr></tbody></table> --><!-- 知识点3 ref --><!-- ref 获取dom或实例引用的语法 --><!-- ref在dom标签上,则this.$refs.name 获取的是这个dom元素 --><!-- ref在组件上,则this.$refs.name 获取的是这个组件的引用,即这个vue子组件实例的引用 --><!-- ref在组件的知识点见知识点4 --><!-- <divref='hello'@click="handleClick">hello world</div> --><!-- 知识点4 --><!-- 实现一个计算器求和的功能 --><!-- ref在组件上,在父组件用this.$refs.name 获取的是这个子组件的引用,即这个vue子组件实例的引用 --> <counter ref="one" @change="handleChange"></counter><counter ref="two" @change="handleChange"></counter><div>{{total}}</div></div><script>// 知识点1// Vue.component('row', {// template: '<tr><td>this is a row</td></tr>'// })// 知识点2 data// Vue.component('row', {// 下面这样错误,只有根组件的data才可以是对象形式// data:{// content:"this is a row"// },// 子组件的data应该是function形式 这个函数返回一个对象// 这样设置的目的是每一个子组件<row>是独享一套数据,而不是和其他<row>共享同一套数据,这样就不会出现不同子组件之间数据互相影响的情况// data:function(){// return {// content:"this is a row"// }// },// template: '<tr><td>{{content}}</td></tr>'// })// 知识点3 ref// vue不建议我们直接操作dom,而是希望通过操作数据来实现对dom的操作// 但必要情况下,我们需要直接操作dom,这就需要用到ref// var vm = new Vue({// el: '#root',// methods:{// handleClick:function(){// alert('click')// this.$refs 指的是整个vue实例中所有的引用// this.$refs.hello 指的是ref名为hello的dom元素// console.log(this.$refs.hello);// console.log(this.$refs.hello.innerHTML);// }// }// })// 知识点4Vue.component('counter',{template:'<div @click="handleClick">{{number}}</div>',data:function(){return {number:0}},methods:{handleClick:function(){this.number++;this.$emit('change')}}})// 注意computed不能监听refs的变化,只能放在methods当中var vm=new Vue({el:'#root',data:{total:0},methods:{handleChange:function(){// 为了父组件能够对两个子组件的数据进行求和,这时候需要用到ref方法// console.log(this.$refs.one.number);this.total=this.$refs.one.number+this.$refs.two.number}}})</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>父传子</title><script src='./vue.js'></script>
</head><body><div id="root"><!-- 父传子 props 单项数据流--><!-- :count="0" 0是数字 "0"是js表达式 --><!-- count="0" 0是字符串 --><counter :count="1"></counter><counter :count="2"></counter></div><script>var counter = {props: ['count'],data: function () {return {number: this.count}},template: "<div @click='handleClick'>{{number}}</div>",methods: {handleClick: function () {// 下面这样直接操作父组件传过来的数据,虽然可以操作成功,但是控制台会报警告说不要这样操作// 单向数据流:子组件只能接收使用父组件传过来的数据,而不可以进行操作// 因为万一传过来的不是值数据而是引用型数据的话,子组件再修改数据,会引起混乱this.number++;}}}var app = new Vue({el: '#root',// 注意局部组件才需要注册components: {counter: counter}})</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>子传父</title><script src='./vue.js'></script>
</head><body><div id="root"><!-- 子监听父的 --><!-- 监听事件 @加上事件名 例如 @inc= --><counter :count="3" @inc="handleInc"></counter><counter :count="2" @inc="handleInc"></counter><div>{{total}}</div></div><script>var counter = {props: ['count'],data: function () {return {number: this.count}},template: "<div @click='handleClick'>{{number}}</div>",methods: {handleClick: function () {this.number = this.number + 2;// 子传父,通过触发事件并且携带参数的方式// 子传父 发送事件名,后面为带过去的数据this.$emit('inc', 2)}}}var app = new Vue({el: '#root',data: {total: 5},components: {counter: counter},methods: {handleInc: function (step) {this.total += step;}}})</script>
</body></html>
十八、组件参数校验和非props
<!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>组件参数校验和非props</title><script src='./vue.js'></script>
</head><body><div id="root"><child content="hello world"></child><child content="hell"></child><!-- 下面为Number,不会通过String类型的校验 控制台会报错 --><!-- <child :content="123"></child> --></div><script>// 组件参数校验// 指的是子组件对父组件传递过来的content进行一些校验,比如必须要是字符串,如果是别的我不要// 要进行参数校验的话,就不能是props:['content']这种数组格式,应该写成对象,如下// props特性:父传子,子要接(一个属性),即子在props内进行了声明 父子组件有一个对应关系// 非props特性:父传子,子不接(一个属性),即子没有在props内进行声明// props特性的特点:// (1)传递的这个属性不会出现在最终渲染的标签上// (2)子可以通过插值表达式或者this.的方式获取父传过来的属性值// 非props特性的特点:// (1)传递的这个属性 会展示在子组件最外面的dom标签的html之中,即是attribute而不是property// (2)子无法获取父组件的这个内容,没法用Vue.component('child', {// 校验1// props: {// content: Number// },// 校验2 // props: {// content: [Object, String]// },// 校验3 // props: {// content: {// type: Number// }// },// 校验4// props: {// content: {// type: String,// required:false, //true指的是这个值是必传的,就会报错。false则是可传可不传// default:'default value' //required:false 时如果没传则会用这个默认值// 更复杂的校验项// validator: function (value) {// 要求传过来的值的长度要大于5,否则报错// return (value.length > 5)// }// }// },template: "<div>{{content}}</div>"})var app = new Vue({el: '#root'})</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>给组件绑定原生事件</title><script src='./vue.js'></script>
</head><body><div id="root"><!-- @click.native --><!-- 加了native之后,此时监听的是原生事件,而不是组件的自定义事件 --><!-- 给组件绑定原生事件:在后面加上 .native修饰符即可 --><child @click.native="handleClick"></child></div><script>Vue.component('child', {template: '<div>Child</div>',// template: '<div @click="handleClick">Child</div>',// methods: {// handleClick: function () {// // alert('child click');// this.$emit('click');// }// }})var app = new Vue({el: '#root',methods: {handleClick: function () {alert('click')}}})</script>
</body></html>
二十、非父子组件传值(Bus/总线/发布订阅模式/观察者模式)
<!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>非父子组件传值(Bus/总线/发布订阅模式/观察者模式)</title><script src='./vue.js'></script>
</head><body><div id="root"><child content="Dell"></child><child content="Lee"></child></div><script>Vue.prototype.bus = new Vue();// 这样可以使后面创建的每个组件或者每个vue实例都具有bus这个属性// 并且这个vue属性将指向同一个vue实例// 这个vue实例存在的意义Vue.component('child', {data: function () {return {selfContent: this.content}},props: {content: String},template: "<div @click='handleClick'>{{selfContent}}</div>",methods: {handleClick: function () {// console.log(this.content);this.bus.$emit('change', this.selfContent);}},// this.bus是一个vue实例,所以具有emit和on方法mounted: function () {this.bus.$on('change', (msg) => {// alert(msg)this.selfContent = msg;})}})var app = new Vue({el: '#root'})</script>
</body></html>
二十一、vue插槽(slot)
<!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>vue插槽(slot)</title><script src='./vue.js'></script>
</head><body><div id="root"><!-- 旧的方案 props --><!-- <child content="<p>Dell</p>"></child> --><!-- 新的方案 slot --><!-- <child><p>Dell</p></child><child></child> --><!-- 具名插槽 slot --><body-content><div class="header" slot="header">header</div><div class="footer" slot="footer">footer</div></body-content></div><script>// 插槽的使用场景// 需求:div标签里面不仅要展示p标签,还需要展示一个标签,但是这个标签不是由子组件决定的,是由父组件传递过来的// 1.按以前的解决方法:props// 缺点1:// 这样会在p标签外多一层div标签// <div v-html="this.content"></div>// 这个模板占位符不管用// <template v-html="this.content"></template>// 缺点2:// 一旦父组件传递过来的内容变多了,就会变得阅读性困难// 单插槽// 2.这时候我们需要用新的解决方案:插槽 slot// 即如何在父子组件之间优雅的传递dom// 在子组件当中直接用<slot></slot> 即可把父组件传递的展示出来// 在子组件当中直接用<slot>默认内容</slot>,若父组件不传递内容过来便展示默认内容,若传递则展示父组件的// 多插槽 具名插槽// Vue.component('child',{// props:['content'],// template:`<div>// <p>hello</p>// <slot>默认内容</slot>// </div>`// })// 具名插槽Vue.component('body-content',{props:['content'],template:`<div><slot name="header"></slot><p>hello</p><slot name="footer"></slot></div>`})var app = new Vue({el: '#root'})</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>作用域插槽</title><script src='./vue.js'></script>
</head><body><div id="root"><child><template slot-scope="props1"><li>{{props1.item}}--hello</li></template></child></div><script>Vue.component('child', {data: function () {return {list: [1, 2, 3, 4]}},template: `<div><ul><slot v-for="item of list":item=item></slot></ul></div>`})var app = new Vue({el: '#root'})</script>
</body></html>
二十三、动态组件 v-once
<!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><script src='./vue.js'></script>
</head><body><div id="root"><!-- <component></component>就是vue里的动态组件 --><!-- 动态组件定义:根据is值的变化动态的加载不同的组件 --><component :is="type"></component><!-- 原始组件 --><child-one v-if="type==='child-one'"></child-one><child-two v-if="type==='child-two'"></child-two><button @click="handleClick">change</button><!-- v-once 内部内容只渲染一次,即使内部内容依赖数据发生变化也不重新渲染 --></div><script>Vue.component('child-one', {template: "<div>child-one</div>"})Vue.component('child-two', {template: "<div>child-two</div>"})var app = new Vue({el: '#root',data: {type: "child-one"},methods: {handleClick: function () {this.type = (this.type === 'child-one' ? 'child-two' : 'child-one')}}})</script>
</body></html>