此学习教程是对官方教程的解析,官方教程地址:介绍 —— Vue.js
一 Vue介绍
1.VUE核心: 声明式渲染
Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统
理解:
Vue.js 的核心是一个系统, 什么样的系统呢?
(1)它有简洁的模板语法:{{ }}的形式
(2)它是声明式的:也就是告诉VUE我要将某个数据和DOM的某个文本/attribute/结构进行绑定,至于怎么将数据渲染进 DOM VUE会替我搞定(渲染是响应式的,数据变化会自动反映在DOM中; 响应式也是VUE的重要特性)。而命令式渲染,指的是你需要自己写程序来将数据渲染到DOM。这很累,对吧?
(3) 如何声明?将数据绑定到DOM。 以下是三种绑定方式:
1.1 文本插值:将数据绑定到DOM文本
在D:\workspace_vue\vue_demo目录创建vue_introduce.html, 输入以下内容:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!-- 尝试 Vue.js 最简单的方法是使用 JSFiddle 上的 Hello World 例子。你可以在浏览器新标签页中打开它,跟着例子学习一些基础用法。或者你也可以创建一个 .html 文件,然后通过如下方式引入 Vue:-->
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<!-- Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统: -->
<div id="app">
{{ message }}
</div>
<script>
var app = new Vue({
el: '#app',<!-- 此实例作用于id为app的div -->
data: {
message: 'Hello Vue!'
}
})
</script>
</body>
</html>
<!--
我们已经成功创建了第一个 Vue 应用!看起来这跟渲染一个字符串模板非常类似,但是 Vue 在背后做了大量工作。现在数据和 DOM 已经被建立了关联,所有东西都是响应式的。我们要怎么确认呢?打开你的浏览器的 JavaScript 控制台 (就在这个页面打开),并修改 app.message 的值,你将看到上例相应地更新。
-->
运行结果
控制台修改app.message的值后:
1.2 控制元素attribute:将数据绑定到DOM元素attribute(使用指令)
指令:带有前缀 v-,以表示它们是 Vue 提供的特殊属性,它们会在渲染的 DOM 上应用特殊的响应式行为。
v-bind: 将元素节点的某个属性和 Vue 实例的某个属性绑定起来,从而保持一致。例如下例v-bind:style="style"的作用是,将<span>元素的style属性和app2的vue实例的style属性(app2的data里面)绑定。
示例(官网的鼠标悬停例子不好截图,所以换成颜色变换的效果):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<!-- 除了文本插值,我们还可以像这样来绑定元素 attribute: -->
<!--
这里我们遇到了一点新东西。你看到的 v-bind attribute 被称为指令。指令带有前缀 v-,以表示它们是 Vue 提供的特殊 attribute。可能你已经猜到了,它们会在渲染的 DOM 上应用特殊的响应式行为。在这里,该指令的意思是:“将这个元素节点的 style attribute 和 Vue 实例的 style 属性保持一致”。
-->
<div id="app-2">
<span v-bind:style="style">
改变我的颜色!
</span>
</div>
<script>
var app2 = new Vue({
el: '#app-2',<!-- 此实例作用于id为app-2的div -->
data: {
style: 'color:dark'
}
})
</script>
</body>
</html>
运行结果
控制台修改app2.style的值后:
1.3 条件与循环:将数据绑定到DOM结构(使用指令)
1.3.1 条件
v-if: 将元素节点的是否显示和 Vue 实例的某个布尔属性绑定起来,从而通过控制这个布尔属性来控制元素节点的切换
控制切换元素示例:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<!-- 控制切换一个元素是否显示也相当简单 -->
<!--
这个例子演示了我们不仅可以把数据绑定到 DOM 文本或 attribute,还可以绑定到 DOM 结构。此外,Vue 也提供一个强大的过渡效果系统,可以在 Vue 插入/更新/移除元素时自动应用过渡效果。
-->
<div id="app-3">
<p v-if="seen">现在你看到我了</p>
</div>
<script>
var app3 = new Vue({
el: '#app-3',
data: {
seen: true
}
})
</script>
</body>
</html>
运行结果:
控制台修改app3.seen的值后:
1.3.2 循环
v-for: 绑定数组的数据来渲染一个项目列表
示例:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<!-- v-for 指令可以绑定数组的数据来渲染一个项目列表 -->
<div id="app-4">
<ol>
<li v-for="todo in todos">
{{ todo.text }}
</li>
</ol>
</div>
<script>
var app4 = new Vue({
el: '#app-4',
data: {
todos: [
{ text: '学习 JavaScript' },
{ text: '学习 Vue' },
{ text: '整个牛项目' }
]
}
})
</script>
</body>
</html>
运行结果:
控制台修改app4.todos的值后:
2.处理用户输入
通过将数据绑定到DOM文本/attribute/结构的方式,VUE替我们完成了将数据渲染到DOM文本/attribute/结构的内部实现。然后我们通过控制台修改数据,DOM文本/attribute/结构就自动发生了相应的变化。 这很神奇。但用户可不会使用控制台。他们只能通过表单组件输入/修改数据。如何实现表单组件和数据的绑定呢?
2.1 按钮输入
v-on:添加一个事件监听器,通过它调用在 Vue 实例中定义的方法
示例:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<!-- 为了让用户和你的应用进行交互,我们可以用 v-on 指令添加一个事件监听器,通过它调用在 Vue 实例中定义的方法: -->
<div id="app-5">
<p>{{ message }}</p>
<button v-on:click="reverseMessage">反转消息</button>
</div>
<script>
var app5 = new Vue({
el: '#app-5',
data: {
message: 'Hello Vue.js!'
},
methods: {
//注意在 reverseMessage 方法中,我们更新了应用的状态,但没有触碰 DOM——所有的 DOM 操作都由 Vue 来处理,你编写的代码只需要关注逻辑层面即可。
reverseMessage: function () {
this.message = this.message.split('').reverse().join('')
}
}
})
</script>
</body>
</html>
运行效果:
按钮点击前
按钮点击后
2.2 表单输入
v-model
:轻松实现表单输入和应用状态之间的双向绑定
示例:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<!-- Vue 还提供了 v-model 指令,它能轻松实现表单输入和应用状态之间的双向绑定 -->
<div id="app-6">
<p>{{ message }}</p>
<input v-model="message">
</div>
<script>
var app6 = new Vue({
el: '#app-6',
data: {
message: 'Hello Vue!'
}
})
</script>
</body>
</html>
运行效果:
文本框内容修改前:
文本框内容修改后:
回到最根本的问题,VUE为什么要实现声明式渲染,并且是它的核心呢?个人认为声明式渲染带来了以下好处:
(1)易入门:相对于命令式,声明式隐藏了实现细节,显得简单、易懂、直观,特别对于初学者友好,易于入门。
(2)便于维护:声明式渲染将数据及实现逻辑和视图进行了解耦, 开发人员可以专注于业务逻辑实现还无须操心DOM的变化。
(3)打下组件化基础:数据及逻辑和视图的解耦为组件化打下了基础。一个组件的内部,就包括了数据、逻辑和视图(组件模板),没有解耦, 组件就难以维护。
3.组件基础
为什么需要组件化:当一个应用很复杂时, 组件化将大大降低开发的难度,提高应用的稳定性和可维护性, 且容易复用。形象地说,打造一个复杂的应用就像搭积木一样。
组件系统:Vue 的另一个重要概念,因为它是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用。
组件: 拥有预定义选项的Vue 实例
组件注册:Vue.component(组件名, 预定义选项)
3.1 无属性的组件
组件最简单的例子:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<ol id="app-7">
<todo-item></todo-item>
<todo-item></todo-item>
<todo-item></todo-item>
</ol>
<script>
// 一个组件本质上是一个拥有预定义选项的一个 Vue 实例。在 Vue 中注册组件很简单
// 定义名为 todo-item 的新组件
Vue.component('todo-item', {
template: '<li>这是个待办项</li>' //组件模板
})
var app7 = new Vue({
el: '#app-7'
})
</script>
</body>
</html>
运行结果:
3.2 带自定义属性的组件
上面的例子,组件模板的html内容都是固定的,这并不灵活。 能给组件传递数据吗? 可以,通过组件的自定义属性。
组件的自定义属性:由组件自定义选项props设置。
3.2.1 非对象属性:
给todo-item组件设置一个非对象属性todo:
Vue.component('todo-item', {
props: ['todo'],
template: '<li>{{todo}}</li>'
})
例子:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app-7">
<ol>
<!--
为 todo-item 组件提供 todo 属性。
注意有无v-bind的区别
-->
<todo-item todo="grocery"></todo-item>
<todo-item v-bind:todo="grocery"></todo-item>
</ol>
</div>
<script>
// 定义名为 todo-item 的新组件
Vue.component('todo-item', {
// todo-item 组件现在接受一个
// "prop",类似于一个自定义 attribute。
// 这个 prop 名为 todo。
props: ['todo'],
template: '<li>{{todo}}</li>'
})
var app7 = new Vue({
el: '#app-7',
data: {
grocery:'蔬菜'
}
})
</script>
</body>
</html>
运行结果:
3.2.2 对象属性:
给todo-item组件设置一个对象属性todo:
Vue.component('todo-item', {
props: ['todo'],
template: '<li>{{todo.text}}</li>'
})
例子:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app-7">
<ol>
<!--
这次todo-item的todo属性是一个对象。
以下方式不起作用, 因为"grocery"是字符串不是对象,没有text属性
-->
<todo-item todo="grocery"></todo-item>
<!-- 使用v-bind绑定对象数据 -->
<todo-item v-bind:todo="grocery"></todo-item>
<todo-item v-bind:todo="grocery_json"></todo-item>
</ol>
</div>
<script>
// 定义名为 todo-item 的新组件
Vue.component('todo-item', {
// todo-item 组件现在接受一个
// "prop",类似于一个自定义 attribute。
// 这个 prop 名为 todo。
props: ['todo'],
template: '<li>{{todo.text}}</li>' //模板里使用了对象的属性
})
var grocery=new Object();
grocery.id="0";
grocery.text="蔬菜";
var app7 = new Vue({
el: '#app-7',
data: {
grocery: grocery, //这是一个javascript对象
grocery_json: { id: 0, text: '蔬菜' }//这是一个JSON对象,更为简洁
}
})
</script>
</body>
</html>
运行结果:
带循环的更复杂的例子:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app-7">
<ol>
<!--
现在我们为每个 todo-item 提供 todo 对象
todo 对象是变量,即其内容可以是动态的。
我们也需要为每个组件提供一个“key”,稍后再
作详细解释。
-->
<todo-item
v-for="item in groceryList"
v-bind:todo="item"
v-bind:key="item.id"
></todo-item>
</ol>
</div>
<script>
// 定义名为 todo-item 的新组件
Vue.component('todo-item', {
// todo-item 组件现在接受一个
// "prop",类似于一个自定义 attribute。
// 这个 prop 名为 todo。
props: ['todo'],
template: '<li>{{ todo.text }}</li>'
})
var app7 = new Vue({
el: '#app-7',
data: {
groceryList: [
{ id: 0, text: '蔬菜' },
{ id: 1, text: '奶酪' },
{ id: 2, text: '随便其它什么人吃的东西' }
]
}
})
</script>
</body>
</html>
<!--
尽管这只是一个刻意设计的例子,但是我们已经设法将应用分割成了两个更小的单元。子单元通过 prop 接口与父单元进行了良好的解耦。我们现在可以进一步改进 <todo-item> 组件,提供更为复杂的模板和逻辑,而不会影响到父单元。
-->
运行结果:
>> 实践一下
以下例子运行下,看会发生什么(请注意生成的HTML的变化):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app-7">
<ol>
<!--
style="color:red"
-->
<todo-item v-bind:todo="grocery" style="color:red"></todo-item>
</ol>
</div>
<script>
// 定义名为 todo-item 的新组件
Vue.component('todo-item', {
// todo-item 组件现在接受一个
// "prop",类似于一个自定义 attribute。
// 这个 prop 名为 todo。
props: ['todo'],
template: '<li><span>{{todo.text}}</span></li>'
})
var app7 = new Vue({
el: '#app-7',
data: {
grocery: { id: 0, text: '蔬菜' }
}
})
</script>
</body>
</html>
3.3 嵌套的组件
这里有一个 (假想的) 例子,以展示使用了组件的应用模板是什么样的:
<div id="app">
<app-nav></app-nav><!-- 应用导航组件,显示导航区-->
<app-view><!-- 应用视图组件,显示视图区-->
<app-sidebar></app-sidebar><-- 应用侧边栏组件,应用视图组件的子组件,显示侧边栏 -->
<app-content></app-content><-- 应用内容组件,应用视图组件的子组件,显示内容 -->
</app-view>
</div>
有四个自定义组件, 显示了一个清晰的组件树:
app-nav:应用导航组件,显示导航区
app-view:应用视图组件,显示视图区
|- app-sidebar:应用侧边栏组件,应用视图组件的子组件,显示侧边栏
|- app-content:应用内容组件,应用视图组件的子组件,显示内容
VUE 介绍部分学习教程结束!
全部教程地址:Vue入门实战教程 | 寒于水学习网