其他章节请看:

vue 快速入门 系列

vue 的基础应用(上)

Tip: vue 的基础应用分上下两篇,上篇是基础,下篇是应用

初步认识 vue一文中,我们已经写了一个 vue 的 hello-world。对 vue 已经有了一个大概的印象。

接下来我们应该掌握 vue 的最基础知识,学会 vue 的基本应用。

比较好的方法就是花个几天的时间将 vue 官网的基础篇尽量走一遍,写一写例子。以下是 vue 2.x 的基础篇的目录:

- 教程 2.x
- 基础
- 安装
- 介绍
- Vue 实例
- 模板语法
- 计算属性和侦听器
- Class 与 Style 绑定
- 条件渲染
- 列表渲染
- 事件处理
- 表单输入绑定
- 组件基础

:如果你像笔者一样,只有 jQuery 开发的经验,在看基础篇的过程种,肯定会有很多的不懂之处,先看下去,把能看懂的先看完。

本文记录的是笔者当初看 vue 基础篇遇到的一些重要的、不好理解的知识点,算是基础篇的一个补充或笔记。

Vue 实例

通过 new Vue() 来创建一个实例,其中 el 选项提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标。

vue 实例会经历一系列的过程,比如数据侦测、模板编译、渲染到视图等,这就是 vue 实例的生命周期,vue 对外提供了生命周期的钩子函数,这就允许我们在 vue 的各个阶段插入一些我们的逻辑。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src='vue.js'></script>
</head>
<body>
<div id='app'>
<p>
{{message}}
</p>
</div>
<script>
// 通过 new Vue() 创建一个实例
var app = new Vue({
// 提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标。
// 可以是 CSS 选择器,也可以是一个 HTMLElement 实例。
el: '#app',
// Vue 实例的数据对象
data:{
message: 'hello',
},
// 生命周期
created: function(){
console.log('实例被创建时触发')
},
mounted: function(){
console.log('被挂载时触发')
} }) </script>
</body>
</html>

Tip: 后续不在提供完整的代码,省略 head、body 等。

模板语法

前文说过 vue 是声明式操作 dom 的框架。我们只需要描述状态与 dom 之间的映射关系即可,状态到视图的转换,框架会帮我们做,状态改变,视图也会自动更新。

而 vue 是通过模板来描述状态与 dom 之间的映射关系。所以模板的知识点稍微会多一点。

条件渲染

用 key 管理可复用的元素

Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。

<div id='app'>
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address">
</template>
<button @click='toggleHandle'>切换</button>
</div> <script>
var app = new Vue({
el: '#app',
data:{
loginType: 'username',
},
methods: {
toggleHandle: function(){
this.loginType = this.loginType === 'username' ? 'email' : 'username';
}
}
})
</script>

在上面的代码中切换 loginType 将不会清除用户已经输入的内容。因为两个模板使用了相同的元素,<input> 不会被替换掉——仅仅是替换了它的 placeholder。如果需要表达“这两个元素是完全独立的,不要复用它们”,只需添加一个具有唯一值的 key attribute 即可。

// 给 input  添加 key 属性
<input placeholder="Enter your username" key="username-input">
<input placeholder="Enter your email address" key="email-input">

v-if vs v-show

v-if 是真正的条件渲染;v-show 只是简单地切换元素的 CSS property display;

例如下面这种场景,点击一个新建按钮,显示弹框组件(custom-dialog),弹框中有一些 input 输入框,如果需要每次点击新建,弹框组件整个都重新生成,则可以使用 v-if;否则在弹框中输入了文字,通过 v-show 隐藏弹框,下次在显示时,可能之前输入的文字、错误信息都还存在。

<custom-dialog v-if='isShow'></custom-dialog>
<button @click='clickHandle'>新建</button>

表单输入绑定

v-model:在表单控件或者组件上创建双向绑定。

应用在表单控件上,请看示例:

<div id='app'>
<input v-model="message" placeholder="edit me"> <!-- {1} -->
<!--
<input type="text" :value='message' @input='handleInput' placeholder="edit me"> // {2}
-->
<p>Message is: {{ message }}</p>
</div>
<script>
var app = new Vue({
el: '#app',
data:{
message: 'a'
},
methods: {
handleInput: function(e){
this.message = e.target.value
}
}
})
</script>

v-model 本质上不过是语法糖。行{1} 的本质其实是 行{2}。

v-model 在组件中的使用请看下文。

组件基础

上面介绍的其实是基础中最简单的部分。而组件是基础篇中最应该掌握的部分。

Vue.component()

可以通过 Vue.component() 注册或获取全局组件。请看示例:

   <div id='app'>
