Vue基础

介绍

Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。其核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与单文件组件和Vue生态系统支持的库结合使用时,Vue 也完全能够为复杂的单页应用程序提供驱动。

注意:由于Vue使用getter/setter等ECMAScript 5特性,所以兼容到Internet Explorer

框架和库的区别?

框架:字面上理解为架子,会基于自身的特点为用户提供一整套的解决方案,倾向于创造一套需要你来遵守的规则和范例,你可以基于这套架子快速实现应用,但前提是你必须按照它的规则来写。

例如: thinkphp 框架,必须要求你按照它的命名规则、代码组织结构来写。

库:是代码集合成的一个产品,供程序员调用,例如: jquery库,只需要引入使用它的功能就可以了,至于你的应用怎样架构,项目目录怎样组织它完全由你自己决定。

生命周期

,beforeCreate: 在实例开始初始化时同步调用。此时数据观测、事件等都尚未初始化。
created: 在实例创建之后调用。此时已完成数据观测、事件方法,但尚未开始DOM编译,即未挂载到document中。
beforeMount: 在mounted之前运行。
mounted: 在编译结束时调用。此时所有指令已生效,数据变化已能触发DOM更新,但不保证$el已插入文档。
beforeUpdate: 在实例挂载之后,再次更新实例(例如更新data) 时会调用该方法,此时尚未更新DOM结构。
updated: 在实例挂载之后, 再次更新实例并更新完DOM结构后调用。
beforeDestroy: 在开始销毁实例时调用,此刻实例仍然有效。
destroyed: 在实例被销毁之后调用。此时所有绑定和实例指令都已经解绑,子实例也被销毁。
activated: 需要配合动态组件keep-/ive属性使用。在动态组件初始化渲染的过程中调用该方法。
deactivated: 需要配合动态组件keep-live属性使用。在动态组件初始化移出的过程中调用该方法。

模板语法

插值

文本

数据绑定最常见的形式就是使用“Mustache”语法 (双大括号) 的文本插值:

<span>Message: {{ msg }}</span>

Mustache 标签将会被替代为对应数据对象上 msg 属性的值。无论何时,绑定的数据对象上 msg 属性发生了改变,插值处的内容都会更新。

通过使用 v-once 指令,你也能执行一次性地插值,当数据改变时,插值处的内容不会更新。但请留心这会影响到该节点上的其它数据绑定:

<span v-once>这个将不会改变: {{ msg }}</span>

Vue还提供了一个v-cloak指令,用于控制数据还未渲染出来时,是否显示未渲染的临时内容。
示例如下:

<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
[v-cloak] {
display: none;
</style>
</head>
<body>
<!-- 当网速慢速时不会显示{{ mess }},但是要和display:none 配合使用,不然还是会
显示{{ mess }} -->
<div id="app" v-cloak>
{{ mess }}
</div>
<script src="https://unpkg. com/vue/dist/vue . min. js"></script>
<script>
let app = new Vue({
el: ' #app',
data: {
mess: 'this is a test'
}
});
	</script>
</body>
原始 HTML

双大括号会将数据解释为普通文本,而非 HTML 代码。为了输出真正的 HTML,你需要使用 v-html 指令:

<p>Using mustaches: {{ rawHtml }}</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>
特性

特性,又被称之为属性。我们知道,一个htm/标签可以含有多个属性,如果需要将属性和data数据进行绑定,达到通过data数据来控制属性值的话,可以使用v-bind指令进行属性的绑定。

<body>
 <div id="app">
 <div v-bind:title="one" v-bind:class="two">动态绑定属性</div>
 </div>
 <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
 <script>
 const app = new Vue({
 el: '#app',
 data: {
 one: 'this is a title',
 two: 'topContent abc'
 }
 })
 </script>
</body>
使用 JavaScript 表达式

迄今为止,在我们的模板中,我们一直都只绑定简单的属性键值。但实际上,对于所有的数据绑定,Vue.js 都提供了完全的 JavaScript 表达式支持。

{{ number + 1 }}

{{ ok ? 'YES' : 'NO' }}

{{ message.split('').reverse().join('') }}

<div v-bind:id="'list-' + id"></div>

这些表达式会在所属 Vue 实例的数据作用域下作为 JavaScript 被解析。有个限制就是,每个绑定都只能包含单个表达式,所以下面的例子都不会生效。

<!-- 这是语句,不是表达式 -->
{{ var a = 1 }}

<!-- 流控制也不会生效,请使用三元表达式 -->
{{ if (ok) { return message } }}
4.动态参数

从2.6.0开始,可以用方括号括起来的JavaScript表达式作为一个动态参数,这样就增大了属性
或者事件的灵活性。
具体示例如下:

4.动态参数
从2.6.0开始,可以用方括号括起来的JavaScript表达式作为一个动态参数,这样就增大了属性
或者事件的灵活性。
具体示例如下:
<body>
<div id="app">
<!--这里为span 绑定了一个动态事件,具体是什么事件取决于abc的值-- >
<span v-on: [abc]="test2">动态参数</ span>
</div>
<script src="https://unpkg. com/vue/dist/vue.min.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
abc: ' mouseenter'
})
</script>
</body>

