一套vue详解! vue.js目前最火的一个前端框架 (持续更新)....

一、vue官方脚手架

1.初识vue

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

一个使用 vue 开发的简单程序的例子如下:

<template> 
<div> {
    
    {
    
    msg}} </div> 
</template>
 <script> 
 export default {
    
    
  data(){
    
    
   return {
    
    
   msg: 'Hello Vue!'
   }
  }
} 
 </scrip>

最终页面的效果如下:
在这里插入图片描述

2.使用vue的方式(2种)

正如前面我们写的例子所示,大家看到了 vue 的写法跟我们传统的 html css js 不太一样,即使长
的很像。但是,把上述代码无论是放在 html 文件,或者是 js 文件中,都是无法运行的。因此,我们首
先要了解如何去使用 vue 。

大体上呢,我们可以分为两种方式,一种是直接 script 引入,另一种是基于 vue 中的单文件组件
的方式。

1、 script 直接引入(不推荐)
在你的 html 文件中加入如下代码:

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"> </script>

意思很明显,就是把 vue 当作一个第三方库来使用,通过 script 标签加载该文件,此时给我
们的注册了一个全局变量 Vue ,接下来就可以通过 Vue 来进行页面开发了。当然这种方式,我
们写的代码还是需要完全符合 html css js 的语法的,也就是说上述的代码不能使用。我们
如果还是要实现刚才的界面,那么就需要编写如下代码

<!--index.html--> <!DOCTYPE html> 
<html lang="zh-CN"> 
<head> 
<title>vue-demo</title>
 <meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"> 
</head> 
  <body> 
  <div id="app"> {
    
    {
    
    msg}} </div> 
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"> </script> 
  <script> new Vue({
    
     
  el: '#app',
   data: {
    
    
    msg: 'Hello Vue!' 
    }
     }) 
  </script> 
  </body> 
  </html>

在使用vue开发的时候,一般是不会使用这种方式,因为该方式很难让vue的组件化方式
得到良好的应用,所以这种方式,仅做了解即可,基于vue单文件组件的开发方式才是正 确的使用方式

2、 基于 vue 的单文件组件(推荐)

最开始我们写的那段代码和 html js 很像的代码,我们已经知道它不应该放在 html 文件也不
应该放在 js 文件中。那么它 应该放在什么类型的文件中呢?答案是 .vue 文件中。
后缀为 .vue 的文件格式是 vue 框架独创的文件格式,目的是更加方便快捷的编写 vue 组件(关
于组件我们在以后会详细解释,现在你只需要明白一个组件代表一段视图,而一段视图又包含
了 html css js 三部分的代码)。那么, vue 格式的规则也很简单分别在 、 、 这三个标签中编写对应的 html js css 代码即可。当然,在这中类型的文件中可以直接使用 vue 相关的功能。

<template> 
<!--编写视图对应的html结构--> 
</template> 
<script>
 // 编写视图所对应的交互(js代码)
  </script> 
<style>
 /*编写视图所对应的样式(css代码)*/ 
 </style>

注意, .vue 格式的文件是不可以直接被加载运行的,想要执行vue文件,并得到最终的
结果,我们需要对vue文件进行编译。那么如何对vue进行编译就涉及到了前端工程化方
面的知识了,前端工程化对nodejs有着很高的要求,但是好在有很多成熟且免费的工具
让我们使用,即使不掌握nodejs照样可以使用,但是如果想要深入理解前端工程化,那
么还是建议学好nodejs

3.搭建vue开发环境

要运行vue程序,需要相应的开发运行环境,如何搭建vue开发环境也是一门很重要的知识。在这里
有必要先简单的提一下vue的版本以及发展历史。

vue的作者是尤雨溪,最初vue完全是他的一个个人项目。时至今日,已成为全世界三大前端框架之
一,github 上拥有 15 万 Star 领先于 React 和 Angular,在国内更是首选。

4.vue的重要版本

2013年,在 Google 工作的尤雨溪,受到 Angular 的启发,开发出了一款轻量框架,最初命名为
Seed 。

2013年12月,更名为 Vue,图标颜色是代表勃勃生机的绿色,版本号是 0.6.0。

2014.01.24,Vue 正式对外发布,版本号是 0.8.0。

2014.02.25,0.9.0 发布,有了自己的代号:Animatrix,此后,重要的版本都会有自己的代号。

2015.06.13,0.12.0,代号Dragon Ball,Laravel 社区(一款流行的 PHP 框架的社区)首次使用
Vue,Vue 在 JS 社区也打响了知名度。

2015.10.26,1.0.0 Evangelion 是 Vue 历史上的第一个里程碑。同年,vue-router、vuex、vue-cli
相继发布,标志着 Vue从一个视图层库发展为一个渐进式框架。

2016.10.01,2.0.0 是第二个重要的里程碑,它吸收了 React 的虚拟 Dom 方案,还支持服务端渲
染。自从Vue 2.0 发布之后,Vue 就成了前端领域的热门话题。