<p>{{message}}</p>
<button-counter></button-counter>
<button-counter></button-counter>
</div>
<script> // 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
// 一个组件的 data 选项必须是一个函数
// 这样,每个组件的数据都是独立的
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
}) var app = new Vue({
el: '#app',
data: {
message: 'hello'
}
})
</script>

组件是可复用的 Vue 实例,且带有一个名字:在这个例子中是 <button-counter>

因为组件是可复用的 Vue 实例,所以它们与 new Vue() 接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。

通常一个应用会以一棵嵌套的组件树的形式来组织,这样就能完成一个功能很复杂的页面。

props

props 用于接收来自父组件的数据。请看示例:

  <div id='app'>
<!-- <button-counter v-bind:msg='message'></button-counter> -->
<!-- 缩写 -->
<button-counter :msg='message'></button-counter>
</div>
<script> Vue.component('button-counter', {
props: ['msg'],
template: `<div>
来自父组件的信息: {{msg}}
</div>`
}) var app = new Vue({
el: '#app',
data: {
message: 'hello'
}
})
</script>

v-bind:msg='message' 可以缩写成 :msg='message'

v-on

v-on 用在自定义元素组件上时,可以监听子组件触发的自定义事件。请看示例:

<div id='app'>
number: {{count}}
<!-- 父组件给子组件注册了事件 chang-count,事件的回调方法是 changCount -->
<button-counter v-on:chang-count='changCount'></button-counter>
</div>
<script> Vue.component('button-counter', {
data: function(){
return {
num: 10
}
},
template: `<div>
<!-- v-on:click 缩写 @click -->
<button @click='triggerHandle'>触发</button> </div>`,
methods: {
triggerHandle: function(){
// 触发事件
this.$emit('chang-count', this.num++);
}
}
}) var app = new Vue({
el: '#app',
data: {
count: 0
},
methods: {
changCount: function(v){
this.count = v;
}
}
})
</script>

v-on 的语法糖是 @。

v-model

v-model 在表单控件或者组件上创建双向绑定。上文已经介绍了如何在表单上使用。而用在组件上,原理是相同的。请看示例:

 <div id='app'>
number: {{count}}
<!-- 父组件给子组件注册了事件 chang-count,事件的回调方法是 changCount -->
<custom-input v-model="count"></custom-input> <!-- {20} -->
<!-- <custom-input :value="count" @input='changCount'></custom-input> --> <!-- {21} -->
</div>
<script> Vue.component('custom-input', {
props: ['value'],
data: function(){
return {
msg: this.value
}
},
template: `<div>
<input :value='msg' @input='inputHandle'/>
</div>`,
methods: {
inputHandle: function(e){
this.msg = e.target.value
// 触发事件
this.$emit('input', this.msg);
}
}
}) var app = new Vue({
el: '#app',
data: {
count: 10
},
methods: {
changCount: function(v){
this.count = v;
}
}
})
</script>

行{20} 与 行{21} 等效。

非父子组件通信

props 用于父组件给子组件传递数据;

子组件给父组件传递数据可以通过事件(例如 vm.$emit());

但非父子之间如何通信?

对于 $dispatch 和 $broadcast 最简单的升级方式就是:通过使用事件中心,允许组件自由交流,无论组件处于组件树的哪一层。由于 Vue 实例实现了一个事件分发接口,你可以通过实例化一个空的 Vue 实例来实现这个目的。—— vue 官网

简单来说,就是使用一个空的 Vue 实例作为中央事件总线,可以帮助我们解决兄弟组件之间的通信。请看示例:

<div id='app'>
<component-a></component-a>
<component-b></component-b>
</div>
<script> Vue.component('componentA', {
data: function(){
return {
msg: '我是 componentA'
}
},
template: `<div>
message: {{msg}}
<button @click='send'>给兄弟发送数据</button>
</div>`,
created: function(){
var that = this;
// 给事件中心注册事件
bus.$on('on-messageA', function(msg){
console.log('received: ' + msg)
that.msg = msg
})
},
methods: {
send: function(e){
// 给事件中心触发事件
bus.$emit('on-messageB', 'from componentA')
}
}
}) Vue.component('componentB', {
data: function(){
return {
msg: '我是 componentB'
}
},
template: `<div>
message: {{msg}}
<button @click='send'>给兄弟发送数据</button>
</div>`,
created: function(){
var that = this;
bus.$on('on-messageB', function(msg){
that.msg = msg
})
},
methods: {
send: function(e){
console.log('from componentB')
bus.$emit('on-messageA', 'from componentB')
}
}
})
// 事件中心
var bus = new Vue()
var app = new Vue({
el: '#app'
})
</script>

这个例子中定义了两个组件,首先用 new Vue() 创建一个中央事件总线(bus),类似一个中介,接着组件(componentA、componentB)给 bus 注册事件,当点击按钮时触发 bus 的事件,并传递数据。

