MVC是后端的分层开发概念
MVVM是前端视图层的概念,主要关注于视图层分离,也就是说:MVVM把前端的视图层分为了三部分Model、View、VM ViewModel
为什么有了MVC还要有MVVM.
分层处理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y8mTvcIh-1599142789218)(img/1593352884511.png)]
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script src="vue.js"></script> <title>Document</title> </head> <body> <!-- 将来new的vue实例,会控制这个 元素中的所有内容 --> <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中要用到的数据 //通过Vue提供的指令,很方便的就能把数据渲染到页面上,程序员不再手动操作DOM元素了 // 【前端的Vue之类的框架,不提倡我们去手动操作DOM元素了】 msg: "欢迎学习vue", } }) </script> </body> </html>v-cloak该属性默认都让该元素display为none;
用法:
这个指令保持在元素上直到关联实例结束编译。和 CSS 规则如 [v-cloak] { display: none }一起用时,这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕。
1.网速调慢,v-cloak不加类样式会有闪烁问题,而v-text默认没有闪烁问题。同时,v-text是没有写插值表达式。
2.v-text会覆盖元素中原本的内容,但是,插值表达式 只会替换自己的这个占位符,不会把整个元素内容清空
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VhJMkmiC-1599142789223)(img/1593433205696.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-57bUhdPr-1599142789225)(img/1593433244866.png)]
v-cloak:解决闪烁问题
v-text=“msg”:在元素中填充数据(如果数据中有标签元素,不会转义,直接把标签输出)
v-html=“msg”:在元素中填充数据(如果数据中有标签元素,会把该元素转成DOM元素输出
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Nuq3nbdA-1599142789228)(img/1593434156579.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RoKycPYk-1599142789230)(img/1593434167243.png)]
v-bind是vue中,提供的用于绑定属性的指令
注意;
v-bind:指令可以被简写为 :要绑定的属性
v-bind中,可以写合法的JS表达式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3Ydjy1ai-1599142789231)(img/1593434439074.png)]
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <!-- 将来new的vue实例,会控制这个 元素中的所有内容 --> <div id="app"> <!-- v-bind是vue中,提供的用于绑定属性的指令 --> <!-- <input type="button" value="按钮"v-bind:title="mytitle + '123'"> --> <!-- 简写方式,只留个冒号,等同于v-bind: --> <input type="button" value="按钮" :title="mytitle + '123'"> </div> <script src="vue.js"></script> <script> var vm = new Vue({ el: "#app", data: { mytitle:"这是一个自己定义的title " } }) </script> </body> </html>[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5ZqnvShK-1599142789232)(img/1593435095210.png)]
v-on缩写为 @绑定事件类型
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <!-- 将来new的vue实例,会控制这个 元素中的所有内容 --> <div id="app"> <!-- DOM操作示例 --> <!-- <input type="button" value="按钮" :title="mytitle + '123'" id="btn"> --> <input type="button" value="按钮" v-on:click="show"> <input type="button" value="按钮" v-on:mouseover="show"> </div> <script src="vue.js"></script> <script> var vm = new Vue({ el: "#app", data: { mytitle:"这是一个自己定义的title " }, methods:{ //这个methods属性中定义了当前vue实例所有可用的方法 show:function(){ alert("你好啊沙雕!") } } }) // // DOM操作 // document.getElementById("btn").οnclick=function(){ // alert("hellow") // } </script> </body> </html>注意:
在vue实例中,如果想要获取data上的数据,或者想要调用methods中的方法,必须通过this.数据属性名 或 this.方法名来进行访问。这里的this就表示我们new出来的VM实例对象
bug存在:采用插值写法即
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JoN7mENi-1599142789234)(img/1593517230301.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vEjV43aS-1599142789235)(img/1593447379991.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-24Fn0689-1599142789236)(img/1593447394964.png)]
阻止冒泡案例。通过 .stop的形式阻止冒泡。其他同上。
总结:
使用.stop 阻止冒泡 //冒泡是从内到外 使用 .prevent 阻止默认行为 //例如链接 使用 .capture 实现捕获触发事件的机制 //捕获是从外到内 使用 .self 实现只有点击当前元素的时候,才会触发事件处理函数 //冒泡和捕获都不会触发,但是只会阻止自己身上的冒泡行为的触发,并不会真正阻止冒泡行为 使用 .once 只触发一次事件函数系统内置的其他按键修饰符
详情查看官网文档
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IBz1je9y-1599142789237)(img/1593709781425.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YdDKmid4-1599142789239)(img/1593710445732.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ffCdnrtG-1599142789241)(img/1593710470740.png)]
注意:只有这一个指令可以实现数据双向绑定
使用 v-model 指令,可以实现表单元素和 Model 中数据的双向数据绑定
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <!-- 将来new的vue实例,会控制这个 元素中的所有内容 --> <div id="app"> <h4> {{msg}} </h4> <input style="width:100%" type="text" v-model="msg"> </div> <script src="vue.js"></script> <script> var vm = new Vue({ el: "#app", data: { msg: "大家都是好学生,爱敲代码,爱学习,爱思考,简直就是完美,没瑕疵~!" }, methods: { //这个methods属性中定义了当前vue实例所有可用的方法 } }) </script> </body> </html>测试:谷歌浏览器实现不了表单数据双向绑定。
谷歌浏览器存在bug;从这个角度来说,谷歌浏览器翻译后,Vue双向数据绑定其实并没有失效,只是翻译导致DOM结构发生了变更,Vue找不到原来的节点去更新数据了。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-daYXykK9-1599142789242)(img/1593528767642.png)]
使用class类样式有以上四种方式。
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>16.中通过属性绑定为元素设置class类样式</title> </head> <style> .red{ color: red; } .thin{ font-weight: 200; } .italic{ font-style: italic; } .active{ letter-spacing: 0.5em; } </style> <body> <div id="app"> <!-- 普通方式 --> <!-- <h1 class=" red thin">这是一个很大很大的标题!!!</h1> --> <!-- 数组方式绑定 需要使用v-bind做数据绑定--> <!-- <h1 :class="['red' ,'thin','italic']">这是一个很大很大的标题!!!</h1> --> <!-- 数组中使用三元表达式写法 --> <!-- <h1 :class="['thin','italic',flag?'red':'']">这是一个很大很大的标题!!!</h1> --> <!-- 数组中使用对象方式写法代替三元表达式,提高代码可读性 --> <h1 :class="['thin','italic',{'red':flag}]">这是一个很大很大的标题!!!</h1> </div> <script src="./vue.js"></script> <script> var vm=new Vue({ el:"#app", data:{ flag:true, }, methods:{} }) </script> </body> </html>[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mZUxqwMV-1599142789243)(img/1593530164100.png)]
主要功能:迭代
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oDdeGOPh-1599142789244)(img/1593531435686.png)]
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> [v-cloak] { display: none; } </style> </head> <body> <div id="app"> <!-- <p v-cloak v-for="item in list">{{item}}</p> --> <p v-cloak v-for="(item,i) in list">索引值:{{i}} === 每一项:{{item}}</p> <!-- 循环对象数组 --> <p v-for="item in list2">{{item.id}} {{item.name}}</p> <p v-for="(val,key) in user">值是:{{val}} === 键是:{{key}}</p> </div> <script src="./vue.js"></script> <script> var vm = new Vue({ el: "#app", data: { list: ["我", "不", 3, 4, 5, 6], list2: [ { id: 1, name: "zs" }, { id: 2, name: "ls" }, { id: 3, name: "lmf" }, { id: 4, name: "fg" } ], user:{ id:1, name:"托尼*乔巴", gender:"男" } }, methods: {} }) </script> </body> </html>
<div id="app"> <!-- in 后面我们放过 普通数组,对象 ,还可以放数字--> <!-- 注意:如果使用v-for迭代数字的话,是从1开始 --> <p v-for="count in 10">这是第{{count}}次循环</p> </div>[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-euTAz6xV-1599142789245)(img/1593534138608.png)]
注意:v-for循环的时候,key属性只能使用number或者string
注意:key在使用的时候 必须使用 v-bind 属性绑定的形式,指定 key 的值
在属性中使用v-for循环的时候,或者在一些特殊情况中,如果v-for 有问题,必须在 使用 v-for 的同时,指定唯一的字符串/数字 类型 :key 值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yUUd9LD4-1599142789246)(img/1593534974263.png)]
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=`, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <input type="button" value="toggle" @click="flag=!flag"> <!-- v-if的特点:每次都会重新删除或创建元素 --> <h3 v-if="flag">这是用v-if控制的元素</h3> <!-- v-show的特点:每次不会重新进行DOM的删除和创建操作,只是切换了元素的display:none样式 --> <h3 v-show="flag">这是用v-show控制的元素</h3> </div> <script src="./vue.js"></script> <script> var vm=new Vue({ el:"#app", data:{ flag:true, }, methods:{ // toggle(){ // this.flag=!this.flag; // } } }) </script> </body> </html>v-if有较高的切换性能消耗;v-show有较高的初始渲染消耗
如果元素涉及到频繁的切换,最好不要使用v-if,推荐v-show;如果元素可能永远也不会显示出来,则推荐使用v-if
day1总结:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e1YmqLSZ-1599142789248)(img/1593536607184.png)]
谷歌对于Vue的调试工具
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vrl7j0oC-1599142789249)(img/1593616310135.png)]
品牌案例
注意:
forEach some filter findIndex //这些都属于数组的新方法,都会对数组中的每一项进行遍历,执行相关的操作。 注意:ES6中,为字符提供了一个新方法,叫做String.prototype.includes("要包含的字符串") //如果包含。则返回true,否则返回false[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wuRTqfg4-1599142789250)(img/1593619808097.png)]
案例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../vue.js"></script> </head> <body> <div id="app"> <p>{{ msg | msgFormat }}</p> </div> <script> // 定义一个Vue全局的过滤器,名字叫做msgFormat Vue.filter("msgFormat",msg=>{ return msg.replace(/单纯/g,"邪恶") }) // 创建vue实例vm var vm = new Vue({ el: "#app", data: { msg: "曾经,我也是一个单纯的少年,傻傻的问谁是世界上最单纯的人" }, methods: {} }) </script> </body> </html>[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EiMwk6km-1599142789252)(img/1593693971953.png)]
注意;Vue中所有的指令,在调用的时候,都以 v- 开头
// 使用Vue.directive()定义全局指令 // 其中参数1:指令名称 注意:在定义的时候,指令的名称前面不需要加v-前缀 // 在调用的时候,必须在前面加上v-前缀 // 参数2:是一个对象,这个对象身上,有一些指令相关的函数,这些函数可以在特定的阶段执行相关的操作 Vue.directive("focus",{ //样式设置,和样式相关的操作,一般都可以在bind中执行 bind:function(el){ //每当指令绑定到元素上的时候,会立即执行这个函数 只执行一次 // 注意:在每个函数中,第一个参数永远是el,表示被绑定了指令的 // 那个元素,这个el参数,是一个原生的JS对象。 // 在元素 刚绑定指令的时候,还没有插入到DOM中去,这时候,调用focus方法没有作用 // 因为一个元素只有插入DOM元素之后,才能获取焦点 // el.focus() }, //行为设置,和JS行为有关的操作,最好在inserted中执行,防止JS行为不生效 inserted:function(el){ //inserted表示元素 插入到DOM中的时候,会执行inserted函数 触发一次 el.focus() }, updated:function(el){ //当VNode更新的时候,会执行updated,可能会触发多次 }[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NM6Qln70-1599142789253)(img/1593883419769.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ErUjDuWb-1599142789254)(img/1593886133013.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IDkXKhPH-1599142789255)(img/1593886147759.png)]
根据以上参数设置:
//元素部分: <p v-color="'blue'"></p> // 自定义一个设置字体颜色的指令 Vue.directive("color",{ // 样式,只要通过指令绑定给了元素,不管这个元素有没有被插入到页面中去,这个元素肯定有了一个内联样式 // 将来元素肯定会显示到页面中去,这时候,浏览器的渲染引擎必然会解析样式,应用给这个元素 bind:function(el,binding){ el.style.color=binding.value } })注意:directive定义私有时,带s的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Cp8BYNI4-1599142789256)(img/1593923258802.png)]
实例:
// 创建Vue实例 var vm=new Vue({ el:"#app2", data:{ dt:"你怎么这么傻逼啊!" }, methods:{}, directives:{ //定义私有指令 'fontweight':{ //设置字体粗细 bind:function(el,binding){ el.style.fontWeight=binding.value } }, //简写方式: 'fontsize':function(el,binding){ //注意:这个function等同于把代码写到bind和updata中去 el.style.fontSize=parseInt(binding.value)+"px" } }[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wRGTnBvq-1599142789257)(img/1593923854280.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RxWIgc7U-1599142789259)(img/1593924335651.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-twSSc7gc-1599142789260)(img/lifecycle.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CIkcHwNM-1599142789261)(img/1593928427429.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NR30pJYu-1599142789262)(img/1593928709910.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IjCBePhb-1599142789263)(img/1593928969279.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bIhziV5i-1599142789265)(img/1593928917148.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bxfgh0Da-1599142789266)(img/1593929205774.png)]
两个函数:
//运行中的两个事件 beforeUpdate(){ //这时候,表示,我们的界面还没有被更新【数据更新了么? 数据肯定更新了】 } updated(){ }[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5wHvfDwP-1599142789267)(img/1593930779384.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xDhzhHga-1599142789268)(img/1593930900775.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fY7mF4Ii-1599142789270)(img/1593931321761.png)]
vue-resource是和vue高度集成的第三方包
除了vue-resource,还可以实使用axios的第三方包实现数据的请求。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jKLZqINp-1599142789271)(img/1593931678828.png)]
使用文档:
https://github.com/pagekit/vue-resource/blob/develop/docs/http.md
vue-resource请求示例:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UvAUCb8x-1599142789273)(img/1593937111638.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hiDn8bW6-1599142789275)(img/1593940250816.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qThmqbJC-1599142789276)(img/1594046939752.png)]
实例:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V5ON0gyG-1599142789277)(img/1594047717923.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iHssZVaX-1599142789279)(img/1594047745595.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XBGZ7OM7-1599142789281)(img/1594049034131.png)]
Vue.http.options.emulateJSON = true;[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8UtEgXGW-1599142789282)(img/1594049133152.png)]
实例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../vue.js"></script> <!-- 自定义两组样式,来控制transition内部元素实现动画 --> <style> /* v-enter【这是一个时间点】,是进入之前,元素的起始状态,此时还没有开始进入 */ /* v-leave-to【这是一个时间点】是动画离开之后,离开的终止状态,此时,元素 动画已经结束 */ .v-enter, .v-leave-to { opacity: 0; transform: translateX(150px); } /* 入场动画时间段*/ /* 离场动画时间段 */ .v-enter-active, .v-leave-active { transition: all .8s ease; } </style> </head> <body> <div id="app"> <input type="button" value="toggle" @click='flag=!flag'> <!-- 需求:点击按钮,让h3显示,再点击,让h3隐藏 --> <!-- 1。使用transition元素,把需要被动画控制得元素,包裹起来 --> <!-- transition元素是Vue官方提的 --> <transition> <h3 v-if="flag">这是一个h3标签</h3> </transition> </div> <script> var vm = new Vue({ el: '#app', data: { flag: false, }, methods: {} }) </script> </body> </html>注意:transition中的name值就是定义前缀,替换样式中的 “.v-” ;同时也是防止冲突
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../vue.js"></script> <!-- 自定义两组样式,来控制transition内部元素实现动画 --> <style> /* v-enter【这是一个时间点】,是进入之前,元素的起始状态,此时还没有开始进入 */ /* v-leave-to【这是一个时间点】是动画离开之后,离开的终止状态,此时,元素 动画已经结束 */ .v-enter, .v-leave-to { opacity: 0; transform: translateX(150px); } /* 入场动画时间段*/ /* 离场动画时间段 */ .v-enter-active, .v-leave-active { transition: all .8s ease; } /* 自定义前缀*/ .vshow-enter, .vshow-leave-to { opacity: 0; transform: translateX(150px); } /* 入场动画时间段*/ /* 离场动画时间段 */ .vshow-enter-active, .vshow-leave-active { transition: all .8s ease; } </style> </head> <body> <div id="app"> <input type="button" value="toggle" @click='flag=!flag'> <!-- 需求:点击按钮,让h3显示,再点击,让h3隐藏 --> <!-- 1。使用transition元素,把需要被动画控制得元素,包裹起来 --> <!-- transition元素是Vue官方提的 --> <transition> <h3 v-if="flag">这是一个h3标签</h3> </transition> <transition name="vshow"> <h3 v-if="flag">自定义前缀</h3> </transition> </div> <script> var vm = new Vue({ el: '#app', data: { flag: false, }, methods: {} }) </script> </body> </html>使用animate.css类库实现动画
链接:
https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.0.0/animate.min.css
官网链接:https://animate.style/
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WgWd5q4e-1599142789283)(img/1594130180311.png)]
基本实例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../vue.js"></script> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.0.0/animate.min.css"> <!-- 入场:bounceIn 离场:bounceOut --> </head> <body> <div id="app"> <input type="button" value="toggle" @click='flag=!flag'> <!-- 需求:点击按钮,让h3显示,再点击,让h3隐藏 --> <transition enter-active-class="animate__animated animate__bounceIn" leave-active-class="animate__animated animate__bounceOut"> <h3 v-if="flag">这是一个h3标签</h3> </transition> </div> <script> var vm = new Vue({ el: '#app', data: { flag: false, }, methods: {} }) </script> </body> </html>可以在 attribute 中声明 JavaScript 钩子
<transition //入场钩子函数 v-on:before-enter="beforeEnter" v-on:enter="enter" v-on:after-enter="afterEnter" v-on:enter-cancelled="enterCancelled" //离场钩子函数 v-on:before-leave="beforeLeave" v-on:leave="leave" v-on:after-leave="afterLeave" v-on:leave-cancelled="leaveCancelled" > <!-- ... -->methods里对应函数写法
// ... methods: { // -------- // 进入中 // -------- beforeEnter: function (el) { // ... }, // 当与 CSS 结合使用时 // 回调函数 done 是可选的 enter: function (el, done) { // ... //这里的done其实就是afterEnter函数 done() }, afterEnter: function (el) { // ... }, enterCancelled: function (el) { // ... }, // -------- // 离开时 // -------- beforeLeave: function (el) { // ... }, // 当与 CSS 结合使用时 // 回调函数 done 是可选的 leave: function (el, done) { // ... done() }, afterLeave: function (el) { // ... }, // leaveCancelled 只用于 v-show 中 leaveCancelled: function (el) { // ... } }实例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../vue.js"></script> <style> .ball { width: 15px; height: 15px; border-radius: 50%; background-color: red; } </style> </head> <body> <div id="app"> <input type="button" value="快到碗里来" @click="flag=!flag"> <!-- 使用transition把小球包裹起来 --> <transition @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter"> <div class="ball" v-if="flag"></div> </transition> </div> <script> var vm = new Vue({ el: "#app", data: { flag: 'false' }, methods: { // 注意:动画钩子函数的第一个参数:el ,表示要执行动画的那个DOM元素,是个原生的JS DOM对象 beforeEnter(el) { // 动画入场之前,动画尚未开始,可以设置起始样式 el.style.transform = "translate(0,0)" }, enter(el,done) { // 这句话,没有实际的作用,但是,如果不写,出不来动画效果 // 可以认为 el.offsetWidth 会强制动画刷新 el.offsetWidth // 表示动画开始之后的样式,这里,可以设置小球动画完成之后的,结束状态 el.style.transform = "translate(150px,450px)" el.style.transition="all 1s ease" done() }, afterEnter(el) { console.log("this ok") this.flag=!this.flag } } }) </script> </body> </html>注意:当只用 JavaScript 过渡的时候,在 enter 和 leave 中必须使用 done 进行回调。否则,它们将被同步调用,过渡会立即完成。
那么怎么同时渲染整个列表,比如使用 v-for?在这种场景中,使用 `` 组件。在我们深入例子之前,先了解关于这个组件的几个特点:
不同于 ,它会以一个真实元素呈现:默认为一个。你也可以通过 tag attribute 更换为其他元素。过渡模式不可用,因为我们不再相互切换特有的元素。内部元素总是需要提供唯一的 key attribute 值。CSS 过渡的类将会应用在内部的元素中,而不是这个组/容器本身。实例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../vue.js"></script> <style> li { border: 1px solid #999; margin: 9px; padding-left: 5px; line-height: 35px; font-size: 12px; } li:hover{ background-color: hotpink; transition: all .5 ease; } .v-enter-, .v-leave-to { opacity: 0; transform: translateY(80px); } .v-enter-active, .v-leave-avtive { transition: all .6s ease; } </style> </head> <body> <div id="app"> <label> Id: <input type="text" v-model='id'> </label> <label> Name: <input type="text" v-model='name'> </label> <input type="button" @click='add' value="添加"> <ul> <!-- 在实现列表过渡的时候,如果需要过渡的元素,是通过v-for循环渲染出来的 --> <!-- 不能使用transition包裹,需要使用transitionGroup --> <!-- 如果要为v-for循环创建的元素设置动画,必须为每一个元素设置:key属性 --> <transition-group name="list" tag="p"> <li v-for="item in list" :key="item.id"> {{item.id}}---{{item.name}} </li> </transition-group> </ul> </div> <script> var vm = new Vue({ el: '#app', data: { id: '', name: '', list: [{ id: 1, name: '赵高' }, { id: 2, name: '秦晖' }, { id: 3, name: '严嵩' }, { id: 4, name: '魏忠贤' } ], }, methods: { add() { this.list.push({ id: this.list.length + 1, name: this.name }) } } }) </script> </body> </html>appear:给transition-group添加appear属性,实现入场时候的效果
tag:指定哪个元素应该被渲染
具体
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1gCBcGZj-1599142789285)(image/image-20200708172021580.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VCb9oQOg-1599142789286)(image/image-20200708172055831.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M4T0IWvm-1599142789287)(img/1594207871167.png)]
什么是组件:组件的出现,就是为了拆分Vue实例的代码量的,能够让我们以不同的组件,来划分不同的功能模块,将来我们需要什么样的功能,就可以去调用对应的组件即可。
组件化和模块化的不同:
模块化是代码逻辑的角度进行划分的;方便代码分层开发,保证每个功能模块的职能单一组件化是从界面的角度进行划分的;(第一种方式简化版)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../vue.js"></script> </head> <body> <div id="app"> <!-- 如果要使用组件。直接把组件的名称,以HTML标签的形式,引入到页面中,即可 --> <mycom1></mycom1> </div> <script> // // 1.1使用Vue.extend来创建全局的Vue组件 // var com1 = Vue.extend({ // // 通过template属性,指定了组件要展示的HTML结构 // template: '<h3>这是使用Vue.extend 创建的组件</h3>' // }) // 1.2使用Vue.component('组件的名称',创建出来的组件模板对象);com1表示要展示的模板里的内容 // 在注册的时候可以驼峰命名;如果没用驼峰命名,上面则不需要"-"代替,直接写就行 Vue.component('mycom1', Vue.extend({ template: '<h3>这是使用Vue.extend 创建的组件</h3>' })) var vm = new Vue({ el: '#app', data: {}, methods: {} }) </script> </body> </html>[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1QAplUPs-1599142789288)(img/1594214593774.png)]
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../vue.js"></script> </head> <body> <div id="app2"> <!-- <mycom1></mycom1> --> <!-- 在被控制的#app外面,使用template元素,定义组件的HTML模板结构 --> <login></login> </div> <template id="tmpl2"> <div> <h1>这是定义的私有组件</h1> </div> </template> <script> var vm = new Vue({ el: '#app2', data: {}, methods: {}, components: { login: { template: '#tmpl2' } } }) </script> </body> </html>语法&写法
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../vue.js"></script> </head> <body> <div id="app"> <mycom1></mycom1> </div> <script> // 1.组件可以有自己的数据 // 2.组件的data和实例的data有点不一样,实例中的data可以为一个对象,但是组件中的data必须是一个方法 // 3.组件中的data除了必须为一个方法外,这个方法内部,还必须返回一个对象才行 Vue.component('mycom1',{ template:'<h1 @click="counts++">这是全局组件:{{counts}}</h1>', data:function(){ return { counts:0 } } }) var vm=new Vue({ el:'#app', data:{}, methods:{} }) </script> </body> </html>注意:
1.组件可以有自己的数据和方法,即data:{ }和methods:{ }
2.组件的data和实例的data有点不一样,实例中的data可以为一个对象,但是组件中的data必须是一个方法
3.组件中的data除了必须为一个方法外,这个方法内部,还必须返回一个对象才行
为什么组件的data必须是一个function?
return出{ 属性名:属性值},每次调用函数等于新开辟了一个对象空间,防止数据共享。但是如果在外面定了了个对象数据,函数内部return了该对象,就会数据同时发生改变。
例子:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qyPR1zhI-1599142789290)(img/1594219573671.png)]
v-if和v-else结合使用flag切换组件;案例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../vue.js"></script> </head> <body> <!-- v-if和v-else结合使用切换组件 --> <div id="app"> <a href="" @click.prevent='flag=true'>登录</a> <a href="" @click.prevent='flag=false'>注册</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>', }) new Vue({ el: '#app', data:{ flag:true } }) </script> </body> </html>实例;
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../vue.js"></script> </head> <body> <div id="app"> <a href="" @click.prevent="comName='login'">登录</a> <a href="" @click.prevent="comName='register'">注册</a> <!-- Vue提供了 component ,来展示对应名称的组件 --> <!-- component是一个占位符, :is 属性,可以用来指定要展示的组件的名称 --> <!-- 不加单引号会当作表达式来解析,不会看作是字符串 --> <component :is="comName"></component> </div> <script> // 登录组件 Vue.component('login',{ template: '<h3>登录组件</h3>', }) // 注册组件 Vue.component('register',{ template: '<h3>注册组件</h3>', }) new Vue({el:'#app',data:{ comName:'login' }}) </script> </body> </html>组件切换案例
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i5Vp1ynb-1599142789291)(img/1594296065971.png)]
案例演示:(错误演示)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../vue.js"></script> </head> <body> <div id="app"> <com1></com1> </div> <script> new Vue({ el:'#app', data:{ msg:'123 啊-父组件中的数据' }, methods:{}, components:{ // 结论:经过演示,发现,子组件中,默认无法访问到 父组件中的data 上的数据和methods中的方法 com1:{ template:"<h1>这是子组件---{{msg}}</h1>" } } }) </script> </body> </html>[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0xKBoZrV-1599142789293)(img/1594300909121.png)]
想要成功父组件向子组件传值,还需要以下两步:
1.给子组件标签用"v-bind:"绑定父组件数据 2.在绑定好了数据后,需要在定义的子组件中设置props(该属性为数组形式)。在props中定义下绑定的属性(相当于注册),才能使用实例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../vue.js"></script> </head> <body> <div id="app"> <!-- 父组件可以在引用子组件的时候,通过属性绑定(v-bind:)的形式,把需要 传递给子组件的数据,以属性绑定的形式,传递到子组件内部,供子组件使用 --> <com1 :parentmsg='msg'></com1> </div> <script> new Vue({ el: '#app', data: { msg: '123 啊-父组件中的数据' }, methods: { }, components: { // 结论:经过演示,发现,子组件中,默认无法访问到 父组件中的data 上的数据和methods中的方法 com1: { data() { //注意: // 1.子组件中的data数据,并不是父组件传递过来的, // 而是自身私有的,比如:子组件通过Ajax,请求回来的数据,都 // 可以放到data身上 // 2.子组件中data中数据都是可读可写的 return { title: '1234', content: 'qqq' } }, template: "<h1>这是子组件---{{parentmsg}}</h1>", // 把父组件传递过来的parentmsg属性,先在props数组中,定义一下,这样,才能使用这个数据 // 注意:: // 1.props中的数据,都是只读的,无法重新赋值 props: ['parentmsg'], methods: { }, }, } }) </script> </body> </html>[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KOubgNXT-1599142789294)(img/1594302213099.png)]
利用绑定事件函数和$emit去触发
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../vue.js"></script> <link rel="stylesheet" href="../bootstrap-3.3.7/dist/css/bootstrap.min.css"> </head> <body> <div id="app"> <cmt-box @func="localComments"></cmt-box> <ul class="list-group"> <li class="list-group-item" v-for="item in list" :keys="item.id"> <span class="badge">评论人:{{item.user}}</span> {{item.content}} </li> </ul> </div> <template id="tmpl1"> <div> <div class="form-group"> <label>评论人:</label> <input type="text" class="form-control" v-model="user"> </div> <div class="form-group"> <label>评论内容:</label> <input type="text" class="form-control" v-model="content"> </div> <div class="form-group"> <input type="button" value="发表评论" class="btn btn-primary" @click="postComment"> </div> </div> </template> <script> // 评论盒子 var commentBox = { template: "#tmpl1", data() { return { user: "", content: "" } }, methods: { postComment() { //发表评论的方法 // 分析:发表评论的业务逻辑 // 1.评论数据存到哪里去?存放到了localStorage中 // 2.先组织一个最新的评论数据对象 // 3.想办法,把第二步中,得到的评论对象,保存到localStorage中 // 3.1localStorage只支持存放字符串数据,要先调用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.$emit('func') } } } var vm = new Vue({ el: '#app', data: { list: [ { id: Date.now(), user: '李白', content: '天生我才必有用' }, { id: Date.now(), user: '江小白', content: '劝君更进一杯酒' }, { id: Date.now(), user: '夫子', content: '天不生夫子,万古如长夜' }, { id: Date.now(), user: '李慢慢', content: '我已经学会了打架' }, ] }, beforeCreate() { //注意:这里不能调用localStorage方法,因为在执行这个钩子 //函数的时候,data和methods都还没有被初始化 }, created() { // 不能直接访问调用,需要用this来进去访问 this.localComments(); }, methods: { // 从本地的localStorage中,加载评论列表 localComments(){ var list=JSON.parse(localStorage.getItem('cmts')||'[]') this.list=list } }, components: { "cmt-box": commentBox } }) </script> </body> </html>[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZF0Q60hs-1599142789295)(img/1594311898654.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OKvIQK06-1599142789297)(img/1594311917150.png)]
类型:Object
只读
详细:
一个对象,持有注册过 ref attribute 的所有 DOM 元素和组件实例。
参考:
子组件 ref特殊 attribute - ref案例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../vue.js"></script> </head> <body> <div id="app"> <input type="button" value="获取DON元素" @click='getDOM' ref="mybtn"> <p id="RT" ref="getEle">我就是那个DOM</p> <hr> <login ref="mylogin"></login> </div> <script> var login={ template:'<h1>登录组件</h1>', data(){ return { msg:"李荣浩你妈的" } }, methods: { show(){ console.log("子组件的方法") } }, } var vm=new Vue({ el:'#app', data:{}, methods: { getDOM(){ console.log(this.$refs.mylogin.msg) } }, components:{ login:login } }) </script> </body> </html>[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FuEcPtNu-1599142789298)(img/1594384422863.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iWY6mlAc-1599142789299)(img/1594384642089.png)]
1.CDN引用或者下载安装包引入
2.npm下载模块引入
地址:https://router.vuejs.org/installation.html#direct-download-cdn
基本写法(与官网文档稍微不同),但简易理解
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../vue.js"></script> <!-- 1.安装路由模块 --> <script src="../vue-router.js"></script> </head> <body> <div id="app"> <a href="#/login">登录</a> <a href="#/register">注册</a> <!-- 这是vue-router提供的元素,专门当作占位符的,将来,路由规则,匹配到的组件, --> <!-- 就会展示到这个router-view中去 --> <!-- 所以我们可以把它认为是一个占位符 --> <router-view></router-view> </div> <script> // 组件的模板对象 var login = { template: "<h1>登录组件</h1>" }; var register = { template: "<h1>注册组件</h1>" }; // 路由列表 //2. 创建一个路由对象,当导入vue-router包之后,在window全局对象 // 中,就有了一个路由的构造函数,叫做VueRouter // 在new 路由对象的时候,可以为构造函数,传递一个配置对象 var routerObj = new VueRouter({ //route//这个配置中的route表示【路由匹配规则】的意思 routes: [ // 每个路由规则,都是一个对象,这个规则对象,身上,有两个必须的属性 //属性1:是path ,表示监听哪个路由链接地址; //属性2:是component,表示,如果路由时前面匹配到的path,则展示component属性对应的那个组件 // 注意:component的属性值,必须是一个组件的模板对象,不能是组件的引用名称 { path: '/login', component: login }, { path: '/register', component: register } ] }); // 使用插件 // //调用 `MyPlugin.install(Vue)` // Vue.use(MyPlugin) var vm = new Vue({ el: "#app", data: {}, methods: {}, //将路由规则对象,注册到vm实例上,用来监听URL地址的变化,然后展示对应的组件 router: routerObj }) </script> </body> </html>[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lWXCcsk8-1599142789300)(img/1594399718296.png)]
示例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../vue.js"></script> <script src="../vue-router.js"></script> <style> .router-link-active, .myactive{ color: red; font-weight: 700; font-style: italic; font-size: 60px; text-decoration: underline; } </style> </head> <body> <div id="app"> <router-link to="/login">登录</router-link> <router-link to="/register">注册</router-link> <!-- 占位符 --> <router-view></router-view> </div> <script> // 组件模板 var login={ template:"<h1>登录组件</h1>" } var register={ template:"<h1>注册组件</h1>" } // 创建路由实例 var routerObj = new VueRouter({ // 配置路由列表及组件 routes: [ { path: "/login", component: login }, { path: "/register", component: register } ], // 该属性可以把该默认类名改成自己设定的类 linkActiveClass:"myactive", // linkExactActiveClass:"linkClass" }) var vm = new Vue({ el: '#app', data: {}, methods: {}, // 注册路由实例 router: routerObj }) </script> </body> </html>示例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../vue.js"></script> <script src="../vue-router.js"></script> <style> .router-link-active, .myactive { color: red; font-weight: 700; font-style: italic; font-size: 60px; text-decoration: underline; } .v-enter, .v-leave-to{ opacity: 0; transform: translateX(140px); } .v-enter-active, .v-leave-active{ transition: all 0.5s ease; } </style> </head> <body> <div id="app"> <router-link to="/login">登录</router-link> <router-link to="/register">注册</router-link> <transition mode="out-in"> <!-- 占位符 --> <router-view></router-view> </transition> </div> <script> // 组件模板 var login = { template: "<h1>登录组件</h1>" } var register = { template: "<h1>注册组件</h1>" } // 创建路由实例 var routerObj = new VueRouter({ // 配置路由列表及组件 routes: [ { path: "/login", component: login }, { path: "/register", component: register } ], // 该属性可以把该默认类名改成自己设定的类 // linkActiveClass: "myactive", // linkExactActiveClass:"linkClass" }) var vm = new Vue({ el: '#app', data: {}, methods: {}, // 注册路由实例 router: routerObj }) </script> </body> </html>r o u t e 和 route和 route和refs差不多,都是vue的实例。打印出来都是一个对象。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../vue.js"></script> <script src="../vue-router.js"></script> </head> <body> <div id="app"> <router-link to="/login?id=10&name=张三">登录</router-link> <router-link to="/register">注册</router-link> <!-- 占位 --> <router-view></router-view> </div> <script> // 组件模板 var login = { // template里的this可以省略直接写$route.query.id template: "<h1>登录---{{$route.query.id}}---{{$route.query.name}}</h1>", created() { //组件的生命周期 钩子函数 // 该$route和该$refs差不多,也是个实例 console.log(this.$route) }, } var register = { template: "<h1>注册</h1>" } // 实例化路由 const routerObj = new VueRouter({ // 配置路由参数及列表 routes: [ { path: "/login", component: login }, { path: "/register", component: register } ] }) var vm = new Vue({ el: '#app', data: {}, methods: {}, // 注册路由实例 router: routerObj }) </script> </body> </html>[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-avO9UiXZ-1599142789301)(img/1594476154076.png)]
路由参数匹配的第二种形式params
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../vue.js"></script> <script src="../vue-router.js"></script> </head> <body> <div id="app"> <router-link to="/login/12/张三">登录</router-link> <router-link to="/register">注册</router-link> <!-- 占位 --> <router-view></router-view> </div> <script> // 组件模板 var login = { // template里的this可以省略直接写$route.query.id template: "<h1>登录---{{$route.params.id}}---{{$route.params.name}}</h1>", created() { //组件的生命周期 钩子函数 // 该$route和该$refs差不多,也是个实例 console.log(this.$route) }, } var register = { template: "<h1>注册</h1>" } // 实例化路由 const routerObj = new VueRouter({ // 配置路由参数及列表 routes: [ { path: "/login/:id/:name", component: login }, { path: "/register", component: register } ] }) var vm = new Vue({ el: '#app', data: {}, methods: {}, // 注册路由实例 router: routerObj }) </script> </body> </html>写法区别:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GIxq2HpP-1599142789303)(img/1594476740351.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3gxuJ55i-1599142789304)(img/1594476756173.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tC1qNK4f-1599142789305)(img/1594476801502.png)]
示例:(嵌套写法)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../vue.js"></script> <script src="../vue-router.js"></script> </head> <body> <div id="app"> <router-link to="/account">展示Account</router-link> <router-view></router-view> </div> <template id="tmpl"> <div> <h1>这是Account 组件</h1> <router-link to="/account/login">登录</router-link> <router-link to="/account/register">注册</router-link> <router-view></router-view> </div> </template> <script> // 组件模板 const account = { template: "#tmpl" } const login = { template: "<h3>登录</h3>" } const register = { template: "<h3>注册</h3>" } // 创建路由模块 const router = new VueRouter({ routes: [ { path: '/account', component: account, //使用children属性,实现子路由,同时,子路由的path前面,不要带/ , // 否则永远以根路径开始请求,这样不方便我们用户去理解url地址 children: [ { path: 'login', component: login }, { path: 'register', component: register } ] }, ] }) const vm = new Vue({ el: '#app', data: {}, methods: {}, router: router }) </script> </body> </html>[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iGGWaFzz-1599142789306)(img/1594483354062.png)]
利用router-view中的name属性和创建路由时配置路由的命名路由名字联系,实现经典布局
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../vue.js"></script> <script src="../vue-router.js"></script> <style> html,body{ margin: 0; padding: 0; } .header{ background-color: orange; height: 80px; } h1{ margin: 0; padding: 0; font-size: 16px; } .container{ display: flex; height: 600px; } .left{ background-color: lightgreen; flex: 2; } .main{ background-color: lightpink; flex: 8; } </style> </head> <body> <div id="app"> <router-view></router-view> <div class="container"> <router-view name="left"></router-view> <router-view name="main"></router-view> </div> </div> <script> var header = { template: "<h1 class='header'>Header头部区域</h1>" } var leftBox = { template: "<h1 class='left'>侧边栏区域</h1>" } var mainBox = { template: "<h1 class='main'>主体区域</h1>" } // 创建路由 const router = new VueRouter({ routes: [ { //利用name属性来匹配路由,实现视图布局 path: '/', components: { default: header, left: leftBox, main: mainBox } }, ] }) var vm = new Vue({ el: "#app", data: {}, methods: {}, router }) </script> </body> </html>[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8IpHK3Qi-1599142789307)(img/1594732225005.png)]
关于命名视图的名称到底是变量还是字符串的说明
举例:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wXFn2cTD-1599142789309)(img/1594732392697.png)]
例如在name属性前加冒号了,说明等号后面的是变量,如果不加的话,永远都是个值。
案例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../vue.js"></script> <script src="../vue-router.js"></script> </head> <body> <div id="app"> <!-- 分析: --> <!-- 1.我们要监听到 文本框数据的改变,这样才知道 什么时候去拼接 出一个 fullname --> <!-- 2.如何监听到 文本框的数据改变呢??? --> <input type="text" v-model="firstname" @keyup="getFullname"> + <input type="text" v-model="lastname" @keyup="getFullname"> = <input type="text" v-model="fullname"> </div> <script> const vm = new Vue({ el: "#app", data: { firstname: '', lastname: '', fullname: '' }, methods: { getFullname() { this.fullname = this.firstname + "-" + this.lastname } } }) </script> </body> </html>利用watch代替监听事件。
使用这个属性,可以监视data中指定数据的变化,然后触发这个watch中对应的 function处理函数
案例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../vue.js"></script> <script src="../vue-router.js"></script> </head> <body> <div id="app"> <input type="text" v-model="firstname"> + <input type="text" v-model="lastname"> = <input type="text" v-model="fullname"> </div> <script> const vm = new Vue({ el: "#app", data: { firstname: ''||0, lastname: ''||0, fullname: '' }, methods: {}, watch: { //使用这个属性,可以监视data中指定数据的变化,然后触发这个watch中对应的 // function处理函数 //这样写代表要监视firstname这个属性,数据改变了就会触发后面的这个处理函数 // 注意:firstname需不需要加引号的问题:有横线的时候(first-name),需要加引号,没有横线的时候可加可不加 firstname: function () { this.fullname=parseInt(this.firstname)+parseInt(this.lastname) }, lastname: function () { // console.log("监听到了fastname的变化") this.fullname=parseInt(this.firstname)+parseInt(this.lastname) } }, }) </script> </body> </html>watch可以监测到事件监测不到的东西,比如路由的变化
案例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../vue.js"></script> <script src="../vue-router.js"></script> </head> <body> <div id="app"> <router-link to="/login">登录</router-link> <router-link to="/register">注册</router-link> <router-view></router-view> </div> <script> // 创建子组件 var login = { template: "<h3>这是登录子组件</h3>" } var register = { template: "<h3>这是登录父组件</h3>" } // 创建并配置路由 const router = new VueRouter({ routes: [ // { path: "/", redirect: "/login" }, { path: "/login", component: login }, { path: "/register", component: register } ] }) const vm = new Vue({ el: "#app", data: {}, methods: {}, router, watch: { //this.$route.path "$route.path":function(newVal,oldVal){ // console.log(newVal+"--"+oldVal) if(newVal=="/login"){ console.log("欢迎进入登录页面") }else if(newVal=="/register"){ console.log("欢迎进入注册页面") } } }, }) </script> </body> </html>具体用法查示例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../vue.js"></script> <script src="../vue-router.js"></script> </head> <body> <div id="app"> <input type="text" v-model="firstname"> + <input type="text" v-model="lastname"> + <input type="text" v-model="middlename"> = <input type="text" v-model="fullname"> <p>{{fullname}}</p> <p>{{fullname}}</p> <p>{{fullname}}</p> </div> <script> const vm = new Vue({ el: "#app", data: { firstname: '', lastname: '', middlename: '' }, methods: {}, computed: { //在computed中可以定义一些属性,这些属性,叫做【计算属性】。 //计算属性的本质,就是一个方法,只不过,我们在使用这些计算属性的时候, //是把它们的名称,直接当作属性来使用的,并不会把计算属性当作方法去调用 // 注意1:计算属性,在引用的时候,一定不要加小括号去调用,直接把它当作普通属性去使用就好 // 注意2:只要计算属性,这个function内部,所用到的任何data中的数据发生了变化,就会 //触发这个属性立即重新计算这个 计算属性的值 // 注意3:计算属性的求值结果,会被缓存起来,方便下次直接使用,如果 计算属性方法中,所以来的 // 任何数据,都没有发生变化,则不会重新对 计算属性求值,比如ok只打印了一次 "fullname": function () { console.log("ok") return this.firstname + this.middlename + this.lastname } }, }) </script> </body> </html>[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mvGPQjs7-1599142789311)(img/1594816273965.png)]
注意:nrm只是单纯的提供了几个常用的下载包的URL地址,在这几个地址之间,很方便的进行切换,但是,我们每次装包的时候,使用的装包工具,都是npm
官网地址:https://webpack.js.org/
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LimCdQ8n-1599142789312)(img/1594827785496.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gaC0B8SM-1599142789314)(img/1594827673528.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Zv9zpIO0-1599142789315)(img/1594828282937.png)]
webpack4.0+入门使用教程:(输入输出及配置)
https://www.jianshu.com/p/b30cf56a431f总结:
1.创建package.json文件 npm init -y 2.安装webpack4和webpack-cli //注意:webpack4及以上需要同时安装webpack-cli 3.删除package.json中 "main": "index.js" 项,加上 "private": true 项 4.在src文件夹下创建 index.js 文件 和 index.html 文件 5.在index.html文件中body下面引用script标签,导入文件st/main.js (此时main.js文件还未生成) 6.配置webpack的config,创建webpack.config.js文件,配置内容如下: const path = require('path'); module.exports = { entry: './src/index.js', output: { filename: 'main.js', path: path.resolve(__dirname, 'dist') } }; 7.修改package.json文件中 "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }该项为 "scripts": { "build": "webpack" }, 8.运行打包命令 npm run build[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zx8Q9yf2-1599142789316)(image/image-20200716153534955.png)]
工具:webpack-dev-server
webpack-dev-server的基本使用[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A1b8ysbT-1599142789317)(image/image-20200716155016010.png)]
webpack-dev-server相当于nodemon这类工具,自动监听原文件代码的改变自动运行执行同步更改后的打包文件
使用webpack-dev-server这个工具,来实现自动打包编译的功能
1.运行npm i webpack-dev-server -D 把这个工具安装到项目的本地开发依赖 2.安装完毕后,这个工具的用法,和webpack命令的用法,完全一样 3.由于,我们市在项目中,本地安装的webpack-dev-server,所以,无法把它当作脚本命令,在powershell终端直接运行,(只有那些 安装到全局 -g 的工具,才能在终端中正常执行) 解决方式: 在package.json中的"script":{ "dev":"webpack-dev-server" }项配置运行命令 执行npm run dev 即可运行该工具不常用,了解就行(案例未能实现,以后查阅)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YdrRifHk-1599142789319)(img/1594907285271.png)]
webpack插件2:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3d1G24pi-1599142789320)(img/1594909893992.png)]
这个插件的两个作用:
自动在内存中根据指定的页面生成一个内存的页面自动把打包好的bundle.js引用追加到页面中去[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jb1GdoyB-1599142789322)(img/1594912129141.png)]
用import语法,导入css样式表
import "./css/index.css"注意:webpack默认只能打包处理JS类型的文件,无法处理其他非JS类型的文件
如果要处理非 JS 类型的文件,我们需要手动安装一些 合适的第三方loader 加载器
安装笔记:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Dgzn9CsP-1599142789323)(img/1594912890767.png)]
第一步:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3XYGIg16-1599142789324)(img/1594913652486.png)]
总结:两个文件需要针对配置
1.webpack.config.js
1.下载安装该两个插件 //npm i style-loader css-loader 2.节点配置,规则匹配 //表示启用哪些模块来进行处理匹配节点配置,规则匹配:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kMCVnNOV-1599142789325)(img/1594914745527.png)]
2.入口编译文件index.js
调用import语法引入css文件[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MOnT1gue-1599142789326)(img/1594914888767.png)]
3.命令刷新页面:
npm run dev注意:webpack处理第三方文件类型的过程:
1。发现这个 要处理的文件不是js文件,然后就去 配置文件中,查找有没有对应的第三方 loader 处理 这种文件类型 2.如果能找到对应的规则,就会调用 对应的 loader 处理 这种文件类型 3.在调用loader 的时候,是从后往前 调用的; 4.当最后的一个loader 调用完毕后,会把 处理的结果,直接交给 webpack 进行 打包合并,最终输出到bundle.js中去安装:
npm i less-loader -D npm i less -D配置步骤与配置css文件规则一致,正则匹配几乎一致
安装
npm i sass-loader -D npm i node-sass -D入口文件引入scss文件,配置规则
url-loader的使用
默认情况下,webpack是无法处理css文件中的url地址,不管是图片还是字体库,只要是url地址,都处理不了
安装:
npm i url-loader file-loader -D注意:url-loader同时也依赖于内部的一个file-loader模块,配置文件中不必配置file-loader
传参方式:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-38fRJdqw-1599142789327)(img/1595019162094.png)]
limit是给定的值,是图片的大小,单位是byute,如果我们引用的图片,大于或等于给定的limit值,则不会被转为base64格式的字符串,如果图片小于给定的limit值,则会被转为base64的字符串
如果不想改变图片名称:则可以传参为:
use:"url-loader?limit=7631&name=[name].[ext]"注:name传参为固定写法
也可以利用hash值拼接原图片名,写法如下:展示的是:hash值前八位-原图片名称
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6UUmbym4-1599142789328)(img/1595022559833.png)]
百度或者查阅文档
1.json中不能写注释
前提:
//class 关键字,是ES6中提供的新语法,是用来实现ES6面向对象编程的方式 class Person { //使用static关键字,可以定义静态属性 //所谓的静态属性,就是 可以直接通过 类名,直接访问的属性:例如Person.info //实例属性:只能通过类的实例,来访问的属性,叫做实例属性 static info = {name:"zs",age:20} } //访问Person类身上的 info 静态属性 console.log(Person.info) 注: 在webpack中,默认只能处理一部分ES6的新语法,一些更高级的ES6语法或者ES7语法,webpack是处理不了的;这时候,就需要 借助于第三方的 loader ,来帮助webpack 处理这些高级的语法,当第三方loader把高级语法转为低级语法之后,会把结果交给webpack去打包到bundle.js中 //通过Babel,可以帮我们将高级的语法转换为 低级的语法 //在webpack中,可以运行如下两套命令,安装两套包,去安装Babel 相关的loader功能: //第一步: babel-loader是加载器 第一套包:npm i babel-core babel-loader babel-plugin-transform-runtime -D 第二套包:npm i babel-preset-env babel-preset-stage-0 -D //第二步: 打开webpack的配置文件,在module节点下的rules数组中,添加一个新的 匹配规则: {test:/\.js$/,use:"babel-loader",exclude:/node_modules/} //注意1:exclude是排除的意思,排除node_modules这个文件夹里的Js文件。 //注意2:在配置babel的loader规则时候,必须把node_modules目录,通过exclude选项排除掉,原因有俩: //2.1:如果不排除node_modules,则Babel会把node_modules中所有的第三方JS文件,都打包编译,这样,会非常消耗CPU,同时,打包速度非慢; //2.2:哪怕最终,Babel 把所有 node_modules 中JS转换完毕了,但是,项目也无法正常运行! //第三步: 在项目的 根目录中,新建一个 叫做 .babelrc 的Babel 配置文件,这个配置文件,属于JSON格式,所以,在写 .babelrc配置的时候,必须符合JSON语法规范;不能写注释,字符串必须用双引号。 //配置入下: //大家可以把preset翻译成语法的意思 { "presets":["env","stage-0"], "plugins":["transform-runtime"] }注释:babel在webpack中配置更新很快,简易网络查询,笔记中配置可能会出差错(具体差错原因可能包被废弃或者少包,目前正常),同时,加载器babel-loader的版本对应babel-core核心包的版本相差一个版本(例如:babel-core@6,对应的是babel-loader@7版本)
packag.json第三方模块安装图如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7HdF7xT8-1599142789330)(img/1595155180550.png)]
render函数会渲染组件,但是只会渲染单个组件。
原理:render函数会把挂载的 el容器替换掉为组件。原先的容器直接会被删除掉。
实例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../vue.js"></script> </head> <body> <div id="app"></div> <script> // 组件模板对象 var login={ template:"<h1>这是登录组件</h1>" } var vm = new Vue({ el:"#app", data:{}, methods:{}, render:function(createElement){ return createElement(login); } }) </script> </body> </html>components注册的组件相当于插值表达式,只替换当前位置,不会把容器清空。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9MW3bRK2-1599142789332)(image/image-20200720172347940.png)]
入口文件:
// 第二种引入方式,在webpack里加一个节点,跟modules平级 import Vue from 'vue' // 导入login组件 import login from "./login.vue" // 默认 webpack 无法打包 .vue文件,需要安装 相关的loader加载器: // 1. vue-loader 内部依赖 vue-template-compiler // npm i vue-loader vue-template-compiler -D // 2. 在配置文件中新增一个配置项,{test:/\.vue$/,use:"vue-loader"} var vm =new Vue({ el:"#app", data:{ msg:"123" }, // components:{ // login // } render:function(createElement){ return createElement(login) } })login.vue文件:
<template> <div> <h1>这是登录组件,使用 .vue 文件定义出来的</h1> </div> </template>配置文件webpack.config.js:
const path = require('path'); // 导入在内存中生成的HTML页面的插件 // 只要是插件,都一定要放到plugins节点中去 const htmlWebpackPlugin = require("html-webpack-plugin"); const VueLoaderPlugin = require('vue-loader/lib/plugin') module.exports = { // entry: path.join(__dirname, './src/index.js'), entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') }, devServer: { port: 3000, contentBase: path.join(__dirname, 'dist'), open: true }, plugins: [ //配置插件的节点 new htmlWebpackPlugin({ //创建一个 在内存中生成的 HTML 页面的插件 //指定 模板页面,将来会根据指定的页面路径,去生成内存中的页面 template: path.join(__dirname, "./src/index.html"), filename: "index.html" //指定生成的页面的名称 }), new VueLoaderPlugin(), ], module: { //这个节点,用于配置 所有 第三方模块 加载器 rules: [ //所有第三方模块匹配规则 { test: /\.css$/, //配置处理 .css文件第三方的第三方loader规则 use: ["style-loader", "css-loader"] }, { test: /\.less$/, //配置处理 .less文件的第三方loader规则 use: ["style-loader", "css-loader", "less-loader"] }, { test:/\.scss$/,use:["style-loader","css-loader","sass-loader"] }, { test:/\.(jpg|png|gif|bmp|jpeg)$/,use:"url-loader?limit=7631&name=[name].[ext]" }, { test:/\.(ttf|eot|svg|woff|woff2)$/,use:"url-loader" }, // babel配置来转换高级的ES语法 { test:/\.js$/,use:"babel-loader",exclude:/node_modules/ }, // vue-loader配置项 {test:/\.vue$/,use:"vue-loader"} ] }, resolve:{ alias:{ //修改Vue被导入时候的包的路径 "vue$":"vue/dist/vue.js" } } }配置 vue-loader 和 vue-template-compiler 巨坑之一:
Webpack+Vue+Vue-loader+Vue-template-compiler的坑1
注意:具体错误形式我也懒得写了,心累死了。 就是一定要注意在配置Webpack+Vue的时候,版本的依赖问题! 如果Vue是什么版本,Vue-loader也要是什么版本,以此减少错误。 还有就是如果使用了Vue-template-compiler的15x以上的版本,还要在Webpack.config.js中添加: const VueLoaderPlugin = require('vue-loader/lib/plugin') 在下面的plugins中添加 new VueLoaderPlugin(), 这里有一个坑,如果使用的不是15x版本的话,则不需要添加后面的/lib/plugin,但是如果使用了这个版本的话,一定要记得添加上,否则就会出现cannot find plugin的错误。 ———————————————— 版权声明:本文为博主「西大野」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/qq_39339233/java/article/details/84857035[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c2cu1n08-1599142789333)(img/1595260230967.png)]
注意:Node暴露成员和引入方式 与 ES6暴露成员和引入方式 不要混用
其他写法:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E7RpgnHT-1599142789334)(image/image-20200721093039973.png)]
(模块化工具)
官网:https://router.vugejs.org/zh/installation.html
实例:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L4vnwB7u-1599142789335)(image/image-20200721160032322.png)]
入口文件:Index.js
import Vue from "vue" // 1.导入vue-router import VueRouter from "vue-router" // 2.手动安装VueRouter Vue.use(VueRouter) // 导入app组件 import app from "./app.vue" // 导入Account,goodslist组件 import account from "./main/Account.vue" import goodslist from "./main/Goodslist.vue" // 3.创建路由对象 const router = new VueRouter({ routes: [ // account goodslist {path:"/account",component:account}, {path:"/goodslist",component:goodslist} ] }) var vm = new Vue({ el: "#app", render: c => c(app), //4.将路由对象挂载到vue实例上 router })app.vue组件:
<template> <div> <h1>这是 App 组件</h1> <router-link to="/account">Account</router-link> <router-link to="/goodslist">Goodslist</router-link> <router-view></router-view> </div> </template> <script> export default {}; </script> <style lang=""> </style>Account.vue组件:
<template> <div> <h1>这是 Account 组件</h1> </div> </template> <script> export default { } </script> <style lang=""> </style>Goodslist.vue组件:
<template> <div> <h1>这是 Goodslist 组件</h1> </div> </template> <script> export default { } </script> <style lang=""> </style>vscode扩展包:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1BqlZhHR-1599142789336)(image/image-20200721161716021.png)]
实例:
import Vue from "vue" // 1.导入vue-router import VueRouter from "vue-router" // 2.手动安装VueRouter Vue.use(VueRouter) // 导入app组件 import app from "./app.vue" // 导入Account,goodslist组件 import account from "./main/Account.vue" import goodslist from "./main/Goodslist.vue" // 导入Account的登录子组件 import login from "./subcom/login.vue" import register from "./subcom/register.vue" // 3.创建路由对象 const router = new VueRouter({ routes: [ // account goodslist { path: "/account", component: account, children: [{ path: "login", component: login }, { path: "register", component: register } ] }, { path: "/goodslist", component: goodslist } ] }) var vm = new Vue({ el: "#app", render: c => c(app), //4.将路由对象挂载到vue实例上 router })嵌套路由写法:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bXZibT6P-1599142789337)(image/image-20200721172518547.png)]
vue 单文件组件中样式加载
在写单文件组件时,一般都是把标签、脚本、样式写到一起,这样写个人感觉有点不够简洁,所以就想着把样式分离出去。
采用import加载样式
在局部作用域(scoped)采用**@import加载进来的样式文件,想法是美好的。以为这样加载进来的样式文件也只对当前组件有效;可现实是残酷的,这样加载进来的样式无法限制其作用域**。
<style scoped> @import "样式文件"; </style>解决方案
采用 src属性加载样式。
<style src="样式路径" scoped></style>单个子组件示例:
<template> <div> <h3>这是Account的登录子组件</h3> </div> </template> <script> export default {}; </script> <style lang="less" scoped> // 普通得style标签只支持 普通得样式, // 如果想要启用scss或less,需要为style元素,设置lang属性 // 只要咱们的style标签,是在 .vue 组件中定义的,那么,推荐都为style开启scoped body { div { color: red; } } </style>新建一个inde,js平级中新建一个router.js。把创建路由对象部分抽离出去,再把路由对象通过export default {}暴露出来,在index.js中引入router.js模块
router.js文件:
// 1.导入vue-router import VueRouter from "vue-router" // 导入Account,goodslist组件 import account from "./main/Account.vue" import goodslist from "./main/Goodslist.vue" // 导入Account的登录子组件 import login from "./subcom/login.vue" import register from "./subcom/register.vue" // 3.创建路由对象 const router = new VueRouter({ routes: [ // account goodslist { path: "/account", component: account, children: [{ path: "login", component: login }, { path: "register", component: register } ] }, { path: "/goodslist", component: goodslist } ] }) export default router入口文件index.js:
import Vue from "vue" // 导入app组件 import app from "./app.vue" // 2.手动安装VueRouter Vue.use(VueRouter) // 导入 自定义路由模块 import router from "./router.js" var vm = new Vue({ el: "#app", render: c => c(app), //4.将路由对象挂载到vue实例上 router })[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pxck14PH-1599142789339)(image/image-20200722102046222.png)]
组件中样式的scoped是通过 css 的属性选择器实现的,scoped会为添加了样式的容器自动添加一个自定义属性,转换的 css中再利用属性选择器选中该容器为其添加样式。
Mint UI :基于Vue.js的移动端组件库
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kfShgQfD-1599142789340)(image/image-20200722104042268.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pHU0lbaH-1599142789341)(image/image-20200722104253438.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B8TSrjAL-1599142789343)(image/image-20200722104314465.png)]
官网:http://mint-ui.github.io/docs/#/zh-cn2/button
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m7xEKTgW-1599142789344)(image/image-20200722112340981.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SEgzBEJE-1599142789346)(image/image-20200722112414994.png)]
两种形式:
1.完整引入 完整导入下,CSS Components中的css部分就不需要再进行引入了,直接拿标签过去用就行了 2.按需导入 按需导入下,css部分都需要进行相关引入[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FtazmlwB-1599142789348)(image/image-20200722112237333.png)]
建议直接浏览官方文档
Button组件的使用
Toast组件的使用 //js组件一般都需要引入
实例:
<template> <div> <h1>这是 App 组件</h1> <!-- 为什么这里叫做 mt-button 的 button 直接就能用 因为已经被注册为全局组件了--> <mt-button type="primary" icon="more" @click="show">default</mt-button> <mt-button type="danger" size="large" plain>danger</mt-button> <router-link to="/account">Account</router-link> <router-link to="/goodslist">Goodslist</router-link> <router-view></router-view> </div> </template> <script> import { Toast } from "mint-ui"; export default { data() { return {}; }, methods: { show() { Toast("提示信息"); } } }; </script> <style lang=""> </style>[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-17aJj6iZ-1599142789349)(img/1595430940120.png)]
官网:https://dev.dcloud.net.cn/mui/
MUI是一套好用的代码片段,里面提供了配套的样式,配套的HTML代码段,类似于Bootstrap,而Mint-UI,是真正的组件库,是使用Vue技术封装出来的成套的组件,可以无缝的和VUE项目进行集成开发。
注意:mui并不能使用 npm 去下载,需要自己手动从 github 上,下载现成的包,自己解压出来,然后手动拷贝到项目中
LICENSE文件:开源协议
开源协议:https://zhuanlan.zhihu.com/p/31881162
官网文档:http://mockjs.com/
官网模板案例:http://mockjs.com/examples.html
哔哩哔哩视频教程
案例查看请移步至https://github.com/RNGboy/vue-project
Promise-关于Promise要解决回调地狱的问题的说明
需求:你要封装一个方法,我给你一个要读取的文件的路径,你这个方法能帮我读取文件,并把内容返回给我 const fs = require("fs") const path = require("path") function getFileByPath(fpath,succCb,errCb){ fs.readFile(fpath,"utf-8",(err,dataStr)=>{ if(err) return errCb(err) succCb(dataStr) }) } //嵌套回调 getFileByPath(path.join(__dirname,"./files/1.txt"),function(data){ console.log(data) getFileByPath(path.join(__dirname,"./files/1.txt"),function(data){ console.log(data) getFileByPath(path.join(__dirname,"./files/1.txt"),function(data){ console.log(data) }) }) })Promise通过.then指定成功和失败的回调
//初衷:给路径,返回读取到的内容 function getFileByPath(fpath){ var promise = new Promise(function(resolve,reject){ fs.readFile(fpath,"utf-8",(err,dataStr)=>{ if(err) return reject(err) resolve(dataStr) }) }) return promise } var p = getFileByPath("./files/1.txt") p.then(function(data){ console.log(data+"---") },function(err){ console.log(err.message) })[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3yMhJWZA-1599142789350)(img/1595860810735.png)]
当 我们有这样的需求时:哪怕前面大的 Promise 执行失败了,但是,不要影响后续 promise 的正常执行,此时,我们可以单独为每个 promise ,通过.then 指定一下失败的回调;
有问题,我们有这样的需求,上面的的需求刚好相反:如果 后续的 Promise 执行,依赖于 前面 Promise 执行的结果,如果前面的失败了,则后面就没有继续执行下去的意义了,此时,我们想要实现,一旦有报错,则立即终止所有的 Promise 的执行;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6aLxHrUF-1599142789352)(img/1595861479241.png)]
catch作用:如果上面任何一个.then失败了,立即终止执行都会进入catch捕获处理。
也可以单独为每一个指定失败的回调。都可以 。
jQuery中的Ajax也提供了 Promise 操作:
$(function(){ $("#btn").on("click",function(){ $.ajax({ url:"./data.json", type:"get", dataType:"json" }) //利用.then代替success回调函数输出数据 .then(function(data){ console.log(data) }) }) })一个Vue集成PhotoSwipe图片预览插件,可以实现图片预览
官网:https://github.com/LS1231/vue-preview
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZtKvlpBh-1599142789353)(img/1596550285486.png)]
``vue
Promise通过.then指定成功和失败的回调
//初衷:给路径,返回读取到的内容 function getFileByPath(fpath){ var promise = new Promise(function(resolve,reject){ fs.readFile(fpath,"utf-8",(err,dataStr)=>{ if(err) return reject(err) resolve(dataStr) }) }) return promise } var p = getFileByPath("./files/1.txt") p.then(function(data){ console.log(data+"---") },function(err){ console.log(err.message) })[外链图片转存中…(img-3yMhJWZA-1599142789350)]
当 我们有这样的需求时:哪怕前面大的 Promise 执行失败了,但是,不要影响后续 promise 的正常执行,此时,我们可以单独为每个 promise ,通过.then 指定一下失败的回调;
有问题,我们有这样的需求,上面的的需求刚好相反:如果 后续的 Promise 执行,依赖于 前面 Promise 执行的结果,如果前面的失败了,则后面就没有继续执行下去的意义了,此时,我们想要实现,一旦有报错,则立即终止所有的 Promise 的执行;
[外链图片转存中…(img-6aLxHrUF-1599142789352)]
catch作用:如果上面任何一个.then失败了,立即终止执行都会进入catch捕获处理。
也可以单独为每一个指定失败的回调。都可以 。
jQuery中的Ajax也提供了 Promise 操作:
$(function(){ $("#btn").on("click",function(){ $.ajax({ url:"./data.json", type:"get", dataType:"json" }) //利用.then代替success回调函数输出数据 .then(function(data){ console.log(data) }) }) })一个Vue集成PhotoSwipe图片预览插件,可以实现图片预览
官网:https://github.com/LS1231/vue-preview
[外链图片转存中…(img-ZtKvlpBh-1599142789353)]