2019.02.05,Vue 发布了 2.6.0 ,这是一个承前启后的版本,在它之后,将推出 3.0.0。

2019.12.05,在万众期待中,尤雨溪公布了 Vue 3 源代码,目前 Vue 3 处于 Alpha 版本。

目前我们主要使用的是vue2.x的版本

在1.0版本之前,vue仅仅提供了构建页面视图的核心逻辑,并没有考虑到工程化方面的改进。但
是,随之前端不断的发展,工程化迫在眉睫。但是好在此时市面上已经有了 babel webpack gulp rollup … 等构建工具,可以对vue程序进行构建,从而便于进行vue开发,但是依然有一定的门槛。

为了降低使用vue的门槛,在2015.10 又发布了 vue-cli ,一个零配置开箱即用的 vue 脚手架工
具。之后又对该工具进行了整理和升级,目前新的工具根据功能划分了成了以下几个包:

@vue/cli 
@vue/cli-service 
@vue/cli-service-global

5.使用@vue/cli进行vue开发环境的构建

Vue CLI 是一个基于 Vue.js 进行快速开发的完整系统,提供:

  • 通过 @vue/cli 实现的交互式的项目脚手架。
  • 通过 @vue/cli + @vue/cli-service-global 实现的零配置原型开发。
  • 一个运行时依赖 ( @vue/cli-service ),该依赖:
    • 可升级;
    • 基于 webpack 构建,并带有合理的默认配置;
    • 可以通过项目内的配置文件进行配置;
    • 可以通过插件进行扩展。
  • 一个丰富的官方插件集合,集成了前端生态中最好的工具。
  • 一套完全图形化的创建和管理 Vue.js 项目的用户界面。

即可平稳衔接,这样你可以专注在撰写应用上,而不必花好几天去纠结配置的问题。与此同时,它也
为每个工具提供了调整配置的灵活性,无需 eject。

关于 @vue/cli 的相关功能有很多,目前对于初学者的我们只需要掌握最基本最简单的用法即
可。

  1. 安装
npm install @vue/cli @vue/cli-service-global -g

全局安装以上两个包,此时在我们的pc系统中注入了这几个命令 vue serve 、 vue build 、 vue create 、 vue ui ,可以分别查看版本
在这里插入图片描述
2. 使用 vue serve app.vue 对 vue 文件进行编译并显示。
3. 使用 vue build app.vue 对 vue 文件进行构建。
4. 使用 vue create vue-app 创建一个 vue 项目,其中 vue-app 为项目的名字
在这里插入图片描述
可查看创建好的项目,在 src/main.js 文件中带入如下:

import Vue from 'vue' // 引入Vue类 
import App from './App.vue' // 引入App单文件组件 Vue.config.productionTip = false // 关闭产品提示 
new Vue({
    
     // 实例化Vue 
render: h => h(App), // 该项表示组件被渲染 
}).$mount('#app') // 挂载于页面中的 #app标签
  1. 使用 vue ui 可以展示一个界面,可以通过界面去管理所有的vue项目(自行研究)

我们本次对vue的学习将全部基于 @vue/cli 提供的开发环境下进行学习。

6.vue基础知识

首先,要明确vue中是通过一个单文件组件来描述视图的,而完整的视图又是由 html css js 组成
的,因此vue的单文件组件被设计成了由三部分组成,这些是在前面已经接触过了的。在这里我们还要
引入三个概念:数据(data),方法(methods),指令(order)。先来看看这三个概念出现在模板的
什么位置。

<template>
<div>
<!--这里的@还有v-html都属于指令-->
<span @click="disCount()">-</span>
<span v-html="count"></span>
<span @click="addCount()">+</span>
</div>
</template>
<script>
export default {
    
    
data(){
    
     // data用于表示该段视图中的所有数据
return {
    
    
count: 0
}
},
methods: {
    
     // methods表示视图中涉及到的方法
addCount(){
    
    
this.count += 1
}disCount(){
    
    
this.count -= 1
}
}
}
</script>

1.数据(data)

在编写视图的时候,肯定会产生一定量的数据,比如控制开关的布尔值,展示菜单的数组等等,这
些都是与视图相关的数据,vue中定义了data用于存储我们所用到的视图数据,请记住data必须是函
数。

<scripts>
export default {
    
    
data(){
    
    
return {
    
    
// 这里写数据
}
}
}
</scripts>

2.方法(methods)

除了视图数据之外,我们还需要写很多的逻辑,比如点击事件的逻辑,根据不同条件进行展示的逻
辑等等,这些与视图相关的逻辑,我们可以拆成一个个的方法写在methods中。

<scripts>
export default {
    
    
methods:{
    
    
// 这里写方法
}
}
</scripts>

3.指令(order)

大家应该也看到了,vue中的指令是用于模板中的html标签的。在指令的帮助下,我们可以在视图
中灵活的使用我们定义的数据和方法。vue中内置了多个指令可以帮助我们实现各种视图的交互逻辑。
有的同学有疑问了,我的逻辑明明是写在methods中的,为什么还需要指令,其实指令在这里的作用是
把methos和data中的逻辑和数据关联到模板中。比如,addCount里边的逻辑需要在点击+之后才能触
发,这里我们就需要 @ 这个指令帮我们进行绑定事件。

