引言
静态页面
最初的网页以HTML为主,是纯静态网页,网页是只读的,信息流只能从服务端到客户端单项流通,开发人员也只关心页面的样式和显示内容。
异步刷新
1995年,网景工程师Brendan Eich 花了10天时间设计了JavaScript语言。
随着JavaScript的诞生,我们可以操作页面的DOM元素及样式,页面有了一些动态的效果,但是依然是以静态为主
ajax横空出世
和Ajax的巨大影响力相比,它的历史却简短得多, 2005年2月,Adaptive Path公司的Jesse James Garrett最早提出这个概念,它出现在Garrett的文章"Ajax:A new approach to Web Applications"中,这篇文章描述了混合使用XHTML,CSS,javascript,DOM,XMLHttpRequst进行Web开发将会成为一种新的趋势。2005之后,ajax逐渐被前端开发人员所重视,因为不用刷新页面就可以更新页面的数据和渲染效果。
此时的开发人员不仅仅要编写HTML样式,还要懂ajax与后端交互,然后通过JS操作Dom元素来实现页面动态效果。比较流行的框架如jQuery就是典型代表。
MVVM,关注模型和视图
什么是MVVM
M:即Model,模型,包括数据和一些基本操作
V:即View,视图,页面渲染结果
VM:即View-Model,模型与视图间的双向操作(无需开发人员干涉)
在MVVM之前,开发人员从后端获取需要的数据模型,然后要通过DOM操作Model渲染到View中。而后当用户操作视图,我们还需要通过DOM获取View中的数据,然后同步到Model中。而MVVM中的VM要做的事情就是把DOM操作完全封装起来,开发人员不用再关心Model和View之间是如何互相影响:
- 只要Model发生了改变,View上自然就会表现出来。
- 当用户修改了View,Model中的数据也会跟着改变。
把开发人员从繁琐的DOM操作中解放出来,把关注点放在如何操作Model上。
MVVM 的发展
2008年,google的Chrome发布,随后就以极快的速度占领市场,超过IE成为浏览器市场的主导者。
2009年,Ryan Dahl在谷歌的Chrome V8引擎基础上,打造了基于事件循环的异步IO框架:Node.js。基于时间循环的异步IO单线程运行,避免多线程的变量同步问题JS可以编写后台diamante,前后台统一编程语言node.js的伟大之处不在于让JS迈向了后端开发,而是构建了一个庞大的生态系统。
2010年,NPM作为node.js的包管理系统首次发布,开发人员可以遵循Common.js规范来编写Node.js模块,然后发布到NPM上供其他开发人员使用。目前已经是世界最大的包模块管理系统。
而后在node基础上又涌现出一大批框架
vue作为国内优秀的前端框架之一,小猿非常乐意去学习并掌握它。
vue
vue的概述
Vue (读音 /vjuː/,类似于 view) 是一款有国人主导开发的一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层, 不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
前端框架三巨头:Vue.js、React.js、AngularJS,vue.js以其轻量易用著称,vue.js和React.js发展速度最快。
渐进式:可以选择性的使用该框架的一个或一些组件,这些组件的使用也不需要将框架全部组件都应用;而且用了这些组件也不要求你的系统全部都使用该框架。
vue所解决的问题
vue 所解决问题的本质是将赋值部分和逻辑部分进行分离,既做到m和v分离并实现双向操作。
vue的基本操作
使用vue就需要导入vue基础js文件。
插值表达式
数据绑定最常见的形式就是使用“Mustache”语法 (双大括号) 的文本插值,Mustache 标签将会被替代为对应数据对象上属性的值。无论何时,绑定的数据对象上属性发生了改变,插值处的内容都会更新。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>quickstart</title>
<script src="../js/vuejs-2.5.16.js"></script>
</head>
<body>
<div id="app">
{{message}}
{{number+1}}
{{true? "yes":"no"}}
</div>
</body>
<script>
//view model
new Vue({
el:"#app", //有vue接管id为app的数据区域
data:{
message:"hello vue!!!", // 处处不要加分号
number: 1000
}
});
</script>
</html>
插值表达式属 Vue 实例的数据作用域下作为 JavaScript 会被解析器被解析。有个限制就是,每个绑定都只能包含单个表达式,所以下面的例子都不会生效。
<!-- 这是语句,不是表达式 -->
{{ var a = 1 }}
<!-- 流控制也不会生效,请使用三元表达式 -->
{{ if (ok) { return message } }}
vuejs常用的指令
v-on
v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码
v-on:click
<!DOCTYPE html>
<meta charset="utf-8" />
<title>v-on:click</title>
<script src="../js/vuejs-2.5.16.js"></script>
</head>
<body>
<div id="app">
{{message}}
<button v-on:click="fun1('vue-on')" >vue的onclick</button>
</div>
</body>
<script>
//view model
new Vue({
el:"#app", //有vue接管id为app的数据区域
data:{
message:"hello vue!!!", // 处处不要加分号
number: 1000
},
methods:{
fun1:function (message) {
alert("hello vue!!!");
this.message = message;
}
}
});
</script>
</html>
v-on:keydown
检测按键事件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>v-on:keydown</title>
<script src="../js/vuejs-2.5.16.js"></script>
</head>
<body>
<div id="app">
{{message}}
{{number+1}}
<input type="text" v-on:keydown="fun($event)">
<hr/>
traditional<input type="text" onkeydown="showKeyCode()" >
</div>
</body>
<script>
//view model
//$event为vue中的事件对象,与传统对象中的event对象一致
new Vue({
el: "#app",
data:{
message: "vue Input",
number: 1000
},
methods: {
fun(event){
var keyCode = event.keyCode;
if(keyCode<48 || keyCode>57){
event.preventDefault();
}
}
}
})
//传统js代码
function showKeyCode() {
var keyCode = event.keyCode;
if(keyCode<48 || keyCode>57){
event.preventDefault();
}
}
</script>
</html>
v-on:mouseover
鼠标移入事件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>v-on:mouseover</title>
<style>
#div ,#div2 {
background-color: red;
width: 400px;
height: 300px;
}
</style>
<script src="../js/vuejs-2.5.16.js"></script>
</head>
<body>
<div id="app">
<div @mouseover="fun1" id="div">
<textarea @mouseover="fun2($event)">这是一vue个文件域</textarea>
</div>
</div>
<hr/>
<hr/>
<hr/>
<hr/>
<div >
<div onmouseover="fun3()" id="div2" >
<textarea onmouseover="fun4()">这是一个传统文件域</textarea>
</div>
</div>
</body>
<script>
//view model
new Vue({
el: "#app",
data:{
message: "vue Input",
number: 1000
},
methods: {
fun1:function(){
alert("这是vueDIV域!!!");
},
fun2:function(event){
alert("这是vue文件域!!!");
event.stopPropagation();
}
}
});
//传统方法
function fun3(){
alert("这是传统DIV域!!!");
}
function fun4() {
alert("这是传统文件域!!!");
event.stopPropagation();
}
</script>
</html>
v-on书写形式
<!-- 完整语法 -->
<a v-on:click="doSomething">...</a>
<!-- 缩写 -->
<a @click="doSomething">...</a>
事件修饰符
Vue 允许为 v-on 在监听键盘事件时添加按键修饰符,事件修饰符有以下种类
.enter
.tab
.delete (捕获 "删除" 和 "退格" 键)
.esc
.space
.up
.down
.left
.right
.ctrl
.alt
.shift
.meta
下面是示例代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>v-on:事件修饰符</title>
<style>
#div ,#div2 {
background-color: red;
width: 400px;
height: 300px;
}
</style>
<script src="../js/vuejs-2.5.16.js"></script>
</head>
<body>
<form action="http://www.baidu.com" onsubmit="return checkform()">
<input type="submit" value="Go">
</form>
<br/>
<br/><br/>
<br/>
<div id="app">
<!--典型的事件修饰符,所对应的事件是prevent-->
<form v-on:submit.prevent action="http://www.baidu.com" >
<input type="submit" value="Go">
</form>
<br/>
<br/>
<div @click="fun">
<a @click.stop href="http://www.baidu.com">BAIDU</a>
</div>
<br/>
<br/>
<br/>
<div >
<!--典型的事件修饰符,所对应的事件是stop-->
<div @mouseover="fun1" id="div">
<textarea @mouseover.stop="fun2($event)">这是一vue个文件域</textarea>
</div>
</div>
</div>
</body>
<script>
//view model
function checkform() {
return false;
}
new Vue({
el: "#app",
data:{
message: "vue Input",
number: 1000
},
methods: {
fun1:function(){
alert("这是vueDIV域!!!");
},
fun2:function(event){
alert("这是vue文件域!!!");
/*event.stopPropagation();*/
},
fun:function () {
alert("www.baidu.com");
}
}
});
</script>
</html>
v-text与v-html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>v-text与v-html</title>
<script src="js/vuejs-2.5.16.js"></script>
</head>
<body>
<div id="app">
<div v-html="message" id="div1"></div>
<div v-text="message" id="div2"></div>
</div>
<div id="div3"></div>
<div id="div4"></div>
</body>
<script>
//view model
new Vue({
el: "#app",
data:{
message: "hello python",
number: 1000
}
});
window.onload=function () {
document.getElementById("div3").innerHTML="<h1>hello python</h1>";
document.getElementById("div4").innerText="<h1>hello python</h1>";
}
</script>
</html>
v-text与v-html 的区别
v-bind
插值语法不能作用在 HTML 特性上,遇到这种情况应该使用 v-bind指令。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>v-if and v-show</title>
<script src="../js/vuejs-2.5.16.js"></script>
</head>
<body>
<div id="app">
<font :size="size1" v-bind:color="yl1" v-if="flag" >小猿</font><br/>
<font v-bind:size="size2" :color="yl2" v-show="flag" >加油学习</font><br/>
<button @click="toggle">button</button>
</div>
</body>
<script>
//view model
new Vue({
el: "#app",
data: {
yl1: "green",
yl2: 'red',
size1: 5,
size2: 10,
flag : true
},
methods: {
toggle: function () {
this.flag = !this.flag;
}
}
});
</script>
</html>
v-bind书写方式
<!-- 完整语法 -->
<a v-bind:href="url">...</a>
<!-- 缩写 -->
<a :href="url">...</a>
v-model
v-model指令实现复选框的双向绑定
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>v-text与v-html在v-bind上的使用</title>
<script src="../js/vuejs-2.5.16.js"></script>
</head>
<body>
<div id="app">
<form action="www.baidu.com" method="get">
<input type="text" name="username" v-model="user.username" /><br/>
<input type="text" name="password" v-model="user.password"/><br/>
<input type="submit" value="submit" class="button" >
</form>
</div>
</body>
<script>
//view model
new Vue({
el: "#app",
data:{
user:{
username: "feitian",
password: "123456"
}
}
});
</script>
</html>
v-for
遍历数组
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>v-for遍历对象</title>
<script src="../js/vuejs-2.5.16.js"></script>
</head>
<body>
<div id="app">
<ul>
<li v-for="(item,index) in array" >{{index}} :{{item}}</li>
</ul>
</div>
</body>
<script>
//view model
new Vue({
el: "#app",
data: {
array: [1,2,3,4,5]
},
methods: {
}
});
</script>
</html>
遍历对象内容
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>v-for</title>
<script src="../js/vuejs-2.5.16.js"></script>
</head>
<body>
<div id="app">
<ul>
<li v-for="(key,value) in product" >{{key}}:{{value}}</li>
</ul>
</div>
</body>
<script>
//view model
new Vue({
el: "#app",
data: {
product: {
id: 12,
name: "server",
price: 100000
}
},
methods: {
}
});
</script>
</html>
遍历对象数据
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>v-for遍历对象</title>
<script src="../js/vuejs-2.5.16.js"></script>
</head>
<body>
<div id="app">
<table border="1">
<tr>
<td>序号号</td>
<td>编号</td>
<td>名称</td>
<td>价格</td>
</tr>
<tr v-for="(product,index) in products" >
<td>{{index}}</td>
<td >{{product.id}}</td>
<td>{{product.name}}</td>
<td>{{product.price}}</td>
</tr>
</table>
</div>
</body>
<script>
//view model
new Vue({
el: "#app",
data: {
products: [{id: 12, name: "server", price: 100000},
{id: 14, name: "mobile", price: 3000},
{id: 18, name: "television", price: 2000},
{id: 17, name: "router", price: 300},
{id: 10, name: "printer", price: 2900},]
},
methods: {
}
});
</script>
</html>
vue计算属性
computed计算属性的应用场景:可以应用在插值或者指令表示式复杂的时候。可以将一些属性数据经过方法处理之后返回,这样就可以在某些地方
替代插值表达式。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vuejs测试</title>
<script src="../js/vuejs-2.5.16.js"></script>
</head>
<body>
<div id="app">
<h2>
你的生日是:
{{new Date(birthday).getFullYear()}}-{{new Date(birthday).getMonth()+1}}-{{new Date(birthday).getDay()}}
</h2>
<hr>
<h2>
你的生日是:
{{birth}}
</h2>
</div>
<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
birthday:1429032123201
},
computed:{
birth(){
const date = new Date(this.birthday);
return date.getFullYear() + "-" + (date.getMonth()+1) + "-" + date.getDay();
}
}
});
</script>
</body>
</html>
vue watch
在vue实例中数据属性;因为在页面中修改而产生了变化;可以通过watch监控获取其改变前后的值。如果是修改的对象数据属性,可以开启深度监控获取修改后最新的对象数据。如:person.name。
watch使用场景:可以监控视图中数据的变化而做出响应;如:下拉框列表中,当如果选择了对于的下拉框选项之后,要根据最新的值去加载一些其它数据的话。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vuejs测试</title>
<script src="../js/vuejs-2.5.16.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="message">
<hr><br>
<input type="text" v-model="person.name"><br>
<input type="text" v-model="person.age"><button @click="person.age++">+</button>
<h2>
姓名为:{{person.name}};年龄为:{{person.age}}
</h2>
</div>
<script type="text/javascript">
var app = new Vue({
el:"#app",
data:{
message:"黑马",
person:{"name":"heima", "age":13}
},
watch:{
message(newValue, oldValue){
console.log("新值:" + newValue + ";旧值:" + oldValue);
},
person: {
//开启深度监控;监控对象中的属性值变化
deep: true,
//可以获取到最新的对象属性数据
handler(obj){
console.log("name = " + obj.name + "; age=" + obj.age);
}
}
}
});
</script>
</body>
</html>
vue 组件
在项目往往需要重用某个模块(头部、尾部、新闻。。。)的时候,可以将模块抽取成组件,其它页面中注册组件并引用。
小案例quickstart
小栗子是通过局部注册组件完成组件的使用,但在小栗子中加入了全局注册方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vuejs测试</title>
<script src="../js/vuejs-2.5.16.js"></script>
</head>
<body>
<div id="app">
<!--使用组件-->
<mycounter></mycounter>
<counter></counter>
<counter></counter>
<counter></counter>
</div>
<script type="text/javascript">
//定义全局组件
Vue.component("mycounter",{
template:'<button v-on:click="count++">你点了我 {{ count }} 次,我记住了.</button>',
data(){
return {count:0}
}
});
//定义局部组件
const counter = {
template:"<button @click='num++'>你点击了{{num}}次</button>",
data(){
return {num:0}
}
};
//全局注册组件:在所有的vue实例中都可以使用组件
//参数1:组件名称,参数2:具体的组件
//Vue.component("counter", counter);
var app = new Vue({
el:"#app",
components:{
//为K:V 形式
counter: counter
}
});
</script>
</body>
</html>
父组件将字符串更新传递到子组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vuejs测试</title>
<script src="../js/vuejs-2.5.16.js"></script>
</head>
<body>
<div id="app">
<!--使用组件-->
<introduce :title="msg"></introduce>
</div>
<script type="text/javascript">
//定义组件
const introduce = {
template:"<h2>{{title}}</h2>",
//定义接收父组件的属性
props:["title"]
};
//全局注册组件:在所有的vue实例中都可以使用组件
//参数1:组件名称,参数2:具体的组件
Vue.component("introduce", introduce);
var app = new Vue({
el:"#app",
data:{
msg:"父组件的msg属性数据内容"
}
});
</script>
</body>
</html>
父组件将数组更新传递到子组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vuejs测试</title>
<script src="../js/vuejs-2.5.16.js"></script>
</head>
<body>
<div id="app">
<!--使用组件-->
<my-list :items="lessons" ></my-list>
</div>
<script type="text/javascript">
//定义组件
const myList = {
template:`
<ul>
<li v-for="item in items" :key="item.id">{{item.id}}--{{item.name}}</li>
</ul>
`,
//定义接收父组件的属性
props:{
items:{
//数据类型,如果是数组则是Array,如果是对象则是Object
type:Array,
//默认值
default:[]
}
}
};
var app = new Vue({
el:"#app",
data:{
msg:"父组件的msg属性数据内容",
lessons:[
{"id":1, "name":"Java"},
{"id":2, "name":"c++"},
{"id":3, "name":"python"}
]
},
components:{
myList
}
});
</script>
</body>
</html>
在子组件中点击对应按钮实现父组件中数据的改变
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vuejs测试</title>
<script src="../js/vuejs-2.5.16.js"></script>
</head>
<body>
<div id="app">
<h2>num = {{num}}</h2>
<!--使用组件-->
<counter @plus="numPlus" @reduce="numReduce" :snum="num"></counter>
</div>
<script type="text/javascript">
//定义组件
const counter = {
template:`
<div>
<button @click='incrNum'>+</button>
<button @click='decrNum'>-</button>
</div>
`,
props:["snum"],
methods:{
//递增
incrNum(){
//调用到父组件中的方法
return this.$emit("plus");
},
decrNum(){
//调用到父组件中的方法
return this.$emit("reduce");
}
}
};
//全局注册组件:在所有的vue实例中都可以使用组件
//参数1:组件名称,参数2:具体的组件
//Vue.component("counter", counter);
var app = new Vue({
el:"#app",
components:{
counter: counter
},
data:{
num:0
},
methods:{
numPlus(){
this.num++;
},
numReduce(){
this.num--;
}
}
});
</script>
</body>
</html>
本小结的vue的基础知识就回顾到这里,下一节开始复习vue的异步请求操作和有关vue生命周期的内容。