这种方式其实可以实现任何组件之间的通信,包括父子、兄弟、跨级等,因为在 bus 看来,我(bus)就是中介,其他组件只是我的客户。

Tip:项目比较大时,通常会使用 vuex,后续会介绍 vuex 这个状态管理工具。

父组件和子组件

vm.$parent 可以取得父组件;通过 vm.$children 取得当前实例的直接子组件,并通过 vm.$refs 取得指定子组件。请看示例:

<div id='app'>
<component-a ref='comA'></component-a>
<component-a ref='comB'></component-a>
</div>
<script> Vue.component('componentA', {
data: function(){
return {
msg: 'hello'
}
},
template: `<div>
message: {{msg}}
</div>`,
watch: {
msg: function(){
// 通过 vm.$parent 取得父组件
console.log(this.$parent.name)
// 通过 ref 指定子组件索引名称
// 通过 vm.$refs 取得子组件
console.log(this.$parent.$refs.comA.msg)
}
}
}) var app = new Vue({
el: '#app',
data: {
name: '我是父'
}
})
// 通过 vm.$children 直接更改子组件的数据
console.log(app.$children[1].msg = 'hello2')
</script>

通过插槽分发内容

插槽也可以叫 slot 内容分发。请看示例:

  <div id='app'>
<component-a ref='comA'>
<p>子元素的 slot 插槽将会被我替换</p> <!-- {30} -->
</component-a>
</div> <script>
Vue.component('componentA', {
template: `<div>
hello
<slot></slot>
</div>`, }) var app = new Vue({
el: '#app',
})
</script>

我们在组件A中定义了一个插槽(<slot></slot>),父组件中的 p(行{30})将会替换子组件的 slot。

Tip: props、事件以及 slot 内容分发构成了 Vue 组件的 3 个 API 来源。

作用域插槽,概念不太好理解,直接看示例:

  <div id='app'>
<component-a>
<!-- slot-scope 用于将元素或组件表示为作用域插槽 -->
<template slot-scope='props'>
<p>来自父组件</p>
<p>{{props.msg}}</p>
</template>
</component-a>
</div> <script>
Vue.component('componentA', {
data: function(){
return {
msg: '来自子组件的内容'
}
},
template: `<div>
hello
<slot :msg='msg'></slot>
</div>`, }) var app = new Vue({
el: '#app',
})
</script>

作用域插槽,就是让插槽的内容能够访问子组件中才有的数据。

:由于笔者的 vue 是 2.5.x,所以用的是 slot-scope。而在 2.6.x 中,scope、slot和slot-scope 都推荐使用 v-scope。

其他

过滤器

Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化。请看示例:

  <div id='app'>
<p>{{msg | toUpperCase}}</p>
</div>
<script> var app = new Vue({
el: '#app',
data: {
msg: 'hello'
},
// 过滤器
filters: {
toUpperCase: function(v){
return v.toUpperCase()
}
}
})
</script>

.sync 修饰符

在有些情况下,我们可能需要对一个 prop 进行“双向绑定”。不幸的是,真正的双向绑定会带来维护上的问题,因为子组件可以变更父组件,且在父组件和子组件都没有明显的变更来源。这也是为什么我们推荐以 update:myPropName 的模式触发事件取而代之。—— vue 官网

简单来说,父组件给子组件传递了一个属性,子组件不要直接更改父组件的这个属性,而应该通知父组件,让父组件自己去更改这个属性。请看示例:

<div id='app'>
父组件: name = {{name}}
<!--
当在父级组件监听事件的时候,我们可以通过 $event 访问到被抛出的这个值
-->
<custom :name="name" v-on:update:name="updateName($event)"></custom> <!-- {40} -->
<!-- 相等 -->
<!-- <custom :name.sync="name"></custom> --> <!-- {41} --> </div>
<script>
let seed = 1;
Vue.component('custom', {
props: ['name'],
template: `
<div>
<p>子组件: name = {{name}}</p>
<p><button @click='handleClick'>change name</button></p>
</div>
`,
methods: {
handleClick: function(){
// update:name 就是一个事件名
// 改为 update--name 也可以
this.$emit('update:name', seed++)
}
}
})
const app = new Vue({
el: '#app',
data: {
name: 'hello'
},
methods: {
updateName: function(v){
this.name = v
}
}
})
</script>

为了方便起见,我们为这种模式(行{40})提供一个缩写,即 .sync 修饰符(行{41})

其他章节请看:

vue 快速入门 系列

