基础
Vue
官网https://cn.vuejs.org/
数据绑定
-
使用
{{}}
j进行数据绑定<p>{{变量}}</p>
-
使用
v-ones
可以指定元素只改变一次<p v-ones>{{变量}}</p>
-
如果返回的数据是一个带有
html
格式的字符串,需要按照格式显示则需要v-html="变量"
<p v-html="code"></p>
-
如过想要将返回的值放在属性上则需要
v-bind:属性="变量"
,其中v-bind
可以省略,直接写:
<img v-bind:scr="logo" alt=""> <img :src="logo" alt="">
Class和style的绑定
- 通过
b-bind
来绑定
<p :class="{title:true,'main-title':false}">我爱你:世界</p>
- 通过对象的形式
<p :class="{title:true,'main-title':false}">我爱你:XXX</p>
- 直接写style的方式
<p :style="[pStyle,fontW]">我爱你:oooo</p>
<script>
new Vue({
el: '#app',
data: {
username: "张锐",
pclass1: "title",
pclass2: "main-title",
strong: false,
pStyle:{
'color': "red",
"fontSize":"30px"
},
fontW:{
"fontWeight":"800"
}
}
})
</script>
- 在使用花括号或者属性绑定时可以直接使用
js
的表达式和函数- 常见表达式有:变量读取、变量运算、三目运算符、函数调用、取反等。
条件判断
- 条件判断,使用方式和其他语言一样,只是需要在前面加
v-
,如果需要判断的代码有很多则可以使用使用template
标签来包裹,默认情况会重用相同的代码,如果想要不使用重用则可以在标签上加入key
属性,实例代码如下
<div id="app">
<p v-if="weather=='sun'">去公园</p>
<p v-else-if="weather=='rain'">去看电影</p>
<p v-else>呆在家</p>
<tamplate v-if="age<18">
<p>数学考了多少分</p>
</tamplate>
<tamplate v-else-if="age>18&&age<25">
<p>有没有女朋友</p>
</tamplate>
<tamplate v-else>
<p>工资多少啊</p>
</tamplate>
<template v-if="loginType=='username'" key='username'>
<label>用户名</label>
<input type="text" name="username" placeholder="用户名">
</template>
<template v-else="loginType=='email'">
<label>邮箱</label>
<input type="text" name="email" placeholder="email">
</template>
<button @click="changeLoginType">更换登陆类型</button>
</div>
<script>
new Vue({
el: '#app',
data: {
weather: "sun",
age:25,
loginType: "username"
},
methods:{
say(){
return "早上好"
},
changeLoginType(){
this.loginType = this.loginType=='username'?"email":"username"
}
}
})
</script>
v-if
和v-show
的区别v-if
只有在第一次为真时才会渲染,调整的标签的渲染v-show
在加载的时候就会全部加载上,只是display
属性为none
而已,在修改时只是会调整这个属性- 一般来说
v-if
有更高的切换开销,而v-show
有更好的渲染开销,因此如果一个元素需要频繁的切换则一般使用v-show
较好,如果在运行时条件很少改变则使用v-if
比较好
循环语句
- 循环遍历列表,使用
v-for
语句,可以只取元素,也可以将元素和索引都取出来,第一个参数为列表中的每一个元素,第二个参数为索引,使用in
或of
的方式遍历 。 - 循环遍历对象,使用
v-for
的语句,可以只取元素,也可以将元素和键都取出来,
第一个参数为元素第二个参数为键,使用 in
或of
的方式遍历 。
- 一般使用循环的时候通常会绑定一个属性作为
key
,以Vue
默认使用代码重用引发意想不到的bug - 如果在自定义组件中使用
v-for
则key
是必须的
<div id="app">
<table>
<thead>
<tr>
<th>序号</th>
<th>标题</th>
<th>作者</th>
</tr>
</thead>
<tbody>
<tr v-for="(book,index) in books" :key="book.title">
<td>{{ index }}</td>
<td>{{ book.title }}</td>
<td>{{ book.author }}</td>
</tr>
</tbody>
</table>
<div>
<p v-for="(value,key) in user">{{key}}->{{value}}</p>
</div>
</div>
<script>
new Vue({
el: '#app',
data: {
books:[
{
"title": "三国演义",
"author": "罗贯中"
},
{
"title": "西游记",
"author": "吴承恩"
},
{
"title": "水浒传",
"author": "施耐庵"
},
{
"title": "红楼梦",
"author": "曹雪芹"
},
],
user:{
"name":"zr",
"age":"19"
}
}
})
</script>
触发视图更新
更新类型
-
直接赋值更新。
this.heros=[]
,模板会立即更新 -
通过函数更新。
this.heros.push("xxx")
push、pop、shift、unshift、splice、sort
这些函数会直接触发更新- 其他函数可能不会触发更新,可以将修改后的数据进行赋值来更新
<div id="app"> <ul> <li v-for="hero in heros" :key="hero">{{hero}}</li> </ul> <button @click="update">直接更新</button> <button @click="fun_show_update">函数显示更新</button> <button @click="fun_update">函数不显示更新</button> <button @click="fun_concat">拼接</button> </div> <script> new Vue({ el: '#app', data: { heros:["蜘蛛侠","美国队长"] }, methods:{ update(){ this.heros=["绿巨人"] }, fun_show_update(){ // 追加一个 // this.heros.push("绿巨人") // 删除最后一个 // this.heros.pop() // 删除第一个 // this.heros.shift() // this.heros.unshift("绿巨人") // 删除两个 // this.heros.splice(0,2) // 在第一个位置插入一个元素 // this.heros.splice(0,0,"绿巨人") // 将从0开始的两个元素替换为绿巨人 // this.heros.splice(0,2,"绿巨人") }, fun_update(){ this.heros.slice(0,1) // 不能触发更新的还有 filter 、 concat 、 slice // 可以采用直接赋值来取消这种结果 }, fun_concat(){ this.heros = this.heros.concat(["蝙蝠侠","超人"]) } } }) </script>
视图更新
1、如果直接修改数组中的某个值不会触发视图更新,着用情况需要使用splice
或者Vue.set
方法来实现。
Vue.set(this.books,0,"钢铁是怎么练成的")
2、如果同台给对象添加属性,也不会触发视图更新,只能通过Vue.set
来进行添加。
Vue.set(this.user,"age",18)
事件绑定
- 使用
v-on
来绑定事件,可以直接使用变量或者函数。 - 也可以使用语法糖
@
符号来完成。 - 在调用函数的时候可以传递参数
<div id="app">
<p v-for="book in books" :key="book" @click="fun_click(book)">{{ book }}</p>
</div>
<script>
new Vue({
el:'#app',
data: {
books: ["水浒传","三国演义","红楼梦","西游记"]
},
methods:{
fun_click(value){
alert(value)
}
}
})
</script>
-
传入
js
的事件event
,使用固定写法$event
<div id="app"> <a href="http:www.baidu.com" @click="fun($event)">点击不跳转</a> </div> <script> new Vue({ el:app, data: { }, methods:{ fun(event){ event.preventDefault() alert("不跳转") } } }) </script>
-
阻止标签的默认行为,
prevent
<a href="http:www.baidu.com" @click.prevent="">点击不跳转</a>
-
常见修饰符,用于事件后的修饰
.stop
:event.stopPropagation
阻止事件冒泡.capture
:事件捕获.once
:这个事件只执行一次.self
:代表当前这个被点击的元素自己.passive
:在页面滚动的时候告诉浏览器不会阻止默认行为,从而让滚动更流畅
-
js
中的冒泡机制冒泡机制就是在嵌套的元素中内部元素触发的事件会冒泡到外面元素,也就是说外面元素会监听到内部元素的事件。阻止这种冒泡的方法可以在需要阻断的位置加入
.stop
修饰符。 -
js
中的事件捕获机制捕获的方式就是会先执行捕获,可以使用
.capture
来进行捕获
计算属性和监听器
计算属性
-
计算属性都写在
computed
中 -
计算属性默认情况中只有
get
,没有set
,如果想要实现set
,那么就必须实现get
,放到计算属性的名字中 -
扩展:取到输入框中的值可以使用
v-model:value
或者简写v-model
<div id="app"> <div> <label>宽:</label> <input type="text" v-model="width"> </div> <div> <label>高:</label> <input type="text" v-model="height"> </div> <div> 面积:{{ area }} </div> <div> <label>省:</label> <input type="text" v-model:value="province"> </div> <div> <label>市:</label> <input type="text" v-model:value="city"> </div> <div> <label>区:</label> <input type="text" v-model:value="district"> </div> <div> <label>详细地址:</label> <input type="text" v-model="address"> </div> </div> <script> new Vue({ el:'#app', data: { width:0, height:0, province:"", city:"", district:"" }, computed:{ // 默认只有get area(){ return this.width*this.height }, address:{ // 取值的时候会调用这个方法 get(){ let result = "" if(this.province){ result += this.province + "省" } if(this.city){ result += this.city + "市" } if(this.district){ result += this.district + "区" } return result }, set(value){ // xx省xx市xx区 let result = value.split(/省|市|区/) if(result && result.length > 0){ this.province = result[0] } if(result && result.length > 1){ this.city = result[1] } if(result && result.length > 2){ this.district = result[1] } } } } }) </script>
监听属性
- 监听的属性需要写在
watch
中,默认会传递两个参数,一个新的值,一个是旧的值
<div id="app">
<div>
<input type="text" v-model="kw">
</div>
<div>
<span>推荐的关键字</span>
{{result}}
</div>
</div>
<script>
new Vue({
el:'#app',
data: {
kw:"",
result:""
},
watch:{
kw(newValue,oldVaule){
// 模拟加载
this.result = "正在加载中...."
setTimeout(()=>{
this.result = "推荐结果:" + newValue
},1000)
}
}
})
</script>
表单输入绑定
输入绑定
- 普通文本输入框采用
v-model
来绑定属性获取输入值 - 多选框
checkbox
需要注意v-model
的值必须是同一个,然后返回值为一个数组,数组中存放的是每一个选择框的value
- 单选框
radio
同一组单选按钮的v-model
也必须绑定同一个值,返回的是选中的按钮的value
的值 - 下拉框
select
需要将v-model
绑定到select
标签上,如果option
中没有value
属性,默认会区其中显示的值,如果指定了value
属性,则选中的value
值
修饰符
.lazy
会在输入框输入完成后才更新.number
会将输入的值转换为数值类型,如果字符串不能被转换为数字则不会修改值,而且会清掉输入框中的字符串.trim
会将输入的字符串首尾的空白字符串清理掉
自定义组件
基本使用
-
注册方式使用
Vue.component("组件名",{data,template})
。data
: 必须为一个函数,这个函数返回一个对象,用法和Vue
中的data
用法相同template
:用来表示这个组件的渲染后的具体代码
<div> <button-count></button-count> </div> <script> Vue.component("button-count",{ // template 为渲染内容 template:"<button @click='count+=1'>点击了{{count}}次</button>", // data 为数据,必须是函数,然后返回一个对象 data: function () { return {count: 0} } }) </script>
-
注意: 组件模板中必须只包含同一个 根标签
为组件添加属性
- 使用
props
来表示属性,props
可以采用数组的方式,或者是对象的方式,采用对象的方式可以提供一些限制。- 限制包含
type
类型、required
是否必须、default
默认值
- 限制包含
<div id="app">
<article-list :articles="articles"></article-list>
</div>
<script>
Vue.component("article-list",{
// props:["articles"],
props:{
articles:{
type:Array,
required:true
}
},
// ``符号用于可以换行的字符
template: `
<table>
<thead>
<tr>
<th>序号</th>
<th>标题</th>
</tr>
</thead>
<tbody>
<tr v-for="(article,index) in articles" :key="article.title">
<td>{{index+1}}</td>
<td>{{article.title}}</td>
</tr>
</tbody>
</table>
`
})
new Vue({
el:'#app',
data: {
articles:[
{
title:"《三国演义》"
},
{
title:"《水浒传》"
},
{
title:"《红楼梦》"
},
]
},
})
</script>
自定义组件添加事件
- 需要在组件模板中添加事件
- 在主键的
methods
中定义这个事件应该执行的函数 - 在这个函数中执行
this.$emit('xxx',传参)
来执行函数(外部传过来的函数 比如叫xxx),这里需要注意这个xxx不要使用驼峰命名法,可以使用-
。 - 在外部绑定函数,使用
@XXX='外部定义的函数'
<div id="app">
<blog-item v-for="blog in blogs" :blog="blog" @check-change="outChange"></blog-item>
<h1>选中的博客:</h1>
<div v-for="blog in select_blogs">
{{blog.title}}
</div>
</div>
<script>
Vue.component("blog-item",{
props: ["blog"],
template: `
<div>
<span>{{blog.title}}</span>
<input type="checkbox" @click="onClick">
</div>
`,
methods: {
onClick(){
this.$emit("check-change",this.blog)
}
}
})
new Vue({
el:app,
data: {
blogs:[
{
"title": "这是一个测试",
"id": 1
},
{
"title": "这也是一个测试",
"id": 2
}
],
select_blogs:[]
},
methods: {
outChange(blog){
// 判断元素在数组中的位置,如果值为非负数,则是下标
let index = this.select_blogs.indexOf(blog)
if(index>=0){
this.select_blogs.splice(index,1)
}else{
this.select_blogs.push(blog)
}
}
}
})
</script>
自定义组件的V-model
- 在模板中配置
model
event
表示什么情况下触发v-model
的行为prop
表示传给v-model
的变量绑定到模板中的哪个变量上
- 在合适的时机调用
this.$emit(model.event,计算结果)
就可以了,注意这里面只需要返回计算结果而不需要改变值,Vue
会自动改变这个值同时改变模板外面的值
<div id="app">
<Stepper v-model="goods_count"></Stepper>
<!--外部的值也会同步更改-->
<span>{{goods_count}}</span>
</div>
<script>
Vue.component("Stepper",{
props: ["count"],
model:{
// model 的事件
event: "xxx",
// 绑定的值
prop: "count"
},
template: `
<div>
<button @click="sub">-</button>
<span>{{ count }}</span>
<button @click="add">+</button>
</div>
`,
methods:{
// 这里面不需要修改this.count的值,只要把结果传出去就可以
sub(){
this.$emit("xxx",this.count-1)
},
add(){
this.$emit("xxx",this.count+1)
}
}
})
new Vue({
el:"#app",
data: {
goods_count: 0
}
})
</script>
自定义组件的插槽
- 在模板中使用
<slot></slot>
来占位,以后在标签内写入的内容(包括标签)就会在<slot></slot>
的位置进行替换
<div id="app">
<navigation-link url="www.baidu.com">百度</navigation-link>
</div>
<script>
Vue.component("navigation-link",{
props: ["url"],
template: `
<a :href="url">
<slot></slot>
</a>
`
})
</script>
- 可以在
<slot>默认值</slot>
中添加默认值,也就是在使用模板但模板标签中无任何值的时候显示
命名插槽
- 在定义插槽的时候指定
<slot name="xxxx"></slot>
属性表示名字 - 未指定名字的插槽名字为
default
- 在使用组件时需要在
<template v-slot="xxxx"></template>
指定名字,来加载不同的数据
<div id="app">
<main>
<template v-slot="header">
<p>这是头部</p>
</template>
<template v-slot="body">
<p>这是主体</p>
</template>
<template v-slot="footer">
<p>这是尾部</p>
</template>
</main>
</div>
<script>
Vue.component("mian",{
props: ["url"],
template: `
<div class="main">
<slot name="header"></slot>
<slot name="body"></slot>
<slot name="footer"></slot>
</div>
`
})
</script>
插槽作用于
- 在模板中定义的变量插槽是无法访问到的,也就说作用域不同,不可见。’
- 可以在插槽中通过
v-bind:
传参的方式传入 - 在使用的时候可以以
v-slot:header="headerProps"
讲插槽里面的值得到存入headerProps
里 - 当组件中只有一个插槽并且这个插槽没有名字的时候可以使用
v-slot="props"
来简写
<div id="app">
<container>
<template v-slot:header="headerProps">
<p>{{ headerProps.navs }}</p>
</template>
<template v-slot:body>
<p>这是主体</p>
</template>
<template v-slot:footer="footerProps">
<p>{{footerProps.address}}</p>
<p>{{footerProps.aboutus}}</p>
</template>
</container>
</div>
<script>
Vue.component("container",{
template: `
<div class="main">
<slot name="header" :navs="navs"></slot>
<slot name="body"></slot>
<slot name="footer" :address="address" :aboutus="aboutus"></slot>
</div>
`,
data: function () {
return {
address: "公司地址",
aboutus: "关于我们",
navs: ["首页","新闻","课程"]
}
}
})
new Vue({
el:"#app",
data: {
username: "张锐"
}
})
</script>
生命周期函数
创建阶段
beforeCreate
:Vue
已经创建了,但是data
和methods
还没有创建好creadted
:data
和methods
已经创建好了beforeMount
:模板经过编译,还没有挂在到网页中mounted
:模板经过编译,并且已经挂在到网页中,创建阶段的事情都做好了
运行期间
beforeUpdate
:数据data
已经更新了,但是模板还未更新updated
:在data
中更新了,在模板中也更新了
销毁期间
beforeDestory
:Vue
执行实例或者组件销毁之前执行的函数,在这个函数中Vue
或者组件中的所有属性都是可以使用的。destoryed
:Vue
实例或者组件被销毁以后执行的。此时Vue
实例上所有东西都会解绑,所有事件都会被移除,所有元素都会被销毁。
过滤器
-
使用:
{{username|strip}}
的方式可以为属性username
添加过滤器,也可以为<a :href="url|strip></a>"
这样的标签属性添加过滤器 -
定义:都是定义一个函数,这个函数的第一个参数永远都是被过滤的变量
- 局部定义:在组件中添加一个属性
filters
,然后在filters
中添加过滤器。 - 全局定义:通过
Vue.filter("过滤器名",函数)
的方式定义
- 局部定义:在组件中添加一个属性
-
传参:如果使用过滤器的时候还需要传递额外的参数,那么可以在定义过滤器的时候,提供其他参数,在使用的时候与普通函数相同。
<body> <div id="app"> {{username|strip("-")}} </div> <script> Vue.filter("strip",function (value, str) { // 将空格替换为 str return value.replace(" ",str) }) new Vue({ el:"#app", data: { username: "张 锐" } }) </script>
VueRouter
基本使用
-
创建一个
VueRouter
对象:new VueRouter()
。 -
在
VueRouter
中,需要传递一个routes
参数。这个参数是一个数组类型,数组中存储的是对象,对象中最少有两个属性,一个是path
,代表url
,第二个是component
,代表数据更新的组件,示例代码如下:
let index = Vue.extend({template:"<h1>首页</h1>>"})
let find = Vue.extend({template:"<h1>发现音乐</h1>>"})
let friend = Vue.extend({template:"<h1>我的朋友</h1>>"})
let router = new VueRouter({
routes: [
{path:"/",component:index},
{path:"/find",component:find},
{path:"/friend",component:friend},
]
})
-
将
router
传给Vue
new Vue({ el:"#app", router: router })
-
将网页中之前的
a
标签,替换成router-link
。然后指定参数to
表示需要跳转的路径。<li><router-link to="friend">我的朋友</router-link></li>
-
使用
router-view
指定网页中哪个地方需要被更新
extend
和component
之间的区别extend
只是创建了一个组件,但是没有加载的Vue
中component
是创建了一个组件,并且起了一个名字,然后加载到Vue
中
动态路由
$route
和$router
的区别$route
是表示当前访问的路由,其中参数有fullpath
:完整路径name
:路由名字params
:参数query
:查询字符串参数,或者叫get
参数
$router
表示全局的VueRouter
对象
- 在
url
中定义一个参数,那么以后url
中就可以动态的传递这个参数。语法是:/about/:参数名
。 - 在组件中可以通过
this.$oute.params.参数名
拿到这个参数,或者在组件的模板中,可以直接使用$route.params.参数名
拿到。 this.$route
和this.$router
组件复用
-
使用动态路由的时候,如果只有请求参数的不同,则
Vue
默认使用组件的复用,这虽然回加快渲染效率,但是由于组件一直存在,所以不会在调用生命周期函数,可能出现问题。-
解决这个问题可以采用监听属性
let index = Vue.extend({template:"<h1>首页</h1>"}) let about = Vue.extend({ template:"<h1>个人中心:{{$route.params.userid}}</h1>", mounted(){ console.log(this.$route.params.userid); }, watch: { "$route": function (to, from_) { console.log(to); console.log(from_); } } }) let friend = Vue.extend({ template:"<h1>我的朋友</h1>", }) let router = new VueRouter({ routes: [ {path:"/",component:index}, {path:"/about/:userid",component:about}, {path:"/friend",component:friend}, ] }) new Vue({ el:"#app", router: router })
-
使用路由守卫
beforeRouteUpdate: function (to, from, next) { console.log(to); console.log(from); next() }
to
表示下一个路由from
表示当前路由next
是一个函数,也就是跳转函数
-
匹配404错误
- 使用
*
来匹配未知的路由,可以将将这个路由映射到一个404的组件中 - 数据不存在的处理,这种情况,前端是无法判断的,只能通过访问服务器来判断存不存在,如果服务器返回不存在,那么我们可以通过
this.$router.replace
来跳转到404的页面
<div id="app">
<nav class="navbar navbar-default">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">网易云音乐</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="active"><router-link to="/">首页</router-link></li>
<li><router-link to="find">发现音乐</router-link></li>
<li><router-link to="friend">我的朋友</router-link></li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
<div class="container">
<router-view></router-view>
</div>
</div>
<script>
let index = Vue.extend({template:"<h1>首页</h1>"})
let find = Vue.extend({template:"<h1>发现音乐</h1>"})
let friend = Vue.extend({
template:"<h1>我的朋友{{$route.params.user_id}}</h1>",
mounted(){
if(this.$route.params.user_id !== '123'){
this.$router.replace("/404")
}
},
watch:{
"$route": function (to, from) {
// 监听user_id改变
// 想服务端发送请求,验证是否存在
// 如果返回不存在需要跳转到404页面
}
}
})
let notfound = Vue.extend({
template:"<h1>404页面没有找到</h1>",
})
let router = new VueRouter({
routes: [
{path:"/",component:index},
{path:"/find",component:find},
{path:"/friend/:user_id",component:friend},
{path:"/404",component:notfound},
{path:"*",component:notfound},
]
})
new Vue({
el:"#app",
router: router
})
</script>
嵌套路由
-
在大的路由下面有时候可能使用一些子路由来切换数据,那么这时候可以使用路由嵌套。
-
首先在定义路由的时候不需要放在
routes
中,而是应该放在父路由的children
中。 -
在父路由的组件中,要记得添加路由出口
<router-view>
,示例代码如下。<div id="app"> <nav class="navbar navbar-default"> <div class="container-fluid"> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">网易云音乐</a> </div> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <li class="active"><router-link to="/">首页</router-link></li> <li><router-link to="find">发现音乐</router-link></li> </ul> </div><!-- /.navbar-collapse --> </div><!-- /.container-fluid --> </nav> <div class="container"> <router-view></router-view> </div> </div> <script> let index = Vue.extend({template:"<h1>首页</h1>"}) let find = Vue.extend({ template:` <div> <h1>发现音乐</h1> <ul class="nav nav-pills"> <li role="presentation" class="active"><router-link to="/find">刘德华</router-link to=></li> <li role="presentation"><router-link to="/find/lm">黎明</router-link to=></li> <li role="presentation"><router-link to="/find/gfc">郭富城</router-link to=></li> </ul> <div class="container"><router-view></router-view></div> </div> ` }) let user_ldh = Vue.extend({ template:`<h1>刘德华</h1>` }) let user_lm = Vue.extend({ template:`<h1>黎明</h1>` }) let user_gfc = Vue.extend({ template:`<h1>郭富城</h1>` }) let router = new VueRouter({ routes: [ {path:"/",component:index}, { path:"/find", component:find, children: [ {path:"",component:user_ldh}, {path:"lm",component:user_lm}, {path:"gfc",component:user_gfc}, ] }, ] }) new Vue({ el:"#app", router: router }) </script>
编程式导航
this.$router.push
:跳转到下一个url
,会把新转入的url
添加到浏览器的history
中。参数- 字符串:直接路径
- 对象:
path
和name
都可以,但是如果使用了path
,那么参数必须放到path
中,放到params
中无用
this.$router.replace
:用法和push
一样,只是会替换当前页面,不会存在历史记录,也就是当点击前进或者后退的时候都没有这个页面。this.$router.go
:前进或者后退。- 正数表示前进
this.$router.go(1)
,前进一步 - 负数表示后退
this.$router.go(-2)
,后退两步 - 如果无法前进或者后退了,那么执行将没有任何结果
- 正数表示前进
<div id="app">
<button @click="gotoPost">帖子列表</button>
<button @click="gotoProfile">个人中心</button>
<button @click="gotoLogin">登陆页面</button>
<router-view></router-view>
</div>
<script>
let post = Vue.extend({
template: `<h1>帖子列表</h1>`
})
let profile = Vue.extend({
template: `<h1>个人中心{{$route.params.userid}}</h1>`
})
let login = Vue.extend({
template: `<h1>登陆页面{{$route.query}}</h1>`
})
let router = new VueRouter({
routes:[
{
path:"/post",
component:post
},
{
path:"/profile/:userid",
component:profile,
name:"myprofile"
},
{
path:"/login",
component:login,
name:"login"
},
]
})
new Vue({
el: "#app",
router:router,
methods:{
gotoPost(){
this.$router.push("/post")
},
gotoProfile(){
// 传url路径
// this.$router.push("/profile/123")
// 传对象
// this.$router.push({path:"/profile/123"})
// 传命名
this.$router.push({name:"myprofile",params:{userid:"123"}})
},
gotoLogin(){
let currentPath = this.$route.fullPath
this.$router.push({name:"login",query:{from:currentPath}})
}
}
})
</script>
命名路由和命名视图
命名路由
-
在定义路由的时候指定
name
属性作为路由的名字,然后在使用路由的时候传递一个对象,这个对象中包含name
属性,使用方法和this.$router.push
中参数一样。 -
需要注意使用
router-link
的时候要在to
前使用:
因为使用了变量。<router-link :to="{ name: 'myprofile',params:{userid:123}}">个人中心</router-link>
命名视图(多组件)
- 在一个路由下面展示多个组件,需要使用命名的视图。
- 在定义路由的时候需要传递
components
参数,然后把所有需要展示的组件都放到这个里面components
是一个对象,{name:组件}
映射。 - 在模板中,通过
<router-view name="组件名"></router-view>
来实现。 - 默认没有名字的出口是
default
,可以在components
中指定这个出口对应的组件。
<body>
<div id="app">
<div class="header">
<router-view name="header"></router-view>
</div>
<div class="body">
<div class="sidebar">
<router-view name="sidebar"></router-view>
</div>
<div class="main">
<router-view name="main"></router-view>
</div>
</div>
<div class="footer">
<router-view name="footer"></router-view>
</div>
</div>
</body>
<script>
let headerComponent = Vue.extend({
template: `<div>header部分</div>`
})
let sidebarComponent = Vue.extend({
template: `<div>sidebar部分</div>`
})
let mainComponent = Vue.extend({
template: `<div>main部分</div>`
})
let footerComponent = Vue.extend({
template: `<div>footer部分</div>`
})
let router = new VueRouter({
routes:[
{
path:"/",
components:{
header: headerComponent,
sidebar:sidebarComponent,
main:mainComponent,
footer:footerComponent
}
}
]
})
new Vue({
el: "#app",
router:router
})
</script>
重定向和别名
- 重定向可以在定义路由的时候指定参数
redirect
来指定重定向的位置。 - 起别名可以在定义路由的时候指定参数
alias
来指定url
的别名。起别名之后,也可以通过别名来访问这个路由。
<div id="app">
<router-view></router-view>
</div>
<script>
let index = Vue.extend({template: "<h1>首页</h1>"})
let article = Vue.extend({template:"<h1>文章列表页</h1>"})
let router = new VueRouter({
routes: [
{path: "/", redirect:"/article"},
// {path: "/", redirect:{name:"article"}},
{path: "/article", component: article,name:"article",alias:"/list"},
]
})
new Vue({
el: "#app",
router: router
})
</script>
全局导航守卫
beforeEach
-
全局导航守卫就是在
VueRouter
上实现的。 -
这个是在路由发生变化了,但是页面还没有跳转时候执行的函数。
-
beforeEach(to,from,next)
to
:是上一个路由对象from
: 是下一个路由对象next
:表示下一步该怎么走next()
:按照正常走next('/')
:中断之前的路由,重新走到/
路由上,也可以传递{name:'/'}
这种指定名字的路由next(false)
:中断路由,什么也不做,不会导向任何一个路由。
afterEach
- 这是在路由完成后的回调函数
afterEach(to,from)
to
:表示上一个路由from
:表示下一个路由
<div id="app">
<router-link to="/">首页</router-link>
<router-link to="/account">我的账户</router-link>
<router-link to="/order">我的订单</router-link>
<router-link to="/login">登陆</router-link>
<router-view></router-view>
</div>
<script>
const logined = false
let index = {template: "<h1>首页</h1>"}
let account = {template:"<h1>我的账户</h1>"}
let order = {template:"<h1>我的订单</h1>"}
let login = {template:"<h1>登陆</h1>"}
let router = new VueRouter({
routes: [
{path: "/", component:index,name:'index'},
{path: "/account", component:account,name:'account'},
{path: "/order", component:order,name:'order'},
{path: "/login", component:login,name:'login'},
]
})
router.beforeEach(function (to, from, next) {
// next(): 按照正常的跳转
// next():传递一个路由,就会跳转到指定路由
// next(false)或者没有调用next()则不会做任何跳转
next()
const authRoutes = ['account','order']
if(authRoutes.indexOf(to.name)>=0){
if(!logined){
console.log(from.name)
next({path:'/login'})
console.log(to.name)
}else{
next()
}
}else if(to.name === 'login'){
if(logined){
next('/')
}
}else{
next()
}
})
new Vue({
el: "#app",
router: router
})
</script>
路由导航守卫
-
是绑定到路由上的,在定义路由的时候需要指定
beforeEnter
属性<div id="app"> <router-link to="/">首页</router-link> <router-link to="/account">我的账户</router-link> <router-link to="/order">我的订单</router-link> <router-link to="/login">登陆</router-link> <router-view></router-view> </div> <script> const logined = true let index = {template: "<h1>首页</h1>"} let account = {template:"<h1>我的账户</h1>"} let order = {template:"<h1>我的订单</h1>"} let login = {template:"<h1>登陆</h1>"} let router = new VueRouter({ routes: [ {path: "/", component:index,name:'index'}, {path: "/account", component:account,name:'account'}, {path: "/order", component:order,name:'order'}, { path: "/login", component:login, name:'login', beforeEnter: function (to, from, next) { if(logined){ next('/') }else{ next() } } }, ] }) new Vue({ el: "#app", router: router }) </script>
组件导航守卫
-
主键导航守卫是绑定到组件上的,有三个方法:
-
veforeRouteEnter
:是在组件之前调用- 在渲染组件的对应路由呗
comfirm
之前调用 - 注意:这这个函数中不能使用
this
来代表组件,因为组件还没创建 - 可以在
next
中使用vm
来代表组件next(vm=>{ console.log(vm.username) })
- 在渲染组件的对应路由呗
-
beforeRouteYpdate
:这个是在进入组件之前调用,也就是当前路由改变,页面还没渲染的时候调用- 这个函数主要用于监听路由发生变化,当页面组件被复用的时候也会调用
- 在这个函数中可以访问组件实例
this
-
beforeRouteLeave
:这个是在即将离开组件路由的时候执行的函数- 这个函数主要用于一些未保存的确认按钮
- 这里可以访问
this
导航解析流程
- 导航被触发
- 在失活的组件里调用离开守卫
- 调用全局的
beforeEach
守卫 - 在重用的组件里调用
beforeRouteUpdate
守卫 - 在路由配置里调用
beforeEnter
- 解析异步路由组件
- 在激活的组件里调用
beforeRouteEnter
- 调用全局的
beforeResolve
守卫(2.5+) - 导航被确认
- 调用全局的
afterEach
- 触发
DOM
更新元素 - 用创建好的实例调用
beforeRouteEnter
守卫传递next
的回调函数
Vue-cli
组件定义和导入
- 定义:
.Vue
中分成三个模块,template
、script
、style
。template
:模板script
:js相关代码style
:样式相关代码
- 导入:使用
import XXX from XXX
style
- 默认情况下
.vue
中的style
中的样式是全局可用的 - 在
style
标签中加入scoped
属性后,使样式只能在当前标签可用<style scoped>
- 因为
App.vue
作为主入口文件,因此一般全局的样式会写在这个中,比如清空浏览器默认样式等 - 指定属性
lang='scss'
可以用来写sass
语法
适配移动端
-
使用包
postcss-pxtorem
和lib-flexible
npm install postcss-pxtorem --save-dev npm install lib-flex --save-dev
-
需要配置
package.json
文件
"postcss": {
"plugins": {
"autoprefixer": {},
"postcss-pxtorem": {
"rootValue": 37.5,// 基数,也就是1rem = 多少px,一般为设计师给的数除以10
"propList": [ // 什么属性支持转换
"*"
],
"selectorBlackList": [ // 什么不用转换
"van-*"
]
}
}
},
-
引用组件需要安装包
babel-plugin-import
,用于解析import
cnpm install babel-plugin-import --save
-
需要配置
babel.config.js
文件- 如果这个配置文件写错可能出现找不到
babel-plugin-vant
错误
module.exports = { presets: [ '@vue/app' ], plugins : [ ['import',{ libraryName: 'vant', libraryDirectory: 'es', style : true, },'vant'] ] }
- 如果这个配置文件写错可能出现找不到
-
导入语法
{ botton } from 'vant'
-