Vue-的基础使用
5.5.v-if和v-show
5.5.1.基本使用
v-if,顾名思义,条件判断。当得到结果为true时,所在的元素才会被渲染。
语法:v-if="布尔表达式"
v-if="布尔表达式"
示例:
html
<div id="app">
<button v-on:click="show = !show">点我呀</button>
<br>
<h1 v-if="show">
看到我啦?!
</h1>
<h1 v-show="show">
看到我啦?!show
</h1>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var app = new Vue({
el: "#app",
data: {
show: true
}
})
</script>
效果:
5.5.2.与v-for结合
当v-if和v-for出现在一起时,v-for优先级更高。也就是说,会先遍历,再判断条件。
修改v-for中的案例,添加v-if:
html
<ul>
<li v-for="(user, index) in users" v-if="user.gender == '女'">
{{index + 1}}. {{user.name}} - {{user.gender}} - {{user.age}}
</li>
</ul>
5.5.3.v-else
你可以使用 v-else
指令来表示 v-if
的"else 块":
html
<div id="app">
<h1 v-if="Math.random() > 0.5">
看到我啦?!if
</h1>
<h1 v-else>
看到我啦?!else
</h1>
</div>
v-else
元素必须紧跟在带 v-if
或者 v-else-if
的元素的后面,否则它将不会被识别。
v-else-if
,顾名思义,充当 v-if
的"else-if 块",可以连续使用:
html
<div id="app">
<button v-on:click="random=Math.random()">点我呀</button><span>{{random}}</span>
<h1 v-if="random >= 0.75">
看到我啦?!if
</h1>
<h1 v-else-if="random > 0.5">
看到我啦?!if 0.5
</h1>
<h1 v-else-if="random > 0.25">
看到我啦?!if 0.25
</h1>
<h1 v-else>
看到我啦?!else
</h1>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var app = new Vue({
el: "#app",
data: {
random: 1
}
})
</script>
类似于 v-else
,v-else-if
也必须紧跟在带 v-if
或者 v-else-if
的元素之后。
演示:
5.5.4.v-show
另一个用于根据条件展示元素的选项是 v-show
指令。用法大致一样:
ini
<h1 v-show="ok">Hello!</h1>
不同的是带有 v-show
的元素始终会被渲染并保留在 DOM 中。v-show
只是简单地切换元素的 CSS 属性 display
。
示例:
html
<div id="app">
<!--事件中直接写js片段-->
<button v-on:click="show = !show">点击切换</button><br/>
<h1 v-if="show">
你好
</h1>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
show:true
}
})
</script>
5.6.v-bind
html属性不能使用双大括号形式绑定,只能使用v-bind指令。
在将 v-bind
用于 class
和 style
时,Vue.js 做了专门的增强。表达式结果的类型除了字符串之外,还可以是对象或数组。
html
<div id="app">
<!--可以是数据模型,可以是具有返回值的js代码块或者函数-->
<div v-bind:title="title" style="border: 1px solid red; width: 50px; height: 50px;"></div>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var app = new Vue({
el: "#app",
data: {
title: "title",
}
})
</script>
在将 v-bind
用于 class
和 style
时,Vue.js 做了专门的增强。表达式结果的类型除了字符串之外,还可以是对象或数组。
计算属性:
在插值表达式中使用js表达式是非常方便的,而且也经常被用到。
但是如果表达式的内容很长,就会显得不够优雅,而且后期维护起来也不方便,例如下面的场景,我们有一个日期的数据,但是是毫秒值:
data:{
birthday:1529032123201 // 毫秒值
}
scss
<h1>您的生日是:{{
new Date(birthday).getFullYear() + '-'+ new Date(birthday).getMonth()+ '-' + new Date(birthday).getDay()
}}
</h1>
虽然能得到结果,但是非常麻烦。
Vue中提供了计算属性,来替代复杂的表达式:
javascript
var vm = new Vue({
el:"#app",
data:{
birthday:1429032123201 // 毫秒值
},
computed:{
birth(){// 计算属性本质是一个方法,但是必须返回结果
const d = new Date(this.birthday);
return d.getFullYear() + "-" + d.getMonth() + "-" + d.getDay();
}
}
})
- 计算属性本质就是方法,但是一定要返回数据。然后页面渲染时,可以把这个方法当成一个变量来使用。
页面使用:
我们可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的依赖进行缓存的 。计算属性只有在它的相关依赖发生改变时才会重新求值。这就意味着只要birthday
还没有发生改变,多次访问 birthday
计算属性会立即返回之前的计算结果,而不必再次执行函数。
5.8.watch
watch可以让我们监控一个值的变化。从而做出相应的反应。
示例:.
html
<div id="app">
<input type="text" v-model="message">
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
data:{
message:""
},
watch:{
message(newVal, oldVal){
console.log(newVal, oldVal);
}
}
})
</script>
6.组件化
在大型应用开发的时候,页面可以划分成很多部分。往往不同的页面,也会有相同的部分。例如可能会有相同的头部导航。
但是如果每个页面都独自开发,这无疑增加了我们开发的成本。所以我们会把页面的不同部分拆分成独立的组件,然后在不同页面就可以共享这些组件,避免重复开发。
在vue里,所有的vue实例都是组件
全局组件
我们通过Vue的component方法来定义一个全局组件。
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<hello></hello>
<hello></hello>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
Vue.component("hello",{
template:"<button @click='num++'>{{num}}点我一下</button>",
data(){
return {
num:0
}
}
})
const app=new Vue({
el:"#app"
})
</script>
</body>
</html>
组件其实也是一个Vue实例,因此它在定义时也会接收:data、methods、生命周期函数等
不同的是组件不会与页面的元素绑定,否则就无法复用了,因此没有el属性。
但是组件渲染需要html模板,所以增加了template属性,值就是HTML模板
全局组件定义完毕,任何vue实例都可以直接在HTML中通过组件名称来使用组件了。
data必须是一个函数,不再是一个对象。
效果:
你会发现每个组件互不干扰,都有自己的count值。怎么实现的?
组件的data属性必须是函数!
当我们定义这个 <counter>
组件时,它的data 并不是像之前直接提供一个对象:
取而代之的是,一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝:
data: function () { return { count: 0 } }
如果 Vue 没有这条规则,点击一个按钮就会影响到其它所有实例!
局部组件:
一旦全局注册,就意味着即便以后你不再使用这个组件,它依然会随着Vue的加载而加载。
因此,对于一些并不频繁使用的组件,我们会采用局部注册。
我们先在外部定义一个对象,结构与创建组件时传递的第二个参数一致:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<hello></hello>
<hello></hello>
<hello></hello>
<hello></hello>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
const constr={
template:"<button @click='num++'>点我一下{{num}}</button>",
data(){
return{
num:0
}
}
}
const app=new Vue({
el:"#app",
components:{
hello:constr
}
})
</script>
</body>
</html>
components就是当前vue对象子组件集合。
#### 其key就是子组件名称
#### 其值就是组件对象名
效果与刚才的全局注册是类似的,不同的是,这个counter组件只能在当前的Vue实例中使用
效果:
6.4.1.props(父向子传递)
- 父组件使用子组件时,自定义属性(属性名任意,属性值为要传递的数据)
- 子组件通过props接收父组件数据,通过自定义属性的属性名
父组件使用子组件,并自定义了title属性:
Go
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<hello :nu="num"></hello>
<hello :nu="num"></hello>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
Vue.component("hello",{
template:"<button @click='nu++'>点我一下{{nu}}</button>",
props:["nu"]
})
const app=new Vue({
el:"#app",
data:{
num:0
}
})
</script>
</body>
</html>
6.4.2.props验证
我们定义一个子组件,并接收复杂数据:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<hello :nu="num"></hello>
<hello :nu="num"></hello>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
Vue.component("hello",{
template:"<button @click='nu++'>点我一下{{nu}}</button>",
props:{
nu:{
require:true,
type:Number
}
}
})
const app=new Vue({
el:"#app",
data:{
num:0
}
})
</script>
</body>
</html>
这个是校验得小练习
6.4.4.子向父的通信:$emit
来看这样的一个案例:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<hello :ti="num" @incrs="inc()"></hello>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
Vue.component("hello",{
template:"<button @click='sub' >{{ti}}点我一下</button>",
props:["ti"],
methods:{
sub(){
this.$emit("incrs")
}
}
})
const app=new Vue({
el:"#app",
data:{
num:0
},
methods:{
inc(){
this.num++;
}
}
})
</script>
</body>
</html>
效果:
7.2.vue-router简介和安装
使用vue-router和vue可以非常方便的实现 复杂单页应用的动态路由功能。
使用npm安装:npm install vue-router --save
在index.html中引入依赖:
<script src="../node_modules/vue-router/dist/vue-router.js"></script>
7.3.快速入门
新建vue-router对象,并且指定路由规则:
html
const router=new VueRouter({
routes:[
{
path:"/login",
component: loginForm
},{
path:"/register",
component:registerForm
}
]
})
-
创建VueRouter对象,并指定路由参数
-
routes:路由规则的数组,可以指定多个对象,每个对象是一条路由规则,包含以下属性:
- path:路由的路径
- component:组件名称
在父组件中引入router对象:
html
const app=new Vue({
el:"#app",
components:{
loginForm,
registerForm
}
,router
})
页面跳转控制:
html
<div id="app">
<span>
<router-link to="/login">
登录
</router-link>
</span>
<span>
<router-link to="/register">
注册
</router-link>
</span>
<hr>
<div>
<router-view></router-view>
</div>
</div>
- 通过
<router-view>
来指定一个锚点,当路由的路径匹配时,vue-router会自动把对应组件放到锚点位置进行渲染 - 通过
<router-link>
指定一个跳转链接,当点击时,会触发vue-router的路由功能,路径中的hash值会随之改变
效果:
注意:单页应用中,页面的切换并不是页面的跳转。仅仅是地址最后的hash值变化。
事实上,我们总共就一个HTML:index.html
Vue-总结:
1.搭建后台管理前端
1.1.导入已有资源
1.2.安装依赖
你应该注意到,这里并没有node_modules文件夹,方便给大家下发,已经把依赖都删除了。不过package.json中依然定义了我们所需的一切依赖:
我们只需要打开终端,进入项目目录,输入:npm install
命令,即可安装这些依赖。
项目结构:
理一下:
- index.html:html模板文件。定义了空的
div
,其id为app
。 - main.js:实例化vue对象 ,并且通过id选择器绑定到index.html的div中,因此main.js的内容都将在index.html的div中显示 。main.js中使用了App组件,即App.vue,也就是说index.html中最终展现的是App.vue中的内容。index.html引用它之后,就拥有了vue的内容(包括组件、样式等),所以,main.js也是webpack打包的入口。
- index.js:定义请求路径和组件的映射关系。相当于之前的
<vue-router>
- App.vue中也没有内容,而是定义了vue-router的锚点:
<router-view>
,我们之前讲过,vue-router路由后的组件将会在锚点展示。 - 最终结论:一切路由后的内容都将通过App.vue在index.html中显示。
- 访问流程:用户在浏览器输入路径,例如:http://localhost:9001/#/item/brand --> index.js(/item/brand路径对应pages/item/Brand.vue组件) --> 该组件显示在App.vue的锚点位置 --> main.js使用了App.vue组件,并把该组件渲染在index.html文件中(id为"app"的div中)
2.Vuetify框架
2.1.为什么要学习UI框架
Vue虽然会帮我们进行视图的渲染,但样式还是由我们自己来完成。这显然不是我们的强项,因此后端开发人员一般都喜欢使用一些现成的UI组件,拿来即用,常见的例如:
- BootStrap
- LayUI
- EasyUI
- ZUI
然而这些UI组件的基因天生与Vue不合,因为他们更多的是利用DOM操作,借助于jQuery实现,而不是MVVM的思想。
而目前与Vue吻合的UI框架也非常的多,国内比较知名的如:
- element-ui:饿了么出品
- i-view:某公司出品
然而我们都不用,我们今天推荐的是一款国外的框架:Vuetify
2.2.为什么是Vuetify
有中国的为什么还要用外国的?原因如下:
- Vuetify几乎不需要任何CSS代码,而element-ui许多布局样式需要我们来编写
- Vuetify从底层构建起来的语义化组件。简单易学,容易记住。
- Vuetify基于Material Design(谷歌推出的多平台设计规范),更加美观,动画效果酷炫,且风格统一
这是官网的说明:
缺陷:
- 目前官网虽然有中文文档,但因为翻译问题,几乎不太能看。
2.3.怎么用?
基于官方网站的文档进行学习:
一个典型的三块布局。包含左,上,中三部分:
里面使用了Vuetify中的2个组件和一个布局元素:
v-navigation-drawer
:导航抽屉,主要用于容纳应用程序中的页面的导航链接。
v-toolbar
:工具栏通常是网站导航的主要途径。可以与导航抽屉一起很好地工作,动态选择是否打开导航抽屉,实现可伸缩的侧边栏。
v-content
:并不是一个组件,而是标记页面布局的元素。可以根据您指定的app组件的结构动态调整大小,使得您可以创建高度可定制的组件。
那么问题来了:v-content
中的内容来自哪里?
- Layout映射的路径是
/
- 除了Login以外的所有组件,都是定义在Layout的children属性,并且路径都是
/
的下面 - 因此当路由到子组件时,会在Layout中定义的锚点中显示。
- 并且Layout中的其它部分不会变化,这就实现了布局的共享。