缩写

v-bind可以缩写为:
示例:<div v-bind:title="one" :class="two">动态绑定属性</div>
v-on 缩写

<!-- 完整语法 -->
<a v-on:click="doSomething">...</a>

<!-- 缩写 -->
<a @click="doSomething">...</a>

计算属性

模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。例如:

<div id="example">
  {{ message.split('').reverse().join('') }}
</div>

在这个地方,模板不再是简单的声明式逻辑。你必须看一段时间才能意识到,这里是想要显示变量 message 的翻转字符串。当你想要在模板中多次引用此处的翻转字符串时,就会更加难以处理。

所以,对于任何复杂逻辑,你都应当使用计算属性。
计算属性对应的数据选项为computed,类似于data,只不过data对应的是一个值,而计算属性对应的是一个方法。在方法里面就可以书写复杂的计算,然后将结果进行返回。

<div id="example">
  <p>Original message: "{{ message }}"</p>
  <p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
var vm = new Vue({
  el: '#example',
  data: {
    message: 'Hello'
  },
  computed: {
    // 计算属性的 getter
    reversedMessage: function () {
      // `this` 指向 vm 实例
      return this.message.split('').reverse().join('')
    }
  }
})

计算属性与方法的区别

计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。这就意味着只要 message 还没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。

当触发重新渲染时,调用方法将总会再次执行函数。

什么时候使用计算属性与方法

假设我们有一个性能开销比较大的计算属性 A,它需要遍历一个巨大的数组并做大量的计算。然后我们可能有其他的计算属性依赖于 A 。如果没有缓存,我们将不可避免的多次执行 A 的 getter!如果你不希望有缓存,请用方法来替代。

计算属性的 setter

计算属性默认只有 getter ,不过在需要时你也可以提供一个 setter :

// ...
computed: {
  fullName: {
    // getter
    get: function () {
      return this.firstName + ' ' + this.lastName
    },
    // setter
    set: function (newValue) {
      var names = newValue.split(' ')
      this.firstName = names[0]
      this.lastName = names[names.length - 1]
    }
  }
}
// ...

现在再运行 vm.fullName = ‘John Doe’ 时,setter 会被调用,vm.firstName 和 vm.lastName 也会相应地被更新。

侦听器

虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch 选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。

<body>
	<div id="app">
		<button @click="a++">a加1</button>
		<p>当前a的值为: {{ a }}</p>
		<p>{{ message }}</p>
	</div>
	<script src="https://unpkg. com/vue/dist/vue.min.js"></script>
	<script>
		const Vm = new Vue({
			el: '#app' ,
			data: {
				a: 1,
				message:
			},
			watch: {
				//对data数据中的a进行监控
				//发生改变时,新值和旧值会传入回调函数
				a: function (val, oldVal) {
					this. message = 'a的旧值为' + oldVal + ',新值为' + val;
				}
			}
		})
	</script>
</body>

除了watch数据选项以外,实例对象的$watch方法也可以监听data数据的改变。

//实例对象的$watch方法也可以监听data 数据的改变
//将新值和旧值传入到回调函数里面
vm. $watch(监听的对象, function (val, oldVal) {
this. message = 'a的旧值为' + oldVal + ',新值为' + val;
})

Class 与 Style 绑定

绑定 HTML Class

对象语法

我们可以传给 v-bind:class 一个对象,以动态地切换 class:

<body>
	<div id="app">
		<!-- 可以为class 属性绑定一个对象,这样更加灵活-- ->
		<div v-bind:class="test"></div>
	</div>
	<script src="https://unpkg. com/vue/dist/vue.min.js"></script>
	<script>
		new Vue({
			el: ' #app',
			data: {
				//根据test对象的属性决定有哪些值
				test: {
					abc: true,
					def: true,
					ghi: false
				}
			}
		});
	</script>
</ body>

效果:<div class="abc def"></div>

数组语法

我们可以把一个数组传给 v-bind:class,以应用一个 class 列表:

<body>
	<div id="app">
		<!--可以为class属性绑定一个数组
		数组中的每一项表示data数据的键,每一个键所对应的值为挂 上去的样式-->
		<div v-bind:class="[a,b,c]"></div>
	</div>
	<script src="https://unpkg. com/vue/dist/vue.min.js"></script>
	<script>
		new Vue({
			el: ' #app',
			data: {
				a: 'abc',
				b: 'def',
				c: 'ghi'
			});
	</script>
</body>

用在组件上

当在一个自定义组件上使用 class 属性时,这些 class 将被添加到该组件的根元素上面。这个元素上已经存在的 class 不会被覆盖。

例如,如果你声明了这个组件:

Vue.component('my-component', {
  template: '<p class="foo bar">Hi</p>'
})

然后在使用它的时候添加一些 class:

<my-component class="baz boo"></my-component>

HTML 将被渲染为:

<p class="foo bar baz boo">Hi</p>

绑定内联样式

对象语法

v-bind:style 的对象语法十分直观——看着非常像 CSS,但其实是一个 JavaScript 对象。CSS 属性名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用引号括起来) 来命名:

<body>
	<div id="app">
		<div v-bind:style="test">Lorem ipsum dolor sit amet.</div>
	</div>
	<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
	<script>
		const vm = new Vue({
			el: '#app',
			data: {
				test : {
					color : 'red',
					fontSize : '30px'
				}
			}
		});
	</script>
</body>
数组语法

v-bind:style 的数组语法可以将多个样式对象应用到同一个元素上:

