vue简单使用
1.什么是MVVM
MVVM(Model-View-ViewModel)是一种软件设计模式,由微软WPF(用于替代WinForm,以前就是用这个技术开发桌面应用程序的)和Silverlight(类似于Java Applet,简单点说就是在浏览器上运行WPF)的架构师Ken Cooper和Ted Peters开发,是一种简化用户界面的事件驱动编程方式。由John Gossman(同样也是WPF和Sliverlight的架构师)与2005年在他的博客上发表。
MVVM源自于经典的MVC(Model-View-Controller)模式。MVVM的核心是ViewModel层,负责转换Model中的数据对象来让数据变得更容易管理和使用。其作用如下:
- 该层向上与视图层进行双向数据绑定
- 向下与Model层通过接口请求进行数据交互
MVVM已经相当成熟了,主要运用但不仅仅在网络应用程序开发中。当下流行的MVVM框架有Vue.js
,Anfular JS
2.为什么要使用MVVM
MVVM模式和MVC模式一样,主要目的是分离视图(View)和模型(Model),有几大好处
低耦合:视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的View上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
可复用:可以把一些视图逻辑放在一个ViewModel里面,让很多View重用这段视图逻辑。
独立开发:开发人员可以专注于业务逻辑和数据的开发(ViewMode),设计人员可以专注于页面设计。
可测试:界面素来是比较难以测试的,而现在测试可以针对ViewModel来写。
(1)View
View是视图层, 也就是用户界面。前端主要由HTH L和csS来构建, 为了更方便地展现vi eu to del或者Hodel层的数据, 已经产生了各种各样的前后端模板语言, 比如FreeMarker,Thyme leaf等等, 各大MV VM框架如Vue.js.Angular JS, EJS等也都有自己用来构建用户界面的内置模板语言。
(2)Model
Model是指数据模型, 泛指后端进行的各种业务逻辑处理和数据操控, 主要围绕数据库系统展开。这里的难点主要在于需要和前端约定统一的接口规则
(3)ViewModel
ViewModel是由前端开发人员组织生成和维护的视图数据层。在这一层, 前端开发者对从后端获取的Model数据进行转换处理, 做二次封装, 以生成符合View层使用预期的视图数据模型。
3.vue
(1)MVVM模式的实现者
Model:模型层, 在这里表示JavaScript对象
View:视图层, 在这里表示DOM(HTML操作的元素)
ViewModel:连接视图和数据的中间件, Vue.js就是MVVM中的View Model层的实现者
在MVVM架构中, 是不允许数据和视图直接通信的, 只能通过ViewModel来通信, 而View Model就是定义了一个Observer观察者
ViewModel能够观察到数据的变化, 并对视图对应的内容进行更新
ViewModel能够监听到视图的变化, 并能够通知数据发生改变
至此, 我们可以大致了解, Vue.js就是一个MV VM的实现者, 他的核心就是实现了DOM监听与数据绑定
(2)为什么使用Vue.js
轻量级, 体积小是一个重要指标。Vue.js压缩后有只有20多kb(Angular压缩后56kb+,React压缩后44kb+)
移动优先。更适合移动端, 比如移动端的Touch事件
易上手,学习曲线平稳,文档齐全
吸取了Angular(模块化) 和React(虚拟DOM) 的长处, 并拥有自己独特的功能,如:计算属性
开源,社区活跃度高
4.SPA(Single Page Application)单页面应用
传统的网页:通过a标签的href属性实现页面跳转,每次跳转都会发送一个新的http请求,在PC端没有问题,因为PC端的处理器比较强大,但是在移动端就会出现卡顿的现象
SPA,单页面应用,就是将所有的网页封装的一个html文件的不同的div(template模板)里面,每个网页对应一个div(template),再通过div的显示、隐藏达到页面跳转的效果
组件化、模块化
目的是提升代码的复用性,例如,订餐系统中的数量加减操作、轮播图等可能在多个地方都使用,就可以将该功能设计成一个组件
实例化Vue对象
语法:
let app = new Vue({})
接收一个对象作为参数,主要用来配置Vue
1.1 Vue配置项
el:将哪个标签挂着到Vue中,使用Vue进行管理,通常我们将根元素挂着到Vue
data:定义数据项,所有的数据,都在这里定义
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="js/vue.js">
</script>
</head>
<body>
<div id="app">
数据渲染
<h1>{{fruit}}</h1>
</div>
<script type="text/javascript">
let app = new Vue({
el:'#app',
data:{
fruit:'西瓜'
}
})
</script>
</body>
</html>
数据渲染
将data里面的数据项的内容,渲染到视图层:
语法:{{数据项名称}}
指令
旧时公文的一种,上级对下级的批示。
计算机领域,一段代码,告诉计算机从事某一运算
在Vue中指令(Directives)是写在html标签上的带有 v- 前缀的特殊属性。指令的职责就是当其表达式的值改变时相应地将某些行为应用到 DOM 上
数据绑定指令
v-text,将数据项绑定到标签上,作用类似于{{数据项}}
v-html,将数据项绑定到标签上,作用类似于{{数据项}}
v-text和v-html的区别在于:v-html可以解析数据项中的html标签,v-text原封不动输出
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="js/vue.js">
</script>
</head>
<body>
<div id="app">
<h1 v-text="fruit"></h1>
<h1 v-html="fruit"></h1>
</div>
<script type="text/javascript">
let app = new Vue({
el:'#app',
data:{
fruit:'西瓜'
}
})
</script>
</body>
</html>
v-model,通常是将输入框的值绑定到一个变量上,实现双向数据绑定
前提:需要在data里面定义变量名
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="js/vue.js">
</script>
</head>
<body>
<div id="app">
<h1 v-text="fruit"></h1>
<h1 v-html="fruit"></h1>
<input type="" name="" v-model="inputValue">{{inputValue}}
</div>
<script type="text/javascript">
let app = new Vue({
el:'#app',
data:{
fruit:'<em>西瓜</em>',
inputValue:''
}
})
</script>
</body>
</html>
属性指令
属性指令,将数据项绑定到属性上,例如:img的src属性、a标签的href属性,class,
style属性等
语法:v-bind:属性名=”变量名”,通常会省略v-bind,简写为:
:src
:href
:class
:style
:style 语法:
:style的值可以是一个对象,设置多个样式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="js/vue.js">
</script>
</head>
<body>
<div id="app">
<p :style="info">{{content}}</p>
</div>
<script type="text/javascript">
let app = new Vue({
el:'#app',
data:{
myhref:"http://www.baidu.com",
content:"这是一个段落",
active:false,
info:{width:"100px",height="100px",background:"#ccc"}
}
})
</script>
</body>
</html>
条件指令
v-if v-else-if v-else,根据条件确定是否创建该dom节点
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="js/vue.js">
</script>
</head>
<body>
<div id="app">
<p v-if="money > 5000">北京欢迎你</p>
<p v-if-else="money > 3000">为你开天辟地</p>
<p v-else>充满着朝气</p>
</div>
<script type="text/javascript">
let app = new Vue({
el:'#app',
data:{
money:7000
}
})
</script>
</body>
</html>
v-show:根据条件控制该节点的显示、隐藏,控制的是display属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="js/vue.js">
</script>
</head>
<body>
<div id="app">
<p v-show="isshow">折叠菜单显示隐藏</p>
</div>
<script type="text/javascript">
let app = new Vue({
el:'#app',
data:{
money:7000,
isshow:true
}
})
</script>
</body>
</html>
循环指令
v-for循环指令,用来遍历数组、对象等多个数据的
语法:
v-for=”(value, key) in 数组|对象”
每遍历一条记录,会将值赋给value,将下标(属性名)赋值给key
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=\, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="js/vue.js"></script>
</head>
<body>
<div id="app">
<ul>
<li v-for="(item,index) in fruits">
{{item}} --- {{index}}
</li>
</ul>
</div>
<script type="text/javascript">
let app = new Vue({
el:'#app',
data:{
fruits:['苹果','橘子','香蕉','西瓜','杨梅']
}
})
</script>
</body>
</html>
Vue实例方法
我们在实例化vue对象的时候,除了其提供的data属性之外,还提供了methods方法。作用就是保存一些逻辑代码,像函数一样去调用
语法
methods:{
方法名:function(){}
简化写法:
方法名(){}
}
补充JavaScript的reduce、map方法
reduce,使用一个函数作为累加器,将数组的元素依次传递到函数中
map,使用一个函数或方法作用于数组的每个元素,最终返回一个新的数组
会将数组的每个元素的值传递到该函数中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=\, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="js/vue.js"></script>
</head>
<body>
<div id="app">
{{f1()}} --- {{f2()}}
</div>
<script type="text/javascript">
var numbers = [44,65,11,09]
// 使用函数作为累加器作用数组的每个元素
var result = numbers.reduce(function(total,current){
return total + current;
})
console.log(result)
// 计算这个数组每个元素的平方根 通过map方法指定一个函数作用于数组的每个元素
var result = numbers.map(Math.sqrt)
console.log(result)
</script>
</body>
</html>
计算属性computed
模板内使用表达式非常便利,但是如果在模板中放入太多的逻辑会让模板过重,且难以维护,所以对于任何复杂逻辑,都应当使用计算属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=\, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="js/vue.js"></script>
</head>
<body>
<div id="app">
{{age > 18 ? '光明正大的上网':'偷偷摸摸的上网'}}
</div>
<script type="text/javascript">
let app = new Vue({
el:"#app",
data:{
age:17
},methods:{
}
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=\, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="js/vue.js"></script>
</head>
<body>
<div id="app">
{{computedAge}}
</div>
<script type="text/javascript">
let app = new Vue({
el:"#app",
data:{
age:17
},computed:{
computedAge(){
return this.age > 18 ? '光明正大的上网':'偷偷摸摸的上网';
}
}
})
</script>
</body>
</html>
计算属性和实例方法的区别
计算属性有缓存,而实例方法没有缓存,Ø 所以我们建议大家使用计算属性
使用计算属性的时候,{{计算属性名}}
使用实例方法时,{{方法名()}}
过滤器
过滤器就是将数据被渲染到视图之前进行格式化处理,而不会修改作用域中原有的数值
语法:
定义过滤器
filters:{
过滤器1:function(参数1,参数2…){}
//简写方式
过滤器2 (参数1,参数2…){}
}
说明:定义过滤器时,必须声明参数,并且参数1是固定的,指的是要操作的数据,剩余的参数是调用过滤器时传递进来的
使用过滤器
{{变量名 | 过滤器1 | 过滤器2….}}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=\, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="js/vue.js"></script>
</head>
<body>
<div id="app">
{{avg | fix(4) | insertBe}}
</div>
<script type="text/javascript">
let app = new Vue({
el:"#app",
data:{
avg:76.32789723
},
filters:{
// 参数1,表示操作的数据
// 参数2 调用过滤器时传递进来的
fix(d,n){
return d.toFixed(n)
},
insertBe(d){
return '$'+d
}
}
})
</script>
</body>
</html>
vue事件处理
事件介绍
事件指的就是用户和网页交互的行为,这些行为,包括:鼠标单击、鼠标双击、键盘按下、抬起等等
事件由3个部分组成:事件源、事件类型、事件处理程序
先监听事件,这样当事件发生时,我们才会做出相应的处理
语法:
v-on:事件类型=”事件处理函数”
可以简写为:@事件类型=”事件处理函数”
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="js/vue.js"></script>
</head>
<body>
<div id="app">
<button v-on:click="btnClick">按钮</button>
<button @click="btnClick">按钮</button>
</div>
<script type="text/javascript">
let app = new Vue({
el:'#app',
data:{
avg:98.3322334
},
methods:{
btnClick(){
alert("单击事件")
}
}
})
</script>
</body>
</html>
事件类型总结:
属性事件:click、dblclick、mouseover、mouseout、mouseenter、mouseleave、mousedown、mouseup、mousemove
键盘事件:keydown、keyup、keypress
ui事件:scroll、resize、load、unload
表单事件:focus、blur、select、change、submit
事件处理函数的位置
如果代码较少,可以将事件处理代码直接写到行内
如果代码较多,将事件处理程序写在methods的方法中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="js/vue.js"></script>
</head>
<body>
<div id="app">
<h3>标题
<span @click="isshow = !isshow"> {{isshow ? '隐藏':'展开'}} </span>
</h3>
<div v-show="isshow">这是折叠菜单的内容</div>
</div>
<script type="text/javascript">
let app = new Vue({
el:'#app',
data:{
isshow:true
},
})
</script>
</body>
</html>
事件对象
事件对象就是用来获取当事件发生时,事件源的一些信息状态,例如,当鼠标移动事件发生时,想获得鼠标的坐标等,就通过事件对象来获得
在Vue中当事件发生时,会自动给事件处理函数传递一个$event事件对象,不需要手动传递,只需要接收即可
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="js/vue.js"></script>
<style type="text/css">
.parent{
width: 300px;
height: 300px;
background:green ;
}
</style>
</head>
<body>
<div id="app">
<div class="parent" @mousemove="move">
</div>
</div>
<script type="text/javascript">
let app = new Vue({
el:'#app',
data:{
isshow:true
},
methods:{
// 自动将事件对象传递过来 我只需要接受即可
move(ev){
console.log(ev)
}
}
})
</script>
</body>
</html>
事件修饰符
在原生JavaScript中,通过event.preventDefault阻止默认行为,
例如:enter键表示回车换行
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="js/vue.js"></script>
<style type="text/css">
.parent{
width: 300px;
height: 300px;
background:green ;
}
</style>
</head>
<body>
<div id="app">
<p v-text="message"></p>
<textarea name="" id="" cols="5" rows="30" @keydown="postMessage"></textarea>
</div>
<script type="text/javascript">
let app = new Vue({
el:'#app',
data:{
massage:""
},
methods:{
postMessage(ev){
// 事件对象啊的keyCode属性获取按下的是哪个按键
// console。log
if(ev.keyCode == 13){
//说明按下的时enter键
// 将输入框的内容显示到p段落中 target属性指的就是事件源
this.message = ev .target.value +'<br>'
ev.target.value = ''
// 通过事件对象的preventDefault方法阻止回车默认行为
ev.preventDefault();
}
}
}
})
</script>
</body>
</html>
Vue给我们提供了如下事件修饰符:
.prevent,阻止默认行为
.stop,阻止事件冒泡
事件冒泡指的是,执行完子元素身上的事件之后,在执行父元素身上的事件
.capture冒泡改为捕获(默认是冒泡,捕获的意思是先执行父元素,再执行自己)
.self 只处理自己身上的事件,不理会冒泡或捕获
.once 一次性事件,只执行一次
表单的的处理
我们在使用Vue处理表单数据的时候,通过v-model实现双向数据绑定
v-mode会同时监视表单输入、模型数据的更新,如果表单内容变化了,模型中的变量会跟着变化,同样,模型中的变量发生变化了,视图层(界面也会跟着变化)
v-mode会将输入框的内容赋值给变量,同样,变量内容变化了,输入框的内容也跟着变
输入框 单选框
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="js/vue.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="user">
<input type="radio" name="sex" value="男" v-model="sex">男
<input type="radio" name="sex" value="女" v-model="sex">女
<input type="radio" name="sex" value="大好的年纪去变性" v-model="sex">人妖
<p>您选择的性别是{{sex}}</p>
</div>
<script type="text/javascript">
let app = new Vue({
el:"#app",
data:{
sex:''
},methods:{
}
})
</script>
</body>
</html>
复选框
由于选择多个,我们通常使用数组来表示复选框的内容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="js/vue.js"></script>
</head>
<body>
<div id="app">
爱好:
<input type="checkbox" name="sport" value="bashetball" v-model="hobby">篮球
<input type="checkbox" name="sport" value="football" v-model="hobby">足球
<input type="checkbox" name="sport" value="yumao" v-model="hobby">羽毛球
<input type="checkbox" name="sport" value="pingpang" v-model="hobby">兵兵球
</div>
<script type="text/javascript">
let app = new Vue({
el:"#app",
data:{
hobby:[]
},methods:{
}
})
</script>
</body>
</html>
下拉列表
注意:v-model监视的是select标签,获取的是option选项的value值,同样v-model的变量值改变了,select下拉列表的内容也会跟着变
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="js/vue.js"></script>
</head>
<body>
<div id="app">
<select name="" id="" v-model="city">
<option value="beijing">北京</option>
<option value="shanghai">上海</option>
<option value="guangzhou">广州</option>
</select>
<p>{{city}} </p>
</div>
<script type="text/javascript">
let app = new Vue({
el:"#app",
data:{
city:''
},methods:{
}
})
</script>
</body>
</html>
v-model修饰符
语法:
v-model.修饰符=”变量”
lazy,文本框失去焦点后再去更新数据
number,从字符串中获取数字部分
trim,删除文本框中的前后空格
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="js/vue.js"></script>
</head>
<body>
<div id="app">
<p>
用户名:<input v-model.lazy.trim=" user">
</p>
<p>
年龄:<input v-model.number="age">
</p>
<p> {{user}} </p>
<p> {{age}} </p>
</div>
<script type="text/javascript">
let app = new Vue({
el:"#app",
data:{
user:'',
age:''
},methods:{
}
})
</script>
</body>
</html>
vue.js组件
组件介绍
组件(component)是vue.js最强大的功能之一。组件的作用就是封装可重用的代码,通常一个组件就是一个功能体,便于在多个地方都能够调用这个功能体
每个组件都是Vue的实例对象
根组件
我们实例化的vue对象就是一个组件,而是所有组件的根组件
组件分类
全局组件
通过Vue的静态方法component定义的,全局组件可以在所有组件中使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="js/vue.js"></script>
</head>
<body>
<div id="app">
<my-header></my-header>
</div>
<script type="text/javascript">
Vue.component("my-header",{
template:"<div>我是头部组件</div>"
})
let app = new Vue({
el:"#app"
})
</script>
</body>
</html>
局部组件的使用流程
先定义组件对象
组件对象名,采用驼峰法命名
组件对象的配置项基本和Vue实例的配置项一样,除了data数据项之外
在组件对象中,data数据项是一个方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="js/vue.js"></script>
</head>
<body>
<div id="app">
<my-header></my-header>
</div>
<script type="text/javascript">
// 定义局部组件对象
let MyHeader = {
// 组件的模板 my-header表示id为my-header的 模板
template:'#my-header',
// 组件的数据项,data和vue实例中的data属性不一样
// 在组件对象中,data是一个方法
data(){
return {
// 数据项
name:"李世民"
}
}
}
</script>
</body>
</html>
定义组件模板中,必须要有一个根元素,不能直接写h1 p span等内容
<template id="my-header">
<div>
<h3>我是头部组件</h3>
<p>{{name}}</p>
</div>
</template>
注册组件
注册组件,组件在哪里使用,就注册到哪里
let app = new Vue({
el:'#app',
components:{
// 将MyHeader这个组件注册到app跟组件中
MyHeader
}
})
使用组件
<div id="app">
<my-header></my-header>
</div>
<template id="my-header">
<div>
<h3>我是头部组件</h3>
<p>{{name}}</p>
</div>
</template>
template语法规则
组件对象的template属性用来设置组件的模板内容,模板内容有三种写法
直接写在字符串
将模板内容写在template标签里面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="js/vue.js"></script>
</head>
<body>
<div id="app">
<my-header></my-header>
</div>
<template id="my-header">
<div>
<h3>我是头部组件</h3>
<p>{{name}}</p>
</div>
</template>
<script type="text/javascript">
// 定义局部组件对象
let MyHeader = {
// 组件的模板 my-header表示id为my-header的 模板
template:'#my-header',
// 组件的数据项,data和vue实例中的data属性不一样
// 在组件对象中,data是一个方法
data(){
return {
// 数据项
name:"李世民"
}
}
}
let app = new Vue({
el:'#app',
components:{
// 将MyHeader这个组件注册到app跟组件中
MyHeader
}
})
</script>
</body>
</html>
将模板内容写在script标签里面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="js/vue.js"></script>
</head>
<body>
<div id="app">
<my-header></my-header>
</div>
<script type="text/x-template" id="my-header">
<div>
<h3>我是头部组件</h3>
<p>{{name}}</p>
</div>
</script>
<script type="text/javascript">
// 定义局部组件对象
let MyHeader = {
// 组件的模板 my-header表示id为my-header的 模板
template:'#my-header',
// 组件的数据项,data和vue实例中的data属性不一样
// 在组件对象中,data是一个方法
data(){
return {
// 数据项
name:"李世民"
}
}
}
let app = new Vue({
el:'#app',
components:{
// 将MyHeader这个组件注册到app跟组件中
MyHeader
}
})
</script>
</body>
</html>
组件间的相互通信
介绍
组件实例是孤立的,所以我们不能在子组件中,直接使用父组件中的数据
这一点符合我们组件的高内聚、低耦合的特性
实现相互通信
父组件通过props向下传递数据,子组件通过emit向上发射事件传播数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="js/vue.js"></script>
</head>
<body>
<div id="app">
{{number}}
<my-collapse :num="number"></my-collapse>
</div>
<!-- 定义组件模板 -->
<template id="my-collapse">
<div>
<h3> {{num}} </h3>
<p> {{say()}} </p>
</div>
</template>
<script type="text/javascript" >
// 定义组件对象
let MyCollapse = {
template:'#my-collapse',
props:{
// 接受父组件传递过来的变量 Number类型约束,表示传递过来的是数值类型
num:Number
},
data(){
return {
}
},methods:{
say(){
console.log(this.num)
}
}
}
let app = new Vue({
el:"#app",
data:{
// 父组件的数据项
number:1000
},components:{
MyCollapse
}
})
</script>
</body>
</html>
props细节
每一个数据项,都可以有3个属性进行约束
type,类型约束,约束父组件给子组件传递的数据类型,类型可以是:Object、Array、
Number、String、Boolean
default,指定默认值,如果父组件没有传递数据,可以指定默认值
required,指定该数据项是否必须传递
vue实例的生命周期
我们实例化的Vue对象(根组件)以及我们自定义的组件对象,都有生命周期。
Vue的设计者为了方便我们调试程序,给我们提供了8个钩子函数:
<script type="text/javascript">
let app = new Vue({
beforeCreate(){
alert('beforeCreate')
},
created(){
alert('beforeCreate')
},
beforeMount(){
alert('beforeCreate')
},
mounted(){
alert('beforeCreate')
},
beforeUpdata(){
alert('beforeCreate')
},
updated(){
alert('beforeCreate')
},
beforeDestroy(){
alert('beforeCreate')
},
destroyed(){
alert('beforeCreate')
},
})
</script>
生命周期函数作用:
在不同的阶段,做相应的工作
created阶段,初始化数据的,创建数据对象
mounted阶段,使用数据项替换模板,也就是将数据挂载到DOM元素节点上
updated阶段,当dom节点里面的数据发生改变,在这个阶段进行更新
动态组件
我们可以定义多个组件,然后再使用 :is 属性动态的在多个组件之间切换
语法:
<component v-bind:is="组件名"></component>
Component就相当于一个占位符,具体显示哪一个组件呢,通过:is指定的
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="js/vue.js"></script>
</head>
<body>
<div id="app">
<component :is="currenCom"></component>
</div>
<template id="com1">
<div>
这是第一个组件
</div>
</template>
<template id="com2">
<div>
这是第二个组件
</div>
</template>
<script type="text/javascript">
let Com1 = {
template:'#com1'
}
let Com2 = {
template:'#com2'
}
let app = new Vue({
el:"#app",
data:{
currenCom:'Com2'
},
components:{
Com1,
Com2
}
})
</script>
</body>
</html>
vue.js 响应式
响应式原理
当我们在Vue中定义一个数据对象之后, Vue 将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。
当我们给数据对象赋值时,自动执行set方法
当我们获取属性值时,自动执行get方法
Vue.nextTick
Vue是异步执行DOM更新的,当数据发生改变之后并不会马上修改视图层(更新DOM),而是要等到所有的数据对象的属性值都更新完毕之后再去更新DOM
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="js/vue.js"></script>
</head>
<body>
<div id="app">
<h1 ref="h1"> {{msg}} </h1>
<button @click="f1">按钮</button>
</div>
<script type="text/javascript">
let app = new Vue({
el:"#app",
data:{
msg:"info"
},methods:{
f1(){
console.log(this.$refs.h1.innerHTML);
this.msg = 'abcd';
console.log(this.$refs.h1.innerHTML);
Vue.nextTick(()=>{
console.log(this.$refs.h1.innerHTML)
})
}
}
})
</script>
</body>
</html>
vue.js路由
SPA页面的原理:将一个网站所有的页面写在一个文件,通过不同的div进行区分,再通过div的显示,隐藏实现跳转的效果
动态组件的缺点,在跳转的时候,没办法传递参数,就无法实现同一个界面
根据不同的参数显示不同内容
路由工作原理和路由器相似,路由器将网线的总线的IP分发到每一台设备上
Vue中的路由,也是在一个网页中根据用户点击,将其引导到对应的页面
安装vue-router或者直接引入vue-router.js
router-link,组件会被解析为a标签
router-view,路由显示的内容会显示到router-view里面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript" src="js/vue-router.js"></script>
</head>
<body>
<div id="app">
<div>
<router-link to="/home">首页</router-link>
<router-link to="/find">发现</router-link>
<router-link to="/setting">设置</router-link>
<router-view></router-view>
</div>
</div>
<template id="home">
<div>
<h1>首页</h1>
</div>
</template>
<template id="home">
<div>
<h1>发现页面</h1>
</div>
</template>
<template id="home">
<div>
<h1>设置页面</h1>
</div>
</template>
<script type="text/javascript">
let Home = {template:'#home'}
let Find = {template:'#find'}
let Setting = {template:'#setting'}
let route = new VueRouter({
routes:[
{
path:'/home',
component:Home
},
{
path:'/find',
component:Find
},
{
path:'/setting',
component:Setting
},
]
})
let app = new Vue({
el:"#app",
components:{
Home,
Find,
Setting
},
router:route
})
</script>
</body>
</html>
动态路由
同一个路由地址,根据传递的不同参数,显示不同的内容
例如,商品详情页:
https://m.mi.com/#/product/view?product_id=(https://m.mi.com/)1000002210000022
https://m.mi.com/#/product/view?product_id=6458
上面2个地址其实共用一个页面,通过传递不同的参数加以区分,这种带有动态参数的路由,称为动态路由
首先,我们在定义路由规则时,将动态参数使用 :变量 进行参数绑定
路由重定向
重定向,当我们访问一个路由地址时,自动跳转到其他的理由地址,这就称为重定向
vue脚手架
Vue-cli是vue的设计者,为了提升开发效率而提供的一个脚手架工具,我们可以通过vue-cli快速的构造项目结构
cmd创建项目
vue init webpack 项目名称
运行项目
npm run dev
vue-cli项目目录结构
build 构建项目的配置目录
config 配置目录,默认配置没有问题,所以我们也不用管
node_modules 项目开发依赖的一些模块
src 开发目录,基本上绝大多数工作都是在这里开展的
static 静态资源目录,图片、字体等资源
.xxx 配置文件,语法配置,git配置。基本不用管
main.js 项目的入口文件
App.vue 根组件,同时也是单文件组件。
router/index.js 路由配置文件
components 自定义的组件保存目录
项目打包
会将项目上线之后运行时需要的文件打包到一个文件中
npm run build
执行完毕,会在vuedemo目录下创建dist目录,里面保存了打包之后的文件
本地安装http-server环境
npm install http-server -g
Axios异步通信
Axios是一个开源的可以用在浏览器端和Node.js的异步通信框架,主要作用就是Ajax异步通信
Axios特点:
从浏览器中创建 XMLHttpRequests
从 node.js 创建 http 请求
支持 Promise API
拦截请求和响应
转换请求数据和响应数据
取消请求
自动转换 JSON 数据
客户端支持防御 XSRF
Axios语法
<script>
let url = 'data.json'
axios.get(url)
.then(function(res){
console.log(res)
})
.catch(function (err) {
console.log(err)
})
</script>
get,请求方式,如果表单请求,请使用post
url,请求的文件地址
then,请求成功时回调函数
catch,请求失败时的回调函数
在vue-cli中使用axios
通过npm安装axios
npm install axios --save
<template>
<div>
<h3>赚钱</h3>
<p>刑法</p>
<msg-list :msg="msglist"></msg-list>
<add-msg @post-msg="receive"></add-msg>
<button @click="getData">点击获取数据</button>
</div>
</template>
<script>
import AddMsg from '@/components/AddMsg'
import MsgList from '@/components/MsgList'
import axios from 'axios'
export default {
components:{
AddMsg,
MsgList
},
data(){
return{
msglist:[]
}
},
methods:{
receive(msg){
console.log(msg)
this.msglist.push(msg)
},
getData(){
// 通过axios请求data/json文件
let url = 'static/data.json'
axios.get(url)
.then(function(res){
console.log(res)
})
.catch(function (err) {
console.log(err)
})
}
}
}
</script>
<style scoped>
</style>
json格式
{
"name":"北辰",
"age":22,
"fruits":["apple","pear","grape"]
}
JSON和js对象互转
- 要实现从JSON字符串转换为JS对象,使用
JSON.parse()
方法:
<script>
var str = '{"name": "北辰","age":22}';
var obj = JSON.parse(str);
console.log(obj);
</script>
2.js对象转换为json字符串,JSON.stringify()
<script>
var str = '{"name": "北辰","age":22}';
var obj = JSON.parse(str);
console.log(obj);
var jsonstr = JSON.stringify(obj);
console.log(jsonstr);
</script>