vue2.x基础知识学习笔记
一、vue环境搭建 vue官网地址:https://cn.vuejs.org/index.html
准备工作:
①安装node.js
查看安装版本:node -v
②安装淘宝镜像加速(下载速度会更快)
npm install cnpm
③安装vue-cli (vue脚手架)
npm install -g @vue/cli (新版本)
创建项目:
管理员身份打开poweerShell或者cmd
①vue create 项目名称(只能小写字母,- 组成,最好不要使用下划线)
注:这一步如果有错误:无法加载文件,则执行下面操作:
set-ExecutionPolicy RemoteSigned ,之后选择 y ,再次创建即可
②↑ ↓选择到Manually select features回车
③选择Babel ,router(空格选择)回车
④询问是否选择history路由模式,默认no
⑤询问配置信息存储位置,选择packge.json即可,也可以自定义一个文件
⑥询问是否将此配置保存为模板,以便下次使用
⑦创建完成
⑧用提示信息两行命令开启服务器
安装插件、依赖:
安装element组件库、引入、注册 官网地址:https://element.eleme.cn/#/zh-CN
npm install element-ui --save
路由安装、引入、注册
npm install vue-router@4
axios安装 中文网地址:http://www.axios-js.com/zh-cn/docs/
npm install axios
二、vue的七大对象:
① el
② data
③ methods
④ template
⑤ render
⑥ computed
⑦ watch
三、vue-cli脚手架目录大致结构:
四、vue基本指令:
五、了解MVVM模式
六、vue路由基本用法:
七、vue生命周期(钩子函数)
八、组件(自定义标签,可复用,一个页面就是由很多组件构成)
1、基本用法:
html部分:
<div id="app"> <chencan></chencan> <chenhe></chenhe> <chen-shan></chen-shan> </div>
js部分
<script> //组件格式: Vue.component("自定义标签名" , {该组件的一些对象包含data,methods,computed等,vue实例包含的组件都可以用}) /** *组件中的data要使用函数的形式,这样在组件复用的时候组件之间的数据就不会冲突 *Vue实例其实就是一个组件,只不过他是一个顶层组件 *template里面只能有一个根组件 */ //组件嵌套(在一个组件里面写另外一个或者多个组件),组件嵌套的时候要注意被包含的组件要写在包含的组件之前(如果是局部组件用的第二种写法的话) Vue.component("chencan" ,{ template: "<div><h4 @click='adds(item)' v-for='item in this.fruits'>{{item}}</h4><chen-q></chen-q></div>", data: function(){ return{ fruits: ["苹果" , "车厘子" , "鹰嘴芒" , "西瓜" , "榴莲"] } }, methods: { adds: function(obj){ alert(obj); } }, components: { "chen-q":{ template:"<div @click='add'>{{d}}</div>", data: function(){ return{ d:3, } }, methods: { add: function(){ return this.d += 2; } } } } }); //组件的第二种定义形式,这是第一步,第二部是在vue实例中注册组件 var chenShan = { template: "<h2>{{name}}</h2>", data: function(){ return{ name: "局部组件😄,第二种写法", } } }
//vue实例 var vue = new Vue({ el: '#app', data: { }, methods: { }, //计算属性 computed: { }, //侦听属性(想要侦听哪个属性,方法名就是那个属性) watch: { }, //组件注册(局部组件),局部组件有两种写法,还可以把对象提到外面 components:{ chenhe: { template: "<h2>{{name}}</h2>", data: function(){ return{ name: "局部组件😄,第一种写法", } } }, chenShan, } }); </script>
2、组件中属性的传值
<body> <div id="app">
<!--从标签中传值,绑定一个属性--> <chencan :name="list"></chencan> </div> </body> <script> var app = new Vue({ el: '#app', data: {
//这是传的值 list:[ { name: "孙悟空", age: 500, nickname: '齐天大圣' }, { name: "猪八戒", age: 540, nickname: '天蓬元帅' }, { name: "沙悟净", age: 300, nickname: '卷帘大将' }, ], }, methods: { }, components:{ "chencan":{
//使用{{}}插值表达式将传过来的值渲染出来 template: "<div><div v-for='item in name' :key='item.name'>{{item.nickname}}---{{item.name}}</div></div>", data: function(){ return { } }, methods:{ //方法中可以修改props中接收的值,但是不建议这样做,如果父组件也使用了这个数据的话会造成父组件的数据也改变,vue中建议使用单向数据流 //如果非常有这个必要,建议将这个方法放到vue实例中去 // btn: function(){ // return this.name[0].name = "玉皇大帝"; // } }, //prop接收组件传过来的值,prop当中的值和data中的基本一样 //对props中接受的参数做验证,例如下面的表示验证接收的参数name是否是一个数组 props:{name:Array}, } } }); </script>
3、子组件向父组件传值,使用自定义事件内容分发 ( $emit()函数 )
操作步骤:
①在子组件中定义一个事件来触发传值
②在事件中编写自定义函数 this.$emit("自定义名称" , "要传递的值"); ###要传递的值可以是普通类型,也可以是数组,也可以是对象
③在子组件标签中监听要传递的值
④在父组件中定义方法接收传过来的值
<div id="app"> <component-b></component-b> </div> <script> //子组件 var componentA = {
//子组件中定义一个方法来触发传值 template: "<div><input v-model='val'/><button @click='fn'>向父组件传递</button></div>", data: function(){ return { val: '', } }, methods: { fn: function(){
//自定义事件$emit绑定要传的值 this.$emit("val" , this.val); } } } //父组件 var componentB = {
//在子组件中定义接收传过来的值的方法 template: "<div>子组件传过来的值:<span>{{val}}</span><component-a v-on:val='receive'></component-a></div>", data: function(){ return { val: '', } }, methods: {
//父组件中定义方法接收传过来的值 receive: function(data){ this.val = data; } }, components: { componentA } } //vue实例 var app = new Vue({ el: '#app', data: { }, methods: { }, components:{ componentB, } }); </script>
4、动态组件
1 <div id="app"> 2 <div> 3 4 <button v-for="item in coms" @click="showComName =item.name">{{item.btn}}</button> 5 6 </div> 7 <!--动态组件的标签 component 配合is属性使用 is等于那个组件就显示哪个组件 --> 8 <!--光使用component配合is属性使用时,每次切换组件,切换之前的组件都会销毁,切换之后的组件都是重新创建,这样操作dom的频率过高--> 9 <!--改进:再component的外面用一个<keep-alive> 标签包起来,这样就不会频繁销毁和创建--> 10 <keep-alive> 11 <component v-bind:is="showComName"></component> 12 </keep-alive> 13 14 </div> 15 16 17 <script> 18 19 var comA = { 20 template: "<div>这是组件A</div>", 21 } 22 var comB = { 23 template: "<div>这是组件B</div>", 24 } 25 var comC = { 26 template: "<div>这是组件C</div>", 27 } 28 var comD = { 29 template: "<div>这是组件D</div>", 30 } 31 var comE = { 32 template: "<div>这是组件E</div>", 33 } 34 35 var app = new Vue({ 36 el: '#app', 37 data: { 38 showComName: 'com-a', 39 coms: [{name:'com-a' , btn:'组件A'}, 40 {name:'com-b' , btn:'组件B'}, 41 {name:'com-c' , btn:'组件C'}, 42 {name:'com-d' , btn:'组件D'}, 43 {name:'com-e' , btn:'组件E'}] 44 }, 45 watch: { 46 showComName: function(a , b){ 47 console.log(a); 48 } 49 }, 50 components: { 51 comA, 52 comB, 53 comC, 54 comD, 55 comE 56 }, 57 58 }); 59 </script>
九、网络通信 (axios) 中文官网地址:http://www.axios-js.com/zh-cn/docs/
axios只需在需要使用的地方引入即可,无需注册
十、计算属性
var vue = new Vue({ el: '#app', data: { name: '陈灿', age: 20, hobby: { name: '打球', time: '3年' }, x: 10, y: 30, firstNum: 10, secondNum: 10, symbol: '+', }, //计算属性 computed: { sum: function(){ return this.x + this.y; }, result: function(){ switch(this.symbol){ case '+': return this.firstNum + this.secondNum; break; case '-': return this.firstNum - this.secondNum; break; case '×': return this.firstNum * this.secondNum; break; case '÷': return this.firstNum / this.secondNum; break; } } } });
</script>
十一、侦听属性
- 侦听属性是侦听一个属性(包括一般的属性和计算属性)的变化,相当于一个回调函数,当属性的值发生改变时,会执行某些操作
- 一般用来做数据同步:比如用户修改了自己的网名,个性签名后,可以在侦听属性中发起异步请求将数据库中的数据更新
//侦听属性(想要侦听哪个属性,方法名就是那个属性) watch: { //curr:属性变化之后的值 last:属性变化之前的值 firstNum: function(curr , last){ console.log("变化之后的值:"+curr + "变化之前的值:"+last); }, //也可以侦听计算属性 result: function(after , before){ console.log("变化之后:"+after +"变化之前:"+before); } }
十二、过滤器
- 针对插值(插值就是 {{}} 里面的内容)可以将原始数据进行处理
- 过滤器可以累加,一个过滤器处理后的结果再交给另一个过滤器处理
- 场景:给up主点赞,当赞的数量达到1000之后,显示1k、1.2k这种,当数量到达10000以上时,显示1w、1.2w类似的
//过滤器
filters: { //value就是传过来的原始数据 yesNumHandle: function(value){ if(value >= 1000 && value < 10000){ return (parseInt((value / 1000)*100) / 100) + "k"; }else if(value >= 10000){ return (parseInt((value / 10000)*100) / 100) + "w"; } } }
十三、渲染函数
- 渲染函数具有非常强大的功能,使用的时候比较繁琐,在开发中使用的非常少(可以了解vue底层的实现)
- 渲染函数出现,body里面的所有标签都会消失
- 格式: createElement("标签的类型" , {属性、事件、样式} , [里面包含的标签] , "标签中的文本")
- 例如: createElement("div" ,{attrs:{id:"app"} , on:{click:this.btn} , style:{fontSize:"14px",color:"red"}} , [createElement("span" , "哈哈")])
//渲染函数 render: function(createElement){ var divs_ = []; for(var i = 0 ; i < this.news.length ; i++){ var div_ = createElement("div" , [ createElement("h4" , [ this.news[i].title, createElement("span" ,{on:{click:this.btn} ,style:{color:"red" , fontSize:"13px"}} , this.yesNumHandle(this.news[i].like)) ]) ]) divs_.push(div_); } return createElement("div" , {attrs:{id: "app"}} , [ createElement("div" , divs_) ]); }
十四、插槽
- 只有一个插槽的时候,标签之间的内容默认都在插槽内
- 有多个插槽的时候,需要给插槽指定名称,用的时候用template标签包裹起来,并使用v-slot指定使用那个插槽
- 具名插槽:有具体名字的插槽
- 默认插槽:没有名字的插槽(default)
- 当模板中有多个插槽时,要清楚有没有默认插槽,哪个是默认插槽,在使用中如果有多个插槽,只有一个没有名字,那这个就是默认插槽,使用的时候,不用template配合v-slot指明使用哪个插槽的话,就会使用默认插槽
- 直接在模板中的slot标签内写的内容称为后备内容
1、基本使用:
<div id="app"> <com-a> <!--此时这三个tmplate的位置无所谓前后了,显示的位置是按照模板中定义的位置--> <!--直接使用{{value}} 使用的是父元素的value值--> <template v-slot:slot-1>这是第一个插槽之间的内容 -- {{value}}</template> <!--使用v-slot:slot-2="绑定一个值" 再使用{{绑定的值.val}} 得到的值是自己的val,并且只能再自己的template里面使用--> <template v-slot:slot-2="toget">这是第二个插槽之间的内容 -- {{toget.val}}</template> <template v-slot:slot-3>这是第三个插槽之间的内容</template> </com-a> </div>
十五、路由组件
1、嵌套路由
父组件: var parent= {template:'<div>父组件中的内容<router-view></router-view></div>'} var child = {template:'<div>这是子组件</div>'} router:[ { path: '/parent', component:parent, children:[ { path:'child',//子组件的路径 component:child //子组件 } ] } ] <router-view to="/parent">显示父组件</router-view> <router-view to="/parent/child">显示子组件</router-view>
2、命名路由
3、动态路由
动态传参 this.$router.push({path:'', params:{} , query:{}}) 前面是path,就不可以用params传值,只能用query传值;前面是name就可以使用params,也可以使用query
4、路由守卫,一般指(路由独享守卫)
1)全局前置守卫
var router = new VueRouter({}) router.beforeEach(function(to , from , next){ })
2)解析守卫
router.beforeResolve(function(to , from , next){})
3)后置守卫
router.afterEach(function(to , from){})
4)组件中的路由守卫
beforeRouteEnter:function(to , from , next){ console.log("组件进入"); } beforeRouteUpdate:function(to , from , next){ console.log("组件被复用的情况下调用(数据变动的时候)"); } beforeRouteLeave:function(to , from , next){ console.log("离开组件的时候"); }
5、路由守卫的全部过程分析
- 导航被触发。
- 在失活的组件里调用 beforeRouteLeave 守卫。
- 调用全局的 beforeEach 守卫。
- 在重用的组件里调用 beforeRouteUpdate 守卫(2.2+)。
- 在路由配置里调用 beforeEnter。
- 解析异步路由组件。
- 在被激活的组件里调用 beforeRouteEnter。
- 调用全局的 beforeResolve 守卫(2.5+)。
- 导航被确认。
- 调用全局的 afterEach 钩子。
- 触发 DOM 更新。
- 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。
十六、history路由模式和hash路由模式
路由重定向: 在路由中加参数 redirect: '/login'
十七、404通配符
routes:[ //放在最后面 { path:'*' component:notFound //组件的名称 } ]
十八、命名视图
<router-view name="left"></router-view> <router-view name="right"></router-view> var left = {template:'<div><p>左边</p></div>'} var right = {template:'<div><p>右边</p></div>'} routes:[ { path:'/a' components:{ left:'left', right:'right' } } ]