<body>
	<div id="app">
		<!--同样绑定2套样式--2>
		<div v-bind:style="[style1, style2]">Lorem ipsum dolor </div>
	</div>
	<script src="https://unpkg. com/vue/dist/vue .min.js"></script>
	<script>
		const vm = new Vue({
			el: ' #app',
			data: {
				style1: {
					color: 'red'
				},
			style2: {
				textDecoration: ' underline'
			}
		});
	</script>
</ body>

自动添加前缀

当 v-bind:style 使用需要添加浏览器引擎前缀的 CSS 属性时,如 transform,Vue.js 会自动侦测并添加相应的前缀。

多重值

从 2.3.0 起你可以为 style 绑定中的属性提供一个包含多个值的数组,常用于提供多个带前缀的值,例如:
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>
这样写只会渲染数组中最后一个被浏览器支持的值。在本例中,如果浏览器支持不带浏览器前缀的 flexbox,那么就只会渲染 display: flex。

条件渲染

v-if v-else v-else-if

<body>
	<div id="app">
		<!--type为04的随机数-->
		<div v-if="type === 1">
			type的值为1
		</div>
		<div v-else-if-"type === 2">
			type的值为2
		</div>
		<div v-else-if="type === 3">
			type的值为3
		</div>
		<div v-else- if="type === 4">
			type的值为4
		</div>
		<div v-else>
			Not 1/2/3/4 is 0
		</div>
	</div>
	<script src="https://unpkg. com/vue/dist/vue.min. js"></script>
	<script>
		const Vm = new Vue({
			el: '#app',
			data: {
				type: Math. floor (Math. random() * 5)
			}
		});
	</script>
</body>

注:v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面,否则它将不会被识别。
类似于 v-else,v-else-if 也必须紧跟在带 v-if 或者 v-else-if 的元素之后。
当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级。

在 元素上使用 v-if 条件渲染分组

因为 v-if 是一个指令,所以必须将它添加到一个元素上。但是如果想切换多个元素呢?此时可以把一个 元素当做不可见的包裹元素,并在上面使用 v-if。最终的渲染结果将不包含 元素。

<template v-if="ok">
  <h1>Title</h1>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</template>
用 key 管理可复用的元素

Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。这么做除了使 Vue 变得非常快之外,还有其它一些好处。例如,如果你允许用户在不同的登录方式之间切换:

v-show

另一个用于根据条件展示元素的选项是 v-show 指令。用法大致一样:
<h1 v-show="ok">Hello!</h1>
不同的是带有 v-show 的元素始终会被渲染并保留在 DOM 中。v-show 只是简单地切换元素的 CSS 属性 display。

注意,v-show 不支持 元素,也不支持 v-else。

v-if 与 v-show

v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。

v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。

相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。

一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。

列表渲染

我们可以用 v-for 指令基于一个数组来渲染一个列表。v-for 指令需要使用 item in items 形式的特殊语法,其中 items 是源数据数组,而 item 则是被迭代的数组元素的别名。

<body>
	 <div id="app">
		 <p v-for="item in items">
		 	my name is {{ item.name }}҅I'm {{ item.age }} years old.
		 </p>
	 </div>
	 <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
	 <script>
		 const vm = new Vue({
			 el: '#app',
			 data: {
				 items: [
					 {'name' : 'xiejie','age' : 18},
					 {'name' : 'yajing','age' : 20},
					 {'name' : 'xizhi','age' : 2}
				 ]
			 }
		 });
	 </script>
</body>

在 v-for 块中,我们可以访问所有父作用域的属性。v-for 还支持一个可选的第二个参数,即当前项的索引。

<ul id="example-2">
  <li v-for="(item, index) in items">
    {{ parentMessage }} - {{ index }} - {{ item.message }}
  </li>
</ul>

你也可以用 of 替代 in 作为分隔符,因为它更接近 JavaScript 迭代器的语法:
<div v-for="item of items"></div>

也可以用 v-for 来遍历一个对象的属性。

<!--1个参数为值,第2个参数为键,第3个参数为索引-->
<li v-for="(value, key, index) in stu">{{ index+1 }}. {{ key }} :{{ value }}</li>

维护状态

当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。这个类似 Vue 1.x 的 track-by="$index"。

这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出。

为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性:

<div v-for="item in items" v-bind:key="item.id">
  <!-- 内容 -->
</div>

建议尽可能在使用 v-for 时提供 key attribute,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。

因为它是 Vue 识别节点的一个通用机制,key 并不仅与 v-for 特别关联。后面我们将在指南中看到,它还具有其它用途。

不要使用对象或数组之类的非基本类型值作为 v-for 的 key。请用字符串或数值类型的值。

数组更新检测

当数组里面的数据发生更新时,Vue会检测到其更新,然后自动重新渲染视图。更新数组的方法
可以分为2大类:变异方法和非变异方法。

变异方法

所谓变异方法,是指在调用了该方法后会改变原本的数组。
Vue包含-组观察数组的变异方法,它们将会触发视图更新。
具体包含以下方法:
●push: 接收任意数量的参数,把它们逐个添加到数组末尾,并返回修改后数组的长度。
●pop:从数组末尾移除最后-项,减少数组的length值,然后返回移除的项。
●shift: 移除数组中的第一个项并返回该项,同时数组的长度减1。
●unshift: 在数组前端添加任意个项并返回新数组长度。
●splice:删除原数组的一部分成员,并可以在被删除的位置添加入新的数组成员。
●sort:调用每个数组项的toString方法,然后比较得到的字符串排序,返回经过排序之后的数组。
●reverse: 用于反转数组的顺序,返回经过排序之后的数组。

非变异方法

除了上面所列举的变异方法以外,JavaScript 中也存在不会改变原来数组的非变异方法。这个时候,我们可以使用新数组来替换旧数组。
常见的非变异方法如下:
●concat: 先创建当前数组的副本,然后将接收到的参数添加到该副本的末尾,最后返回新构
建的数组。
●slice: 基于当前数组中一个或多个项创建一个新数组,接受一个或两个参数,即要返回项的
起始和结束位置,最后返回新数组。
●map:对数组的每一项运行给定函数,返回每次函数调用的结果组成的数组。
●filter: 对数组中的每一 项运行给定函数,该函数会返回true的项组成的数组。

注意事项

由于 JavaScript 的限制,Vue 不能检测以下数组的变动:

当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue
当你修改数组的长度时,例如:vm.items.length = newLength

如果要设置数组某- -个具体的项目,可以使用Vue实例的set方法。而如果要改变数组的长度,可以使用splice 来进行替代。

显示过滤/排序后的结果

有时,我们想要显示一个数组经过过滤或排序后的版本,而不实际改变或重置原始数据。在这种情况下,可以创建一个计算属性,来返回过滤或排序后的数组。

例如:

<li v-for="n in evenNumbers">{{ n }}</li>
data: {
  numbers: [ 1, 2, 3, 4, 5 ]
},
computed: {
  evenNumbers: function () {
    return this.numbers.filter(function (number) {
      return number % 2 === 0
    })
  }
}

在计算属性不适用的情况下 (例如,在嵌套 v-for 循环中) 你可以使用一个方法:

<li v-for="n in even(numbers)">{{ n }}</li>
data: {
  numbers: [ 1, 2, 3, 4, 5 ]
},
methods: {
  even: function (numbers) {
    return numbers.filter(function (number) {
      return number % 2 === 0
    })
  }
}

事件处理

绑定事件

有两种方法

<button v-on:click="say('hi')">Say hi</button>
<button @click="say('hi')">Say hi</button>

修饰符

.stop: 阻止冒泡。
.prevent: 阻止默认事件。
.capture: 使用事件捕获模式。
.self: 只在当前元素本身触发。
.once: 只触发一次。
.passive: 默认行为将会立即触发。

<!--阻止单击事件继续传播-- ->
<a v-on:click. stop="doThis"></a>
<!--提交事件不再重载页面
<form v-on: submit. prevent="onSubmit"></ form>
修饰符可以串联-->
<a v-on:click. stop. prevent="doThat"></a>
<!--只有修饰符
<form v-on: submit. prevent></ form>
<!--添加事件监听器时使用事件捕获模式-->
<!--即元素自身触发的事件先在此处理,然后才交由内部元素进行处理-->
<div v-on:click. capture="doThis">...</div>
<!--只当在event. target 是当前元素自身时触发处理函数-->
<!--即事件不是从内部元素触发的-- >
<div v-on:click. self="doThat">... </div>
<!-- 点击事件将只会触发- --->
<a v-on:click. once="doThis"></a>
<!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 -->
<!-- 而不会等待 `onScroll` 完成  -->
<!-- 这其中包含 `event.preventDefault()` 的情况 -->
<div v-on:scroll.passive="onScroll">...</div>

注意:使用修饰符时,顺序很重要,相应的代码会以同样的顺序产生。
因此,用@click. prevent.self会阻止所有的点击,而@click. self.prevent只会阻止元素上的点击。

按键修饰符

<!--鼠标修饰符-- >
.left左键
.right右键
.middle滚轮
<!--键值修饰符-- >
<!-- 只有在keyCode 是13时调用vm. submit() - ->
<input v-on: keyup. 13-="submit">
<!--记住所有的keyCode 比较困难,所以Vue 为最常用的按键提供了别名-- ->
.enter回车
.tab 制表键
.delete (捕获“删除”和“退格”键)
.esc返回
.space 空格
.up上
. down 下
.left左
.right右
<!--修饰键-->
.ctrl
.alt
. shift
. meta
<!-- Alt+C-->
<input @keyup. alt.67="clear*">
<!-- Ctrl + Click -->
<div @click. ctrl="doSomething">Do something</div>

表单输入绑定

可以用 v-model 指令在表单 、 及 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但 v-model 本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。

v-model 会忽略所有表单元素的 value、checked、selected 特性的初始值而总是将 Vue 实例的数据作为数据来源。你应该通过 JavaScript 在组件的 data 选项中声明初始值。

v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:

text 和 textarea 元素使用 value 属性和 input 事件;
checkbox 和 radio 使用 checked 属性和 change 事件;
select 字段将 value 作为 prop 并将 change 作为事件。

对于需要使用输入法 (如中文、日文、韩文等) 的语言,你会发现 v-model 不会在输入法组合文字过程中得到更新。如果你也想处理这个过程,请使用 input 事件。

修饰符

.lazy
在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步 (除了上述输入法组合文字时)。你可以添加 lazy 修饰符,从而转变为使用 change 事件进行同步:

<!-- 在“change”时而非“input”时更新 --> <input v-model.lazy="msg" >
.number
如果想自动将用户的输入值转为数值类型,可以给 v-model 添加 number 修饰符:

<input v-model.number="age" type="number">
这通常很有用,因为即使在 type=“number” 时,HTML 输入元素的值也总会返回字符串。如果这个值无法被 parseFloat() 解析,则会返回原始的值。

.trim
如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符:
<input v-model.trim="msg">

组件

组件化的概念

Web中的组件其实就是页面组成的一部分,好比是电脑中的每一一个元件(如硬盘、键盘、鼠标),它是一个具有独立的逻辑和功能或界面,同时又能根据规定的接口规则进行相互融合,变成一个完整的应用。一个页面正是由一个个类似这样的部分组成的,比如导航、列表、弹窗、下拉菜单等。页面只不过是这些组件的容器,组件自由组合形成功能完善的界面,当不需要某个组件,或者想要替换某个组件时,可以随时进行替换和删除,而不影响整个应用的运行。

组件化的特性

高内聚性,组件功能必须是完整的,如我要实现下拉菜单功能,那在下拉菜单这个组件中,就把下拉菜单所需要的所有功能全部实现。
低耦合度,通俗点说,代码独立不会和项目中的其他代码发生冲突。在实际工程中,我们经常会涉及到团队协作,传统按照业务线去编写代码的方式,就很容易相互冲突,所以运用组件化方式就可大大避免这种冲突的存在,每一个组件都有子集清晰的职责,完整的功能,较低的耦合便于单元测试和重复利用。

组件化的优点

提高开发效率
方便重复使用
简化调试步骤
提升整个项目的可维护性
便于协同开发

全局注册

Vue.component(组件名, { /* … */ });

局部注册

new Vue({
 el: 挂载的对象,
 components: {
 'component-a': ComponentA,
 'component-b': ComponentB
 }
})

组件的使用

<body>
 <div id="app1">
 <test></test>
 </div>
 <div id="app2">
 <test></test>
 </div>
 <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
 <script>

 Vue.component('test', {
 // 模板
 template: `
 <div>
 <h1>{{name}}</h1>
 <ul>
 <li>apple</li>
 <li>pear</li>
 <li>banana</li>
 </ul>
<button @click="changeName">change name</button>
 </div>
 `,
 // හഝ
 data: function () {
 return {
 name: 'xiejie'
 }
 },
 //方法
 methods: {
 changeName: function () {
 this.name = 'yajing'
 }
 }
 });
 new Vue({
 el: '#app1'
 });
 new Vue({
 el: '#app2'
 });
 </script>
</body>

Props

作用:主要用于父组件向子组件传递值。
如果我们想要向子组件传递数字、布尔值、数组、对象,需要使用v-bind指令,否则传递过去的只是单纯的字符串。

单向数据流

在Vue中,所有的prop都使得其父子prop之间形成了一-个单向下行绑定,父级prop的更新会向下流动到子组件中,但是反过来则不行。

Prop 验证

我们可以为组件的 prop 指定验证要求,例如你知道的这些类型。如果有一个需求没有被满足,则 Vue 会在浏览器控制台中警告你。这在开发一个会被别人用到的组件时尤其有帮助。

为了定制 prop 的验证方式,你可以为 props 中的值提供一个带有验证需求的对象,而不是一个字符串数组。例如:

Vue.component('my-component', {
  props: {
    // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
    propA: Number,
    // 多个可能的类型
    propB: [String, Number],
    // 必填的字符串
    propC: {
      type: String,
      required: true
    },
    // 带有默认值的数字
    propD: {
      type: Number,
      default: 100
    },
    // 带有默认值的对象
    propE: {
      type: Object,
      // 对象或数组默认值必须从一个工厂函数获取
      default: function () {
        return { message: 'hello' }
      }
    },
    // 自定义验证函数
    propF: {
      validator: function (value) {
        // 这个值必须匹配下列字符串中的一个
        return ['success', 'warning', 'danger'].indexOf(value) !== -1
      }
    }
  }
})

当 prop 验证失败的时候,(开发环境构建版本的) Vue 将会产生一个控制台的警告。

注意那些 prop 会在一个组件实例创建之前进行验证,所以实例的属性 (如 data、computed 等) 在 default 或 validator 函数中是不可用的。

组件通信

自定义事件

<body>
	<div id="app">
		<parent></parent>
	</div>
<script src="./vue.js"></script>
<script>
	//父组件
	//父组件中一-旦触发increment 事件,会触发inc rementTotal事件
	Vue . component( 'parent', {
		template:`
			<div>
				<p>{{total}}</p>
				<child @increment=" inc rementTotal"></child>
			</div>`
		data() {
			return {
				'total': 0
			}
		},
		methods: {
			// value为从子组件传递过来的值
			inc rementTotal(value) {
				this. total = value;
			}
		}
	});
	//在子组件中修改counter 的值,每次修改都会触发父组件的increment 事件
	//触发父组件事件时,还会将counter 数据传递给父组件
	Vue . component('child', {
		template:`
			<div>
				<button @click="addValue">+1</ button>
				<button @click="minusValue">-1</button>
			</div>`
		data() {
			return {
				counter: e
			}
		},
		methods: {
			addValue() {
				this. counter++;
				this. $emit(' increment'this. counter); 
			},
			minusValue() {
				this. counter--;
				this. $emit( ' increment'this. counter);
			}
		}});
	 new Vue({
		 el: '#app'
	 });
	</script>
</body>

使用v-model

<body>
	<div id='app '>
		<p>总数: {{ total }}</p>
		<com v-model='total'></com>
	</div>
<script src="./vue.js"></script>
<script>
	//组件中每次点击会触发eventHandle 事件
	// eventHandle事件会触发父组件的input 事件
	//但是在父组件中并没有书写@input 而是采用了v-model
	Vue . component( 'com' {
		template:`
			<button @click=' eventHandle'>+1</button>`
		data: function () {
			return {
				counter: 0
			}
		},
		methods: {
			eventHandle: function () {
				this . counter++;
				this . $emit( 'input', this. counter);
			}
		});
		const app = new Vue({
			el: '#app',
			 data: {
				 total: 0
			 },
		 });
	 </script>
</body>

非父子组件之间通信

即创建一个中间商来传递数据

<body>
	<div id=" app">
		<com-1></com-1>
		<com-2></com-2>
	</div>
<script src=" ./vue.js"></script>
<script>
	const bus = new Vue(); //中间商
	Vue.component('com-1', {
		template:`
			<div>
				<p @click='test1'>这是组件1</ p>
			</div>`
		methods: {
			test1() {
			//中间商触发test 事件,并传递数据
			bus. $emit('test', '这是来自组件1的数据');
		}
	});
	Vue.component('com-2', {
		template:`
			<div>
				<p>这是组件2,当前数据为: {{ name }}</p>
			</div>`
		data: function () {
			return {
				name: 'xiejie'
			}
		},
		mounted() {
			//如果使用一般的函数,this 的指向为全局对象
			//所以使用箭头函数来指向当前的组件
			//中间商监听test事件并将接收到的数据赋值给data 数据
			bus. $on('test', (value) => {
				this.name = value;
			})
		},
	});
	new Vue({
		el: ' #app'
	});
</script>
</body>

父链子链

在子组件中,用this.$parent能直接访问该组件的父实例或组件。
父组件也能用this. $children访问它所有的子组件。注意要加索引
而且可以递归向上或向下无限访问,直到根实例或最内层的组件。

子组件索引

当子组件较多时,通过this.$children来-个-个遍历出我们需要的一个组件实例是比较困难
的,尤其是组件动态渲染时,它们的序列是不固定的。
Vue提供了子组件索引的方法,用特殊的属性ref来为子组件指定-个索引名称。

<body>
	<div id='app'>
		<p>当前数据为: {{ name }}</p>
		<button @click= 'getComValue'>获取子组件的数据</button>
		<!--为每个子组件设置ref属性,相当于给了一-个别名-->
		<com1 ref='c1'></ coml>
		<com2 ref='c2'></ com2>
	</div>
<script src="./vue.js"></script>
<script>
	//组件1
	Vue. component( 'com1', {
		template:`
			<p>{{ message }}</p>`
		data: function () {
			return {
				message: ' 这是子组件1的数据'
			}
		}
	});
	//组件2
	Vue . component( 'com2', {
		template:`
			<p>{{ message }}</p>`
		data: function () {
			return {
				message: '这是子 组件2的数据'
			}
		}
	});
	const app = new Vue({
		el: ' #app',
		data:{
			name:'this is a test'
		}
		methods: {
			getComValue() {
				//直接通过(this. $refs.组件别名.数据)来获取组件的数据信息
				this.name = this.$refs.c1.message + this.$refs. c2. message;
			}
		}
	});
</script>
</ body>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值