我们可以这样理解指令:模板中写的都是标签,我们想要在模板中嵌入数据和逻辑。但是数据
和逻辑又是存在与js环境中的。那么指令就可以帮我们在模板中构建出js环境以便于我们嵌入数据
和逻辑。因此,指令的格式是key:value格式。key需要我们稍微记忆以下,但是value就是js表达
式。一般来说js中合法的都可以写在指令的值上。

那么vue中都内置了哪些指令呢?

  1. v-html 绑定js环境中的一些值到对应标签的innerHTML
  2. v-text 跟 v-html 基本是一样的,但是它会把标签字符串原样输出,简写为{ {}}
    在这里插入图片描述
  3. v-bind 把对应标签的对应属性(attribute)跟js环境中的数据进行绑定,可以简写成 :
<div v-bind:class="active">active</div>
<!--简写-->
<div :class="active">active</div>
  1. v-for 循环结构
<div v-for="(item,key) in shopData" class="panel panel-default">

v-for 循环的是它的载体及其所有后代元素
5. v-if v-else v-show

<div v-if="isShow" :style="[oCss, {backgroundColor: 'red'}]"></div>
<div v-else :style="[oCss, {backgroundColor: 'blue'}]"></div>

v-if 根据其值(布尔)控制载体的加载与卸载, v-else 配合 v-if
v-show 和 v-if 机制一样,但是 v-show 是通过 display:none 的方式来控制元素显示隐藏

6.v-model 一般用于 input 标签,作用是绑定 input 的value值,但是该绑定是双向的。

<input :value="inputVal" type="text" />
<input v-model="inputVal" type="text" />
  1. v-on 用于给对应的标签绑定事件,可以简写成 @
<p v-on:click="inputVal = inputVal.split('').reverse().join('')">
{
    
    {
    
    inputVal}}</p>
<p @click="inputVal = inputVal.split('').reverse().join('')">{
    
    {
    
    inputVal}}
</p>

4.todolist

通过实现一个之前写过的todolist来加强相关vue知识的理解
在这里插入图片描述

二、案例练习(自定义表单)

在这里插入图片描述
项目地址:自定义表单
这里有两个基本的知识点需要注意一下

  1. vue组件中的js和css可以通过外部引入
<style scoped src="../common/dragFormStyle.css"></style>
import {
    
     oftenList, selfList } from "../common/dragFormData.js";
export default {
    
    
data() {
    
    
return {
    
    
oftenList, // 常用项的数据
selfList, // 自定义项的数据
};
},
};
  1. 需要全局引入css
// 额外的引入css文件
import './assets/icon/iconfont.css'

要学会去打印每个组件的组件实例,每个组件在被创建并实例化后就会拥有一个组件实例,该
实例记录了对应组件的所有信息,可以打印实例查看相关信息,这样有利于我们去理解vue组件。
methods中的函数内部的this就是组件实例。
一般我们可以写下边的代码,去以方便我们打印组件实例

<template>
<button @click="watchComponentObj">查看本组件实例</button>
</template>
<script>
export default {
    
    
methods: {
    
    
watchComponentObj(){
    
    
console.log(this)
}
}
}
</script>

在编写本单元提供的案例的时候,注意应用上述的知识点和技巧。

三、vue组件

关于vue到目前为止,我们需要正式组件这个词了。组件组件叫的很顺口,到底是什么意思呢?其
实,这也是web技术发展的一个方向,就是组件化。

要讲明白组件化,我们还得从基本的网页制作开始说起,我们知道网页包含三部分,结构样式和行
为分别对应着我们的 html css javaScript 这三门语言。这没有什么不对,这样的划分也非常便于
理解,但是哪里有问题呢, html css javaScript 这三门语言的配合有问题,它们是以一个页面为
单位的。也就是说 html 是主体,然后去引入 css 和 js 。一个页面是这样的,一个页面中的某以部分,
比如一个页面中的轮播图,这一部分单独领出来的话,按照原始的方式组织的话,我们得找到跟轮播图
相关的 html css javaScript 代码,然后剥离出来之后再放到一个先的页面中(我们一般叫
demo)。下次用的时候,还得复制,还得看一下使用的页面中如何把该这个 demo 给加进去。

随着web发展的日渐成熟,这个问题就很突出了,不利于代码的复用,因为涉及到了三种不同的代
码。那么换种想法,不要再认为一个网页是界面的最小单元了,页面中的任何一段视图是界面的最小单
元。无论这个界面多小,它也包含了界面的基本三要素(结构样式和行为,即使你的这段视图现在没有
交互效果,但是你能保证将来不给这段视图添加交互效果吗?)。所以呢,我们就给它起了个名字,叫
做组件。

