Vue框架
一.导读:
1.什么是Vue
Vue.js是一个渐进式JavaScript框架
渐进式:vue从小到控制页面中的一个变量到页面一块内容到整个页面,最终大到整个项目,都可以用vue框架来实现
2.vue可以做哪些事
将数据渲染到指定区域(数据可以是后台获取,也可以由前台自己产生)
可以与页面完成基于数据的交互方式
3.为什么学习Vue
1.整合了Angular React框架的优点(第一手API文档是中文的)
2.单页面应用(得益于vue的组件化开发 => 前台代码的复用),减少IO,提高效率
3.虚拟DOM(提高操作DOM的效应)
4.数据的双向绑定(如:两个输入框同步数据)
二.如何使用Vue:
1 <body> 2 <div id="box1"> 3 <!--{{ }} 会被vue解析为数据的渲染的指定语法--> 4 {{ }} 5 </div> 6 <hr> 7 <div class="box2"> 8 {{ }} 9 </div> 10 </body> 11 <script src="js/vue.js"></script> 12 <script> 13 // 如何使用jq框架 <= 拿到jq框架的对象 $ | jQuery 14 // 类比:如何使用vue框架 <= 拿到vue框架的对象 new Vue() 15 16 // vue对象需要手动创建, 原因:一个vue对象可以只控制页面中的某一部分, 如果一个页面有多个部分都需要被控制,那么就需要创建多个vue对象 17 // vue对象如何与控制的页面进行关联(绑定),采用的是vue对象中的挂载点(挂载点可以唯一标识页面中的某一个区域) 18 new Vue({ 19 el: "#box1" 20 // 挂在在id为box1的div上,那么该div下的所有内容都由该vue对象来控制 21 }) 22 23 new Vue({ 24 el: '.box2' 25 // 挂在在class为box2的div上,那么该div下的所有内容都由该vue对象来控制(尽量使用id,唯一标识) 26 }) 27 </script>
三.Vue实例成员:
1.挂载点
new Vue({ el: '#app' }) // 实例与页面挂载点一一对应 // 一个页面中可以出现多个实例对应多个挂载点 // 实例只操作挂载点内部内容
2.数据data
1 <body> 2 <div id="app"> 3 {{ msg }} 4 </div> 5 </body> 6 <script src="js/vue.js"></script> 7 <script> 8 // Vue实例会根据数据产生虚拟DOM,最终替换掉挂载点的真实DOM(不要挂在到body上) 9 var app = new Vue({ 10 el: '#app', 11 data: { 12 msg: "今晚嘿嘿" 13 } 14 }); 15 16 // 如果需要使用vue对象(实例), 那么久可以接受Vue创建的结果, 反之就不需要接收 17 console.log(app); 18 console.log(app.$attrs); // vue实例的变量都是以$开头 19 console.log(app.$el); 20 console.log(app.$data.msg); 21 console.log(app.msg); 22 // app对象 = new Vue()实例 = 标签div #app组件 23 24 </script>
3.方法methods
1 <style> 2 .box { background-color: orange } 3 </style> 4 <div id='app'> 5 <p class="box" v-on:click="pClick">测试</p> 6 <p class="box" v-on:mouseover="pOver">测试</p> 7 </div> 8 <script> 9 var app = new Vue({ 10 el: '#app', 11 methods: { 12 pClick () { 13 // 点击测试 14 }, 15 pOver () { 16 // 悬浮测试 17 } 18 } 19 }) 20 </script> 21 <!-- 了解v-on:为事件绑定的指令 --> 22 <!-- methods为事件提供实现体-->
4.计算computed
1 <body> 2 <div id="app"> 3 姓<input type="text" v-model="first_name"> 4 <hr> 5 名<input type="text" v-model="last_name"> 6 <hr> 7 <p>{{ first_name + " " + last_name }}</p> 8 <p>{{ full_name_fn() }}</p> 9 <!-- 一个变量的值依赖于多个变量的值 --> 10 <p>{{ full_name }}</p> 11 </div> 12 </body> 13 <script src="js/vue.js"></script> 14 <script> 15 new Vue({ 16 el: "#app", 17 data: { 18 first_name: "", 19 last_name: "", 20 }, 21 methods: { 22 // 声明的是函数, 该函数必须手动调用 23 full_name_fn: function () { 24 return this.first_name + " " + this.last_name 25 } 26 }, 27 computed: { 28 // 声明变量full_name, 该变量的值等于后方函数的返回值 29 // 函数中包含的所有vue变量值只要有发生变化的系统就会调用该函数 30 full_name: function () { 31 return this.first_name + " " + this.last_name 32 } 33 } 34 }) 35 </script>
5.监听watch
1 <body> 2 <div id="app"> 3 姓名<input type="text" v-model="full_name"> 4 <hr> 5 <p>{{ first_name }}</p> 6 <hr> 7 <p>{{ last_name }}</p> 8 </div> 9 </body> 10 <script src="js/vue.js"></script> 11 <script> 12 new Vue({ 13 el: "#app", 14 data: { 15 full_name: "", 16 first_name: "", 17 last_name: "", 18 }, 19 watch: { 20 // wacth只是对已有的变量进行值变化的监听, 一旦发现值变化,系统自动回调监听变量后的函数 21 // 后方函数和前方变量只有数据变化的监听绑定关系, 没有值相关的联系 22 full_name: function () { 23 arr = this.full_name.split(" "); 24 this.first_name = arr[0]; 25 this.last_name = arr[1]; 26 } 27 } 28 }) 29 </script>
四.基础指令
1.文本指令(v-text/v-html)
1 <body> 2 <div id="app"> 3 <p>{{ info }}</p> 4 <!-- v-text 为vue的文本指令 ="info" , info为vue实例data中的一个变量 --> 5 <p v-text="info"></p> 6 <p v-text="msg"></p> 7 <p v-html="res"></p> 8 </div> 9 </body> 10 <script src="js/vue.js"></script> 11 <script> 12 new Vue({ 13 el: "#app", 14 data: { 15 info: "插值表达式", 16 msg: "文本指令", 17 res: "<b>加粗的文本</b>" 18 } 19 }) 20 </script>
2.属性指令(v-bind/:)
1 <body> 2 <div id="app"> 3 <!-- v-bind:属性 = "变量" --> 4 <!-- 如果abc自定义属性被v-bind:指令绑定了,后面的值也会成为vue变量, 如果就想是普通字符串, 再用''包裹 --> 5 <!-- : 就是 v-bind: 的简写方式 (1.常用 2.一定且只操作属性)-->
#abc不是变量名 6 <p v-bind:abc="'abc'" v-bind:title="h_info" :def="hehe">abc</p> 7 8 <!--最常用的两个属性 class | style--> 9 10 <!--class--> 11 <p :class="a"></p> <!-- 单类名 --> 12 <p :class="[a, b]"></p> <!-- 多类名 --> 13 <p :class="{c: d}"></p> <!-- 了解: c为类名,是否起作用取决于d值为true|false 开关类名 --> 14 <!--style--> 15 <p :style="s1"></p> <!-- s1为一套样式 --> 16 <p :style="[s1, s2, {textAlign: ta}]">12345</p><!-- 了解: s1,s2均为一套样式, ta是一个变量,专门赋值给textAlign("text-align") --> 17 18 </div> 19 </body> 20 <script src="js/vue.js"></script> 21 <script> 22 new Vue({ 23 el: "#app", 24 data: { 25 h_info: "悬浮提示", 26 hehe: "呵呵", 27 a: 'active', 28 b: 'rule', 29 d: false, 30 s1: { // 样式1: 值1, ..., 样式n: 值n 31 width: '200px', 32 height: '200px', 33 background: 'red' 34 }, 35 s2: { 36 borderRadius: '50%' 37 }, 38 ta: 'center' 39 } 40 }) 41 </script>
3.事件指令(v-on:click/@click)
1 <body> 2 <div id="app"> 3 <!-- v-on:事件 = "变量 简写 @ --> 4 <!-- 事件绑定的变量可以在data中赋值,但建议在methods中赋值 --> 5 <p v-on:click="fn1">11111111111111</p> 6 <p @click="fn2">22222222222222</p> 7 <!--vue事件的绑定可以传自定义参数--> 8 <p @click="fn3(333)">3333333333333333</p> 9 <!--vue事件的绑定不传自定义参数, 默认将事件对象传过去了--> 10 <p @click="fn4">4444444444444444</p> 11 <!--vue事件的绑定传自定义参数, 还要将事件对象传过去了, 要明确传$event--> 12 <p @click="fn5(555, $event)">5555555555555555</p> 13 14 </div> 15 </body> 16 <script src="js/vue.js"></script> 17 <script> 18 new Vue({ 19 el: "#app", 20 data: { 21 // 事件在data中提供一个函数地址,可以实现事件 22 fn1: function () { 23 console.log("11111111111111") 24 } 25 }, 26 // 事件尽量(要求)都放在vue实例的methods中 27 methods: { 28 fn2: function () { 29 console.log("22222222222222") 30 }, 31 fn3 (arg) { // ES6语法 32 console.log(arg) 33 }, 34 fn4: function (ev) { 35 console.log(ev) 36 }, 37 fn5: function (arg, ev) { 38 console.log(arg) 39 console.log(ev) 40 }, 41 } 42 }) 43 </script>
4.表单指令(v-model)
1 <body> 2 <div id="app"> 3 <!-- v-model = "变量" 本质操作的就是表单元素的value --> 4 <!--v-model就是完成数据的双向绑定--> 5 <form action=""> 6 <input type="text" v-model="info"> <!-- info变量就是代表输入框的value --> 7 <input type="text" v-model="info"> 8 9 </form> 10 <p> {{ info }} </p> 11 <!--v-once只会被赋值一次,就不再改变,并且要结合插值表达式使用--> 12 <p v-once="info">{{ info }}</p> 13 </div> 14 </body> 15 <script src="js/vue.js"></script> 16 <script> 17 new Vue({ 18 el: "#app", 19 data: { 20 // info: "初始value", 21 info: "" 22 }, 23 }) 24 </script>
5.条件指令(v-if/v-show)
1 <style> 2 .wrap { 3 width: 300px; 4 } 5 .box { 6 width: 100px; 7 height: 100px; 8 } 9 .red { 10 background-color: red; 11 float: left; 12 } 13 .orange { 14 background-color: orange; 15 float: right; 16 } 17 </style> 18 <body> 19 <div id="app"> 20 <button @click="rAction">red切换</button> 21 <button @click="oAction">orange切换</button> 22 <div class="wrap"> 23 <!-- v-if 值为false时, 不会被渲染 --> 24 <!-- 了解 :key由vue控制的属性key值需要唯一标识,因为key的值就是vue对该组件在内存中建立缓存的key --> 25 <div class="box red" v-if="r_show" :key="key" ></div> 26 <!-- v-show 值为false时, 以display:none被渲染 --> 27 <div class="box orange" v-show="o_show"></div> 28 </div> 29 </div> 30 </body> 31 <script src="js/vue.js"></script> 32 <script> 33 new Vue({ 34 el: "#app", 35 data: { 36 r_show: true, 37 o_show: true 38 }, 39 methods: { 40 rAction: function () { 41 this.r_show = !this.r_show; 42 }, 43 oAction: function () { 44 this.o_show = !this.o_show; 45 } 46 } 47 }) 48 </script>
-
条件案例:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <title>条件指令案例</title> 6 <style> 7 .box { 8 height: 100px; 9 } 10 .r { background-color: red } 11 .y { background-color: yellow } 12 .b { background-color: blue } 13 </style> 14 </head> 15 <body> 16 <div id="app"> 17 <ul> 18 <li @click="rfn">红</li> 19 <li @click="yfn">黄</li> 20 <li @click="bfn">蓝</li> 21 </ul> 22 <div class="box r" v-if="tag == 0"></div> 23 <div class="box y" v-else-if="tag == 1"></div> 24 <div class="box b" v-else></div> 25 </div> 26 </body> 27 <script src="js/vue.js"></script> 28 <script> 29 new Vue({ 30 el: '#app', 31 data: { 32 tag: 0 33 }, 34 methods: { 35 rfn: function () { 36 this.tag = 0 37 }, 38 yfn: function () { 39 this.tag = 1 40 }, 41 bfn: function () { 42 this.tag = 2 43 }, 44 } 45 }) 46 </script> 47 </html>
6.循环指令(v-for)
1 <body> 2 <div id="app"> 3 <ul> 4 <li>{{ ls[0] }}</li> 5 <li>{{ ls[1] }}</li> 6 <li>{{ ls[2] }}</li> 7 <li>{{ ls[3] }}</li> 8 </ul> 9 <ul> 10 <li v-for="(ele, index) in ls">{{ ele }} {{ index }}</li> 11 </ul> 12 <ul> 13 <li v-for="(value, key, index) in dic">{{ key }} {{ value }} {{ index }}</li> 14 </ul> 15 </div> 16 </body> 17 <script src="js/vue.js"></script> 18 <script> 19 new Vue({ 20 el: "#app", 21 data: { 22 ls: ['张三', '李四', '王五', '赵六', '钱七'], 23 dic: { 24 name: 'Bob', 25 age: 88, 26 gender: '男' 27 } 28 }, 29 30 }) 31 </script>
-
循环案例:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <title>条件案例</title> 6 <style> 7 li { 8 cursor: pointer; 9 } 10 </style> 11 </head> 12 <body> 13 <div id="app"> 14 <form action=""> 15 <input type="text" v-model="msg"> 16 <button type="button" @click="fn">留言</button> 17 </form> 18 <ul> 19 <li v-for="(m, i) in msgs" @click="deleteAction(i)">{{ m }}</li> 20 </ul> 21 </div> 22 </body> 23 <script src="js/vue.js"></script> 24 <script> 25 new Vue({ 26 el: "#app", 27 data: { 28 msg: "", 29 msgs: ["初始留言"] 30 }, 31 methods: { 32 fn: function () { 33 if (this.msg) { 34 // this.msgs.push(this.msg) // 在后添加 35 this.msgs.unshift(this.msg); // 在前添加 36 //将输入框内文本置空 37 this.msg = ""; 38 } 39 }, 40 deleteAction: function (index) { 41 console.log(index); 42 // 从什么索引开始 操作多少位 操作是什么,不写就替换为空 43 this.msgs.splice(index, 1) 44 } 45 } 46 }) 47 </script> 48 </html>
五.组件
-
组件初识:
- 每个组件均具有自身的模板template,根组件的模板就是挂载点
1 <body> 2 <div id="app"> 3 {{ msg }} 4 </div> 5 </body> 6 <script src="js/vue.js"></script> 7 <script> 8 // 每个组件均具有自身的模板template,根组件的模板就是挂载点 9 new Vue({ 10 // 根组件一定需要挂载点(否则无法渲染到页面中), 一般情况下, 根组件的template就取挂载点,不需要自定义 11 el: "#app", 12 data: { 13 msg: "信息" 14 }, 15 // template就是组件的html架构 16 // 每个组件模板只能拥有一个根标签 17 template: "<div><p>锻炼</p></div>" 18 }) 19 </script>
1.根组件(new Vue)
1 <div id="app"> 2 <h1>{{ msg }}</h1> 3 </div> 4 <script type="text/javascript"> 5 // 通过new Vue创建的实例就是根组件(实例与组件一一对应,一个实例就是一个组件) 6 // 每个组件组件均拥有模板,template 7 var app = new Vue({ 8 // 根组件的模板就是挂载点 9 el: "#app", 10 data : { 11 msg: "根组件" 12 }, 13 // 模板: 由""包裹的html代码块,出现在组件的内部,赋值给组件的$template变量 14 // 显式书写模块,就会替换挂载点,但根组件必须拥有挂载点 15 template: "<div>显式模板</div>" 16 }) 17 // app.$template 18 </script>
2.局部组件(var localTag)
-
点击次数案例
1 <body> 2 <div id="app"> 3 <abc></abc> 4 <abc></abc> 5 <abc></abc> 6 </div> 7 <hr> 8 <div id="main"> 9 <local-tag></local-tag> 10 <local-tag></local-tag> 11 </div> 12 </body> 13 <script src="js/vue.js"></script> 14 <script> 15 // 局部组件 16 var localTag = { 17 // 子组件的数据具有作用域,以达到组件的复用, 每一个复用的组件具有自身独立的一套数据 18 data: function () { 19 return { // 返回值是一个数据字典(一套数据) 20 count: 0 21 } 22 }, 23 template: "<div @click='fn'>点击{{ count }}次</div>", 24 methods: { 25 fn: function () { 26 this.count += 1; 27 } 28 } 29 } 30 31 // app根组件 32 new Vue({ 33 el: "#app", 34 // 注册 35 components: { 36 'abc': localTag 37 } 38 }) 39 // main根组件 40 new Vue({ 41 el: "#main", 42 components: { 43 // localTag 44 'local-tag': localTag 45 } 46 }) 47 </script>
3.全局组件(Vue.component)
1 <body> 2 <!-- 两个全局vue实例可以不用注册全局组件,就可以使用 --> 3 <div id="app"> 4 <global-tag></global-tag> 5 </div> 6 <div id="main"> 7 <global-tag></global-tag> 8 </div> 9 </body> 10 <script src="js/vue.js"></script> 11 <script> 12 // 创建全局组件 组件名 {} 13 Vue.component('global-tag', { 14 template: "<div @click='fn'>全局组件点击了 {{ count }} 次</div>", 15 data: function () { 16 return { 17 count: 0 18 } 19 }, 20 methods: { 21 fn: function () { 22 this.count++; 23 } 24 } 25 }); 26 // 两个挂载点 27 new Vue({ 28 el: "#app", 29 }); 30 new Vue({ 31 el: "#main", 32 }); 33 </script>
六.信息传递
1.
采用属性绑定的方式 1.父级提供数据 2.绑定给子组件的自定义属性 3.子组件通过props的数组拿到自定义属性从而拿到数据
1 <body> 2 <div id="app"> 3 <input type="text" v-model="sup_data"> 4 <!-- 步骤2 -->子组件的自定义属性 5 <global-tag :abcde="sup_msg" :sup_data="sup_data"></global-tag> 6 </div> 7 </body> 8 <script src="js/vue.js"></script> 9 <script> 10 // 创建全局组件,子组件 11 Vue.component('global-tag', { 12 // 步骤3 13 props: ['abcde', 'sup_data'], 14 template: "<div @click='fn'>{{ abcde }}</div>", 15 methods: { 16 fn: function () { 17 alert(this.sup_data) 18 } 19 } 20 }); 21 // 将父组件的信息传递给子组件 22 // 采用属性绑定的方式: 1,父级提供数据 2.绑定给子组件的自定义属性 3.子组件通过props的数组拿到自定义属性从而拿到数据 23 new Vue({ 24 el: "#app", 25 data: { 26 // 步骤1 27 sup_msg: "父级的msg", 28 sup_data: "" 29 } 30 }); 31 </script>
采用发生事件的方式: 1.在子组件的内容系统事件中来定义一个自定义事件,采用$emit绑定到自定义组件名上(可以携带子组件内容数据) 2.在父组件复用子组件时, 实现子组件自定义数据的功能, 在父组件中的methods中为功能绑定函数(函数的参数就是携带出来的数据) 3.当子组件内部激活系统事件,就会激活自定义事件,$emit发生给父级,激活父级绑定的函数,该函数被执行,同时拿到数据
1 <body> 2 <div id="app"> 3 <!-- abc为子组件的自定义事件,该事件的含义要在子组件内容声明规定 --> 4 <!-- 2 --> 5 <global-tag @abc="action"></global-tag> 6 <global-tag @abc="action"></global-tag> 7 {{ sup_info }} 8 </div> 9 10 </body> 11 <script src="js/vue.js"></script> 12 <script> 13 // 创建全局组件,子组件 14 Vue.component('global-tag', { 15 template: "<div><input v-model='info'><p @click='sendMsg'>子组件</p></div>", 16 data: function () { 17 return { 18 info: "", 19 msg: "子组件的信息" 20 } 21 }, 22 methods: { 23 // 1 24 sendMsg: function () { 25 // alert(123) 26 // 激活自定义事件 abc 27 this.$emit('abc', this.msg, this.info) 28 }, 29 30 } 31 });37 new Vue({ 38 el: "#app", 39 data: { 40 sup_info: "" 41 }, 42 methods: { 43 // 3 44 action: function (msg, info) { 45 alert(msg) 46 this.sup_info = info 47 } 48 } 49 }); 50 </script>
-----组件完成留言板-----
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <title>留言板</title> 6 <style> 7 ul { 8 margin: 0; 9 padding: 0; 10 } 11 a { 12 color: black; 13 text-decoration: none; 14 display: block; 15 height: 21px; 16 } 17 p { 18 margin: 0; 19 color: orange; 20 float: left; 21 } 22 span { 23 color: red; 24 float: right; 25 } 26 </style> 27 </head> 28 <body> 29 <div id="app"> 30 <input type="text" v-model="msg"> 31 <button @click="btnClick">留言</button> 32 <hr> 33 <ul> 34 <!-- 如果每一个渲染的列表项是一个相对复杂的结构, 该复杂的结构可以封装成组件 --> 35 <li v-for="(v, i) in list"> 36 <global-tag :value="v" :index="i" @delete="delAction"></global-tag> 37 </li> 38 </ul> 39 </div> 40 </body> 41 <script src="js/vue.js"></script> 42 <script> 43 new Vue({ 44 el: "#app", 45 data: { 46 msg: "", 47 list: [], 48 list2: [] 49 }, 50 methods: { 51 btnClick: function () { 52 if (this.msg) { 53 this.list.push(this.msg); 54 this.msg = ""; 55 } 56 }, 57 delAction: function (index) { 58 this.list.splice(index, 1) 59 } 60 } 61 }); 62 63 Vue.component('global-tag', { 64 props: ['value', 'index'], 65 template: "<a href='javascript:void(0)'><p>{{ value }}</p><span @click='sendDel'>x</span></a>", 66 methods: { 67 sendDel: function () { 68 this.$emit('delete', this.index) 69 } 70 } 71 }); 72 </script> 73 </html>