02、Vue基础详解
环境准备
1、安装node.js,为了使用npm
2、装完后,cmd进入控制台,查看node版本号node -v,查看npm版本号npm -v
3、查看path环境变量,cmd进入控制台,输入path查看是否有node字样,没问题进入下一步。
4、安装git,为了快捷地开发
5、装完之后,在需要开发的文件夹里面右击,选择Git Bash Here
6、由于npm源在国外速度慢,可以选择换源,或者使用淘宝镜像工具
7、安装淘宝npm镜像,可以使用cnpm,代替npm
npm install -g cnpm --registry=https://registry.npm.taobao.org
8、安装vue(其中的npm命令可以适当换成cnpm)
//全局安装vue-cli npm install --global vue-cli //创建一个基于webpack模板的新项目 vue init webpack my-project //其他选项都可以直接回车或输入N回车,在vue-router的时候,输入Y回车
//当看见All packages installed,就完成了
//安装依赖包 cd my-project npm install npm run dev
9、项目进行中时不要关闭git,若关闭了重新打开:cd my-project ,npm run dev 即可
项目的创建
1、在src目录下面创建自己的项目文件夹,如bb
2、在该项目下面创建视图文件,xxx.vue
<template> <p>Hello World</p> </template>
3、设置路由,src目录下的router下的index.js,如:
import HelloWorld from '@/components/HelloWorld' /*当前@表示src目录*/ import xiangmu from '@/xiangmu/index.vue' /*第二种引入方式*/ export default new Router({ routes: [{ path: '/', //当地址栏输入/的时候,找到下面component的地址 name: 'HelloWorld', //按照需求给这个路由命名 component: HelloWorld //地址栏 }, //记得两个路由之间要加上逗号 { path: '/xiangmu', name: 'xiangmu', // component: require('@/xiangmu/index.vue') //第一种引入方式,这种方式有些版本不支持 component: xiangmu //第二种方式,全通用 } ] })
4、去掉默认大logo,src目录下App.vue,删除开头的的<img src="./assets/logo.png">标签,完成
5、浏览器访问 http://localhost:8080/#/ 到达首页
生命周期
生命周期图片:https://cn.vuejs.org/images/lifecycle.png
组件生成的时候就会自动调用生命周期函数,具体生命周期的实现如:
<script> export default{ data(){ //每个组件都会有data这个函数 return{} }, //两函数之间要用逗号隔开 beforeCreate(){ console.log('beforeCreate 创建之前'); }, created(){ console.log('created 已经创建'); }, beforeMount(){ console.log('beforeMount 挂载之前'); }, mounted(){ console.log('mounted 已经挂载'); }, //生命周期函数监听到才触发 beforeUpdate(){ console.log('beforeUpdate 更新之前'); }, updated(){ console.log('updated 已经更新'); }, beforeDestroy(){ console.log('beforeDestroy 销毁之前'); }, destroyed(){ console.log('destroyed 已经销毁'); } } </script>
选项数据
data
export default { data() { return { bb: 'hello', //两个变量之间用逗号分隔 cc: 'how are you' //这里定义的是全局变量,视图模板可以用,后续函数也可以用 } },
//code... }
模板调用
<template> <div> <!-- 如需调用不多个选项数据,那必须在该div里面 --> <div>{{bb}}</div> <!--模板调用只需要 {{变量名}} 即可-->
<!-- code... --> </div> </template>
computed
//接着上面的export default 里面定义
computed: { //computed是一个对象,里面可以定义各种函数 hi() { return this.bb + this.cc; //调用data里面的变量 = this.变量名 } },
模板调用
//接着在模板{{bb}}后面写
<div>{{hi}}</div>
methods
methods:{ //methods对象,里面定义各种行为性的函数 hello(){ alert("hello"); } }
模板调用
//接着在模板{{hi}}后面写 <div @click="hello()">打招呼</div> //用@click给该div绑定点击事件
//函数不需要传参时,后面()可写可不写
模板语法
data语法
//在模板输出data属性(选项数据说过)
//data定义 data() { return { bb: 'Hello!' } } //模板输出 <div>{{bb}}</div>
嵌入js语法
//在模板上面嵌入js
//data定义 data() { return { bb: 'Hello! ', //两个变量之间用逗号分隔 cc: 'How are you?' //这里定义的是全局变量,视图模板可以用,后续函数也可以用 } } //模板输出 <div>{{bb + cc +bb}}</div> //js的字符串拼接
v-html
//动态地嵌入html标签
//data定义 data() { return { dt:"<p>html是动态的,更改data里面属性值,html就会变化</p>" } } //模板输出 <div v-html="dt"></div> //将dt里面的html嵌入到这个div里面
v-bind
//动态的属性名
//data定义 data() { return { lei:"nihao" } } //模板输出 <div v-bind:class="lei"></div> //class = data里面lei的value 。 //更改lei的value,该div的class就会发生改变
v-on
//绑定事件函数
//methods定义 methods:{ say(h){ alert(h); } } //模板输出 <div v-on:click="say(hi)">点击触发函数</div> //缩写形式:@click="say(hi)"
过滤器
//对模板中的变量进行过滤,通过过滤器,改变原来的输出
//data定义 data() { return { bb:"你好!" } }, //filters定义,filters里面定义各种过滤器函数 methods:{ say(h){ alert(h+h); } } //模板输出 <div> {{bb | say(bb)}} </div> //输出结果:你好!你好! //没有过滤器的时候直接输出bb变量,通过say(bb)过滤器,输出了两个bb变量
计算属性(computed)
//模板与js分离(过多的嵌套js会导致模板页面维护成本变高)
//js分离:模板文件容易维护 //data定义 data() { return { bb:"Hello!" } }, //computed定义 computed: { fanzhuan(){ return this.bb.split('').reverse().join(''); } } //模板输出 <div> {{bb}} </div>
class动态绑定
第一种方式
//模板输出 <div v-bind:class="{'inner':isinner,'active':isactive}">第一种</div> <!-- 用了引号的是class名,没用引号的是变量 --> //data定义 data(){
return{ isinner:true, //true表示该属性生效 isactive:false //false表示该属性不生效
}
}
第二种方式(个人推荐)
//模板输出 <div :class="classObject">第二种</div> <!-- :class 是 v-bind:class 的缩写 --> //data定义 data(){ return{ isinner:false, //false表示该属性不生效 isactive:true //true表示该属性生效 //这里可以添加适当多的class } }
第三种
//模板输出 <div :class="[aclass,bclass]">第三种</div> <!-- 这里aclass和bclass指的是data的变量 --> //data定义 data(){ return{ aclass:'abc', bclass:'def' } }
style动态绑定
//不推荐style嵌套在html中
第一种
//模板输出 <div v-bind:style="{'color':color1,'background-color':color2}">style第一种</div> <!-- 这里color1 和 color2指的是data的变量 --> //data定义 data(){ return{ color1:'red', //这里所有不加引号的都表示变量 color2:'orange' //加了引号的才表示字符串 } }
第二种
//模板输出 <div v-bind:style="styleObject">style第二种</div> <!-- 所有样式都可以存储在styleObject里面 --> //data定义 data(){ return{ styleObject:{ 'color':'yellow', 'background-color':'green' /*这里可以添加各种样式*/ } } }
第三种
//模板输出 <div v-bind:style="[ziti,beijing]">style第三种</div> <!-- 数组里面的ziti和beijing都是对象,每个对象都可以有多种样式 --> //data定义 data(){ return{ ziti:{ //这里可以添加多种样式 'color':'cyan' }, beijing:{ //这里可以添加多种样式 'background-color':'blue' } } }
条件渲染
v-if
//当v-if的属性值为真就执行
//模板输出 <div v-if="bb">当bb为真,打印出if语句</div> //data定义 data(){ return{ bb:true } }
v-if v-else
//若v-if条件为假,则执行v-else的内容
//模板输出 <div v-if="bb === 'A'">选项A</div><!-- 判断bb变量的值是否===A,是就执行 --> <div v-else>其他选项</div> <!-- 注意v-else后面不需要属性值 --> //data定义 data(){ return{ bb:'A' //这里控制if和else哪个输出 } }
v-if v-else-if v-else
//若条件不等于v-if v-else-if,则输出v-else
//模板输出 <div v-if="dd==='D'">dd==='D'输出这项</div> <div v-else-if="dd==='E'">dd==='E'输出这项</div> <div v-else>dd的变量非DE,输出这项</div> //data定义 data(){ return{ dd:'E' //这里控制输出语句 } }
v-show
//跟v-if差不多一样,只要条件为真就输出
//模板输出 <div v-show="bb">当bb为真输出此语句</div> //data定义 data(){ return{ bb:true } }
列表渲染
v-for循环输出数组
//模板输出 <div> <ul> <li v-for="child in parents">{{child}}</li> <!-- 其中parents为数组变量,child为数组中的每一项数据,child名字自定以 --> </ul> </div> //data定义 data(){ return{ parents:[1,2,3,4,5] //数组定义 } }
v-for循环数组,带下标
//模板输出 <div> <ul> <li v-for="(child,index) in parents">{{child}}下标为{{index}}</li> <!-- 其中parents为数组变量,child为数组中的每一项数据,index为所对应的数组下标 --> </ul> </div> //data定义 data(){ return{ parents:[1,2,3,4,5] //数组定义 } }
v-for循环输出对象
//模板输出 <div> <ul> <li v-for="(value,key) in obj">{{key}}:{{value}}</li> <!-- ()里面的值,第一个必须是属性值value,其次才是key,不然容易混乱 --> <!-- obj为对象变量--> </ul> </div> //data定义 data(){ return{ obj:{ 'name':'张三', 'age':'18岁', 'sex':'female', 'address':'beijing' } } }
事件处理器
//v-on:click的缩写是@click
行内直接执行
//模板输出 <div> <div> <p>按钮被点击了{{a}}次</p> <button v-on:click="a+=1">计算点击次数</button> </div> </div> //data定义 data(){ return{ a:0 } }
行内调用函数(不传参)
//模板输出 <div> <div> <p>按钮被点击了{{a}}次</p> <button v-on:click="count">计算点击次数</button> </div> </div> //data定义 data(){ return{ a:0 } } //methods定义 methods:{ count(){ this.a+=1; } }
行内调用函数(传参)
//模板输出 <div> <div> <button v-on:click="hello('打招呼实参')">调用传参的函数</button> </div> </div> //methods定义 methods:{ hello(a){ alert(a); } }
默认冒泡机制(不阻止)
//点击会有两个弹框
//模板输出 <div> <div @click="hello('第二次冒泡')"> <button v-on:click="hello('第一次冒泡')">调用传参的函数</button> </div> </div> //methods定义 methods:{ hello(a){ alert(a); } }
阻止冒泡
//只会出现一个弹框
//模板输出 <div> <div @click="hello('第二次冒泡')"> <button v-on:click="hello('第一次冒泡')">调用传参的函数</button> //阻止冒泡只需在v-on:click或@click后面加上 .stop 即可 </div> </div> //methods定义 methods:{ hello(a){ alert(a); } }
自定义组件
首先
在src的components下面写好组件
<template> <div>{{time}}</div> </template> <script> export default{ data(){ return{ time:100 } }, mounted(){ //组件被挂载之后执行 var t = this; //把整个data函数存储路径复制过来,这样修改time值才会改变 //原理是引用数据类型直接赋值的是路径,而不是数据本身,直接修改的话是修改源函数 //若直接把this.time复制过来的话,复制的是基本数据类型,更改基本数据类型的数据起不到页面数据更改的效果 setInterval(function(){ t.time--; //这样更改才会改变data里面的源数据 },1000) } } </script>
接着
在需要组件的页面上
<template> <div> <div>引入components插件</div> //<!-- 第四步:在模板某个地方生成组件 --> <daoji> 若在第三步更换了名字,则标签就是该名字 </daoji> </div> </template> <script> //第一步:像写路由一样,把页面引进来 import daoji from '@/components/daoji.vue' export default{ data(){ return{ } }, components:{ //第二步:把引进来的组件写进去才能生效 daoji //第三步:可以更换名字,如:'aa':daoji,这样也能生效 } } </script>
添加组件样式
1、在调用组件的页面,传参到components组件页
<jj col="red">这是生成组件的标签</jj> //将col属性传入components页
2、在components组件页,script部分接收参数
//这个对象定义在export default里面
props:{ //接收数据的对象 col:{ //发送过来的col,满足下面条件才生效 type:String, //要求接收到的是字符串,String首字母一定要大写 default:'black' //默认值,没接收到数据时用 } }
3、在components组件页,template部分定义样式
<template> <p :style="{color:col}">{{time}}</p> </template>
添加组件行为
1、components组件页中,当倒计时结束时,触发函数end
if(t.time == 0){ t.$emit("end"); //当time=0时,触发end,end是自定义的名称 clearInterval(dd); }
2、在调用页中定义@end,并指定页面中触发的函数ending
<jj @end="ending"> 这是生成组件的标签 </jj>
3、同时在调用页中定义ending函数
methods:{ ending(){ alert("结束了"); } }
DOM操作
首先在模板文件定义ref属性,如
<div ref="hhead"></div> //ref属性值自定义
接着在mounted下操作DOM
mounted(){ //在mounted下,所有的DOM都是真实DOM this.$refs.hhead.innerText = '经过Dom操作出来的内容'; //this . $refs . 模板ref属性值 . innerText等操作 }
过渡效果
//没有过渡效果时,隐藏和出现都是一闪而过
//template模板 <div id="demo"> <button v-on:click="show = !show"> //点击按钮实现show的真假转换 Toggle </button> <transition name="fade"> //vue框架的过渡标签,不定义样式不起效果 <p v-if="show">hello</p> //通过获取show的真假,实现p标签是否输出 </transition> </div> //data函数定义 data() { return { show: true } }
//添加过渡效果,实现淡入淡出
<style> /*获取transition标签的name属性*/ .fade-leave,.fade-enter-to{ /*一般默认opacity都是1,这项可省略*/ opacity:1; } .fade-leave-active,.fade-enter-active{ transition: opacity .5s; /*过渡效果为opacity,在0.5秒内完成*/ } .fade-leave-to,.fade-enter{ opacity:0; } /*样式中.fade表示transition的name值*/ </style> //(淡入)隐藏效果opacity从1到0,分为三个状态呈现 //.fade-leave(1) -> .fade-leave-active(.5) -> .fade-leave-to(0) //(淡出)出现效果opacity从0到1,分为三个状态呈现 //.fade-enter(0) -> .fade-enter-active(.5) -> .fade-enter-to(1)
路由跳转(vue-router)
模板直接跳转
<div> <router-link to="/liebiao">列表渲染(直接跳转)</router-link> //<!-- router-link相当于a标签,to相当于href,to的属性值为路由表的path --> </div>
模板带参数跳转(带params)
//视图模板(发送页) <div> <router-link :to="{name:'tiaojian',params:{name:'zhangsan'}}">条件渲染(带参数跳转)</router-link> //<!-- :to表示v-bind:to,后面的参数可以直接用变量 --> //<!-- 跳转方式可以用name跳转(name:'tiaojian'),也可以用path跳转(path:'/tiaojian'),参照router下的路由表 --> //<!-- params后面的参数是通过get的方式发送, --> </div> //路由表 { path:'/tiaojian/:name', //:name表示:接收name属性 所对应的对象params,及后面的对象query,的所有内容 name:'tiaojian', component:tiaojian } //mounted函数(接收页) mounted(){ alert(this.$route.params.name); // 接收params数据用:this.$route.params.属性名 }
模板带参数跳转(带params & query)
//视图模板(发送页) <div> <router-link :to="{ name:'bangding',params:{name:'张三',address:'北京'},query:{age:18} }"> css与style绑定 </router-link> </div> //路由表 { path: '/bangding/:name', //:name表示:接收name属性 所对应的对象params,及后面的对象query,的所有内容 name: 'bangding', component: bangding } //mounted函数(接收页) mounted(){ alert(this.$route.query.age); //接收query数据:this.$route.query.属性名 }
js直接跳转
//视图模板(发送页) <div @click="toUrl">组件(js直接跳)</div> //methods(发送页) methods:{ toUrl(){ this.$router.push({ path:'/zujian' }); } }
js跳转(带params)
//视图模板(发送页) <div v-on:click="url">事件处理(js跳,带params)</div> //methods(发送页) methods:{ url(){ this.$router.push({name:'shijian',params:{fa:'带params参数跳'}}); } } //接收页的路由表 //根据实际情况选择写或不写 //mounted函数(接收页) mounted(){ alert(this.$route.params.fa); }
js跳转(带params & query)
//视图模板(发送页) <div @click="uurl">项目(js跳,带params & query)</div> //methods(发送页) methods:{ uurl(){ this.$router.push({ name:'xiangmu',params:{msg:'params>msg属性值'},query:{gg:'query>gg 属性值'} }); } } //接收页的路由表 //根据实际情况选择写或不写 //mounted函数(接收页) mounted(){ //路由表没有添加params的属性情况 //1、则地址栏接收不到params,但是页面实际是可以收到的 //2、地址栏可以正常接收query alert(this.$route.params.msg); alert(this.$route.query.gg); }
建议:不带参数时用path跳转,带参数时用name跳转