所以说,一个组件在页面中表示出来的是一段功能完整的视图,在代码角度上它肯定也包含了 html
css javaSciprt 这东西。好了,现在组件化思想有了。那么技术上如何实现呢?这又是一个问题。其
实目前呢,已经在推行新的组件化标准了。这也意味着,将来我们就不再是使用 link script 的方式
去组合了。不过,新标准太慢还有漫长的路要走。

但是呢,组件化这种思想很好,深入人心。大家看下边一张图,会深有体会。
在这里插入图片描述
我们可以把一个网页看成是一个大的组件,网页里边的每个视图都可以使一个小组件,小组件有可
以再进行拆分。这样对于开发来说,无疑是一个好消息,而且会方便复用。

例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类
的组件。

刚才说道标准推行比较慢,那么这么好的思想我们就不用了吗?当然不是!伟大的程序员从来没有
停止过探索不步伐(喜欢折腾)。目前,前端的三大框架(vue react angular)都以自己的方式实现了
组件化。具体背后如何实现,我们暂不深究,先学会使用,感受组件化带给我们全新的开发方式吧!

正如我们前边练习的案例(使用vue编写),对了我们管 .vue 的文件叫什么来着?单文件组件是
吧!没错我们写的那种格式就是 vue 中实现组件化的方式。仔细想想,是不是让一个组件完美的包含了
html css javaScript 这些内容。

接下来,让我们对组件有更加深入的认识吧。

1.vue组件的创建

我们使用 vue 单文件组件已经是 vue 中最普遍最常用的方式了,当然也是最推荐的。但是关于 vue
组件除了 单文件组件 的方式之外,还有被的方式,虽然不是特别常用,但是可以加深我们对 vue 组件的
理解,所以非常有学习的必要。

记住一点,组件的形式如何改变,它一定会用自己的方式去包含 html css javaScript 的代码
的。vue单文件组件的代码组织方式是非常明显的。

2.纯javaScript创建组件

也只有 javaScript 有能力去创建组件了,因为 html 在 javaScript 中可以表现为字符串, css 可
以以行内样式的形式出现,同样也可以在 javaScript 中表现为字符串,例如:

const html = '<div style="color: red;">hello world</div>'

在 vue 中用纯 javaScript 创建组件,分为两种 全局组件 和 局部组件 。它们有区别吗?当然有!只
是,暂时先不去讲解它们之间的区别,先学习这两种组件创建的方式。然后,再深入的去对比这两种方
式的区别。

  1. 全局组件
    全局组件使用 Vue.component 方法去创建
Vue.component('组件名称',组件的配置项)

示例如下:

import Vue from 'vue'
Vue.component('global-test', {
    
    
// template: '<div id="box">{
    
    {msg}}</div>',
render(h){
    
     // template和render表示的是同一个意思,但是不能共存
return h('h1', {
    
    id: 'box'}, [this.msg])
}
data() {
    
    
return {
    
    
msg: 'hello i am global-test'
}
}
})

这里我们解释以下细节,组件的配置项部分是一个对象,也就是我们单文件组件中的配置项,
是一个意思。这里多了 一个 template 或者是 render 属性,这两个属性就是提供结构的,因
为这种方式不再有 标签了。唯一多了个标签名,这个我们在前边单
文件组件的时候没用到,但是这个组件名是很有用的。在下边,学习组件组装的时候会用到
的。

  1. 局部组件
    导出一个有组件配置项的对象即可

export default {
template: ‘

{ {msg}}
’,
data() {
return {
msg: ‘i am local-test’
}
}
}

这里我们来看局部组件其实跟全局组件是一样的,配置项这些内容页都一样,但是没有组件名。

3.使用vue 单文件组件

单文件组件的形式呢,我们就不再多说了,因为已经用的很熟了,这一节就简单说说单文件组件如
何被编译的?以及为什么需要单文件组件?有个很直观的问题,大家应该看到了,就是使用纯
javaScript 创建的组件我们写标签的时候,需要写在字符串中,这是很痛苦的,尤其当结构比较多的
时候,简直不可想象。所以,就把 template 的配置项提成 标签了。这样,
我们的结构就很好写了。

所以,我们发现 vue 单文件组件是没法直接在浏览器中使用的,我们需要进行编译。这里就是为什
么我们要给 vue 单文件组件构建开发环境了的原因了。那么编译干了什么事呢?编译过程是借助了
webpack (一款打包工具,以后会学习)进行转码,把 标签中的内容有转换成
了 template 属性中的字符串。

这样,单文件组件就变成了纯 javaScript 编写的组件了,就可以被浏览器加载识别了。所以,
vue 单文件组件本质上就相当于是局部组件。只不过,它的结构写起来很方便。

4.组件的组装

我们已经掌握了创建组件的方式,然而,我们最终的目的还是要形成一个完整的页面。那么,如何
形成完整的页面呢?对!就是要把多个组件按照视图的逻辑关系组装起来。所以,这里我们要学习组件
组装的方式。

比如有两个组件分别为组件A和组件B,那么可以把B组件组装在A组件的内部,这样B组件所代表的
视图就会出现在A组件的内部,这种情况下,我们成A组件是B组件的父组件,而B组件是A组件的子组
件。实现方式如下:

组件A.vue

<template>
<div class="A">
<h1>{
    
    {
    
    title}}</h1>
<b-child></b-child>
</div>
</template>
<script>
import B from './B.vue'
export default {
    
    
data(){
    
    
return {
    
    
title: 'A'
}
},
components: {
    
    'b-child': B}
}
</script>

组件B.vue

<template>
<ul class="B">
<li v-for="(item, index) in list" :key="index">{
    
    {
    
    item.text}}</li>
</ul>
</template>
<script>
export default {
    
    
data(){
    
    
return {
    
    
list: [{
    
    text: 'a'},{
    
    text: 'b'}]
}
}
}
</script>

上述代码中的A组件是一个局部组件,前边说过,局部组件是没有组件名称的。然后,组件名称对
于我么组装组件来说是必不可少的。所以,局部组件要组装的话,我们要先给局部组件起一个名字。哪
一步呢?

<script>
import B from './B.vue' // 引入B组件
export default {
    
    
components: {
    
    'b-child': B} // 注册B组件为A组件的子组件,并给B组件绑定一个组件名为
`b-child`
}
</script>

上述步骤就是把B组件导入,注册B组件为A组件的子组件,给B组件绑定组件名称为 b-child 。此
时,只能说明B组件已经成为A组件的子组件了,但是还未在A组件中嵌入B组件。哪一步呢?

<template>
<div class="A">
<h1>{
    
    {
    
    title}}</h1>
<b-child></b-child> <!-- 在A组件中使用B组件 -->
</div>
</template>

所以,大家看到组件名称的用处了吧!它可以帮我们在组装组件的时候,在父组件中调用对应的子
组件。当然了,B组件可以作为A组件的子组件,也可以作为别的组件的子组件,只要在对应的组件内部
导入并注册就可以了。而且,子组件可以在父组件的模板中多个地方使用,这就很好的实现了我们前边
所说过的组件复用。

那么全局组件呢,它在创建的时候,就有组件名称,所以全局组件是可以直接使用的,这也就是全
局组件和局部组件的区别。

如果想把组件B组装到A组件的内部,那么要看B组件是局部组件还是全局组件,如果是全局组
件,直接B组件的组件名写在A组件模板中即可。如果B组件是局部组件,那么需要先在A组件中导
入B组件,然后把B组件注册到A组件的components配置项中,并给B组件分配一个组件名,然后
把分配的组件名写入A组件的模板中。

请完成下图中红色线框的组件并组装成一个整体(线上参考地址为 https://www.jd.com/

在这里插入图片描述
在这里插入图片描述

5.动态组件

vue 给我们提供了一个动态组件的功能。首先,说说动态组件解决了个啥问题。我们在编写界面的
时候,经常可能会碰到类似于这样的问题,有一个选项卡,但是每个选项对应的展示内容都极为不相
同。那么,这样的情况我们只能给每个内容写一个单独的组件。但是,这些组件我们如何切换呢?大家
很容易可以去想到使用 v-if 或者 v-show 但是它只能切换两个组件,当然多个也能切换,但是相对来说
写起来很麻烦。

基于上述问题, vue 提供了动态组件的功能。好,已经明白了动态组件解决的问题类型了,那么接
下来看看动态组件如何使用?

vue 给我们提供了一个组件名称为 components 的组件,该组件是一个全局组件,我们不需要关
心,该组件是如何被创建出来的,只要明白如何使用该组件即可。因为是全局组件,我们可以在任何组
件布局直接使用该组件。

<components></components>

该组件的 is 属性接受一个组件名,那么对应的组件就会被渲染在这个位置。

<!--A.vue-->
<template>
<div>
<h1>hello world!</h1>
<components is="DragTest"></components>
</div>
</template>
<script>
import DragTest from './dragTest.vue'
export default {
    
    
components: {
    
    
'DragTest':Dragtest
}
}
</script>

上述组件意味着,组件名为 DragTest 的组件会被渲染在 A.vue 组件的内部。
实现一个导航切换的功能(练习一下动态组件吧)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

四、组件通信

组件既然可以互相的组装,那么意味着组件之间存在着父子这样的关系,而且,我们也知道每一个
组件都有自己的数据,且数据是互相独立不影响的。但是在实际编程的时候,我们需要多个组件之间的
数据进行通信。

其实呢,组件之间的通信方式主要有三种:

  1. 父组件向子组件通信
  2. 子组件向父组件通信
  3. 跨级组件的通信(后边讲)
    接下来,让我们来学习一下组件之间是如何通信的。

1.父组件向子组件通信

父组件向子组件通信是最常见的一种通信,首先呢组件之间一定要形成父子关系。然后一定要想明
白这个之间的交互过程,所谓父子通信,就是父组件的消息发送给子组件。那么,父组件在这个过程中
扮演的是发送消息者,子组件在这个过程中扮演的是接受消息者。所以,我们需要学习的是父组件如何
把消息发出去,而子组件如何接受消息。

  1. 父组件传递信息
<template>
<div>
<h1>{
    
    {
    
    title}}</h1>
<!--以key-value的形式传递-->
<sub-title :subTitle="subTitle"></sub-title>
</div>
</template>

这里呢还有一种简便方法,就是假设有一个对象中的数据需要传递的话,我们可以使用 vbind=“obj” 来简写。举个例子:
现在有一个对象

const obj = {
    
    name: 'admin', age: 12, sex: true}

想要把该对象中的数据都以 key-value 的形式传递,那么一个一个写的话是很麻烦的,看下实
际应该如何写

<template>
<div>
<h1>{
    
    {
    
    title}}</h1>
<sub-title v-bind="obj"></sub-title>
</div>
</template>
  1. 子组件接受消息
<script>
import Vue from 'vue'
// 子组件
Vue.Component('sub-title', {
    
    
data(){
    
    return {
    
    }},
props: ['subTitle'], // 放的是父组件定义的key值
template: '<p>{
    
    {subTitle}}</p>' // 在子组件中就可以使用接受的信息了。
})
</script>