vue 快速入门 系列 —— vue 的基础应用(上)的更多相关文章

  1. vue 快速入门 系列 —— vue 的基础应用(下)

    其他章节请看: vue 快速入门 系列 vue 的基础应用(下) 上篇聚焦于基础知识的介绍:本篇聚焦于基础知识的应用. 递归组件 组件是可以在它们自己的模板中调用自身的.不过它们只能通过 name 选 ...

  2. vue 快速入门 系列 —— vue loader 扩展

    其他章节请看: vue 快速入门 系列 vue loader 扩展 在vue loader一文中,我们学会了从零搭建一个简单的,用于单文件组件开发的脚手架.本篇将在此基础上继续引入一些常用的库:vue ...

  3. vue 快速入门 系列 —— vue loader 上

    其他章节请看: vue 快速入门 系列 vue loader 上 通过前面"webpack 系列"的学习,我们知道如何用 webpack 实现一个不成熟的脚手架,比如提供开发环境和 ...

  4. vue 快速入门 系列 —— vue loader 下

    其他章节请看: vue 快速入门 系列 vue loader 下 CSS Modules CSS Modules 是一个流行的,用于模块化和组合 CSS 的系统.vue-loader 提供了与 CSS ...

  5. vue 快速入门 系列 —— Vue(自身) 项目结构

    其他章节请看: vue 快速入门 系列 Vue(自身) 项目结构 前面我们已经陆续研究了 vue 的核心原理:数据侦测.模板和虚拟 DOM,都是偏底层的.本篇将和大家一起来看一下 vue 自身这个项目 ...

  6. vue 快速入门 系列 —— Vue 实例的初始化过程

    其他章节请看: vue 快速入门 系列 Vue 实例的初始化过程 书接上文,每次调用 new Vue() 都会执行 Vue.prototype._init() 方法.倘若你看过 jQuery 的源码, ...

  7. vue 快速入门 系列 —— vue-cli 上

    其他章节请看: vue 快速入门 系列 Vue CLI 4.x 上 在 vue loader 一文中我们已经学会从零搭建一个简单的,用于单文件组件开发的脚手架:本篇,我们将全面学习 vue-cli 这 ...

  8. vue 快速入门 系列 —— vue-cli 下

    其他章节请看: vue 快速入门 系列 Vue CLI 4.x 下 在 vue loader 一文中我们已经学会从零搭建一个简单的,用于单文件组件开发的脚手架:本篇,我们将全面学习 vue-cli 这 ...

  9. vue 快速入门 系列 —— vue-router

    其他章节请看: vue 快速入门 系列 Vue Router Vue Router 是 Vue.js 官方的路由管理器.它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌. 什么是路由 ...

随机推荐

  1. LeetCode & tree & binary tree

    LeetCode & tree & binary tree 树 & 二叉树 refs https://leetcode.com/problemset/all/?topicSlu ...

  2. Online analog video interview

    Online analog video interview 在线模拟视频面试 English 口语 https://www.pramp.com/#/ https://www.pramp.com/faq ...

  3. 翻译:《实用的Python编程》02_01_Datatypes

    目录 | 上一节 (1.7 函数) | 下一节 (2.2 容器) 2.1 数据类型和数据结构 本节以元组和字典为代表介绍数据结构. 原始数据类型 Python 有一些原始数据类型: 整数 浮点数 字符 ...

  4. SSL (Secure Sockets Layer)

    本文转载自SSL (Secure Sockets Layer) TLS简介 The Transport Layer Security (TLS) protocol aims primarily to ...

  5. Redis Lua 脚本使用

    本文转载自Redis Lua 脚本使用 Lua 简介 Lua语言提供了如下几种数据类型:booleans(布尔).numbers(数值).strings(字符串).tables(表格). 下面是一些 ...

  6. idea快捷键:查找类中所有方法的快捷键

    查找类中所有方法的快捷键 第一种:ctal+f12,如下图 第二种:alt+7,如下图

  7. Java中base64与byte[]转换

    1.base64转byte[] 导包: import java.util.Base64 转换: String base64Str = base64的字符串; byte[] bytes = Base64 ...

  8. 第七届蓝桥杯JavaB组——第7题剪邮票

    题目: 剪邮票 如[图1.jpg], 有12张连在一起的12生肖的邮票. 现在你要从中剪下5张来,要求必须是连着的. (仅仅连接一个角不算相连) 比如,[图2.jpg],[图3.jpg]中,粉红色所示 ...

  9. Linux 虚拟文件系统四大对象:超级块、inode、dentry、file之间关系

    更多嵌入式原创文章,请关注公众号:一口Linux 一:文件系统 1. 什么是文件系统? 操作系统中负责管理和存储文件信息的软件机构称为文件管理系统,简称文件系统. 通常文件系统是用于存储和组织文件的一 ...

  10. 给新手的 11 个 Docker 免费上手项目

    转: 给新手的 11 个 Docker 免费上手项目 作者:老K玩代码 来源:toutiao.com/i6882755471015576072 Docker 是一个开源的应用容器引擎,让开发者可以打包 ...