我们发现了子组件接受的时候是在配置项中添加了 props 属性,该属性的值是一个数组。在数
组中,我们放入传递消息的 key 即可(因为消息是采用 key-value 的形式传递的)。设计成数
组的形式,以为着我们可以接受多个数据,那么父组件也可以传递多个数据。

当然 props 的值除了可以是一个数组外,还可以是一个对象,如果设置为对象的话,那么我们
对于接受的消息就可以添加更多的设置,这些设置如下:

key: {
    
     // 接受的消息的key
type: String/Number/Boolean/Array ... // 接受的消息的类型,这里的值是对应
的数据的类
required: true // 该消息必传
default: value / () => value // 该消息的默认值
validator: (value) => condation... // 自定义该消息的验证条件
}

示例:

<script>
export default {
    
    
props: {
    
    
subTitle: {
    
    
type: String,
required: false,
default(){
    
    
return '请输入副标题'
}
}
}
}
</script>

这里还要提一下单项数据流,所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级
prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父级组件的状
态,从而导致你的应用的数据流向难以理解。

额外的,每次父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不
应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。

2.子组件向父组件通信

同样的子组件向父组件中通信的话,子组件就是消息发送者,父组件就是消息接受者。所以,我们
要学习子组件如何发送消息,父组件如何接受消息。

  1. 由父组件给子组件注册一个事件(目的是为了接收)

在这里插入图片描述

3.拖拽组件的组装

父子通信可以让我们复用逻辑,比如实现一个可以拖拽的组件,将其他组件传入到该组件中,从而
实现任意组件都可以拖拽的功能,以实现复用拖拽逻辑代码。
代码如下:

<template>
<div
class="drag-app"
:style="{ left: left + 'px', top: top + 'px' }"
@mousedown="mouseDown"
v-html="NewComponent"
>
</div>
</template>
<script>
export default {
    
    
data() {
    
    
return {
    
    
left: 0,
top: 0,
};
},
props: ['NewComponent']
methods: {
    
    
mouseDown(ev) {
    
    
const disx = ev.clientX - ev.target.offsetLeft;
const disy = ev.clientY - ev.target.offsetTop;
document.onmousemove = (ev) => {
    
    
const x = ev.clientX - disx;
const y = ev.clientY - disy;
this.left = x;
this.top = y;
};
document.onmouseup = () => {
    
    
document.onmousemove = null;
document.onmouseup = null;
};
},
}
};
</script>
<style scoped>
.drag-app {
    
    
position: absolute;
left: 0;
top: 0;
min-width: 30px;
min-height: 30px;
background-color: red;
}
</style>

封装一个通用的弹窗

3.获取真实的dom节点

可能你已经发现了,使用了vue之后,基本上就不再操作真实的dom节点了,但是有些时候dom节
点还是很有用的(虽然绝大多数情况下都用不到真实dom节点)。那么在vue中如何获取真实dom节点
呢?
实现方式如下:

![本质行也就是在标签上添加 ref 属性,然后在组件实例中的 $refs 中可以通过 ref 属性的值取到该
标签的真实的 dom 节点

  1. 尽量不使用dom节点
  2. 不得不使用的时候,可以使用vue预留的接口
  3. 在需要获取的dom节点上添加ref=key属性
  4. 通过this.$refs.key去获取dom节点](https://img-blog.csdnimg.cn/119551e73bf04ed3be876e5369c9f756.png#pic_center)

4.实现自定义滚动条

自定义滚动的效果如下:
在这里插入图片描述
要求:

  1. 对滚动条进行封装,可根据参数控制是横向的还是纵向的
  2. 使滚动条可以通用

自定义滚动条的实现原理如下
在这里插入图片描述

五、组件的生命周期

1.vue生命周期

我们现在已经看到了在我么编写一个组件的时候,在配置项中,预留了一些会在特定时间执行的函
数,比如 mounted 。这些在特定时期执行的函数就是组件的生命周期。一个vue组件在实例化的时候会
经历各个阶段,每个重要的阶段都给我们预留函数,方便我们添加重要的逻辑。除了实例化之外,在组
件内的数据改变的时候也会预留一些函数。具体可参考下图
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.练习

以拆分组件的方式,完成案例,组件的拆分可参考下图
在这里插入图片描述

六、重要配置项(计算属性,监听属性,组件缓存)

前边我们学习过的配置项有 data methods components props ,除此之外能还有一些配置项非常
有用。本单元我们要再学习两个重要的配置项: 计算属性( computed ) 和 监听属性( watch )

除了学习新的配置项外,还要再学习一个内置的全局组件 <keep-alive></keep-alive> ,缓存组件。

1.计算属性

计算属性结局的问题是什么呢?计算属性可以让 data 中的数据进行一些计算从而派生得到新的数
据形式。比如 data 中有数据 sex: true ,但是我们希望显示的是 男生女生 。这个时候我们可以编写一
个表达式 sex ? ‘男生’ : ‘女生’ ,这个表达式放在哪里呢?我们可以放在模板中

{ {sex ? ‘男
生’ : ‘女生’}}
。但是,这样的话会使模板过重从而难以维护。所以我们使用计算属性
computed 。看下边的例子:

<template>
<div>
{
    
    {
    
    sexStr}}
</div>
</template>
<script>
export default {
    
    
data(){
    
    
return {
    
    
sex: true
}
},
computed: {
    
    
sexStr(){
    
    
return this.sex ? '男生' : '女生'
}
}
}
</script>

可以在多个地方使用 sexStr 的结果,并观察一下这个函数执行了多少次。总结一下 computed 的特
点:

  1. 当计算结果需要复用时候,可以使用
  2. 写法像函数,但是本质上是属性
  3. 对大量计算有优化效果
  4. 仅仅在内部依赖的data中的数据发生变化的时候,才执行

2.监听属性

大家可能已经发现了一个特别神奇的功能,就是我们放在 data 中的数据只要跟模板进行绑定了之
后,每次 data 中的数据已修改,对应的视图就会更新。那么可以想到,肯定是 vue 在我们改变 data 中
的数据的时候,去做了 dom 的更新。那么 vue 肯定是能监听 data 中的数据发生了变化的,当然这也是
vue 的核心,具体如何监听呢,这个以后我们再讲,这里 vue 把对 data 数据的监听给暴露了出来。其
实不仅仅是对 data 中数据的监听,而是所有具有响应式功能的数据监听都暴露了出来。 computed 和
props 中的数据也可以进行监听。

看一下,监听属性 watch 的用法:

<template>
<div>
{
    
    {
    
    msg}}
<button @click="reverseStr">反转字符串</button>
</div>
</template>
<script>
export default {
    
    
data(){
    
    
return {
    
    
msg: 'hell vue'
}
},
methods: {
    
    
reverseStr(){
    
    
this.msg = this.msg.split('').reverse().join('')
}
},
watch:{
    
    
'msg'(newVal, oldVal){
    
    
console.log(newVal, oldVal)
}
}
}
</script>

请运行上述组件,并点击按钮之后观察打印的结果,自行总结 watch 的用法。

3.组件缓存

组件在切换的时候,会发生组件的卸载以及重新加载,那么这个时候组件内部的状态会变成初始的
状态。如果想要避免这样的问题,那么可以使用 vue 提供的缓存组件来解决。

vue 提供了一个全局组件 ,来维护组件的状态,同时该组件还有include exclude max 等几个属性。它们的作用如下:

  • include - 字符串或正则表达式。只有名称匹配的组件会被缓存。
  • exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存。
  • max - 数字。最多可以缓存多少组件实例。
    用法示例:
<keep-alive>
<component v-bind:is="currentTabComponent"></component>
</keep-alive>

动态组件切换的时候,组件的状态将被保留下来

七、vue事件和指令修饰符

vue 中的事件还是我们熟悉的那个事件,只不过 vue 框架采用了更加巧妙的方式去添加事件。现在
先来回忆一下,事件的三要素有哪些?

  1. 事件源-承载事件的dom节点

  2. 事件类型-以字符串标识,可以自定义

  3. 事件监听器-在事件触发的时候会跟着执行的函数

先来回忆一下原生的方式如何添加事件

oDiv.onclick = function(){
    
    }
oDiv.addEventListener('click', function(){
    
    }, false)
/**
1. oDiv - 事件源
2. Click - 事件类型
3. Function 事件监听器
/

vue组件中添加事件的时候,其实也体现出了这三个方面,只不过形式不太相同

<template>
<p @click="changeSubTitle">{
    
    {
    
    subTitle}}</p>
</template>
<script>
export default {
    
    
data(){
    
    
return {
    
    subTitle: '美丽的中国'}
},
methods: {
    
    
changeSubTitle(){
    
    
this.subTitle = '完美的世界'
}
}
}
/*
1. p标签是事件源
2. click是事件类型
3. changeSubTitle事件监听器
*/
</script>

上述代码中,因为是直接把 @click 放置在模板的标签上的,所以可以直接锁定事件源而且非常准
确方便。而在 @ 后边可以直接添加事件的类型,比如说 click 。在 = 后边就可以添加事件监听器了,一
般是放在 methods 中的函数。

1.事件对象

在事件触发的时候被浏览器传递给事件监听器的一个参数,该对象记录了事件相关的所有信息

为了更好的理解vue中事件中三要素中的监听器的指向,我们用一个原生的写法来举例子

const p = document.getElementById('p')
function c(e){
    
    
alert('hello')
}
p.onclick = function(ev){
    
    
c()
}

上述代码中,函数c并不是事件监听器,那个匿名函数才是,因此匿名函数的形参ev才是事件对象,
而函数c接受的参数e并不是事件对象,接下来我们看看vue

<template>
<div>
<h1 @click="c1">标题1</h1>
<h2 @click="c2($event)">标题2</h2>
</div>
</template>
<script>
export default {
    
    
methods: {
    
    
c1(ev){
    
    
console.log(ev)
},
c2(ev){
    
    
console.log(ev)
}
}
}
</script>

上述代码中h1和h2的点击事件都会打印出对应的事件对象,如何理解呢,h1上添加的事件的事件监
听器就是函数c1,所以函数c1接受到的参数就是事件对象。而h2上添加的事件的事件监听器是一个隐形
的匿名函数,该函数会在编译的时候被添加,而c2仅仅相当于在监听器中执行的一个函数而已。而在模
板中使用 $event 可以获取事件对象,是vue组件提供的特殊能力。

2.事件修饰符

我们前边学过vue指令的形式为: 指令名:参数=value 的形式,比如: v-bind:type=“t” 其中type
为参数,或者 v-on:click=“btnClick”,其中click为参数 。其实vue中指令的完整形式如下:

指令名:参数[.修饰符1.修饰符2....修饰符n]=

在这里插入图片描述
通过上图我们可以知道,有些指令没有参数,有些指令没有修饰符,有些指令参数和修饰符都有。
关于事件的修饰符,我们可以划分这么几类:通用修饰符,键盘按键修饰符,系统修饰键,鼠标按钮修
饰符

3.通用修饰符

.stop 阻止事件传递的
.prevent 阻止事件的默认行为的
.capture 以捕获的方式添加事件
.self 跳过冒泡和捕获,只有直接作用在该事件源上的事件才会触发
.once 添加的事件仅执行一次
.passive 可以提升移动端的性能,但是不要和.prevent一起使用,否在失效

4.键盘按键修饰符

keyCode 的事件用法已经被废弃了并可能不会被最新的浏览器支持。
因此vue提供了按键修饰符,用来精确的监听被按下的按键
可以直接使用键盘码,例如:

<template>
<input v-on:keyup.13="submit">
</template>

为了在必要的情况下支持旧浏览器,Vue 提供了绝大多数常用的按键码的别名:

.enter
.tab
.delete (捕获“删除”和“退格”键)
.esc
.space (按下空格键)
.up
.down
.left
.right

你还可以通过全局 config.keyCodes 对象自定义按键修饰符别名

// 可以使用 `v-on:keyup.f1`
Vue.config.keyCodes.f1 = 112

5.系统修饰键

可以用如下修饰符来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器

.ctrl
.alt
.shift
.meta 系统键
.exact 允许你控制由精确的系统修饰符组合触发的事件,表示仅当该系统按键按下时,才触发

例如:

<template>
<!-- Alt + C -->
<input v-on:keyup.alt.67="clear">
<!-- Ctrl + Click -->
<div v-on:click.ctrl="doSomething">Do something</div>
<!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
<button v-on:click.ctrl="onClick">A</button>
<!-- 有且只有 Ctrl 被按下的时候才触发 -->
<button v-on:click.ctrl.exact="onCtrlClick">A</button>
<!-- 没有任何系统修饰符被按下的时候才触发 -->
<button v-on:click.exact="onClick">A</button>
</template>

6.鼠标按钮修饰符

这些修饰符会限制处理函数仅响应特定的鼠标按钮。

left 鼠标左键
.right 鼠标右键
.middle 鼠标中键

修饰符不再一一举例了,请自行尝试,并掌握其用法(不用全部记住,要知道,相关修饰符让我们
控制鼠标键盘的时候会更加方便,可以做出更多的交互。)

7.v-model修饰符

v-model指令也有一些修饰符,如下:

  1. .lazy
    在默认情况下, v-model 在每次 input 事件触发后将输入框的值与数据进行同步 。你可以添
    加 lazy 修饰符,从而转为在 change 事件之后进行同步:
<!-- 在“change”时而非“input”时更新 -->
<input v-model.lazy="msg">
  1. .number
    如果想自动将用户的输入值转为数值类型,可以给 v-model 添加 number 修饰符:
<input v-model.number="age" type="number">

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

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

八、8、vue过渡动画

猜你喜欢

转载自blog.csdn.net/m0_55400356/article/details/126053561