精华内容
下载资源
问答
  • 如果需要多使用同段代码,可以把它们封装成函数函数(function)就是组允许在你的代码里随时调用的语句。每个函数实际上是个短小的脚本。 如:要完成多组数和的功能。 var sum; sum = 3+2; alear(sum...
  • 构造函数、析构函数 构造函数: 1.若没提供任何构造函数,则系统会自动提供一个默认的构造函数,初始化所有成员为默认值(引用类型为空引用null,值类型为0,bool类型为...1.只能定义一个,最多运行一次,仅在第一次
  • 学习笔记整理

    万次阅读 多人点赞 2020-05-16 22:05:54
    堆:实际上就是优先队列的种数据结构,第个元素有最高的优先权 在数据结构中,有大根堆和小根堆的概念 概念:叶子节点大于(或小于)父节点 从内存分区的角度来看: 在C++中内存分为五大分区,分别是栈区,堆区...

    本文仅用于作者考研路上的学习与思考,以便日后复习,若有不对,欢迎读者指正

    操作系统

    1 堆,栈有什么区别?

    从数据结构的角度来看:

    栈:在数据结构中,是一种受限的线性表,特点是后进先出,

    堆:实际上就是优先队列的一种数据结构,第一个元素有最高的优先权

    在数据结构中,有大根堆和小根堆的概念

    概念:叶子节点大于(或小于)父节点

    从内存分区的角度来看:

    在C++中内存分为五大分区,分别是栈区,堆区,自由存储区,常量存储区,全局静态存储区

    栈的使用与回收都是系统进行的,而在C语言中使用malloc在堆中申请空间,需要手动使用free释放,在C++中使用new在自由存储区申请空间,delete释放。

    2进程和线程的区别

    进程是系统进行分配资源和内存管理的基本单位,是一段程序在某一个数据集上面的一次运算,运行时,从磁盘中加载到内存。

    线程是系统调度的最小单位,是进程的一部分。

    区别:一个进程包括多个线程,线程是进程执行的每一一个小任务,进程切换时需要切换资源和内存,而线程切换时不需要切换资源和内存,只需要切换pc指针。

    3 什么是死锁

    死锁的定义:如果一组进程中的每一个进程都在等待仅由该组进程中的其他进程才能引发事件,那么该组进程是死锁的。

    死锁的条件:
    ①互斥条件②占有和等待条件③不剥夺条件④循环等待条件

    死锁的常见表现:

    (1)多进程死锁:有A,B两个进程,进程A拥有资源1,需要请求正在被进程B占有的资源2,而进程B拥有资源2,又在请求资源1,两个进程都在等待对方释放资源后请求该资源,而相互僵持,陷入死锁。

    (2)单线程死锁:进程A拥有进程1,而它又在请求资源1,而它所请求的资源1必须等待该资源使用完毕得到释放后才可被请求,这样,就陷入了自己的死锁。

    解决死锁的方法:

    ①终止(或撤销)进程。终止系统中的一个或多个死锁进程,直至打破循环环路,使系统从死锁状态中解除出来。

    (2)抢占资源。从一个或多个进程中抢占足够数量的资源,分配给死锁进程,以打破死锁状态

    4 内存管理有哪些方法

    常见的内存管理方式有分区存储管理,页式管理,段式管理,虚拟存储管理

    连续存储管理,包括固定分区存储管理,非固定分区存储管理
    分页存储管理
    段式存储管理
    虚拟存储管理

    5 操作系统提供给程序员创建进程的接口有哪些

    系统调用fork(),vfork() ,clone()

    6 进程调度算法有哪些?

    先来先服务,短作业优先,高优先权优先(可以动态优先,高响应比优先,也可静态优先权),基于时间片轮转(基于时间片轮转调度算法RR,多级反馈队列算法FB),最短剩余时间优先。

    7 中断嵌套是什么;

    指新的优先级更高的中断会去中断CPU上正在运行的中断程序,并且在新的中断结束后,返回到被中断点处继续执行。

    8 调度什么时候发生?

    ①当进程需要等待某个资源(比如I/O设备)时,主动请求调度让出CPU

    ②当前的时间片用完时

    ③当进程状态状态发生改变时:比如,进程终止,进程睡眠

    ④进程从中断,异常及系统调用返回到用户态时。

    9 操作系统的定义?

    操作系统是管理计算机硬件与软件资源的计算机程序。

    它提供:内存和资源的分配,控制输入输出设备,操作网络和管理文件,提供人机交互界面

    10 一个文件在磁盘上,如何访问到

    缺页中断
    或者主动调用int 19H中断,将磁盘的数据读入到内存

    当程序执行的指令或访问到的数据在内存中时可顺利执行;如果在磁盘中,需要系统自动将这部分信息装入,这称“部分装入”;如此刻没有足够的空闲内存空间,便把内存中不用的信息暂时移到磁盘上,这称部分替换。所以只要“部分装入”和“部分替换能够实现”,实现从磁盘中读入数据,来让CPU执行。
    根据FCB汇集和组织形成的文件目录,文件目录将文件名称转化为磁盘中的存储位置,然后通过访问道磁盘中的数据就可以访问到了。

    11 操作系统的知识结构,内容,包括哪些?

    处理器管理,进程调度,存储管理,设备管理,文件管理

    12 什么是进程,进程调度是调度谁,进程的工作状态

    进程中程序关于一个操作数据集上的一次运行活动,同时,进程也是资源和内存分配的基本单位。

    进程调度是调度谁:因为程序在CPU中是走走停停的,为了使CPU能够达到最大的使用效率,当某一个进程在运行过程中需要停止等待,比如说,需要等待I/O,而这时,访问外设的时候,时间就比较长,这时,该进程就会让出CPU的使用权,按照所规定的调度算法,选择在就绪队列的中的其中一个进程,将当前的CPU进程保存在PCB块中,以linux操作系统为例,就是调用shedul()中的switch_to()进程切换进程。

    进程的工作状态:

    有两种,一种是比较简单的,由运行态,就绪态,和阻塞态

    另外一种是7种模式:有新建态,运行态,就绪态,和阻塞态,挂起就绪态和挂起阻塞态

    13 为什么要有系统调用

    在linux内核中,有实现系统功能的子程序。系统分为内核态和用户态,内核态实现系统功能,用户态实现应用程序,当用户态需要使用的系统资源时,比如访问I/O设备等,就需要系统调用,同时,设置内核态与用户态也是访止用户的态程序随意更改内核的数据。

    14 说一下内存管理方式有哪些

    连续分区管理,分页管理,分段管理,虚拟存储管理技术管理

    15 请求分页页面置换算法列举?

    LRU,LFU,FIFO 第二次机会替换算法 时钟算法 改进的时钟算法

    16 叙述clock置换算法

    用循环队列构造页面队列

    初始化:每一个页设置一个引用位,页面被调入内存时引用位置为1,每一个页面被访问时内存引用位置为1
    进行淘汰时,从指针指向的页面开始扫描,遇到引用位为1的页面,讲引用位置0;遇到引用位为0的页面,淘汰该页面。

    若扫描循环队列,所有页面引用位均为1,则所有页面经过依次扫描引用位均置为0,指针也就回到开始扫描的地方,那下一次扫描一定有页面换出。

    改进的clock有两个位,一个修改位,一是引用位

    第一次扫描,找到未被修改且未被引用的的页,如果找了,就淘汰该页面
    第二次扫描,找到第一个未被修改,且被引用的页,如果找了,淘汰该页,并将扫描过引用位为1的页,将该位置0
    第三次扫描,一定可以找到一个淘汰页

    17 虚拟存储的作用?为什么虚拟存储可以实现?

    内存在计算机中的作用很大,电脑中所有运行的程序都要经过内存来执行,如果执行的程序很大或很多,就很导致内存消耗殆进。为了解决这个问题,拿出一部分硬盘空间来充当内存使用,当内存用完时,计算机就自动调用硬盘来当内存,以缓解内存的内存的紧张。

    为什么虚拟存储可以实现?

    操作系统可以痛过调用系统中断

    18 多级存储系统的作用?

    计算机系统中,运行越快的存储器件,价格越昂贵,寄存器的速度大于存储器,存储器存取速度远远大于磁盘,但是它们的存储容量是相反的,为了缓解储存容量,高速度,低成本之间的关系,在CPU与存储器之间加上cache,来解决cpu与主存储器之间的速度不匹配,在主存器与外存之间加一个TLB快表,使得计算看似扩展了更大的容量空间。

    19 寄存器和存储器的区别

    寄存器存储容量小,但是寄存器速度快

    存储器存储容量比寄存器大很多,但是存取时间长

    寄存器在CPU内,存储器一般只硬盘,U盘等,在CPU外,
    寄存器存储的是直接操作数据,存储器中放的是指令和数据

    20 操作系统中用来表示内存已被占用的数据结构是什么

    根据操作系统所使用的存储技术的不同,所使用的数据结构表也不不同?
    在固定分区存储管理中,内存分配表
    在可变分区存储管理中,使用已分配区表和未分配区表
    在分页存储管理中,使用内存物理块表用来记录页框的状态,管理内存物理块分布
    在段式存储管理中,使用段表管理

    21 系统调用与普通调用的区别?

    计算机组成原理

    1 单片机的引导过程

    操作系统的系统的启动过程
    当Linux 0.11 操作系统进入实模式,并从地址0xFFFF0开始自动执行程序代码,物理地址为0处进行初始化中断向量,然后将第一个扇区读入到内存的7C00处,然后从7c00处开始执行。

    单片机的启动过程:
    单片机上电或者复位后,CS被置为FFFFH,IP被置为0000H,cpu就从内存的FFFF0H处取出第一条指令,开始执行。

    2 DMA控制器是主设备还是从设备,什么时候做主设备

    有的时候是主设备,有的时候是从设备,

    当CPU给DMA发送数据,字节数,此时他就是从设备。

    当DMA控制总线,让外设与存储器之间传输数据时,就是主设备。

    3 8259的中断过程

    8259A有两种模式,一种是操作模式,一种是中断模式
    单片机可通过端口的方式,CPU可发送in,out指令控制发送给8259进入中断模式,8259便接收中断向量号,通过中断判优选择结构选择紧急程度最高的中断进行相应,通过int端口给CPU发送中断请求,CPU收到后响应中断,8259给CPU发送中断向量号,CPU收到中断向量后进行执行。

    4 动态存储和静态存储的区别

    静态存储:指在编译时对数据对象固定的存储位置,运行时始终不变。即一旦存储空间的某个位置分配给某个数据名,则目标程序在运行过程中该地址就属于该地址名

    由静态存储分配产生的数据区称为静态数据区

    静态存储分配适用于不允许递归过程或递归调用,不允许可变体积的数据结构语言

    静态存储分配的特点:简单,易于实现

    动态存储:

    指运行阶段源程序中的数据对象分配存储位置

    实行动态存储分配的语言特点

    允许递归过程

    允许可变数据结构

    允许用于自由申请内存以及释放

    5 设计CPU思路

    设计思路:

    要想设计CPU,就要设计一个的简易指令系统,在根据指令搭建对应的数据通路,在数据通路的基础上实现控制逻辑,下一步是加上流水线,划分流水线,紧接着解决流水线中冲突的问题,提高流水线的效率,最后解决CPU异常的问题。

    6 关于高速缓存 Cache 的两种写 入方法是什么

    什么是cache,cache内存与CPU之间很小的一个缓存,用于存放主存中最近经常使用得数据,用于缓解CPU于主存之间的速度,大大提高了CPU得运行效率。

    写回法:命中,直接修改cache内容,只有当此行被换出时才写回主存。没命中时,从内存中分配一块给 cache,对擦车进行写。

    全写法:当cache命中时,cache与主存同时发生修改,当cache没命中时,有两种方法,一是要访问的内存数据的那一块分配给cache后,cache和内存同时修改;或者只修改内存。

    写一次法:第一次使用全写法,后面都是用写回法

    7 嵌入式系统和普通的系统区别在哪

    区别1:类型

    普通系统:应该指实实在在的一般电脑安装的系统

    嵌入式操作系统:指“看不见”的操作系统,形式多样,应用领域广泛,按应用进行分类;

    区别2:组成

    通用:通用处理器,标准总线和外设,软硬件相对独立

    嵌入式:面向特定应用的微处理器,总线和外设一半集成在处理器内部,软硬件紧密结合,具有很强的专用性,必须结合实际系统进行合理的裁剪利用;

    8 嵌入式系统用什么语言写,什么是嵌入式

    C/C++,可以控制,可以操作或辅助操作机器和设备装置,是一种专用计算机
    汇编语言

    9 单片机为啥叫单片机

    将运算器,存储器,控制器,输入输出,集成到一块硅芯片中,该芯片具有完整的基本计算机的功能,所以称为单片微型计算机,简称单片机

    10 外部中断CPU该如何处理

    CPU从外部中断源接收到中断后,CPU在满足中断的条件下,发送中断响应,并关中断不再响应其他中断。CPU寻找中断源是哪个设备,找到后,保存当前CPU的状态,以及各种寄存器的状态,将PC转移到中断处理程序的地址,完成中断处理程序之后,恢复现场,打开中断,继续开始的中断点执行。

    计算机网络

    1 一个访问网络的过程

    当在网站上输入了地址后,浏览器便会向本地域名服务器请求解析,若本地域名服务器没有,则本地域名服务器以客户的方式向根域名服务器发送请求报文解析请求,根域名判断在DNS.abc的域,将权限域名服务器的地址发送给本地域名服务器,本地域名器向权限域名服务器发送连接请求,权限域名服务器找到后,将域名的IP地址发送给本地域名服务器,本地域名服务器收到后,保存下来,并将IP发送给主机,主机便于IP地址所在的从机建立TCP连接请求,经过三次握手,主机便下载到了html,并以图形化的方式呈现给用户一个界面

    2 DHCP协议的作用

    DHCP(动态主机配置协议)作用:动态分配IP

    从我的理解:

    首先客户端问附近的服务器有ip地址码

    服务器回答,说有啊,服务端就发一一个ip过去

    客户端就申请使用这个ip

    服务端就确认

    简单介绍下DHCP

    A 客户端要IP,发送第一个报文discover

    B 发送一个offer回应它,可以提供IP

    A 就发送一个request请求报文

    B 服务器收到后,如果可以,就发送一个ACK确认

    3 网络OSI的七层结构

    物联网,链路层,网络层,运输层,会话层,表示层,应用层

    5 rarp的作用,相对应的协议是什么,地址解析的过程。

    RARP通过发送反向解析的MAC地址,其他RARP服务器接收到后,在一张映射表中查询,若有,返回的数据中包含了该设备的所需的IP地址,

    相对应的协议是arp;

    地址解析过程:

    当主机A打算给主机B发送IP数据报时,A在缓存区中查看是否有无主机B的IP地址,如有,直接查出其对应的硬件地址,将该硬件地址写入MAC帧,如果没有,就使用目的MAC地址为FF-FF-FF-FF-FF的帧来广播ARP请求,可以使同一个局域网的所有主机收到ARP请求,当B主机收到后,就给A发送响应分组,分组中就包含了该IP地址与MAC地址的映射关系。

    5 发微信用的是TCP还是UDP,为什么,所需的IP地址。

    看发送的文件,当发送一些聊天文字的时候,数据比较小,采用哦个UDP报文传输,当发送一些几十兆几百兆的视频,由于数据比较大,一个报文放不下,所以需要使用TCP传输

    6 路由器和交换机的功能然后他们的区别

    路由器用于大型网络之间的互联,路由转发,拥塞控制等

    交换机用于局域网内部之间的互联。

    区别:

    路由器可以隔离冲突域,也可以隔离广播域

    交换机可以隔离冲突域,不可隔离广播域

    路由器是网络层设备

    交换机是数据链路层设备

    7 TCP拥塞的解决方式,分别解释一下

    慢启动:当新建TCP连接时,拥塞窗口CWND初始化为1,表示一个数据包大小,源端按cwnd发送数据,每收到一个ACK确认,cwnd窗口数就+1,在一个RTT时间内,CWND就会增加一倍,即CWND随着RTT呈指数增长。

    拥塞避免:当cwnd达到ssthresh时,在此阶段,发送方每接收一个ACK确认,CWND就增加1,CWND就会随着RTT呈现线性增长

    当出现由超时指示丢包时,拥塞窗口变为1,开始慢启动过程。这样就可以迅速减少主机发送到网络中的分组数。

    快重传和快恢复:当收到3个以上的重复ACK确认时,说明有可能有数据报丢失,于是需要立刻重传该丢失的数据包,这就是快重传。更新当前的ssthresh为当前CWND的1/2,然后将CWND变为原来的1/2,开始拥塞避免阶段,即随着RTT呈线性增长,这个过程就是快速恢复阶段。

    8 TCP为什么三次握手

    为什么三次握手而不是两次握手,这是为了解决已失效的建立报又发送到了服务端。如果采用两次握手,试想一下出现这样一种情况,客户端向服务器第一次发送数据,由于网络原因,这个数据包走了一条比较长的链路,客户端对该数据包的时间到时,就重新发送一个建立请求报文,此时网络又好了,于是服务端接收到了第二次建立连接请求的报文,于是服务段发送确认,并反向发送连接请求,客户端再发送一个确认,此时建立连接之后,双方互相发送信息,再通过四次挥手,断开连接,此时第一次走了好远的数据报文,又到了服务端,服务段以为客户端又要建立连接,于是就打开了连接,便发向确认,而客户端自己又没发送请求建立连接,所以客户端就把这个确认丢掉,但是此时服务端打开了连接,一直在等待客户端发送数据过来,这也就服务端的资源,而网上的主机很多,这样就造成了很多不必要的浪费。

    9 用自己的话讲TCP连接到底是什么

    TCP:传输控制协议,就是为了保证互联网通信的双方能够可靠传输,所以TCP协议就制定了可靠的传输协议,想慢开始,快回复,拥塞控制,快重传

    数据结构

    1 描述一下你学过的排序算法

    插入排序

    ①:直接插入,折半插入,希尔排序

    ②基于交换的有
    冒泡排序和快速排序

    ③基于选择的有
    简单选择排序和堆排序
    基数排序和归并排序

    冒泡排序 :一个循环,从前到后比较,当后面的一个值比前面的值小,交换,再循环循环上面的过程直到数据有序。

    快速排序:设两个指针,i,j分别指向待排序的数据的两头,左边不动,右边指针左移找到一个比左边指针小的值交换,左边指针移动,找到一个比右边指针大的值交换,直到i>停止。

    选择排序:假设待排序的数据是L[1…n],第i次从L[i…n]中选取最小或者最大的值与L[i]交换,直到所有数据有序

    堆排序:先更具堆的要求,建立大根堆或者小根堆,拿小根堆为例,对建立好的初始堆排序,每次将堆中最后一个元素与第一个元素交换,再进行一次堆调整,接着,把倒数第二个与一个元素交换,重复,直到堆满足小根堆和大根堆定义

    基数排序

    把数据根据相同的各位收集在一起,对每组收集的数据进行插入排序,最后对所有数据进行插入排序

    归并排序:设排序有n个数,把所有待排序的数据,两两和并,得到n/2个长度为二或者1的有序表,重复,直到得到长度为n的序表为止。

    2 数据结构的顺序结构有哪些

    顺序表,队列和栈

    3 给一个链表,如何确定这个链表有环?

    遍历这个链表,将访问过的节点标记已访问,如果继续遍历到已访问过的结点时,则有环,否则,当遍历结束时即遍历到空时,说明该链表无环。

    4 数据结构如何使链表逆置

    只需要遍历一个链表,使用头插法插入到表中

    5 你能描述一下数据结构具体有哪几种吗?

    线性表:

    顺序存储—顺序表

    链式存储 —链表

    栈,和队列

    二叉树,平衡二叉树,haffuman树,完全二叉树,

    深度优先遍历,广度优先遍历

    6 佛洛依德算法 迪杰斯特拉算法

    佛洛依德算法:

    计算多源点间的最短路径

    令 g [ u ] [ v ] 表 示 u 到 v 的 距 离 , 找 到 一 个 k 点 , 使 g [ u ] [ v ] > g [ u ] [ k ] + g [ k ] [ v ] , 则 g [ u ] [ v ] = g [ u ] [ k ] + g [ k ] [ v ] 令 g[u][v]表示 u到v的距离,找到一个k点,使g[u][v]>g[u][k]+g[k][v],则g[u][v]=g[u][k]+g[k][v] g[u][v]uvk使g[u][v]>g[u][k]+g[k][v],g[u][v]=g[u][k]+g[k][v]

    重复该步直至所有结点均已遍历

    迪杰斯特拉算法:求源点到其他结点的最短路径

    先初始化d[i],d[i]为源点A到其他结点的权值,不直接相连为无穷大

    计算,.

    如 果 找 到 一 点 k , 使 得 d [ i ] > [ 0 ] [ k ] + d [ k ] [ i ] , 则 将 d [ i ] = d [ 0 ] [ k ] + [ k ] [ i ] , 每 找 到 一 个 k , 就 放 入 集 合 中 , 重 复 以 上 步 骤 , 直 到 所 有 结 点 均 在 集 合 S 中 如果找到一点k,使得d[i]>[0][k]+d[k][i],则将d[i] = d[0][k]+[k][i] ,每找到一个k,就放入集合中,重复以上步骤,直到所有结点均在集合S中 k使d[i]>[0][k]+d[k][i],d[i]=d[0][k]+[k][i],kS

    数字电路

    数字逻辑主要学了哪些东西

    **BCD编码:**用4位二进制数来表示1位十进制数中的0~9这10个码数,用二进制编码的10进制编码。

    **反演规则:**与变非,非变与,原变量变反变量,1/0互换

    **对偶规则:**与变非,1/0互换

    **什么是最小项?**与或表达式

    n个变量X1,X2…Xn,每个变量都以它得原变量或非变量得形式在乘积项中出现,且出现一次。

    **什么是最大项?**或与表达式

    n个变量X1,X2…Xn,每个变量都以它得原变量或非变量得形式在和//项中出现,且出现一次。

    **两个的关系:**最小项对应最大项取反

    卡诺图:是与变量的最小项对应的按一定规则的方格图,,每一个方格对应一个最小项的有或无

    逻辑门电路 与 或 非 异或和同或

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kzRjwhW3-1589637931309)(C:\Users\Mr. chen\AppData\Roaming\Typora\typora-user-images\image-20200304125810990.png)]

    MOS管:的开关特性相当于一个由UGS控制的无触点开关。

    逻辑代数

    组合逻辑电路

    触发器

    时序逻辑电路

    脉冲波形的产生与变换

    数模与模数转换

    半导体存储器

    数字逻辑基础,组合逻辑电路,常用组合逻辑功能器件,时序逻辑电路

    触发器

    6 组合逻辑电路和时序逻辑电路区别(电路图的区别和性能特性的区别)

    组合逻辑电路:任意时刻的输出仅仅取决于该时刻的输入,与电路原来的状态无关

    时序电路具有记忆功能,时序电路的特点是:输出不仅取决于当时的输入值,而且还与电路过去的状态有关。

    电路图上时序逻辑电路多了一个存储器件。

    7 大信号和小信号的区别

    大信号和小信号是根据放大器动态范围来说的信号分类。

    大信号体现的特性是直流的静态工作点,其直流阻抗就是V/I = b/a

    小信号体现的是静态工作点的斜率,可以成△V/△I

    静态工作点:指的是输入信号为零时,电路处于直流,电压的数值在三极管特性曲线上表示
    为一个确定的点

    8 模电分析方法应该先分析交流还是直流,为什么,怎么进行分析

    遵循先直流,后交流的原则,直流是基础,交流是目的,只有静态工作点Q合适,保证方法信号不失真,进行交流分析才有意义。

    静态工作点Q的作用:

    ①确定放大电压和电流的静态值

    ②选取合适的静态工作点可以防止电路产生非线性失真

    C语言:

    1 数据结构中线性表有哪些?

    线性表,栈,队列

    2 还有快排和冒泡的原理自己他们的空间复杂度是多少

    快排㏒2n,冒泡 O(1)

    C++方面:

    1 几种方法写阶乘;

    3种,static,递归,循环

    2 定义一个结构体,里面一个int类型成员,一个char,int占四位,char占一位,那么在Linux占几位

    8个字节,char 定义了一个字节后,再定义一个int 类型,int的为4个字节,要存储再4的倍数的存储单元种,所以编号为1,2,3的字节要填充,int定义的从4开始。

    3 请设计算法统计一个二进制数中1的个数

    两种方法:

    第一种是:设置一个变量count,将二进制放入string变量中,遍历string变量的每一个字符,当这个字符等于1是,conut++

    第二种方法是:C++中有一个bitset,直接用bitset定义的二进制变量调用count就可以得出1的个数

    4 递归的含义,递归能不能替代循环,递归需要做什么?

    递归其实就是一个函数直接调用或间接调用自己过程。

    递归可以替代循环,递归需要压栈,存放下一条指令的地址以及函数的参数

    递归可以改写成循环,有些递归只需要一个循环就可以实现,有些递归需要循环+栈,需要辅助空间记录过程中的,某些数据才可以。

    5 堆栈需要用的什么

    bp,ss

    6 printf函数在汇编中怎么实现

    在汇编中,先把printf的参数,从右往左压入栈中,再根据栈中,格式,计算对应格式所占的空间,再调用system_call ,来实现输出

    7 printf函数的参数格式,长度等等

    %d %i %u %f %ld %lf c%G c %X %x %s

    8 描述斐波那契序列算法和

    算法①:

    使用递归,当n<=1返回n

    当n>=2时 f(n) = f(n-1)+f(n-2)

    调用f(n)

    if n==1 return faci(1);

    ​ else f(n) = f(n-1)+f(n-2)

    算法②:

    使用迭代的方法:

    循环 1 到 n

    {
    当前值 = f(i-1) + fi;

    f(i-1) = fi;

    f(i) = 当前值;
    }

    9 汉诺塔算法

    算法:有三个柱子ABC,n个盘子在A柱子上

    将A上面n-1个盘子借助于C,移动到B,

    将A上最下面的一个盘子移动到C

    再将B上的n-1个盘子借助于A移动到C(此时问题的规模就变小了,但还是同样的问题规模)

    10 C语言中你习惯定义全局变量还是局部变量

    一般的话,为了方便管理,我会尽量为了模块编程,尽量使各个模块低耦合,定义局部变量使用

    如果实在是

    11 编译的过程是什么

    词法分析, 语法分析, 语义分析及中间代码生成,优化,目标代码生成

    12 专业学了啥

    编程语言学了:C,C++,java,php,C#

    计算机基础课学了:数据结构,操作系统,数据库,计算机组成原理,数据库,计算机网络

    应用型课程学了web前端,web服务端,andriod开发,linux 0.11内核注释

    硬件学了一点:数字逻辑,模拟电路与电子设计,单片机

    自己看过嵌入式系统原理,传感网原理与技术,proteus,DXP,

    13 嵌入式课程教了啥

    大学没有嵌入式课程

    但是自己看过相关的书,什么是嵌入式,家里的冰箱,微波炉点,计算机系统嵌入

    14 斐波那契递归和迭代区别是啥

    递归:自己调用自己,迭代:反复替换

    递归和迭代都是有重复,只是重复的不同,迭代显式使用重复结构,而递归通过重复调用函数实现。

    递归与迭代都是基于控制结构:迭代用重复结构,而递归用选择结构

    递归在遇到基本情况停止,迭代在循环条件失效时停止

    时间复杂度,用递归来求,时间复杂度O(2n),迭代时间复杂度O(n)

    15 递归的定义及优缺点

    16 C 语言的 3个基本结构是啥

    选择结构,循环结构,顺序结构,

    17 全局变量和局部变量分别存储在哪里

    堆,栈,自由存储区,静态/全局变量存储区,常量存储区

    18 数组和指针的区别是什么

    很多区别:

    声明一个数组,编译器将根据数组的大小为他分配内存空间

    声明一个指针,编译器只为指针本身保存内存空间

    另一方面:如果声明一个数组int a[]; 和声明一个指针 int *b;

    表达式b++可通过编译,而a++无法通过编译,因为a是一个常量。

    19 c++的继承方式

    三种继承方式:

    public:父类成员在子类中均可使用

    protected:父类的公有成员变为保护成员,其他成员保持不变

    private:父类所有成员在子类中变为私有成员

    20 .请简述C,C++语言有何区别和联系

    C先出现,C++是在C上扩充,C是C++的子集,C++是C的超集

    C是面向过程,C++是面向对象

    C++在C的基础上,增加了很多关键字,比如bool ,const,protected等等

    malloc和free替换成了new和delete

    C不支持相同参数个数的重载,而c++中支持相同参数个数的重载。

    21 .简述面向对象有哪些好处

    优点:易于维护,复用,扩展,由于,面向对象有封装,继承,多态的特性,可以设计出低耦合的系统,使系统易于维护,更加灵活。

    缺点:性能比比面向过程低

    22 .简述类和对象

    对象是对客观事物的抽象,类是对对象的抽象,类是一种抽象的数据类型。

    它们的关系是,对象是类的实例,类是对象

    23 .什么是重载

    重载:就是函数或者方法有相同的名称,但是参数列表不相同的情形,这样的同名不同参数的函数或者方法之间,互相称之为重载函数或方法。

    重载的作用:

    不用为了对不同的参数类型或参数个数,而写多个函数。多个函数用同一个名字,但参数列表,即参数的个数或数据类型可以不同,调用的时候,虽然方法名字相同,但是可以根据参数自动调用相应的函数

    24 .C++里什么是friend?

    用friend可以声明一个友元函数或者友元类,通过友元函数或或者友元类可以访问一个分装了类中的成员,尽管,friend破坏了类的封装性,但是为了数据共享,提高程序的效率和可读性,这种破坏也是很有必要的。

    25 Java和c++的异同

    相同点:都是面向对象的思想,都有封装,继承,多态等特性

    不同点:
    1.java为解释性语言,程序源代码经过java编译器编译成字节码,然后又JVM解释成机器指令,然后执行。
    C/C++为编译性语言,源代码经过编译,汇编,链接后生成可执行的二进制代码,可直接执行。
    因此java的执行速度比C/C++慢,但java能够跨平台执行,C/C++不同。

    2 . java是纯面向对象语言,除了基本数据类型外,其他类型都是类,而C++兼容面向对象和面对过程,可以定义全局变量和全局函数,而java没有

    3.java不支持C++中的多继承,但java引入了接口的概念。

    4 java不支持运算符重载,而C++语言支持运算符重载。

    5 .java中没有指针的概念,C++有指针的概念

    26 Java与c++的类、继承有什么相同和不同

    重载:C++提供了运算符重载,而java并不提供

    继承:C++支持多重继承,这是C++的一个特征,他允许多父类派生一个类。java只能单继承,但是java通过可以实现多接口,来变相实现了多继承。

    27 面向对象中什么封装,多态,继承

    封装:隐藏对象属性和实现的细节,仅对外公开接口,控制在程序中属性得读和修改得访问级别,将抽象得到的数据和行为相结合形成一个有机得整体类

    多态:用同一相同的指令调用不同的方法,这样的称之为多态,需要使用到virtual关键字,使得虚函数在运行时动态绑定。

    继承:继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种明确表述共性的方法,对象的一个新类可以从现有的类中派生,这个过程称为类的继承。新类称为原始类的派生类,而原始类称为新类的基类或者父类。

    数据库

    1 数据库有几种锁

    加锁是实现数据库并发控制的一个非常重要的技术。

    为什么要上锁?

    当事务在对某个数据对象进行操作前,先向系统发出请求,对其进行加锁。加锁后事务就对该数据对象有了一定的控制,在该事务释放锁之前,其它的事务就不能对此数据对象进行更新操作。

    数据库中有两种类型的锁:

    排它锁和共享锁。

    共享锁的数据对象可以被其他事务读取,但不能修改

    排它锁:其他的事务不能对它读取和修改。

    2 数据库的事务

    什么是数据库事务?
    数据库是指操作多个数据项的一组数据库操作序列,这组序列要么全部执行,要么全部失败,是一个不可分割的工作单位。

    有四个特性:ACID

    a:原子性

    c:一致性

    i:隔离性

    d:持久性

    3 常用的数据库有哪些?

    MySql,SQL server,Ocacle,,Access,redis,HBase

    4 数据库的主码外码?

    主码和外码是用来实现参照完整性的,外码的数据项需要参照主码的数据项来操作,具体实现是创建数据库中时表间创建关系

    1.参照关系比如学生表的学号时学生表的主键,是成绩表的外键,成绩表的学号参照学生表的学号录入的,也就是,如果学生表没有的学号,成绩表是无法录入的

    2.级联操作,当删除主表里面的学号时,从表里面的那个学号会响应的自动删除,修改。外码参照主码修改

    5 数据库范式的定义以及区别

    第一范式:表中的每一个属性都是一个原子,不可再分。

    第二范式:(无重复的行)在满足第一范式的基础上,每一个元组必须可以被唯一地区分,非主属性完全依赖于主键

    第三范式:在满足第二范式的基础上 ,要求一个数据库表中不包含已在其他表中亦包含的非主关键字信息,不能存在非关键字字段对一候选关键字段的传递函数依赖。

    非主属性不存在传递依赖于码和不存在部分依赖于码。

    (巴斯范式):在第三范式的基础上,数据库表中如果不存在任何字段对任一候选关键字段的传递函数依赖。不存在任何字段对任意候选字段传递函数依赖

    离散数学

    1 用离散数学解释下主成分分析是啥

    主程序程序分析(PCA)是一种降维方法,通常用于通过将数量很多的变量转化为仍包含集合中大部分信息的较少变量来降低数据集的维度。

    2 离散数学关于群的定义

    对于<G,*>

    若G关于*封闭

    G上运算*结合律

    G关于*存在么元e

    如果对任意a属于群,a*b等于e,b属于群

    则称代数系统<G,*>为群

    其他

    2 一个方形桌子砍一刀后有几个角?

    还有5个角

    3 解释机器学习

    机器学习其实是一个程序,只是这个程序可以根据输入的数据不断进化,然后通过获得经验来处理未曾见过的数据

    4一个逻辑问题,10框苹果,有9框每个半斤重,有一筐每个四两,如何通过只称重一次,找出那个不一样的

    ( 55 ∗ 5 − m ) = 45 ∗ 5 + 4 ∗ 10 (55*5-m)=45*5 + 4*10 (555m)=455+410

    等式左边是若10篮子是5两的总质量(单位:两)-多计算的两数 = 称重的总两数

    什么是均值?**

    是平均数?一组数据之和除以该数的个数

    7 讲下你的毕设

    10 学校,专业是啥,专业多少人,排名多少

    11 特征值是啥

    如果一个矩阵乘以一个向量 = 一个值乘以该向量,则称该值为该矩阵的特征值

    14 做过什么项目问了

    15 队列和链表相比的缺点

    16 你最喜欢的专业课是什么?

    ​ 计算机网络和C++

    17 怎么求sin 0.1

    用泰勒公式,把sin的展开式写出来,可以通过编程来计算

    18 你学过这个专业相关得专业课有哪些**

    计算机组成原理,单片机

    19 相比于门外等着的人,你觉得你的优势是什么(英语)**

    Frist ,my major is computer and science,so I have some koneledge about my major

    second,I choose the major because I have intense interest,I ever get access it

    the

    20 为什么选择这个方向

    前沿技术

    21 极大似然函数的作用:

    可以根据极大似然函数可以求得极大似然估计值,即用已知的总体和样本结果,反求样本最有可能发生的概率。

    22 一个箱子,放了一个白球,一个黑球,每次取一个便放回去,问至少有一次是白球的概率是多少;

    1-2-n

    23 双聚类 启发式搜索 k均值聚类

    双聚类算法:

    光谱联合聚类:

    在矩阵中,找到的值高于其它行和列中的值,每行和每列只属于一个双聚类,因此重新排列行和列中的这些高值,使这些分区沿着矩阵对角线连续显示。

    启发式搜索:

    利用当前与问题有关的信息作为启发式信息,这些信息是能够提升查找效率以及减少查找次数的。

    如何利用这些信息?

    定义一个估价函数h(x)。h(x)是对当前状态x的一个估计,表示x状态到目标状态的距离。

    1.h(x)>=0

    2.h(x)越小表示越接近目标状态;

    3.如果h(x) == 0,说明达到目标状态

    k均值聚类:

    K均值聚类算法:是一种迭代求解的聚类分析算法,其步骤是,欲将数据分为k组,则随机选取K个对象作为初始聚类的中心,然后计算每个对象与各个种子聚类中心之间的距离,把每个对象分配给距离它最近的聚类中心。重复以上步骤,直到

    ①没有对象被重新分配给不同的聚类

    ②没有聚类中心在发生变化

    ③误差平方和局部最小

    24 学过哪些前沿课程 课程内容是什么 人工智能是什么

    大数据:是指数据的获取,分析,管理,计算超出了当前数据库软件工具的处理能力范围的一种数据集合。

    特点:大,多样,有效度密度低,高速,真实性

    初级阶段有:分布式计算技术,HADOOP,分布式存储技术原理,MAPREDUCE

    hadoop就是一种分布式计算的解决方案

    比如说从1TB或者1PB的数据中寻找关键词,通常可能要消耗几天,但是使用hadoop只需要几个小时,hadoop将数据发送到sou各个HDFS(分布式文件系统中),各个分布式文件处理后,再返回,这就大大缩小了搜索时间。

    内容是什么?

    25 数据挖掘有什么应用

    什么是数据挖掘?

    数据挖掘就是从海量的信息中利用有效的算法提去需要的信息。

    应用:就我们生活中熟知的网上购物,用户可以根据以往其他用户大量评价,来计算机决定该物品是否值得购买~

    27 机器人的定义是啥

    自动执行工作的机器装置,或者可以运行预先编写的程序的机器。能够代替人类的工作,比如基本家务,或者高空作业,高危作业等。

    28人工智能是啥

    人工智能研究,模拟,延伸人的技术,方法,理论的一门技术科学。

    29 人工智能的避障算法是啥

    比较热门的有:遗传算法,神经网络算法,模糊算法

    神经网络:是一种模仿生物神经网络的结构和功能的数学模型或计算模型

    模糊算法:没有根据经典控制理论那样把实际情况加以简化从而建立数学模型,而是通过人的经验和决策进行相应的模糊逻辑推理。

    30 python特殊的数据类型

    列表,元组,字典,集合

    31 机器人的定义。

    机器人:是自动执行工作的机器装置,既可以接收人的指挥,又可以运行预先编排得程序,能够协助人类的工作。

    32 人工智能的定义

    研究和发开用于模拟,延伸和扩展人智能的理论,方法,技术的一门技术科学。

    33PLC与FPGA的中文名称。

    PLC:可编程逻辑控制器

    FPGA:可编码门列阵

    34 设计web服务器;

    和客户交流,确定好需求分析

    系统设计:程序设计+前端UI+数据库设计

    35 机器学习?

    机器学习,赋予机器学习的能力,一台机器通过一定数量的训练,来实现能够根据已知的数据,来解决未知的事情,根据已知的样本情况,来实现相应的功能

    比如说,十字路口的红绿灯,可以设计成,将所有通过这个红绿灯的情况记录在车的系统中,车不用人控制,遇到一种情况,自己与系统的系统中的所有样本比对,从而,装上了机器学习的机器,就会自己做出判断,选择如何做出相应的对策。

    36 计算机视觉的看法

    就是赋予机器具有自然视觉能力的学科把,将图像输入到计算机中,计算机处理,理解,研究图像信息,从而对外界做出相应的反应。

    37 .什么是传感网?

    我们生活中到处都网络互联,手机到路由器,路由器到路由器,等等再到手机,而传感网是互联网是一个部分,它是物联网的一个很重的模块—感知模块,他从各个节点接收数据,处理后,可以存储,再汇聚到汇聚节点,汇聚节点通过卫星发送到服务器,人们就可以再远程去监控,或者判断具体事务的情况啊。

    38 蒙特卡洛求不规则图形面积

    比如一张图,有不规则的图形,可以用散点法,也就是蒙特卡洛,比如在上面撒芝麻,看看有多少芝麻在图上,然后找比例求面积

    39 复变函数的卷积公式

    应该有两个函数,根据这两个函数求第三个函数,求这个函数平滑后的面积,也就是求翻转平移后的面积。

    40 傅里叶变换

    将一个函数或者一个信号,看成若干个小信号或者若干个三角函数叠加,从时域和频域叠加都可以组成原来的信号。

    41 泰勒公式的展开,n取到多少怎么确定

    展开到直到抵消不了为止

    42 什么是蚁群算法?

    通过正反馈机制寻找最优解,这个最优解是全局最优解,可以与运筹学结合起来用,比如说TSP(旅行商问题),指派问题

    43 空间解析几何中的四维空间和解析集合讲了什么

    我觉得应该有点到体积距离,三位以上的方程把,比如说,二维的圆,三位中球的界面是二维的圆,四位中,四位对应的是珍,

    算法设计与分析

    什么是递归算法

    ①程序调用自身的编程技巧称之为递归,通常一个过程或者一个方法在定义或说明中直接调用或间接调用自身的一种方法。通常,它把一个大型的问题层层化为相类似的并且规模较小的问题求解,递归策略只需要较少的代码实现就可描述出问题中所需要的多次重复计算,大大减少了代码量。

    ②递归函数函数需要设置出口,当递归到子问题不能再分解时,就返回。

    什么是分治算法?

    ①把一个大问题划分成K个小问题,如果K个小问题还可以划分,则再把它们分别划分成K个更小的问题,直到问题规模足够小,小到可以直接求解,然后把小问题合并成原问题的解。

    ②分治算法要注意:

    小问题小到一定规模可以求解

    划分的小问题应该可以合并成原问题的解

    划分的小问题应该具有最优的子结构

    划分的小问题应该相互独立性

    什么是贪心算法?

    贪心算法:把大问题拆分成为同类的更加简单求局部最优解的问题,贪心问题求解的最终可能是整体的最优解。贪心算法不适合对所有问题进行求最优解。贪心算法在每一步上能获得局部最优解,但有时产生的不一定是最优的,所以贪心算法不要回溯。

    什么是回溯算法?

    回溯算法也叫试探法,它是一种系统地搜索问题的解的方法。回溯算法的基本思想是:按照深度优先搜索的策略,从一条路往前走,能进则则进,不能进则退回来,换一条路往前走。

    什么是分支限界算法?

    分支限界的基本思想,就是对有约束条件的最优化问题的所有可行解空间进搜索,把全部可行的解空间不断分割为越来越小的分支,并为每一个分支计算一个界,每次分支的时候,对于不满足限界函数的分支不予考虑,从而缩小了搜索范围。

    什么是动态规划问题?

    动态规划基本思想是,将原问题分解相类似且规模较小的子问题,在求解过程中,记录下子问题的解,用子问题的解,一步步求出原问题的解,相比于分治算法,动态规划算法,减少了相同子问题的计算次数。

    政治

    什么是核心价值观?

    富强 民主 文明 和谐
    自由 平等 公正 法治

    爱国 敬业 诚信 友善

    什么是两学一做?

    学党章党规,学系列讲话,做合格党员。

    什么是一个中心,两个基本点?

    以经济建设为中心,坚持四项基本原则,坚持改革开放。

    前沿技术?

    5G站点的开发,截止于2020年5月12日,中国已建设站点19.8万个。

    5G可以应用于各行各业,我们也将迎来,智慧城市,车联网,智慧医疗,以及享受8K视频体验

    什么是区块链技术?

    区块链技术是在多方无需互信的环境下,通过密码学技术让系统中所有参与方协作,来共同记录维护一个可靠的数据日志的方式。

    什么是比特币?

    这个就要举一个粒子,比特币也是一种货币,在这个系统里面,就好比我现实中,没有银行这个系统一样,每一个网络的节点都负责记录网上所有的几张,系统就会奖励其中记账最快的节点,奖励比特币,所以网上的各个节点通过算法平计算能里。

    什么是优先级反转?如何解决?

    指高优先级的进程要去访问一个低优先级使用的资源,而低优先级的正在访问,使得高优先级的进程就要陷入一种等待与阻塞状态。
    使用优先级天花板或者优先级继承的方法解决。

    优先级天花板:每一个信号设置一个优先级天花板,优先级天花板是指优先级高于使用该信号的所有任务,当任务得到该信号时,将优先级设置位优先级天花板的值。

    优先级继承:当一个任务阻塞了一组任务时,若阻塞任务中存在高优先级任务,将该任务的优先级设置位阻塞任务中的最高的优先级的值。

    为什么要有泰勒展开式?对计算机学科的意义是什么?

    可以使用泰勒展开式的无限个多项式对某个函数求近似,计算机科学中在openCV中进行模拟曲线可以用的到

    线性代数中坐标变化的意义是什么?能解决什么问题?

    线性代数可以表示图像中的数值,可以对矩阵进行变化,例如对图像进行二值化,灰度化等。

    一个桶装8斤油,另一个有3斤与5斤桶,怎么就分成两桶4斤油?

    先将8斤油倒入5斤桶中,此时3 0 5

    再将,5斤油倒入3斤油桶中,再将3斤油桶的油倒入第一个桶中,得到了,6 0 2

    接着将2倒入3斤油桶中,再将6斤倒入五斤油桶中,就得到了,1 2 5
    此时只需要,将5斤倒入一斤3斤桶,合并1,3就可以得到两个4 斤油了

    展开全文
  • 狂神说Vue笔记整理

    万次阅读 多人点赞 2020-12-11 09:13:04
    狂神说Vue笔记 ​ 想要成为真正的“互联网Java全栈工程师”还有很长的段路要走,其中前端是绕不开的一门必修课。本阶段课程的主要目的就是带领Java后台程序员认识前端、了解前端、掌握前端,为实现成为“互联网...

    狂神说Vue笔记

    ​ 想要成为真正的“互联网Java全栈工程师”还有很长的一段路要走,其中前端是绕不开的一门必修课。本阶段课程的主要目的就是带领Java后台程序员认识前端、了解前端、掌握前端,为实现成为“互联网Java全栈工程师”再向前迈进一步。

    一、前端核心分析

    1.1、概述

    Soc原则:关注点分离原则

    Vue 的核心库只关注视图层,方便与第三方库或既有项目整合。

    HTML + CSS + JS : 视图 : 给用户看,刷新后台给的数据

    网络通信 : axios

    页面跳转 : vue-router

    状态管理:vuex

    Vue-UI : ICE , Element UI

    1.2、前端三要素

    • HTML(结构):超文本标记语言(Hyper Text Markup Language),决定网页的结构和内容
    • CSS(表现):层叠样式表(Cascading Style Sheets),设定网页的表现样式。
    • JavaScript(行为):是一种弱类型脚本语言,其源码不需经过编译,而是由浏览器解释运行,用于控制网页的行为

    1.3、结构层(HTML)

    太简单,略

    1.4、表现层(CSS)

    CSS层叠样式表是一门标记语言,并不是编程语言,因此不可以自定义变量,不可以引用等,换句话说就是不具备任何语法支持,它主要缺陷如下:

    • 语法不够强大,比如无法嵌套书写,导致模块化开发中需要书写很多重复的选择器;
    • 没有变量和合理的样式复用机制,使得逻辑上相关的属性值必须以字面量的形式重复输出,导致难以维护;
      这就导致了我们在工作中无端增加了许多工作量。为了解决这个问题,前端开发人员会使用一种称之为【CSS预处理器】的工具,提供CSS缺失的样式层复用机制、减少冗余代码,提高样式代码的可维护性。大大的提高了前端在样式上的开发效率。

    什么是CSS预处理器

    CSS预处理器定义了一种新的语言,其基本思想是,用一种专门的编程语言,为CSS增加了一些编程的特性,将CSS作为目标生成文件,然后开发者就只需要使用这种语言进行CSS的编码工作。转化成通俗易懂的话来说就是“用一种专门的编程语言,进行Web页面样式设计,再通过编译器转化为正常的CSS文件,以供项目使用”

    常用的CSS预处理器有哪些

    • SASS:基于Ruby ,通过服务端处理,功能强大。解析效率高。需要学习Ruby语言,上手难度高于LESS。
    • LESS:基于NodeJS,通过客户端处理,使用简单。功能比SASS简单,解析效率也低于SASS,但在实际开发中足够了,所以如果我们后台人员如果需要的话,建议使用LESS。

    1.5、行为层(JavaScript)

    JavaScript一门弱类型脚本语言,其源代码在发往客户端运行之前不需要经过编译,而是将文本格式的字符代码发送给浏览器,由浏览器解释运行。

    Native 原生JS开发

    原生JS开发,也就是让我们按照【ECMAScript】标准的开发方式,简称ES,特点是所有浏览器都支持。截至到当前,ES标准以发布如下版本:

    • ES3
    • ES4(内部,未正式发布)
    • ES5(全浏览器支持)
    • ES6(常用,当前主流版本:webpack打包成为ES5支持)
    • ES7
    • ES8
    • ES9(草案阶段)

    区别就是逐步增加新特性。
    TypeScript 微软的标准
    TypeScript是一种由微软开发的自由和开源的编程语言。它是JavaScript的一个超集, 而且本质上向这个语言添加了可选的静态类型和基于类的面向对象编程。由安德斯·海尔斯伯格(C#、Delphi、TypeScript之父; .NET创立者) 主导。该语言的特点就是除了具备ES的特性之外还纳入了许多不在标准范围内的新特性,所以会导致很多浏览器不能直接支持TypeScript语法, 需要编译后(编译成JS) 才能被浏览器正确执行。

    JavaScript框架

    • JQuery:大家熟知的JavaScript库,优点就是简化了DOM操作,缺点就是DOM操作太频繁,影响前端性能;在前端眼里使用它仅仅是为了兼容IE6,7,8;
    • Angular:Google收购的前端框架,由一群Java程序员开发,其特点是将后台的MVC模式搬到了前端并增加了模块化开发的理念,与微软合作,采用了TypeScript语法开发;对后台程序员友好,对前端程序员不太友好;最大的缺点是版本迭代不合理(如1代–>2 代,除了名字,基本就是两个东西;截止发表博客时已推出了Angular6)
    • React:Facebook 出品,一款高性能的JS前端框架;特点是提出了新概念 【虚拟DOM】用于减少真实 DOM 操作,在内存中模拟 DOM操作,有效的提升了前端渲染效率;缺点是使用复杂,因为需要额外学习一门【JSX】语言;
    • Vue:一款渐进式 JavaScript 框架,所谓渐进式就是逐步实现新特性的意思,如实现模块化开发、路由、状态管理等新特性。其特点是综合了 Angular(模块化)和React(虚拟 DOM) 的优点;
    • Axios:前端通信框架;因为 Vue 的边界很明确,就是为了处理 DOM,所以并不具备通信能力,此时就需要额外使用一个通信框架与服务器交互;当然也可以直接选择使用jQuery 提供的AJAX 通信功能;

    二、前端发展史

    2.1、UI框架

    • Ant-Design:阿里巴巴出品,基于React的UI框架
    • ElementUI、iview、ice:饿了么出品,基于Vue的UI框架
    • BootStrap:Teitter推出的一个用于前端开发的开源工具包
    • AmazeUI:又叫“妹子UI”,一款HTML5跨屏前端框架

    2.2、JavaScript构建工具

    • Babel:JS编译工具,主要用于浏览器不支持的ES新特性,比如用于编译TypeScript
    • WebPack:模块打包器,主要作用就是打包、压缩、合并及按序加载

    注:以上知识点已将WebApp开发所需技能全部梳理完毕

    2.3、三端同一

    混合开发(Hybrid App)

    主要目的是实现一套代码三端统一(PC、Android:.apk、iOS:.ipa)并能够调用到设备底层硬件(如:传感器、GPS、摄像头等),打包方式主要有以下两种:

    • 云打包:HBuild -> HBuildX,DCloud 出品;API Cloud
    • 本地打包: Cordova(前身是 PhoneGap)

    微信小程序

    详见微信官网,这里就是介绍一个方便微信小程序UI开发的框架:WeUI

    2.4、后端技术

    前端人员为了方便开发也需要掌握一定的后端技术但我们Java后台人员知道后台知识体系极其庞大复杂,所以为了方便前端人员开发后台应用,就出现了Node JS这样的技术。Node JS的作者已经声称放弃Node JS(说是架构做的不好再加上笨重的node modules,可能让作者不爽了吧)开始开发全新架构的De no
    既然是后台技术,那肯定也需要框架和项目管理工具, Node JS框架及项目管理工具如下:

    • Express:Node JS框架
    • Koa:Express简化版
    • NPM:项目综合管理工具,类似于Maven
    • YARN:NPM的替代方案,类似于Maven和Gradle的关系

    2.5、主流前端框架

    Vue.js

    iView

    iview是一个强大的基于Vue的UI库, 有很多实用的基础组件比element ui的组件更丰富, 主要服务于PC界面的中后台产品。使用单文件的Vue组件化开发模式基于npm+webpack+babel开发, 支持ES 2015高质量、功能丰富友好的API, 自由灵活地使用空间。

    • 官网地址
    • Github
    • iview-admin

    备注:属于前端主流框架,选型时可考虑使用,主要特点是移动端支持较多

    Element UI

    Element是饿了么前端开源维护的Vue UI组件库, 组件齐全, 基本涵盖后台所需的所有组件,文档讲解详细, 例子也很丰富。主要用于开发PC端的页面, 是一个质量比较高的Vue UI组件库。
    ·官网地址
    ·Git hub
    ·vue-element-admin
    备注:属于前端主流框架,选型时可考虑使用,主要特点是桌面端支持较多

    ICE

    飞冰是阿里巴巴团队基于React/Angular/Vue的中后台应用解决方案, 在阿里巴巴内部, 已经有270多个来自几乎所有BU的项目在使用。飞冰包含了一条从设计端到开发端的完整链路,帮助用户快速搭建属于自己的中后台应用。

    • 官网地址。

    • Git hub

    备注:主要组件还是以React为主, 截止2019年02月17日更新博客前对Vue的支持还不太完善,目前尚处于观望阶段

    VantUI

    Vant UI是有赞前端团队基于有赞统一的规范实现的Vue组件库, 提供了-整套UI基础组件和业务组件。通过Vant, 可以快速搭建出风格统一的页面,提升开发效率。

    • 官网地址
    • Github

    AtUI

    at-ui是一款基于Vue 2.x的前端UI组件库, 主要用于快速开发PC网站产品。它提供了一套n pm+web pack+babel前端开发工作流程, CSS样式独立, 即使采用不同的框架实现都能保持统一的UI风格。
    ·官网地址
    ·Git hub

    Cube Ul

    cube-ui是滴滴团队开发的基于Vue js实现的精致移动端组件库。支持按需引入和后编译, 轻量灵活;扩展性强,可以方便地基于现有组件实现二次开发。

    • 官网地址
    • Github

    混合开发

    Flutter

    Flutter是谷歌的移动端UI框架, 可在极短的时间内构建Android和iOS上高质量的原生级应用。Flutter可与现有代码一起工作, 它被世界各地的开发者和组织使用, 并且Flutter是免费和开源的。

    • 官网地址
    • Github
      备注:Google出品, 主要特点是快速构建原生APP应用程序, 如做混合应用该框架为必选框架

    lonic

    lonic既是一个CSS框架也是一个Javascript UI库, lonic是目前最有潜力的一款HTML 5手机应用开发框架。通过SASS构建应用程序, 它提供了很多UI组件来帮助开发者开发强大的应用。它使用JavaScript MV VM框架和Angular JS/Vue来增强应用。提供数据的双向绑定, 使用它成为Web和移动开发者的共同选择。

    • 官网地址

    ·官网文档
    ·Git hub

    微信小程序

    mpvue

    mpvue是美团开发的一个使用Vue.js开发小程序的前端框架, 目前支持微信小程序、百度智能小程序,头条小程序和支付宝小程序。框架基于Vue.js, 修改了的运行时框架runtime和代码编译器compiler实现, 使其可运行在小程序环境中, 从而为小程序开发引入了Vue.js开发体验。
    ·官网地址
    ·Git hub
    备注:完备的Vue开发体验, 井且支持多平台的小程序开发, 推荐使用

    WeUI

    WeUI是一套同微信原生视觉体验一致的基础样式库, 由微信官方设计团队为微信内网页和微信小程序量身设计, 令用户的使用感知更加统一。包含button、cell、dialog、toast、article、icon等各式元素。

    • 官网地址
    • Github

    三、了解前后分离的演变史

    为什么需要前后分离

    3.1、后端为主的MVC时代

    为了降低开发的复杂度, 以后端为出发点, 比如:Struts、Spring MVC等框架的使用, 就是后端的MVC时代;
    SpringMVC流程为例:
    在这里插入图片描述

    • 发起请求到前端控制器(Dispatcher Servlet)
    • 前端控制器请求HandlerMapping查找Handler,可以根据xml配置、注解进行查找
    • 处理器映射器HandlerMapping向前端控制器返回Handler
    • 前端控制器调用处理器适配器去执行Handler
    • 处理器适配器去执行Handler
    • Handler执行完成给适配器返回ModelAndView
    • 处理器适配器向前端控制器返回ModelAndViewModelAndViewSpringMvc框架的一个底层对象,包括ModelView
    • 前端控制器请求视图解析器去进行视图解析,根据逻辑视图名解析成真正的视图(JSP)
    • 视图解析器向前端控制器返回View
    • 前端控制器进行视图渲染,视图渲染将模型数据(在ModelAndView对象中)填充到request
    • 前端控制器向用户响应结果
      优点
      MVC是一个非常好的协作模式, 能够有效降低代码的耦合度从架构上能够让开发者明白代码应该写在哪里。为了让View更纯粹, 还可以使用Thyme leaf、Frree marker等模板引擎, 使模板里无法写入Java代码, 让前后端分工更加清晰。
      缺点
    • 前端开发重度依赖开发环境,开发效率低,这种架构下,前后端协作有两种模式:
      • 第一种是前端写DEMO, 写好后, 让后端去套模板。好处是DEMO可以本地开发, 很高效。不足是还需要后端套模板,有可能套错,套完后还需要前端确定,来回沟通调整的成本比较大;
      • 另一种协作模式是前端负责浏览器端的所有开发和服务器端的View层模板开发。好处是UI相关的代码都是前端去写就好,后端不用太关注,不足就是前端开发重度绑定后端环境,环境成为影响前端开发效率的重要因素。
    • 前后端职责纠缠不清:模板引擎功能强大,依旧可以通过拿到的上下文变量来实现各种业务逻辑。这样,只要前端弱势一点,往往就会被后端要求在模板层写出不少业务代码,还有一个很大的灰色地带是Controller, 页面路由等功能本应该是前端最关注的, 但却是由后端来实现。Controller本身与Model往往也会纠缠不清,看了让人咬牙的业务代码经常会出现在Controller层。这些问题不能全归结于程序员的素养, 否则JSP就够了。
    • 对前端发挥的局限性:性能优化如果只在前端做空间非常有限,于是我们经常需要后端合作,但由于后端框架限制,我们很难使用[Comet】、【Big Pipe】等技术方案来优化性能。
      注:在这期间(2005年以前) , 包括早期的JSP、PHP可以称之为Web 1.0时代。在这里想说一句, 如果你是一名Java初学者, 请你不要再把一些陈旧的技术当回事了, 比如JSP, 因为时代在变、技术在变、什么都在变(引用扎克伯格的一句话:唯一不变的是变化本身);当我们去给大学做实训时,有些同学会认为我们没有讲什么干货,其实不然,只能说是你认知里的干货对于市场来说早就过时了而已

    3.2、基于AJAX带来的SPA时代

    时间回到2005年A OAX(Asynchronous JavaScript And XML, 异步JavaScript和XML,老技术新用法)被正式提出并开始使用CDN作为静态资源存储, 于是出现了JavaScript王者归来(在这之前JS都是用来在网页上贴狗皮膏药广告的) 的SPA(Single Page Application) 单页面应用时代。
    在这里插入图片描述
    优点
    这种模式下, **前后端的分工非常清晰, 前后端的关键协作点是AJAX接口。**看起来是如此美妙, 但回过头来看看的话, 这与JSP时代区别不大。复杂度从服务端的JSP里移到了浏览器的JavaScript,浏览器端变得很复杂。类似Spring MVC, 这个时代开始出现浏览器端的分层架构
    在这里插入图片描述
    缺点

    • 前后端接口的约定:如果后端的接口一塌糊涂,如果后端的业务模型不够稳定,那么前端开发会很痛苦;不少团队也有类似尝试,通过接口规则、接口平台等方式来做。有了和后端一起沉淀的接口规则,还可以用来模拟数据,使得前后端可以在约定接口后实现高效并行开发。
    • 前端开发的复杂度控制:SPA应用大多以功能交互型为主,JavaScript代码过十万行很正常。大量JS代码的组织,与View层的绑定等,都不是容易的事情。

    3.3、前端为主的MV*时代

    此处的MV*模式如下:

    • MVC(同步通信为主) :Model、View、Controller
    • MVP(异步通信为主) :Model、View、Presenter
    • MVVM(异步通信为主):Model、View、View Model为了降低前端开发复杂度,涌现了大量的前端框架,比如:Angular JSReactVue.jsEmber JS等, 这些框架总的原则是先按类型分层, 比如Templates、Controllers、Models, 然后再在层内做切分,如下图:

    在这里插入图片描述

    优点

    • 前后端职责很清晰:前端工作在浏览器端,后端工作在服务端。清晰的分工,可以让开发并行,测试数据的模拟不难, 前端可以本地开发。后端则可以专注于业务逻辑的处理, 输出RESTful等接口。
    • 前端开发的复杂度可控:前端代码很重,但合理的分层,让前端代码能各司其职。这一块蛮有意思的,简单如模板特性的选择,就有很多很多讲究。并非越强大越好,限制什么,留下哪些自由,代码应该如何组织,所有这一切设计,得花一本书的厚度去说明。
    • 部署相对独立:可以快速改进产品体验缺点
    • 代码不能复用。比如后端依旧需要对数据做各种校验,校验逻辑无法复用浏览器端的代码。如果可以复用,那么后端的数据校验可以相对简单化。
    • 全异步, 对SEO不利。往往还需要服务端做同步渲染的降级方案。
    • 性能并非最佳,特别是移动互联网环境下。
    • SPA不能满足所有需求, 依旧存在大量多页面应用。URL Design需要后端配合, 前端无法完全掌控。

    3.4、Node JS带来的全栈时代

    前端为主的MV*模式解决了很多很多问题, 但如上所述, 依旧存在不少不足之处。随着Node JS的兴起, JavaScript开始有能力运行在服务端。这意味着可以有一种新的研发模式:
    在这里插入图片描述
    在这种研发模式下,前后端的职责很清晰。对前端来说,两个UI层各司其职:

    • Front-end Ul layer处理浏览器层的展现逻辑。通过CSS渲染样式, 通过JavaScript添加交互功能, HTML的生成也可以放在这层, 具体看应用场景。
    • Back-end Ul layer处理路由、模板、数据获取、Cookie等。通过路由, 前端终于可以自主把控URL Design, 这样无论是单页面应用还是多页面应用, 前端都可以自由调控。后端也终于可以摆脱对展现的强关注,转而可以专心于业务逻辑层的开发。
      通过Node, WebServer层也是JavaScript代码, 这意味着部分代码可前后复用, 需要SEO的场景可以在服务端同步渲染,由于异步请求太多导致的性能问题也可以通过服务端来缓解。前一种模式的不足,通过这种模式几乎都能完美解决掉。
      与JSP模式相比, 全栈模式看起来是一种回归, 也的确是一种向原始开发模式的回归, 不过是一种螺旋上升式的回归。
      基于Node JS的全栈模式, 依旧面临很多挑战:
    • 需要前端对服务端编程有更进一步的认识。比如TCP/IP等网络知识的掌握。
    • Node JS层与Java层的高效通信。Node JS模式下, 都在服务器端, RESTful HTTP通信未必高效, 通过SOAP等方式通信更高效。一切需要在验证中前行。
    • 对部著、运维层面的熟练了解,需要更多知识点和实操经验。
    • 大量历史遗留问题如何过渡。这可能是最大最大的阻力。
      注:看到这里,相信很多同学就可以理解,为什么我总在课堂上说:“前端想学后台很难,而我们后端程序员学任何东西都很简单”;就是因为我们后端程序员具备相对完善的知识体系。
      全栈!So Easy!

    3.5、总结

    综上所述,模式也好,技术也罢,没有好坏优劣之分,只有适合不适合;前后分离的开发思想主要是基于Soc(关注度分离原则),上面种种模式,都是让前后端的职责更清晰,分工更合理高效。

    四、第一个Vue程序

    4.1、什么是MVVM

    MVVM(Model-View-ViewModel)是一种软件设计模式,由微软WPF(用于替代WinForm,以前就是用这个技术开发桌面应用程序的)和Silverlight(类似于Java Applet,简单点说就是在浏览器上运行WPF)的架构师Ken Cooper和Ted Peters开发,是一种简化用户界面的事件驱动编程方式。由John Gossman(同样也是WPF和Sliverlight的架构师)与2005年在他的博客上发表。

    MVVM源自于经典的MVC(Model-View-Controller)模式。MVVM的核心是ViewModel层,负责转换Model中的数据对象来让数据变得更容易管理和使用。其作用如下:

    • 该层向上与视图层进行双向数据绑定
    • 向下与Model层通过接口请求进行数据交互

    在这里插入图片描述

    MVVM已经相当成熟了,主要运用但不仅仅在网络应用程序开发中。当下流行的MVVM框架有Vue.jsAnfular JS

    4.2、为什么要使用MVVM

    MVVM模式和MVC模式一样,主要目的是分离视图(View)和模型(Model),有几大好处

    • 低耦合:视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的View上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
    • 可复用:你可以把一些视图逻辑放在一个ViewModel里面,让很多View重用这段视图逻辑。
    • 独立开发:开发人员可以专注于业务逻辑和数据的开发(ViewMode),设计人员可以专注于页面设计。
    • 可测试:界面素来是比较难以测试的,而现在测试可以针对ViewModel来写。
    在这里插入图片描述

    (1)View

    View是视图层, 也就是用户界面。前端主要由HTH L和csS来构建, 为了更方便地展现vi eu to del或者Hodel层的数据, 已经产生了各种各样的前后端模板语言, 比如FreeMarker,Thyme leaf等等, 各大MV VM框架如Vue.js.Angular JS, EJS等也都有自己用来构建用户界面的内置模板语言。

    (2)Model

    Model是指数据模型, 泛指后端进行的各种业务逻辑处理和数据操控, 主要围绕数据库系统展开。这里的难点主要在于需要和前端约定统一的接口规则

    (3)ViewModel

    ViewModel是由前端开发人员组织生成和维护的视图数据层。在这一层, 前端开发者对从后端获取的Model数据进行转换处理, 做二次封装, 以生成符合View层使用预期的视图数据模型。
      需要注意的是View Model所封装出来的数据模型包括视图的状态和行为两部分, 而Model层的数据模型是只包含状态的

    • 比如页面的这一块展示什么,那一块展示什么这些都属于视图状态(展示)
    • 页面加载进来时发生什么,点击这一块发生什么,这一块滚动时发生什么这些都属于视图行为(交互)

    视图状态和行为都封装在了View Model里。这样的封装使得View Model可以完整地去描述View层。由于实现了双向绑定, View Model的内容会实时展现在View层, 这是激动人心的, 因为前端开发者再也不必低效又麻烦地通过操纵DOM去更新视图。
      MVVM框架已经把最脏最累的一块做好了, 我们开发者只需要处理和维护View Model, 更新数据视图就会自动得到相应更新,真正实现事件驱动编程
      View层展现的不是Model层的数据, 而是ViewModel的数据, 由ViewModel负责与Model层交互, 这就完全解耦了View层和Model层, 这个解耦是至关重要的, 它是前后端分离方案实施的重要一环。

    4.3、Vue

    Vue(读音/vju/, 类似于view) 是一套用于构建用户界面的渐进式框架, 发布于2014年2月。与其它大型框架不同的是, Vue被设计为可以自底向上逐层应用。Vue的核心库只关注视图层, 不仅易于上手, 还便于与第三方库(如:vue-router,vue-resource,vue x) 或既有项目整合。

    (1)MVVM模式的实现者

    • Model:模型层, 在这里表示JavaScript对象
    • View:视图层, 在这里表示DOM(HTML操作的元素)
    • ViewModel:连接视图和数据的中间件, Vue.js就是MVVM中的View Model层的实现者

    在MVVM架构中, 是不允许数据和视图直接通信的, 只能通过ViewModel来通信, 而View Model就是定义了一个Observer观察者

    • ViewModel能够观察到数据的变化, 并对视图对应的内容进行更新
    • ViewModel能够监听到视图的变化, 并能够通知数据发生改变

    至此, 我们就明白了, Vue.js就是一个MV VM的实现者, 他的核心就是实现了DOM监听与数据绑定

    (2)为什么要使用Vue.js

    • 轻量级, 体积小是一个重要指标。Vue.js压缩后有只有20多kb(Angular压缩后56kb+,React压缩后44kb+)
    • 移动优先。更适合移动端, 比如移动端的Touch事件
    • 易上手,学习曲线平稳,文档齐全
    • 吸取了Angular(模块化) 和React(虚拟DOM) 的长处, 并拥有自己独特的功能,如:计算属性
    • 开源,社区活跃度高

    4.4、第一个Vue程序

    【说明】IDEA可以安装Vue的插件!
      注意:Vue不支持IE 8及以下版本, 因为Vue使用了IE 8无法模拟的ECMAScript 5特性。但它支持所有兼容ECMAScript 5的浏览器。

    (1)下载地址

    • 开发版本
      • 包含完整的警告和调试模式:https://yuejs.org/js/vue.js
      • 删除了警告, 30.96KB min+gzip:https://vuejs.org/js/vue.min.js
    • CDN
      • <script src=“https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js”></script>
      • <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>

    (2)代码编写

    Vue.js的核心是实现了MVVM模式, 她扮演的角色就是View Model层, 那么所谓的第一个应用程序就是展示她的数据绑定功能,操作流程如下:
      1、创建一个HTML文件

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    </body>
    </html>
    

    2、引入Vue.js

    <!--1.导入Vue.js-->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
    12
    

    3、创建一个Vue实例

    <script type="text/javascript">
        var vm = new Vue({
            el:"#app",
            /*Model:数据*/
            data:{
                message:"hello,vue!"
            }
        });
    </script>
    

    说明:

    • el: '#vue':绑定元素的ID
    • data:{message:'Hello Vue!'}:数据对象中有一个名为message的属性,并设置了初始值 Hello Vue!

    4、将数据绑定到页面元素

    <!--view层,模板-->
    <div id="app">
        {{message}}
    </div>
    

    说明:只需要在绑定的元素中使用双花括号将Vue创建的名为message属性包裹起来, 即可实现数据绑定功能, 也就实现了View Model层所需的效果, 是不是和EL表达式非常像?

    (3)完整的HTML

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    
    </head>
    <body>
    
    <!--view层,模板-->
    <div id="app">
        {{message}}
    </div>
    
    <!--1.导入Vue.js-->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
    <script type="text/javascript">
        var vm = new Vue({
            el:"#app",
            /*Model:数据*/
            data:{
                message:"hello,vue!"
            }
        });
    </script>
    </body>
    </html>
    

    (4)测试

    为了能够更直观的体验Vue带来的数据绑定功能, 我们需要在浏览器测试一番, 操作流程如下:
      1、在浏览器上运行第一个Vue应用程序, 进入开发者工具
      2、在控制台输入vm.message=‘HelloWorld’, 然后回车, 你会发现浏览器中显示的内容会直接变成HelloWorld
      此时就可以在控制台直接输入vm.message来修改值, 中间是可以省略data的, 在这个操作中, 我并没有主动操作DOM, 就让页面的内容发生了变化, 这就是借助了Vue的数据绑定功能实现的; MV VM模式中要求View Model层就是使用观察者模式来实现数据的监听与绑定, 以做到数据与视图的快速响应。

    五、基础语法指令

    4.1、v-bind

    我们已经成功创建了第一个Vue应用!看起来这跟渲染一个字符串模板非常类似, 但是Vue在背后做了大量工作。现在数据和DOM已经被建立了关联, 所有东西都是响应式的。我们在控制台操作对象属性,界面可以实时更新!
      我们还可以使用v-bind来绑定元素特性!
      上代码

    <!DOCTYPE html>
    <html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    
    </head>
    <body>
    
    <!--view层,模板-->
    <div id="app">
        <span v-bind:title="message">
        鼠标悬停几秒钟查看此处动态绑定的提示信息!
      </span>
    </div>
    
    <!--1.导入Vue.js-->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
    <script type="text/javascript">
        var vm = new Vue({
            el:"#app",
            /*Model:数据*/
            data:{
                message: '页面加载于 ' + new Date().toLocaleString()
            }
        });
    </script>
    </body>
    </html>
    

    你看到的v-bind等被称为指令。指令带有前缀v以表示它们是Vue提供的特殊特性。可能你已经猜到了, 它们会在渲染的DOM上应用特殊的响应式行为在这里,该指令的意思是:“将这个元素节点的title特性和Vue实例的message属性保持一致”。
      如果你再次打开浏览器的JavaScript控制台, 输入app, message=‘新消息’,就会再一次看到这个绑定了title特性的HTML已经进行了更新。

    4.2、v-if, v-else

    什么是条件判断语句,就不需要我说明了吧,以下两个属性!

    • v-if
    • v-else

    上代码

    <!DOCTYPE html>
    <html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <!--view层,模板-->
    <div id="app">
        <h1 v-if="ok">Yes</h1>
        <h1 v-else>No</h1>
       
    </div>
    
    <!--1.导入Vue.js-->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
    <script type="text/javascript">
        var vm = new Vue({
            el:"#app",
            /*Model:数据*/
            data:{
                type: true
            }
        });
    </script>
    </body>
    </html>
    

    测试:
    1.在浏览器上运行,打开控制台!
    2.在控制台输入vm.ok=false然后回车,你会发现浏览器中显示的内容会直接变成NO
      注:使用v-*属性绑定数据是不需要双花括号包裹的

    v-else-if

    • v-if
    • v-else-if
    • v-else
      注:===三个等号在JS中表示绝对等于(就是数据与类型都要相等)上代码:
    <!DOCTYPE html>
    <html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <!--view层,模板-->
    <div id="app">
        <h1 v-if="type==='A'">A</h1>
        <h1 v-else-if="type==='B'">B</h1>
        <h1 v-else-if="type==='D'">D</h1>
        <h1 v-else>C</h1>
    
    </div>
    
    <!--1.导入Vue.js-->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
    <script type="text/javascript">
        var vm = new Vue({
            el:"#app",
            /*Model:数据*/
            data:{
                type: 'A'
            }
        });
    </script>
    </body>
    </html>
    

    4.3、v-for

    • v-for

    格式说明

    <div id="app">
        <li v-for="(item,index) in items">
            {{item.message}}---{{index}}
        </li>
    
    </div>
    123456
    

    注:items是数组,item是数组元素迭代的别名。我们之后学习的Thymeleaf模板引擎的语法和这个十分的相似!
      上代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <!--view层,模板-->
    <div id="app">
        <li v-for="(item,index) in items">
            {{item.message}}---{{index}}
        </li>
    
    </div>
    
    <!--1.导入Vue.js-->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
    <script type="text/javascript">
        var vm = new Vue({
            el:"#app",
            /*Model:数据*/
            data:{
                items:[
                    {message:'狂神说Java'},
                    {message:'狂神说前端'},
                    {message:'狂神说运维'}
                ]
            }
        });
    </script>
    </body>
    </html>
    

    测试:在控制台输入vm.items.push({message:'狂神说运维'}),尝试追加一条数据,你会发现浏览器中显示的内容会增加一条狂神说运维.

    4.4、v-on

    v-on监听事件
     emsp;事件有Vue的事件、和前端页面本身的一些事件!我们这里的click是vue的事件, 可以绑定到Vue中的methods中的方法事件!
      上代码

    <!DOCTYPE html>
    <html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    <div id="app">
        <button v-on:click="sayHi">点我</button>
    </div>
    
    <script src="../js/vue.js"></script>
    <script type="text/javascript">
        var vm = new Vue({
            el:"#app",
            data:{
                message:'Hello World'
            },
            methods:{
                sayHi:function(event){
                    //'this'在方法里面指向当前Vue实例
                    alert(this.message);
                }
            }
        });
    </script>
    </body>
    </html>
    

    点击测试
      Vue还有一些基本的使用方式, 大家有需要的可以再跟着官方文档看看, 因为这些基本的指令几乎我们都见过了,一通百通!掌握学习的方式!

    六、表单双绑、组件

    6.1、什么是双向数据绑定

    Vue.js是一个MV VM框架, 即数据双向绑定, 即当数据发生变化的时候, 视图也就发生变化, 当视图发生变化的时候,数据也会跟着同步变化。这也算是Vue.js的精髓之处了。
      值得注意的是,我们所说的数据双向绑定,一定是对于UI控件来说的非UI控件不会涉及到数据双向绑定。单向数据绑定是使用状态管理工具的前提。如果我们使用vue x那么数据流也是单项的,这时就会和双向数据绑定有冲突。

    (1)为什么要实现数据的双向绑定

    Vue.js中,如果使用vuex, 实际上数据还是单向的, 之所以说是数据双向绑定,这是用的UI控件来说, 对于我们处理表单, Vue.js的双向数据绑定用起来就特别舒服了。即两者并不互斥,在全局性数据流使用单项,方便跟踪;局部性数据流使用双向,简单易操作。

    6.2、在表单中使用双向数据绑定

    你可以用v-model指令在表单、及元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇, 但v-model本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
      注意:v-model会忽略所有表单元素的valuecheckedselected特性的初始值而总是将Vue实例的数据作为数据来源。你应该通过JavaScript在组件的data选项中声明初始值!

    (1)单行文本

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <div id="app">
        输入的文本:<input type="text" v-model="message" value="hello">{{message}}
    </div>
    
    <script src="../js/vue.js"></script>
    <script type="text/javascript">
        var vm = new Vue({
            el:"#app",
            data:{
                message:""
            }
        });
    </script>
    </body>
    </html>
    

    (2)多行文本

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <div id="app">
       多行文本:<textarea v-model="pan"></textarea>&nbsp;&nbsp;多行文本是:{{pan}}
    </div>
    
    <script src="../js/vue.js"></script>
    <script type="text/javascript">
        var vm = new Vue({
            el:"#app",
            data:{
                message:"Hello hello!"
            }
        });
    </script>
    </body>
    </html>
    

    (3)单复选框

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    <div id="app">
        单复选框:
        <input type="checkbox" id="checkbox" v-model="checked">
        &nbsp;&nbsp;
        <label for="checkbox">{{checked}}</label>
    </div>
    
    <script src="../js/vue.js"></script>
    <script type="text/javascript">
        var vm = new Vue({
            el:"#app",
            data:{
                checked:false
            }
        });
    </script>
    </body>
    </html>
    

    4多复选框

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    <div id="app">
        多复选框:
        <input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
        &nbsp;&nbsp;
        <label for="jack">Jack</label>
        <input type="checkbox" id="join" value="Join" v-model="checkedNames">
        &nbsp;&nbsp;
        <label for="join">Jack</label>
        <input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
        &nbsp;&nbsp;
        <label for="mike">Mike</label>
        <span>选中的值:{{checkedNames}}</span>
    </div>
    
    <script src="../js/vue.js"></script>
    <script type="text/javascript">
        var vm = new Vue({
            el:"#app",
            data:{
                checkedNames:[]
            }
        });
    </script>
    </body>
    </html>
    

    (6)单选按钮

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    <div id="app">
        单选框按钮
        <input type="radio" id="one" value="One" v-model="picked">
        <label for="one">One</label>
        <input type="radio" id="two" value="Two" v-model="picked">
        <label for="two">Two</label>
        <span>选中的值:{{picked}}</span>
    </div>
    
    <script src="../js/vue.js"></script>
    <script type="text/javascript">
        var vm = new Vue({
            el:"#app",
            data:{
                picked:'Two'
            }
        });
    </script>
    </body>
    </html>
    

    (7)下拉框

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <div id="app">
    <!--    性别:
        <input type="radio" name="sex" value="男" v-model="pan">男
        <input type="radio" name="sex" value="女" v-model="pan">女
        <p>选中了:{{pan}}</p>-->
    
        下拉框:
        <select v-model="pan">
            <option value="" disabled>---请选择---</option>
            <option>A</option>
            <option>B</option>
            <option>C</option>
            <option>D</option>
        </select>
        <span>value:{{pan}}</span>
    
    
    
    </div>
    
    <script src="../js/vue.js"></script>
    <script type="text/javascript">
        var vm = new Vue({
            el:"#app",
            data:{
                pan:"A"
            }
        });
    </script>
    </body>
    </html>
    

    注意:v-model表达式的初始值未能匹配任何选项,元系将被渲染为“未选中”状态。 在iOS中, 这会使用户无法选择第一个选项,因为这样的情况下,iOS不会触发change事件。因此,更推荐像上面这样提供一个值为空的禁用选项。

    6.3、什么是组件

    组件是可复用的Vue实例, 说白了就是一组可以重复使用的模板, 跟JSTL的自定义标签、Thymelealth:fragment等框架有着异曲同工之妙,通常一个应用会以一棵嵌套的组件树的形式来组织:
    在这里插入图片描述
    在这里插入图片描述

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

    (1)第一个Vue组件

    注意:在实际开发中,我们并不会用以下方式开发组件,而是采用vue-cli创建,vue模板文件的方式开发,以下方法只是为了让大家理解什么是组件。
      使用Vue.component()方法注册组件,格式如下:

    <div id="app">
      <pan></pan>
    </div>
    
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
    <script type="text/javascript">
        //先注册组件
        Vue.component("pan",{
            
            template:'<li>Hello</li>'
    
        });
        //再实例化Vue
        var vm = new Vue({
            el:"#app",
        });
    </script>
    

    说明:

    • Vue.component():注册组件
    • pan:自定义组件的名字
    • template:组件的模板

    (2)使用props属性传递参数

    像上面那样用组件没有任何意义,所以我们是需要传递参数到组件的,此时就需要使用props属性了!
      注意:默认规则下props属性里的值不能为大写;

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    <div id="app">
        <!--组件:传递给组件中的值:props-->
      <pan v-for="item in items" v-bind:panh="item"></pan>
    </div>
    
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
    <script type="text/javascript">
        //定义组件
        Vue.component("pan",{
            props:['panh'],
            template:'<li>{{panh}}</li>'
    
        });
        var vm = new Vue({
            el:"#app",
            data:{
                items:["java","Linux","前端"]
            }
        });
    </script>
    </body>
    </html>
    

    说明

    • v-for="item in items":遍历Vue实例中定义的名为items的数组,并创建同等数量的组件
    • v-bind:panh="item":将遍历的item项绑定到组件中props定义名为item属性上;= 号左边的panhprops定义的属性名,右边的为item in items 中遍历的item项的值

    七、Axios异步通信

    7.1、什么是Axios

    Axios是一个开源的可以用在浏览器端和Node JS的异步通信框架, 她的主要作用就是实现AJAX异步通信,其功能特点如下:

    • 从浏览器中创建XMLHttpRequests
    • 从node.js创建http请求
    • 支持Promise API[JS中链式编程]
    • 拦截请求和响应
    • 转换请求数据和响应数据
    • 取消请求
    • 自动转换JSON数据
    • 客户端支持防御XSRF(跨站请求伪造)

    GitHub:https://github.com/axios/axios
      中文文档:http://www.axios-js.com/

    7.2、为什么要使用Axios

    由于Vue.js是一个视图层框架并且作者(尤雨溪) 严格准守SoC(关注度分离原则)所以Vue.js并不包含AJAX的通信功能, 为了解决通信问题, 作者单独开发了一个名为vue-resource的插件, 不过在进入2.0版本以后停止了对该插件的维护并推荐了Axios框架。少用jQuery, 因为它操作Dom太频繁!

    7.3、第一个Axios应用程序

    咱们开发的接口大部分都是采用JSON格式, 可以先在项目里模拟一段JSON数据, 数据内容如下:创建一个名为data.json的文件并填入上面的内容, 放在项目的根目录下

    {
      "name": "狂神说Java",
      "url": "https://blog.kuangstudy.com",
      "page": 1,
      "isNonProfit": true,
      "address": {
        "street": "含光门",
        "city": "陕西西安",
        "country": "中国"
      },
      "links": [
        {
          "name": "bilibili",
          "url": "https://space.bilibili.com/95256449"
        },
        {
          "name": "狂神说Java",
          "url": "https://blog.kuangstudy.com"
        },
        {
          "name": "百度",
          "url": "https://www.baidu.com/"
        }
      ]
    }
    

    测试代码

    <!DOCTYPE html>
    <html lang="en" xmlns:v-binf="http://www.w3.org/1999/xhtml">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <!--v-cloak 解决闪烁问题-->
        <style>
            [v-cloak]{
                display: none;
            }
        </style>
    </head>
    <body>
    <div id="vue">
        <div>地名:{{info.name}}</div>
        <div>地址:{{info.address.country}}--{{info.address.city}}--{{info.address.street}}</div>
        <div>链接:<a v-binf:href="info.url" target="_blank">{{info.url}}</a> </div>
    </div>
    
    <!--引入js文件-->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script type="text/javascript">
        var vm = new Vue({
            el:"#vue",
            //data:属性:vm
            data(){
                return{
                    info:{
                        name:null,
                        address:{
                            country:null,
                            city:null,
                            street:null
                        },
                        url:null
                    }
                }
            },
            mounted(){//钩子函数
                axios
                    .get('data.json')
                    .then(response=>(this.info=response.data));
            }
        });
    </script>
    </body>
    </html>
    

    说明:

    1. 在这里使用了v-bind将a:href的属性值与Vue实例中的数据进行绑定
    2. 使用axios框架的get方法请求AJAX并自动将数据封装进了Vue实例的数据对象中
    3. 我们在data中的数据结构必须和Ajax响应回来的数据格式匹配!

    7.4、Vue的生命周期

    官方文档:https://cn.vuejs.org/v2/guide/instance.html#生命周期图示
      Vue实例有一个完整的生命周期,也就是从开始创建初女台化数据、编译模板、挂载DOM、渲染一更新一渲染、卸载等一系列过程,我们称这是Vue的生命周期。通俗说就是Vue实例从创建到销毁的过程,就是生命周期。
      在Vue的整个生命周期中,它提供了一系列的事件,可以让我们在事件触发时注册JS方法,可以让我们用自己注册的JS方法控制整个大局,在这些事件响应方法中的this直接指向的是Vue的实例。
    在这里插入图片描述

    八、计算属性、内容分发、自定义事件

    1、什么是计算属性

    计算属性的重点突出在属性两个字上(属性是名词),首先它是个属性其次这个属性有计算的能力(计算是动词),这里的计算就是个函数:简单点说,它就是一个能够将计算结果缓存起来的属性(将行为转化成了静态的属性),仅此而已;可以想象为缓存!
      上代码

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <!--view层,模板-->
    <div id="app">
        <p>currentTime1:{{currentTime1()}}</p>
        <p>currentTime2:{{currentTime2}}</p>
    </div>
    
    <!--1.导入Vue.js-->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
    <script type="text/javascript">
        var vm = new Vue({
            el:"#app",
            data:{
              message:"pan"
            },
            methods:{
                currentTime1:function(){
                    return Date.now();//返回一个时间戳
                }
            },
            computed:{
                currentTime2:function(){//计算属性:methods,computed方法名不能重名,重名之后,只会调用methods的方法
                    this.message;
                    return Date.now();//返回一个时间戳
                }
            }
        });
    </script>
    </body>
    </html>
    

    注意:methods和computed里的东西不能重名
    说明:

    • methods:定义方法, 调用方法使用currentTime1(), 需要带括号

    • computed:定义计算属性, 调用属性使用currentTime2, 不需要带括号:this.message是为了能够让currentTime2观察到数据变化而变化

    • 如何在方法中的值发生了变化,则缓存就会刷新!可以在控制台使用vm.message=”q in jiang", 改变下数据的值,再次测试观察效果!

      结论:
        调用方法时,每次都需要讲行计算,既然有计算过程则必定产生系统开销,那如果这个结果是不经常变化的呢?此时就可以考虑将这个结果缓存起来,采用计算属性可以很方便的做到这点,计算属性的主要特性就是为了将不经常变化的计算结果进行缓存,以节约我们的系统开销;

    8.2、内容分发

    Vue.js中我们使用<slot>元素作为承载分发内容的出口,作者称其为插槽,可以应用在组合组件的场景中;

    测试

    比如准备制作一个待办事项组件(todo) , 该组件由待办标题(todo-title) 和待办内容(todo-items)组成,但这三个组件又是相互独立的,该如何操作呢?
      第一步定义一个待办事项的组件

    <div id="app">
        <todo></todo>
    </div>
    <!--1.导入Vue.js-->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
    <script type="text/javascript">
        Vue.component('todo',{
            template:'<div>\
                    <div>代办事项</div>\
                    <ul>\
                        <li>学习狂神说Java</li>\
                    </ul>\
                </div>'
        })
    </script>
    

    第二步 我们需要让,代办事项的标题和值实现动态绑定,怎么做呢?我们可以留一个插槽!
      1-将上面的代码留出一个插槽,即slot

     Vue.component('todo',{
            template:'<div>\
                    <slot name="todo-title"></slot>\
                    <ul>\
                        <slot name="todo-items"></slot>\
                    </ul>\
                </div>'
        });
    

    2-定义一个名为todo-title的待办标题组件 和 todo-items的待办内容组件

    Vue.component('todo-title',{
            props:['title'],
            template:'<div>{{title}}</div>'
        });
       
    12345
    //这里的index,就是数组的下标,使用for循环遍历的时候,可以循环出来!
        Vue.component("todo-items",{
            props:["item","index"],
            template:"<li>{{index+1}},{{item}}</li>"
        });
    

    3-实例化Vue并初始化数据

     var vm = new Vue({
            el:"#vue",
            data:{
                todoItems:['test1','test2','test3']
            }
        });
    

    4-将这些值,通过插槽插入

    <div id="vue">
        <todo>
            <todo-title slot="todo-title" title="秦老师系列课程"></todo-title>
            <!--<todo-items slot="todo-items" v-for="{item,index} in todoItems" v-bind:item="item"></todo-items>-->
            <!--如下为简写-->
            <todo-items slot="todo-items" v-for="item in todoItems" :item="item"></todo-items
        </todo>
    </div>
    

    说明:我们的todo-title和todo-items组件分别被分发到了todo组件的todo-title和todo-items插槽中
      完整代码如下:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <!--view层,模板-->
    <div id="vue">
        <todo>
            <todo-title slot="todo-title" title="title"></todo-title>
            <!--<todo-items slot="todo-items" v-for="{item,index} in todoItems" v-bind:item="item"></todo-items>-->
            <!--如下为简写-->
            <todo-items slot="todo-items" v-for="item in todoItems" :item="item"></todo-items
        </todo>
    </div>
    <!--1.导入Vue.js-->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
    <script type="text/javascript">
        Vue.component('todo',{
            template:'<div>\
                    <slot name="todo-title"></slot>\
                    <ul>\
                        <slot name="todo-items"></slot>\
                    </ul>\
                </div>'
        });
        Vue.component('todo-title',{
            props:['title'],
            template:'<div>{{title}}</div>'
        });
        //这里的index,就是数组的下标,使用for循环遍历的时候,可以循环出来!
        Vue.component("todo-items",{
            props:["item","index"],
            template:"<li>{{index+1}},{{item}}</li>"
        });
    
        var vm = new Vue({
            el:"#vue",
            data:{
                title:"秦老师系列课程",
                todoItems:['test1','test2','test3']
            }
        });
    </script>
    </body>
    </html>
    

    8.3、自定义事件

    通以上代码不难发现,数据项在Vue的实例中, 但删除操作要在组件中完成, 那么组件如何才能删除Vue实例中的数据呢?此时就涉及到参数传递与事件分发了, Vue为我们提供了自定义事件的功能很好的帮助我们解决了这个问题; 使用this.$emit(‘自定义事件名’, 参数) , 操作过程如下:
      1-在vue的实例中增加了methods对象并定义了一个名为removeTodoltems的方法

    var vm = new Vue({
            el:"#vue",
            data:{
                title_text:"秦老师系列课程",
                todoItems:['test1','test2','test3']
            },
            methods:{
                removeItems:function(index){
                    console.log("删除了"+this.todoItems[index]+"OK");
                    //splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目,其中index
                    this.todoItems.splice(index,1);
                }
            }
        });
    

    2-修改todo-items待办内容组件的代码,增加一个删除按钮,并且绑定事件!

     Vue.component("todo-items",{
            props:["item_p","index_p"],
            template:"<li>{{index_p+1}},{{item_p}} <button @click='remove'>删除</button></li>",
            methods:{
                remove:function (index) {
                //这里的remove是自定义事件名称,需要在HTML中使用v-on:remove的方式
                    //this.$emit 自定义事件分发
                    this.$emit('remove',index);
                }
            }
        });
    

    3-修改todo-items待办内容组件的HTML代码,增加一个自定义事件,比如叫remove,可以和组件的方法绑定,然后绑定到vue的方法!

    <!--增加了v-on:remove="removeTodoItems(index)"自定义事件,该组件会调用Vue实例中定义的-->
    <todo-items slot="todo-items" v-for="(item,index) in todoItems"
                        :item_p="item" :index_p="index" v-on:remove="removeItems(index)" :key="index"></todo-items>
    

    对上一个代码进行修改,实现删除功能

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <!--view层,模板-->
    <div id="vue">
        <todo>
            <todo-title slot="todo-title" :title="title_text"></todo-title>
            <!--<todo-items slot="todo-items" v-for="(item,index) in todoItems" v-bind:item="item"></todo-items>-->
            <!--如下为简写-->
            <todo-items slot="todo-items" v-for="(item,index) in todoItems"
                        :item_p="item" :index_p="index" v-on:remove="removeItems(index)" :key="index"></todo-items>
        </todo>
    </div>
    <!--1.导入Vue.js-->
    <script src="../js/vue.js"></script>
    <script type="text/javascript">
        Vue.component('todo',{
            template:'<div>\
                    <slot name="todo-title"></slot>\
                    <ul>\
                        <slot name="todo-items"></slot>\
                    </ul>\
                </div>'
        });
        Vue.component('todo-title',{
            props:['title'],
            template:'<div>{{title}}</div>'
        });
        //这里的index,就是数组的下标,使用for循环遍历的时候,可以循环出来!
        Vue.component("todo-items",{
            props:["item_p","index_p"],
            template:"<li>{{index_p+1}},{{item_p}} <button @click='remove_methods'>删除</button></li>",
            methods:{
                remove_methods:function (index) {
                    //this.$emit 自定义事件分发
                    this.$emit('remove',index);
                }
            }
        });
    
        var vm = new Vue({
            el:"#vue",
            data:{
                title_text:"秦老师系列课程",
                todoItems:['test1','test2','test3']
            },
            methods:{
                removeItems:function(index){
                    console.log("删除了"+this.todoItems[index]+"OK");
                    this.todoItems.splice(index,1);
                }
            }
        });
    </script>
    </body>
    </html>
    

    逻辑理解

    在这里插入图片描述

    8.4、Vue入门小结

    核心:数据驱动,组件化

    优点:借鉴了AngularJS的模块化开发和React的虚拟Dom,虚拟Dom就是把Demo操作放到内存中执行;

    常用的属性:

    • v-if
    • v-else-if
    • v-else
    • v-for
    • v-on绑定事件,简写@
    • v-model数据双向绑定
    • v-bind给组件绑定参数,简写:

    组件化:

    • 组合组件slot插槽
    • 组件内部绑定事件需要使用到this.$emit("事件名",参数);
    • 计算属性的特色,缓存计算数据

    遵循SoC关注度分离原则,Vue是纯粹的视图框架,并不包含,比如Ajax之类的通信功能,为了解决通信问题,我们需要使用Axios框架做异步通信;

    说明

    Vue的开发都是要基于NodeJS,实际开发采用Vue-cli脚手架开发,vue-router路由,vuex做状态管理;Vue UI,界面我们一般使用ElementUI(饿了么出品),或者ICE(阿里巴巴出品)来快速搭建前端项目~~

    官网:

    • https://element.eleme.cn/#/zh-CN
    • https://ice.work/

    九、第一个vue-cli项目

    9.1、什么是vue-cli

    vue-cli官方提供的一个脚手架,用于快速生成一个vue的项目模板;
      预先定义好的目录结构及基础代码,就好比咱们在创建Maven项目时可以选择创建一个骨架项目,这个估计项目就是脚手架,我们的开发更加的快速;
      项目的功能

    • 统一的目录结构
    • 本地调试
    • 热部署
    • 单元测试
    • 集成打包上线

    9.2、需要的环境

    • Node.js:http://nodejs.cn/download/
      安装就是无脑的下一步就好,安装在自己的环境目录下
    • Git:https://git-scm.com/doenloads
      镜像:https://npm.taobao.org/mirrors/git-for-windows/

    确认nodejs安装成功:

    • cmd下输入node -v,查看是否能够正确打印出版本号即可!
    • cmd下输入npm -v,查看是否能够正确打印出版本号即可!
      这个npm,就是一个软件包管理工具,就和linux下的apt软件安装差不多!
        安装Node.js淘宝镜像加速器(cnpm)
        这样的话,下载会快很多~
    # -g 就是全局安装
    npm install cnpm -g
    
    # 或使用如下语句解决npm速度慢的问题
    npm install --registry=https://registry.npm.taobao.org
    

    安装的过程可能有点慢~,耐心等待!虽然安装了cnpm,但是尽量少用!
      安装的位置:C:\Users\administrator\AppData\Roaming\npm

    在这里插入图片描述
      安装vue-cli

    cnpm instal1 vue-cli-g
    #测试是否安装成功#查看可以基于哪些模板创建vue应用程序,通常我们选择webpack
    vue list
    

    在这里插入图片描述

    9.3、第一个vue-cli应用程序

    1.创建一个Vue项目,我们随便建立一个空的文件夹在电脑上,我这里在D盘下新建一个目录

    D:\Project\vue-study;
    

    2.创建一个基于webpack模板的vue应用程序

    #1、首先需要进入到对应的目录 cd D:\Project\vue-study
    #2、这里的myvue是顶日名称,可以根据自己的需求起名
    vue init webpack myvue
    

    一路都选择no即可;
      说明:

    • Project name:项目名称,默认回车即可
    • Project description:项目描述,默认回车即可
    • Author:项目作者,默认回车即可
    • Install vue-router:是否安装vue-router,选择n不安装(后期需要再手动添加)
    • Use ESLint to lint your code:是否使用ESLint做代码检查,选择n不安装(后期需要再手动添加)
    • Set up unit tests:单元测试相关,选择n不安装(后期需要再手动添加)
    • Setupe2etests with Nightwatch:单元测试相关,选择n不安装(后期需要再手动添加)
    • Should we run npm install for you after the,project has been created:创建完成后直接初始化,选择n,我们手动执行;运行结果!

    (1)初始化并运行

    cd myvue
    npm install
    npm run dev
    

    执行完成后,目录多了很多依赖

    当出现问题时,可以查看提示进行处理如下
    img

    十、webpack使用

    10.1、什么是Webpack

    本质上, webpack是一个现代JavaScript应用程序的静态模块打包器(module bundler) 。当webpack处理应用程序时, 它会递归地构建一个依赖关系图(dependency graph) , 其中包含应用程序需要的每个模块, 然后将所有这些模块打包成一个或多个bundle.
      Webpack是当下最热门的前端资源模块化管理和打包工具, 它可以将许多松散耦合的模块按照依赖和规则打包成符合生产环境部署的前端资源。还可以将按需加载的模块进行代码分离,等到实际需要时再异步加载。通过loader转换, 任何形式的资源都可以当做模块, 比如Commons JS、AMD、ES 6、CSS、JSON、Coffee Script、LESS等;
      伴随着移动互联网的大潮, 当今越来越多的网站已经从网页模式进化到了WebApp模式。它们运行在现代浏览器里, 使用HTML 5、CSS 3、ES 6等新的技术来开发丰富的功能, 网页已经不仅仅是完成浏览器的基本需求; WebApp通常是一个SPA(单页面应用) , 每一个视图通过异步的方式加载,这导致页面初始化和使用过程中会加载越来越多的JS代码,这给前端的开发流程和资源组织带来了巨大挑战。
      前端开发和其他开发工作的主要区别,首先是前端基于多语言、多层次的编码和组织工作,其次前端产品的交付是基于浏览器的,这些资源是通过增量加载的方式运行到浏览器端,如何在开发环境组织好这些碎片化的代码和资源,并且保证他们在浏览器端快速、优雅的加载和更新,就需要一个模块化系统,这个理想中的模块化系统是前端工程师多年来一直探索的难题。

    10.2、模块化的演进

    Script标签

    	<script src = "module1.js"></script>
    	<script src = "module2.js"></script>
    	<script src = "module3.js"></script>
    

    这是最原始的JavaScript文件加载方式,如果把每一个文件看做是一个模块,那么他们的接口通常是暴露在全局作用域下,也就是定义在window对象中,不同模块的调用都是一个作用域。
      这种原始的加载方式暴露了一些显而易见的弊端:

    • 全局作用域下容易造成变量冲突
    • 文件只能按照<script>的书写顺序进行加载
    • 开发人员必须主观解决模块和代码库的依赖关系
    • 在大型项目中各种资源难以管理,长期积累的问题导致代码库混乱不堪

    CommonsJS


    服务器端的NodeJS遵循CommonsJS规范,该规范核心思想是允许模块通过require方法来同步加载所需依赖的其它模块,然后通过exports或module.exports来导出需要暴露的接口。

    require("module");
    require("../module.js");
    export.doStuff = function(){};
    module.exports = someValue;
    1234
    

    优点:

    • 服务器端模块便于重用
    • NPM中已经有超过45万个可以使用的模块包
    • 简单易用

    缺点:

    • 同步的模块加载方式不适合在浏览器环境中,同步意味着阻塞加载,浏览器资源是异步加载的
    • 不能非阻塞的并行加载多个模块

    实现:

    • 服务端的NodeJS
    • •Browserify,浏览器端的CommonsJS实现,可以使用NPM的模块,但是编译打包后的文件体积较大
    • modules-webmake,类似Browserify,但不如Browserify灵活
    • wreq,Browserify的前身

    AMD


    Asynchronous Module Definition规范其实主要一个主要接口define(id?,dependencies?,factory);它要在声明模块的时候指定所有的依赖dependencies,并且还要当做形参传到factory中,对于依赖的模块提前执行。

    define("module",["dep1","dep2"],functian(d1,d2){
    	return someExportedValue;
    });
    require(["module","../file.js"],function(module,file){});
    1234
    

    优点

    • 适合在浏览器环境中异步加载模块
    • 可以并行加载多个模块

    缺点

    • 提高了开发成本,代码的阅读和书写比较困难,模块定义方式的语义不畅
    • 不符合通用的模块化思维方式,是一种妥协的实现

    实现

    • RequireJS
    • curl

    CMD


    Commons Module Definition规范和AMD很相似,尽保持简单,并与CommonsJS和NodeJS的Modules规范保持了很大的兼容性。

    define(function(require,exports,module){
    	var $=require("jquery");
    	var Spinning = require("./spinning");
    	exports.doSomething = ...;
    	module.exports=...;
    });
    

    优点:

    • 依赖就近,延迟执行
    • 可以很容易在NodeJS中运行缺点
    • 依赖SPM打包,模块的加载逻辑偏重

    实现

    • Sea.js
    • coolie

    ES6模块


    EcmaScript 6标准增加了JavaScript语言层面的模块体系定义。ES 6模块的设计思想, 是尽量静态化, 使编译时就能确定模块的依赖关系, 以及输入和输出的变量。Commons JS和AMD模块,都只能在运行时确定这些东西。

    import "jquery"
    export function doStuff(){}
    module "localModule"{}
    

    优点

    • 容易进行静态分析
    • 面向未来的Ecma Script标准

    缺点

    • 原生浏览器端还没有实现该标准
    • 全新的命令,新版的Node JS才支持

    实现

    • Babel

    大家期望的模块
      系统可以兼容多种模块风格, 尽量可以利用已有的代码, 不仅仅只是JavaScript模块化, 还有CSS、图片、字体等资源也需要模块化。

    10.3、安装Webpack

    WebPack是一款模块加载器兼打包工具, 它能把各种资源, 如JS、JSX、ES 6、SASS、LESS、图片等都作为模块来处理和使用。
      安装:

    npm install webpack -g
    npm install webpack-cli -g
    

    测试安装成功

    • webpack -v
    • webpack-cli -v

    在这里插入图片描述

    配置

    创建 webpack.config.js配置文件

    • entry:入口文件, 指定Web Pack用哪个文件作为项目的入口
    • output:输出, 指定WebPack把处理完成的文件放置到指定路径
    • module:模块, 用于处理各种类型的文件
    • plugins:插件, 如:热更新、代码重用等
    • resolve:设置路径指向
    • watch:监听, 用于设置文件改动后直接打包
    module.exports = {
    	entry:"",
    	output:{
    		path:"",
    		filename:""
    	},
    	module:{
    		loaders:[
    			{test:/\.js$/,;\loade:""}
    		]
    	},
    	plugins:{},
    	resolve:{},
    	watch:true
    }
    

    直接运行webpack命令打包

    10.4、使用webpack

    1. 创建项目
    2. 创建一个名为modules的目录,用于放置JS模块等资源文件
    3. 在modules下创建模块文件,如hello.js,用于编写JS模块相关代码
    	//暴露一个方法:sayHi
    	exports.sayHi = function(){
    		document.write("<div>Hello Webpack</div>");
    	}
    
    1. 在modules下创建一个名为main.js的入口文件,用于打包时设置entry属性
    //require 导入一个模块,就可以调用这个模块中的方法了
    var hello = require("./hello");
    hello.sayHi();
    
    1. 在项目目录下创建webpack.config.js配置文件,使用webpack命令打包
    module.exports = {
    	entry:"./modules/main.js",
    	output:{
    		filename:"./js/bundle.js"
    	}
    
    }
    
    1. 在项目目录下创建HTML页面,如index.html,导入webpack打包后的JS文件
    	<!doctype html>
    	<html lang="en">
    		<head>
    			<meta charset="UTF-8">
    			<title>狂神说Java</title>
    		</head>
    		<body>
    			<script src="dist/js/bundle.js"></script>
    		</body>
    	</html>
    
    1. 在IDEA控制台中直接执行webpack;如果失败的话,就使用管理员权限运行即可!
    2. 运行HTML看效果

    说明

    # 参数--watch 用于监听变化
    webpack --watch
    

    十一、vue-router路由

    11.1、说明


    学习的时候,尽量的打开官方的文档

    Vue Router是Vue.js官方的路由管理器。它和Vue.js的核心深度集成, 让构建单页面应用变得易如反掌。包含的功能有:

    • 嵌套的路由/视图表
    • 模块化的、基于组件的路由配置
    • 路由参数、查询、通配符
    • 基于Vue js过渡系统的视图过渡效果
    • 细粒度的导航控制
    • 带有自动激活的CSS class的链接
    • HTML5 历史模式或hash模式, 在IE 9中自动降级
    • 自定义的滚动行为

    11.2、安装

    基于第一个vue-cli进行测试学习; 先查看node modules中是否存在vue-router
      vue-router是一个插件包, 所以我们还是需要用n pm/cn pm来进行安装的。打开命令行工具,进入你的项目目录,输入下面命令。

    npm install vue-router --save-dev
    

    如果在一个模块化工程中使用它,必须要通过Vue.use()明确地安装路由功能:

    import Vue from 'vue'
    import VueRouter from 'vue-router'
    
    Vue.use(VueRouter);
    

    11.3、测试

    1、先删除没有用的东西
    2、components 目录下存放我们自己编写的组件
    3、定义一个Content.vue 的组件

    <template>
    	<div>
    		<h1>内容页</h1>
    	</div>
    </template>
    
    <script>
    	export default {
    		name:"Content"
    	}
    </script>
    

    Main.vue组件

    	<template>
    	<div>
    		<h1>首页</h1>
    	</div>
    </template>
    
    <script>
    	export default {
    		name:"Main"
    	}
    </script>
    

    4、安装路由,在src目录下,新建一个文件夹:router,专门存放路由,配置路由index.js,如下

    import Vue from'vue'
    //导入路由插件
    import Router from 'vue-router'
    //导入上面定义的组件
    import Content from '../components/Content'
    import Main from '../components/Main'
    //安装路由
    Vue.use(Router) ;
    //配置路由
    export default new Router({
    	routes:[
    		{
    			//路由路径
    			path:'/content',
    			//路由名称
    			name:'content',
    			//跳转到组件
    			component:Content
    			},{
    			//路由路径
    			path:'/main',
    			//路由名称
    			name:'main',
    			//跳转到组件
    			component:Main
    			}
    		]
    	});
    

    5、在main.js中配置路由

    import Vue from 'vue'
    import App from './App'
    
    //导入上面创建的路由配置目录
    import router from './router'//自动扫描里面的路由配置
    
    //来关闭生产模式下给出的提示
    Vue.config.productionTip = false;
    
    new Vue({
    	el:"#app",
    	//配置路由
    	router,
    	components:{App},
    	template:'<App/>'
    });
    

    6、在App.vue中使用路由

    <template>
    	<div id="app">
    		<!--
    			router-link:默认会被渲染成一个<a>标签,to属性为指定链接
    			router-view:用于渲染路由匹配到的组件
    		-->
    		<router-link to="/">首页</router-link>
    		<router-link to="/content">内容</router-link>
    		<router-view></router-view>
    	</div>
    </template>
    
    <script>
    	export default{
    		name:'App'
    	}
    </script>
    <style></style>
    

    十二、实战快速上手

    我们采用实战教学模式并结合ElementUI组件库,将所需知识点应用到实际中,以最快速度带领大家掌握Vue的使用;

    12.1、创建工程

    注意:命令行都要使用管理员模式运行
    1、创建一个名为hello-vue的工程vue init webpack hello-vue
    2、安装依赖, 我们需要安装vue-router、element-ui、sass-loader和node-sass四个插件

    #进入工程目录
    cd hello-vue
    #安装vue-routern 
    npm install vue-router --save-dev
    #安装element-ui
    npm i element-ui -S
    #安装依赖
    npm install
    # 安装SASS加载器
    cnpm install sass-loader node-sass --save-dev
    #启功测试
    npm run dev
    

    3、Npm命令解释:

    • npm install moduleName:安装模块到项目目录下
    • npm install -g moduleName:-g的意思是将模块安装到全局,具体安装到磁盘哪个位置要看npm config prefix的位置
    • npm install -save moduleName:–save的意思是将模块安装到项目目录下, 并在package文件的dependencies节点写入依赖,-S为该命令的缩写
    • npm install -save-dev moduleName:–save-dev的意思是将模块安装到项目目录下,并在package文件的devDependencies节点写入依赖,-D为该命令的缩写

    12.2、创建登录页面

    把没有用的初始化东西删掉!
      在源码目录中创建如下结构:

    • assets:用于存放资源文件
    • components:用于存放Vue功能组件
    • views:用于存放Vue视图组件
    • router:用于存放vue-router配置

    在这里插入图片描述

    创建首页视图,在views目录下创建一个名为Main.vue的视图组件:

    <template>
    	<div>首页</div>
    </template>
    <script>
    	export default {
    			name:"Main"
    	}
    </script>
    <style scoped>
    </style>
    

    创建登录页视图在views目录下创建名为Login.vue的视图组件,其中el-*的元素为ElementUI组件;

    <template>
      <div>
        <el-form ref="loginForm" :model="form" :rules="rules" label-width="80px" class="login-box">
          <h3 class="login-title">欢迎登录</h3>
          <el-form-item label="账号" prop="username">
            <el-input type="text" placeholder="请输入账号" v-model="form.username"/>
          </el-form-item>
          <el-form-item label="密码" prop="password">
            <el-input type="password" placeholder="请输入密码" v-model="form.password"/>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" v-on:click="onsubmit('loginForm')">登录</el-button>
          </el-form-item>
        </el-form>
    
        <el-dialog title="温馨提示" :visible.sync="dialogVisiable" width="30%" :before-close="handleClose">
          <span>请输入账号和密码</span>
          <span slot="footer" class="dialog-footer">
              <el-button type="primary" @click="dialogVisible = false">确定</el-button>
            </span>
        </el-dialog>
      </div>
    </template>
    
    <script>
        export default {
            name: "Login",
          data(){
              return{
                form:{
                  username:'',
                  password:''
                },
                //表单验证,需要在 el-form-item 元素中增加prop属性
                rules:{
                  username:[
                    {required:true,message:"账号不可为空",trigger:"blur"}
                  ],
                  password:[
                    {required:true,message:"密码不可为空",tigger:"blur"}
                  ]
                },
    
                //对话框显示和隐藏
                dialogVisible:false
              }
          },
          methods:{
              onSubmit(formName){
                //为表单绑定验证功能
                this.$refs[formName].validate((valid)=>{
                  if(valid){
                    //使用vue-router路由到指定界面,该方式称为编程式导航
                    this.$router.push('/main');
                  }else{
                    this.dialogVisible=true;
                    return false;
                  }
                });
              }
          }
        }
    </script>
    
    <style lang="scss" scoped>
      .login-box{
        border:1px solid #DCDFE6;
        width: 350px;
        margin:180px auto;
        padding: 35px 35px 15px 35px;
        border-radius: 5px;
        -webkit-border-radius: 5px;
        -moz-border-radius: 5px;
        box-shadow: 0 0 25px #909399;
      }
      .login-title{
        text-align:center;
        margin: 0 auto 40px auto;
        color: #303133;
      }
    </style>
    

    创建路由,在router目录下创建一个名为index.js的vue-router路由配置文件

    //导入vue
    import Vue from 'vue';
    import VueRouter from 'vue-router';
    //导入组件
    import Main from "../views/Main";
    import Login from "../views/Login";
    //使用
    Vue.use(VueRouter);
    //导出
    export default new VueRouter({
      routes: [
        {
          //登录页
          path: '/main',
          component: Main
        },
        //首页
        {
          path: '/login',
          component: Login
        },
      ]
    
    })
    
    

    APP.vue

    <template>
      <div id="app">
        <router-view></router-view>
      </div>
    </template>
    
    <script>
    
    
    export default {
      name: 'App',
    
    }
    </script>
    
    <style>
    #app {
      font-family: 'Avenir', Helvetica, Arial, sans-serif;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      text-align: center;
      color: #2c3e50;
      margin-top: 60px;
    }
    </style>
    

    main.js

    // The Vue build version to load with the `import` command
    // (runtime-only or standalone) has been set in webpack.base.conf with an alias.
    import Vue from 'vue'
    import App from './App'
    import router from "./router"
    
    import ElementUI from 'element-ui'
    import 'element-ui/lib/theme-chalk/index.css'
    
    Vue.use(router)
    Vue.use(ElementUI)
    
    /* eslint-disable no-new */
    new Vue({
      el: '#app',
      router,
      render:h=>h(App)
    })
    

    测试:在浏览器打开 http://localhost:8080/#/login
    如果出现错误: 可能是因为sass-loader的版本过高导致的编译错误,当前最高版本是8.0.2,需要退回到7.3.1 ;
    去package.json文件里面的 "sass-loader"的版本更换成7.3.1,然后重新cnpm install就可以了;

    12.3、路由嵌套

    嵌套路由又称子路由,在实际应用中,通常由多层嵌套的组件组合而成。
    demo
    1、 创建用户信息组件,在 views/user 目录下创建一个名为 Profile.vue 的视图组件;
    Profile.vue

    <template>
      <h1>个人信息</h1>
    </template>
    <script>
      export default {
        name: "UserProfile"
      }
    </script>
    <style scoped>
    </style>
    

    2、在用户列表组件在 views/user 目录下创建一个名为 List.vue 的视图组件;
    List.vue

    <template>
      <h1>用户列表</h1>
    </template>
    <script>
      export default {
        name: "UserList"
      }
    </script>
    <style scoped>
    </style>
    

    3、 修改首页视图,我们修改 Main.vue 视图组件,此处使用了 ElementUI 布局容器组件,代码如下:
    Main.vue

    <template>
        <div>
          <el-container>
            <el-aside width="200px">
              <el-menu :default-openeds="['1']">
                <el-submenu index="1">
                  <template slot="title"><i class="el-icon-caret-right"></i>用户管理</template>
                  <el-menu-item-group>
                    <el-menu-item index="1-1">
                    <!--插入的地方-->
                      <router-link to="/user/profile">个人信息</router-link>
                    </el-menu-item>
                    <el-menu-item index="1-2">
                    <!--插入的地方-->
                      <router-link to="/user/list">用户列表</router-link>
                    </el-menu-item>
                  </el-menu-item-group>
                </el-submenu>
                <el-submenu index="2">
                  <template slot="title"><i class="el-icon-caret-right"></i>内容管理</template>
                  <el-menu-item-group>
                    <el-menu-item index="2-1">分类管理</el-menu-item>
                    <el-menu-item index="2-2">内容列表</el-menu-item>
                  </el-menu-item-group>
                </el-submenu>
              </el-menu>
            </el-aside>
    
            <el-container>
              <el-header style="text-align: right; font-size: 12px">
                <el-dropdown>
                  <i class="el-icon-setting" style="margin-right: 15px"></i>
                  <el-dropdown-menu slot="dropdown">
                    <el-dropdown-item>个人信息</el-dropdown-item>
                    <el-dropdown-item>退出登录</el-dropdown-item>
                  </el-dropdown-menu>
                </el-dropdown>
              </el-header>
              <el-main>
              <!--在这里展示视图-->
                <router-view />
              </el-main>
            </el-container>
          </el-container>
        </div>
    </template>
    <script>
        export default {
            name: "Main"
        }
    </script>
    <style scoped lang="scss">
      .el-header {
        background-color: #B3C0D1;
        color: #333;
        line-height: 60px;
      }
      .el-aside {
        color: #333;
      }
    </style>
    

    4、 配置嵌套路由修改 router 目录下的 index.js 路由配置文件,使用children放入main中写入子模块,代码如下
    index.js

    //导入vue
    import Vue from 'vue';
    import VueRouter from 'vue-router';
    //导入组件
    import Main from "../views/Main";
    import Login from "../views/Login";
    //导入子模块
    import UserList from "../views/user/List";
    import UserProfile from "../views/user/Profile";
    
    //使用
    Vue.use(VueRouter);
    //导出
    export default new VueRouter({
      routes: [
        {
          //登录页
          path: '/main',
          component: Main,
          //  写入子模块
          children: [
            {
              path: '/user/profile',
              component: UserProfile,
            }, {
              path: '/user/list',
              component: UserList,
            },
          ]
        },
        //首页
        {
          path: '/login',
          component: Login
    
        },
      ]
    })
    

    5、 路由嵌套实战效果图
    在这里插入图片描述

    图 路由嵌套效果图

    12.4、参数传递

    这里演示如果请求带有参数该怎么传递
    demo
     用的还是上述例子的代码 修改一些代码 这里不放重复的代码了
    第一种取值方式
    1、 修改路由配置, 主要是router下的index.js中的 path 属性中增加了 :id 这样的占位符

    {
    	path: '/user/profile/:id', 
    	name:'UserProfile', 
    	component: UserProfile
    }
    

    2、传递参数
     此时我们在Main.vue中的route-link位置处 to 改为了 :to,是为了将这一属性当成对象使用,注意 router-link 中的 name 属性名称 一定要和 路由中的 name 属性名称 匹配,因为这样 Vue 才能找到对应的路由路径;

    <!--name是组件的名字 params是传的参数 如果要传参数的话就需要用v:bind:来绑定-->
    <router-link :to="{name:'UserProfile',params:{id:1}}">个人信息</router-link>
    

    3、在要展示的组件Profile.vue中接收参数 使用 {{$route.params.id}}来接收
    Profile.vue 部分代码

    <template>
      <!--  所有的元素必须在根节点下-->
      <div>
        <h1>个人信息</h1>
        {{$route.params.id}}
      </div>
    </template>
    

    第二种取值方式 使用props 减少耦合
    1、修改路由配置 , 主要在router下的index.js中的路由属性中增加了 props: true 属性

    {
    	path: '/user/profile/:id', 
    	name:'UserProfile', 
    	component: UserProfile, 
    	props: true
    }
    

    2、传递参数和之前一样 在Main.vue中修改route-link地址

    <!--name是组件的名字 params是传的参数 如果要传参数的话就需要用v:bind:来绑定-->
    <router-link :to="{name:'UserProfile',params:{id:1}}">个人信息</router-link>
    

    3、在Profile.vue接收参数为目标组件增加 props 属性
    Profile.vue

    <template>
      <div>
        个人信息
        {{ id }}
      </div>
    </template>
    <script>
        export default {
          props: ['id'],
          name: "UserProfile"
        }
    </script>
    <style scoped>
    </style>
    

    在这里插入图片描述

    图 传参效果图

    12.5、组件重定向

    重定向的意思大家都明白,但 Vue 中的重定向是作用在路径不同但组件相同的情况下,比如:
    在router下面index.js的配置

    {
      path: '/main',
      name: 'Main',
      component: Main
    },
    {
      path: '/goHome',
      redirect: '/main'
    }
    

    说明:这里定义了两个路径,一个是 /main ,一个是 /goHome,其中 /goHome 重定向到了 /main 路径,由此可以看出重定向不需要定义组件;

    使用的话,只需要在Main.vue设置对应路径即可;

    <el-menu-item index="1-3">
        <router-link to="/goHome">回到首页</router-link>
    </el-menu-item>
    

    12.6、路由模式与 404

    路由模式有两种

    • hash:路径带 # 符号,如 http://localhost/#/login
    • history:路径不带 # 符号,如 http://localhost/login

    修改路由配置,代码如下:

    export default new Router({
      mode: 'history',
      routes: [
      ]
    });
    

    404 demo
    1.创建一个NotFound.vue视图组件
    NotFound.vue

    <template>
        <div>
          <h1>404,你的页面走丢了</h1>
        </div>
    </template>
    <script>
        export default {
            name: "NotFound"
        }
    </script>
    <style scoped>
    </style>
    

    2.修改路由配置index.js

    import NotFound from '../views/NotFound'
    {
       path: '*',
       component: NotFound
    }
    

    3.效果图
    在这里插入图片描述

    图 404效果图

    路由钩子与异步请求

    beforeRouteEnter:在进入路由前执行
    beforeRouteLeave:在离开路由前执行

    在Profile.vue中写

      export default {
        name: "UserProfile",
        beforeRouteEnter: (to, from, next) => {
          console.log("准备进入个人信息页");
          next();
        },
        beforeRouteLeave: (to, from, next) => {
          console.log("准备离开个人信息页");
          next();
        }
      }
    

    参数说明:
    to:路由将要跳转的路径信息
    from:路径跳转前的路径信息
    next:路由的控制参数
    next() 跳入下一个页面
    next(’/path’) 改变路由的跳转方向,使其跳到另一个路由
    next(false) 返回原来的页面
    next((vm)=>{}) 仅在 beforeRouteEnter 中可用,vm 是组件实例

    在钩子函数中使用异步请求

    1、安装 Axios

    cnpm install --save vue-axios
    

    2、main.js引用 Axios

    import axios from 'axios'
    import VueAxios from 'vue-axios'
    Vue.use(VueAxios, axios)
    

    3、准备数据 : 只有我们的 static 目录下的文件是可以被访问到的,所以我们就把静态文件放入该目录下。
    数据和之前用的json数据一样 需要的去上述axios例子里

    // 静态数据存放的位置
    static/mock/data.json
    

    4.在 beforeRouteEnter 中进行异步请求
    Profile.vue

      export default {
        //第二种取值方式
        // props:['id'],
        name: "UserProfile",
        //钩子函数 过滤器
        beforeRouteEnter: (to, from, next) => {
          //加载数据
          console.log("进入路由之前")
          next(vm => {
            //进入路由之前执行getData方法
            vm.getData()
          });
        },
        beforeRouteLeave: (to, from, next) => {
          console.log("离开路由之前")
          next();
        },
        //axios
        methods: {
          getData: function () {
            this.axios({
              method: 'get',
              url: 'http://localhost:8080/static/mock/data.json'
            }).then(function (response) {
              console.log(response)
            })
          }
        }
      }
    

    5.路由钩子和axios结合图
    在这里插入图片描述

    图 效果图

    到此结束 完结★,°:.☆( ̄▽ ̄)/$:.°★

    展开全文
  • WNetAddConnection 创建同一个网络资源的永久性连接 WNetAddConnection2 创建同一个网络资源的连接 WNetAddConnection3 创建同一个网络资源的连接 WNetCancelConnection ... WNetCloseEnum 结束一次枚举操作
  • 联邦学习笔记整理

    千次阅读 2020-03-26 14:10:28
    联邦学习-笔记整理什么是联邦学习横向联邦学习谷歌分布式系统纵向联邦学习加密的实体对齐如何改变文本的样式插入链接与图片如何插入段漂亮的代码片生成个适合你的列表创建个表格设定内容居中、居左、居右...


    当前虽然是大数据的时代,但是我们面临着如信息孤岛以及数据隐私保护等问题,很多数据无法直接汇总到一起进行建模。为了在多方数据进行联合建模的同时保护数据隐私,我们需要联邦学习。前段时间我对联邦学习进行了一些调研,现将整理笔记附上。

    什么是联邦学习

    联邦学习的概念是2016年由谷歌提出的,其初衷是针对多个手机终端,各自利用其本地数据,共同训练一个模型这样的场景。而现在这一场景被延伸到了很多其它地方。
    图片取自:dsad
    关于谷歌联邦学习2016年的文章可以参考:Andrew Hard et al., Federated learning for mobile keyboard prediction. Google, 2019。

    假设存在N个数据拥有方( U 1 U_1 U1, U 2 U_2 U2, …, U N U_N UN),其拥有的数据为( D 1 D_1 D1, D 2 D_2 D2,…, D N D_N DN)。传统的机器学习是将多方数据进行整合 D = D 1 ∪ D 2 ∪ . . . ∪ D N D=D_1 \cup D_2 \cup...\cup D_N D=D1D2...DN, 建模得到模型M。而联邦学习是在多方数据彼此不可见的情况下共同建模M’。假设模型M的Loss为 L L L,模型M’的Loss为 L ′ L' L, 若 ∣ L − L ′ ∣ < δ |L-L'|<\delta LL<δ,则称联邦学习算法损失精度为 δ \delta δ

    联邦学习根据数据和数据持有者的性质可以分为:横向联邦学习,纵向联邦学习和迁移联邦学习。

    横向联邦学习

    谷歌分布式系统

    特点:

    1. 多个用户,一个服务器
    2. 所有数据特征维度相同
    3. 用户本地训练
    4. 用户通过服务器共享参数

    大致步骤如下:

    1. 对于用户K,其拥有的数据个数为 n k n_k nk,定义 F k ( w ) = 1 n k ∑ i f i ( w ) F_k(w)=\frac{1}{n_k}\sum_i f_i(w) Fk(w)=nk1ifi(w),计算参数梯度 g k = ∇ F k ( w ) g_k=\nabla F_k(w) gk=Fk(w),上传到服务器。其中, f i ( w ) f_i(w) fi(w)为第 i i i个数据的损失函数。
    2. 对于服务器,更新参数 w t + 1 = w t − η ∑ k n k n g k w_{t+1}=w_{t}-\eta\sum_k\frac{n_k}{n}g_k wt+1=wtηknnkgk。其中 t t t表示第 t t t次参数更新。
    3. 用户下载最新的参数 w t + 1 w_{t+1} wt+1,并进行本地更新。

    可以看到,只有服务器为信息安全负责。那么如何做到隐私保护呢?

    可以加密上传的梯度。只有收集到所有用户的梯度之后,其和才能被计算出来。这一点类似于要开启一个密室,需要6把钥匙,缺少任何一把密室都不能被开启。具体如何加密,这一点我没有做深入研究。

    横向联邦学习有一些可以供参考的文献,如:
    Reza Shokri and Vitaly Shmatikov. Privacy-Preserving Deep Learning. ACM. 2015
    Jakub Konecny et al. Federated Learning: Strategies for Improving Communication Efficiency. Google, 2017

    横向联邦学习相对来说比较简单。

    纵向联邦学习

    先假定只有A,B两方进行联合建模。
    假设:只有一方有标签Y。
    挑战:只有X的一方无法建立模型;双方不能交换共享数据。
    预期:双方均获得数据保护;模型无损失。

    在这一方面,微众银行做了很多工作。以下很多内容参考自微众银行关于联邦学习的报告。

    Qiang Yang et al. 2019
    上图摘自:Qiang Yang et al., Federated Machine Learning: Concept and Applications. 2019

    下面我会介绍上述场景如何用联邦学习的方法解决。

    加密的实体对齐

    首先,上述场景下,A方和B方拥有的数据特征重叠较少,但是用户重叠较多。那么如何获知双方共同用户名单且不暴露其它名单呢?
    可以用一种叫 CLK (cryptographic longterm key)的方法给双方用户信息进行加密,加密后的信息上传到一个可靠的第三方,第三方通过比对双方信息返回给双方两个结果:一是如何对原数据进行重新排列,二是加密的关于原数据对应用户是否为双方共有用户的信息。这里说的有点绕,以后有时间再详说。

    推荐文献:
    Stephen Hardy et al., Privated federated learning on vertically partitioned data via
    Entity resolution and additively homomorphic encryption. arXiv:1711.1067 7

    一个简单的例子

    以线性回归和同态加密技术为例:
    在这里插入图片描述
    在这里插入图片描述
    上述例子摘自:Qiang Yang et al., Federated Machine Learning: Concept and Applications. 2019

    上述例子中,A和B的用户相同,但是数据特征不同,且只有B有数据标签。双方共同训练模型,对应双方特征的参数分别为 Θ A \Theta_A ΘA Θ B \Theta_B ΘB。公式中 [ [ [[ [[表示加密。为了保护双方数据隐私,对外展示的计算结果都是加密的。根据同态加密的性质,可以对加密后的损失函数进行一些分解。 [ [ L ] ] [[\mathcal{L}]] [[L]]分为了 [ [ L A ] ] [[\mathcal{L}_A]] [[LA]], [ [ L B ] ] [[\mathcal{L}_B]] [[LB]]以及 [ [ L A B ] ] [[\mathcal{L}_{AB}]] [[LAB]]。为了更新 Θ A \Theta_A ΘA Θ B \Theta_B ΘB,A和B都需要知道 [ [ d i ] ] [[d_i]] [[di]],而 [ [ d i ] ] [[d_i]] [[di]]的计算则同时需要A和B的数据,那么这时需要进行双方的数据交换。

    首先,由第三方C将加密的公钥分别发给A和B(公钥加密,私钥解密,私钥由可靠的第三方保存)。
    第一步:A计算 u i A u_i^A uiA;
    第二步:A进行加密操作 [ [ u i A ] ] [[u_i^A]] [[uiA]], 和 [ [ ∑ i ( ( u i A ) 2 + λ 2 Θ A 2 ] ] [[\sum_i((u_i^A)^2+\frac{\lambda}{2}\Theta_A^2]] [[i((uiA)2+2λΘA2]]
    第三步:A将 [ [ u i A ] ] [[u_i^A]] [[uiA]] [ [ ∑ i ( ( u i A ) 2 + λ 2 Θ A 2 ] ] [[\sum_i((u_i^A)^2+\frac{\lambda}{2}\Theta_A^2]] [[i((uiA)2+2λΘA2]]发送给B。
    在这里插入图片描述
    图片参考自:《联邦学习的研究与应用》, 刘洋,范涛,2019.

    第四步:B计算 [ [ L ] ] [[\mathcal{L}]] [[L]],并将 [ [ L ] ] [[\mathcal{L}]] [[L]]发送
    给第三方C。同时,B计算 [ [ d i ] ] [[d_i]] [[di]],并将 [ [ d i ] ] [[d_i]] [[di]]发送给A。
    在这里插入图片描述
    第五步:有了 [ [ d i ] ] [[d_i]] [[di]],A和B可以分别计算 [ [ ∂ L ∂ Θ A ] ] [[\frac{\partial\mathcal{L}}{\partial\Theta_A}]] [[ΘAL]] [ [ ∂ L ∂ Θ B ] ] [[\frac{\partial\mathcal{L}}{\partial\Theta_B}]] [[ΘBL]]。为了避免C得到A和B的梯度信息,A和B分别在梯度上加一个自定义的数字加密后再传给C。即A和B分别将 [ [ ∂ L ∂ Θ A ] ] + [ [ m a s k A ] ] [[\frac{\partial\mathcal{L}}{\partial\Theta_A}]]+[[mask^A]] [[ΘAL]]+[[maskA]] [ [ ∂ L ∂ Θ b ] ] + [ [ m a s k B ] ] [[\frac{\partial\mathcal{L}}{\partial\Theta_b}]]+[[mask^B]] [[ΘbL]]+[[maskB]]传递给C。
    第六步:C利用私钥对 [ [ ∂ L ∂ Θ A ] ] + [ [ m a s k A ] ] [[\frac{\partial\mathcal{L}}{\partial\Theta_A}]]+[[mask^A]] [[ΘAL]]+[[maskA]] [ [ ∂ L ∂ Θ b ] ] + [ [ m a s k B ] ] [[\frac{\partial\mathcal{L}}{\partial\Theta_b}]]+[[mask^B]] [[ΘbL]]+[[maskB]]解密并传递给A和B。
    第七步:和B更新各自的参数: Θ A = Θ A − η ∂ L ∂ Θ A \Theta_A=\Theta_A-\eta\frac{\partial\mathcal{L}}{\partial\Theta_A} ΘA=ΘAηΘAL, Θ B = Θ B − η ∂ L ∂ Θ B \Theta_B=\Theta_B-\eta\frac{\partial\mathcal{L}}{\partial\Theta_B} ΘB=ΘBηΘBL

    上述过程便是A和B如何通过可靠的第三方C进行联合训练。训练过程中,A和B保护了各自的数据隐私,而C仅获得了整个模型的Loss,以便于判断模型的训练结果。

    模型训练好了以后,A和B分别得到了 Θ A \Theta_A ΘA Θ B \Theta_B ΘB,那么如何进行推断呢?

    第一步:C将需要预测的用户id分别传达给A和B,A和B各自计算 u A u^A uA u B u^B uB,并利用公钥进行加密。
    第二步:A和B分别将加密好的 [ [ u A ] ] [[u^A]] [[uA]] [ [ u B ] ] [[u^B]] [[uB]]发送给C。
    第三步:C计算 [ [ y ] ] = [ [ u A ] ] + [ [ u B ] ] [[y]]=[[u^A]]+[[u^B]] [[y]]=[[uA]]+[[uB]],并利用私钥解密,得到 y y y,即预测值。

    在这里插入图片描述

    展开全文
  • Makefile笔记整理

    千次阅读 2016-02-26 10:57:33
    GCC常用选项 -DMACRO选项 ...仅选用静态程序库进行链接,如果个目录中静态库和动态库都存在,则仅选用静态库 -g 包括调试信息 -On 优化程序,n代表优化级别,n常为2 -Wall 打开警告信息 M

    GCC常用选项

    • -DMACRO选项
      -DOS_LINUX将宏定义OS_LINUX

    • -Idir
      添加头文件搜索目录dir

    • -Ldir
      添加链接库搜索目录dir。gcc优先使用共享程序库

    • -static
      仅选用静态程序库进行链接,如果一个目录中静态库和动态库都存在,则仅选用静态库

    • -g
      包括调试信息

    • -On
      优化程序,n代表优化级别,n常为2

    • -Wall
      打开警告信息


    Makefile规则基本格式

    TARGET...: DEPENDEDS...
        COMMAND
        ...
        ...

    TARGET:规则定义的目标
    DEPENDEDS:执行规则锁必须依赖的条件(DEPENDEDS也可以是某个TARGET,形成嵌套)
    COMMAND:规则所执行的命令

    Makefile中常用变量及含义

    变量名含义默认值
    AR生成静态库文件的程序名称ar
    AS汇编编译器的名称as
    CCC语言编译器的名称cc
    CPPC语言预编译器的名称$(CC) -E
    CXXC++语言编译器的名称g++
    FCFORTRAN语言编译器的名称f77
    RM删除文件程序的名称rm -f
    ARFLAGS生成静态库库文件程序的选项\
    ASFLAGS汇编语言编译器的编译选项\
    CFLAGSC语言编译器的编译选项\
    CPPFLAGSC语言预编译的编译选项\
    CXXFLAGSC++语言编译器的编译选项\
    FFLAGSFORTRAN语言编译器的编译选项\

    Makefile中的自动变量

    变量含义
    $*表示目标文件的名称,不包含目标文件的扩展名(GUN make特有,其他make不一定支持)
    $+所有依赖项的集合,不会去除重复的依赖项
    $<表示依赖项中第一个依赖文件的名称
    $?依赖项中,所有目标文件时间戳晚的依赖文件,以来稳健之间以空格分开
    $@目标项中目标文件的名称
    $^依赖项中,所有不重复的依赖文件,这些文件之间以空格分开

    Makefile中的VPATH变量

    使用方法:

    VPATH=add:sub(加入addsub搜索路径)

    VPATH 只控制.c/.cpp的查找路径(将.c/.cpp文件所在文件夹添加到VPATH后只用写文件名gcc即可查找到文件),对于.h文件,需要使用-I./header。

    Makefile中的= := ?= +=赋值运算符

    = 是最基本的赋值
    := 是覆盖之前的值
    ?= 是如果没有被赋值过就赋予等号后面的值
    += 是添加等号后面的值

    1“=”
    make会将整个makefile展开后,再决定变量的值。也就是说,变量的值将会是整个makefile中最后被指定的值。看例子:
    x = foo
    y = $(x) bar
    x = xyz
    在上例中,y的值将会是 xyz bar ,而不是 foo bar 。

    2“:=”
    “:=”表示变量的值决定于它在makefile中的位置,而不是整个makefile展开后的最终值。
    x := foo
    y := $(x) bar
    x := xyz
    在上例中,y的值将会是 foo bar ,而不是 xyz bar 了。

    Makefile中的.PHONY

    .PHONY:romfs   # .PHONY修饰romfs只有规则,没有依赖
    romfs
    all:main1 main2 clean
    main1: main1.c
        @gcc main1.c -o main1
    main2: main2.o
        @gcc main2.o -o main2
    main2.o: main2.c
        @gcc -c main2.c 
    clean:
        @rm -f main2.o

    但是当我们make之后main2.o仍然存在,怎么回事呢makefile中的all和.PHONY的作用
    原来这里的目标clean没有任何依赖,make执行时认为这已经到“根上”了(就是认为磁盘上有clean,就像main2.c),将其忽略(尽管它有规则)。
    关键字.PHONY可以解决这问题,告诉make该目标是“假的”(磁盘上其实没有clean),这时make为生成这个目标就会将其规则执行一次。.PHONY修饰的目标就是只有规则没有依赖。
    加上一句.PHONY:clean即可:

    all:main1 main2 clean
    main1: main1.c
        @gcc main1.c -o main1
    main2: main2.o
        @gcc main2.o -o main2
    main2.o: main2.c
        @gcc -c main2.c 
    .PHONY:clean
    clean:
        @rm -f main2.o

    Makefile中的@

    makefile中@是不打印命令本身的意思 ,以下Makefile执行make clean时终端不会打印rm -f main2.o的信息。

    clean:
        @rm -f main2.o

    递归make

    递归调用的方式
    make可以递归调用每个子目录中的Makefile。我们可以用如下方式编译add中的文件:

    add:
        cd add && $(MAKE)

    等价于:

    add:
        $(MAKE) -C add

    上面两个例子都是先进入子目录下add中,然后执行make命令。

    总控Makefile
    调用“$(MAKE) -C”的Makefile叫做总控Makefile。如果总控Makefile中的一些变量需要传递给下层的Makefile,可以使用export命令,如:

    export OBJSDIR=./objs

    Makefile中的函数

    获取匹配模式的文件名wildcard
    这个函数功能是查找当前目录下所有符合模式PATTERN的文件名,其返回值是以空格分割的、当前目录下的所有符合模式PATTERN的文件名列表。原型如下:

    $(wildcard PATTERN)

    例如,如下模式返回当前目录下所有扩展名为.c的文件列表

    $(wildcard *.c)

    模式替换函数patsubst
    这个函数的功能是查找字符串text中按照空格分开的单词,将符合模式pattern的字符串替换成replacement。pattern中的模式可以使用通配符,%代表0到n个字符,当pattern和replacement中都有%时,符合条件的字符将被replacement中的替换。函数的返回值是替换后的新字符串。原型如下:

    $(patsubst pattern,replacement,text)

    返回值:例如需要将.c文件替换成.o文件可以使用如下模式

    $(patsubst %.c,%.o,$(wildcard *.c))

    输出的字符串将当前扩展名为.c的文件替换成扩展名为.o的文件列表

    循环函数foreach
    函数原型:

    $(foreach VAR,LIST,TEXT)

    foreach将LIST字符串中的一个人空格分隔符的单词,先传给临时变量VAR,然后执行TEXT表达式,TEXT表达式处理结束后输出。其返回值是空格分割表达式TEXT的计算结果。
    例如,对于存在add和sub的两个目录,设置DIRS为“add sub ./”包含目录add、sub和当前目录。表达式$(wildcard$(dir)/*.c),可以去除目录add和sub及当前目录中的所有扩展名为.c的文件。

    DIRS = sub add ./
    
    #查找所有目录下的扩展名为.c的文件,复制给变量FILES
    FILES = $(foreach dir, $(DIRS), $(wildcard $(dir)/*.c)) 

    其他

    Makefile中的目标命令前的@、+、-号

    【make中命令行前面加上减号】

    就是,忽略当前此行命令执行时候所遇到的错误。

    而如果不忽略,make在执行命令的时候,如果遇到error,会退出执行的,加上减号的目的,是即便此行命令执行中出错,比如删除一个不存在的文件等,那么也不要管,继续执行make。

    【make中命令行前面加上at符号@】

    就是,在make执行时候,输出的信息中,不要显示此行命令。

    而正常情况下,make执行过程中,都是会显示其所执行的任何的命令的。如果你不想要显示某行的命令,那么就在其前面加上@符号即可。

    【make中命令行前面加上加号+】

    +号修饰符,要求make执行命令,即使使用了-n选项。

    make –help
    帮助中-n选项的含义
    -n, –just-print, –dry-run, –recon
    Don’t actually run any commands; just print them.

    使用加号修饰符让命令始终执行。

    简单的示例Makefile
    all:
    @echo aaaa
    @+echo bbbb

    使用make执行的结果为

    $ make
    aaaa
    bbbb

    使用make -n执行的结果为

    echo aaaa
    echo bbbb
    bbbb

    Makefile依赖项中的FORCE

    在内核的 Makefile 中会在多处地方看到 FORCE ,比如:

    # vmlinux image - including updated kernel symbols
    vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o $(kallsyms.o) FORCE

    实际上它是一个伪目标:

    PHONY +=FORCE
    FORCE:
    
    # Declare the contents of the .PHONY variable as phony.  We keep that
    # information in a variable so we can use it in if_changed and friends.
    
    .PHONY: $(PHONY)

    从上面看到,FORCE 既没有依赖的规则,其底下也没有可执行的命令。

    如果一个规则没有命令或者依赖,而且它的目标不是一个存在的文件名,在执行此规则时,目标总会被认为是最新的。也就是说,这个规则一旦被执行,make 就认为它所表示的目标已经被更新过。当将这样的目标(FORCE)作为一个规则的依赖时(如上的 vmlinux: ),由于依赖总被认为是被更新过的,所以作为依赖所在的规则定义的命令总会被执行。
    比如上面的 vmlinux: 在每次 make 时,它下面的这些命令总会被执行:

    ifdef CONFIG_HEADERS_CHECK
            $(Q)$(MAKE)-f $(srctree)/Makefile headers_check
    endif
    ifdef CONFIG_SAMPLES
            $(Q)$(MAKE) $(build)=samples
    endif
    ifdef CONFIG_BUILD_DOCSRC
            $(Q)$(MAKE) $(build)=Documentation
    endif
            $(call vmlinux-modpost)
            $(call if_changed_rule,vmlinux__)
            $(Q)rm -f .old_version

    用一个直观的例子可以清楚看到这一点,比如有 1 Makefile 文件:

    helloworld:file1.o file2.o
    gcc file1.o file2.o -o helloworld
    
    file1.o:file1.c file2.h
    gcc -c file1.c -o file1.o
    
    file2.o:file2.c file2.h
    gcc -c file2.c -o file2.o
    
    clean:  
    rm -rf *.o helloworld
    
    PHONY   +=FORCE
    FORCE:
    
    .PHONY: $(PHONY)

    在执行 make 后,观察文件的生成时间:

    [beyes@SLinux Makefile]$ ll
    total 32
    -rw-rw-r--. 1 beyes beyes  129 Apr 16 19:00 file1.c
    -rw-rw-r--. 1 beyes beyes  924 Apr 16 20:20 file1.o
    -rw-rw-r--. 1 beyes beyes  108 Apr 16 19:01 file2.c
    -rw-rw-r--. 1 beyes beyes  139 Apr 16 18:49 file2.h
    -rw-rw-r--. 1 beyes beyes  880 Apr 16 20:20 file2.o
    -rwxrwxr-x. 1 beyes beyes 4786 Apr 16 20:20 helloworld
    -rw-rw-r--. 1 beyes beyes  246 Apr 16 20:20 Makefile

    helloworld 文件的生成时间是 20:20
    如果将上面的 Makefile 文件的 helloworld:file1.o file2.o 这一句后面加个 FORCE,那么再过几分钟后再 make 时,再观察一下 helloworld 的生成时间,可以看到是重新生成的了,当然在 make 执行时命令的输出也能知道该命令被再次执行:

    [beyes@SLinux Makefile]$ ll
    total 32
    -rw-rw-r--. 1 beyes beyes  129 Apr 16 19:00 file1.c
    -rw-rw-r--. 1 beyes beyes  924 Apr 16 20:20 file1.o
    -rw-rw-r--. 1 beyes beyes  108 Apr 16 19:01 file2.c
    -rw-rw-r--. 1 beyes beyes  139 Apr 16 18:49 file2.h
    -rw-rw-r--. 1 beyes beyes  880 Apr 16 20:20 file2.o
    -rwxrwxr-x. 1 beyes beyes 4786 Apr 16 20:26 helloworld
    -rw-rw-r--. 1 beyes beyes  246 Apr 16 20:20 Makefile

    其他资料:
    Makefile 使用总结:http://www.cnblogs.com/wang_yb/p/3990952.html

    展开全文
  •  http://blog.csdn.net/zhmxy555/article/details/7318264作者:毛星云 邮箱: happylifemxy@qq.com  在从第节开始看这个笔记系列的话,大家会发现,上来就开始讲DirectX相关的内容,但是写了几节之后,又...
  • tensorflow单变量线性回归(一次函数拟合) 本文章为本人自己写的jupyter笔记,图片显示有一点问题(下面的每个图片都变成同一张图片),所以仅供预览。 需要下载ipynb文件的朋友可以关注我并找到我上传的资源。 ....
  • LOAM主要由四个节点组成:multiScanRegistration、...其中,核心算法封装在BasicScanRegistration、BasicLaserOdomotry、BasicLaserMapping和BasicTransformMaintenance中,这几个类的实现不涉及ROS的函数,为l...
  • uORB笔记整理

    千次阅读 2017-09-24 15:14:36
    功能:订阅者可以用来检查一个主题在发布者上一次更新数据后,有没有订阅者调用过ob_copy来接收、处理过; 说明:如果主题在在被公告前就有人订阅,那么这个API将返回“not-updated”直到主题被公告。可以不用...
  • Batch Normalization(笔记整理

    万次阅读 多人点赞 2019-05-03 00:46:27
    关于Batch Normalization的白话理解和算法流程之超详细笔记整理
  • word笔记整理

    千次阅读 2016-12-07 20:09:53
    快速访问工具栏------【撤销】按钮 / ctrl+Z-------撤销上一次误操作; 注意:若要撤销多次操作,单击【撤销】按钮右边的下拉箭头,从下拉列表框中选择要撤销的操作; 操作的恢复: 快速访问工具栏------【恢复...
  • 上篇博客推到损失函数,损失函数特点是二次函数,是开口朝上的二次函数,有个唯一的极小值点。 有最小二乘法,也可以说是最小平方法。 目标:体现的是预测值和真实值的差的最小化。 最小二乘法,即最小平方法...
  • MySQL常用函数汇总,建议收藏
  • Delphi的笔记整理(

    千次阅读 2012-10-31 21:16:20
    这几天清理资料,把以前学Delphi时的笔记翻出来了。大概是2005年时的吧,有些资料都没有什么价值了。以后再整理吧。   Delphi Note 1、触发器的使用。 源数据库: 名称:info 字段:idd、namee、age、sex...
  • Oracle学习笔记整理手册

    千次阅读 多人点赞 2018-09-02 17:41:06
    PS:本博客收录自己工作中遇到学到的一些Oracle技能,有时间就更新整理一下 (1)Oracle正则匹配使用 PS:这条SQL可以通过正则匹对查询一下,表A的字段a是否有非数字的数据,有时候数据表的一些字段是varchar类型...
  • 1) with as a) WITH AS短语,也叫做子查询部分(subquery factoring),可以定义一个SQL片断,该SQL片断会被整个SQL语句所用到。...临时表在一次查询结束自动清除。c) 应用:需多次调用;union all中;d
  • SpringMVC学习笔记整理详细

    千次阅读 多人点赞 2020-06-09 19:28:57
    个MVC程序配置版注解版小结4.RestFul和控制器控制器Controller实现Controller接口使用注解@ControllerRequestMappingRestFul 风格扩展:小黄鸭调试法5.数据处理及跳转结果跳转方式ModelAndView
  • 计算机网络原理 笔记整理

    千次阅读 多人点赞 2020-06-16 21:38:49
    ╭第章 计算机网络概述 |第二章 网络应用 |第三章 传输层 |第四章 网络层 内容大纲< |第五章 数据链路层与局域网 |第六章 物理层 |第七章 无线与移动网络 ╰第八章 网络安全基础 第章 计算机网络...
  • 软件工程笔记整理

    千次阅读 2016-12-14 16:05:00
    5.条件组合覆盖每个判定中各条件的每一种组合至少出现一次。 6.路径覆盖使程序中每一条可能的路径至少执行一次。       多态: 1 ,方法重载, 2 ,运行时候多态(不同的类的对象对同一消息做出...
  • 信息论基础(学习笔记整理

    万次阅读 多人点赞 2019-06-08 13:24:12
    整理信息论基础的知识点。
  • Deep Learning(深度学习)学习笔记整理系列之(三)

    万次阅读 多人点赞 2013-04-09 00:37:38
    Deep Learning(深度学习)学习笔记整理系列 zouxy09@qq.com http://blog.csdn.net/zouxy09 作者:Zouxy version 1.0 2013-04-08 声明: 1)该Deep Learning的学习系列是整理自网上很大牛和机器学习专家所...
  • Deep Learning(深度学习)学习笔记整理系列之(七)

    万次阅读 多人点赞 2013-04-10 10:48:21
    Deep Learning(深度学习)学习笔记整理系列 zouxy09@qq.com http://blog.csdn.net/zouxy09 作者:Zouxy version 1.0 2013-04-08 声明: 1)该Deep Learning的学习系列是整理自网上很大牛和机器学习专家所...
  • 由于routine代码分成了好几篇博客分析,然后现在在宏观上对函数和结构上进行小小的总结和整理、常用的函数接口 以下函数是最上层的函数(供平时编程调用的函数) int co_create( stCoRoutine_t **ppco,...
  • 笔记根据B站编程不良人视频整理,视频链接:【编程不良人】VUE全家桶入门到实战,学VUE看这个就够了,已完结!基于企业最流行Vue实战技术, 需要md格式笔记的可以私信我。 目录1、Vue 引言2、Vue入门2.1、下载Vuejs...
  • 这里,我们以房屋面积(x)与房屋价格(y)为例,显而易见,二者是种线性关系,房屋价格正比于房屋面积,我们假设比例为w: y^=w∗x\hat{y} = w * xy^​=w∗x 然而,这种线性方程一定是过原点的,即当x为0时,y...
  • 13年5月 软考笔记整理

    千次阅读 2014-04-21 09:49:10
    它将内存(主存)与外存(辅存)结合使用,好像有个容量巨大的内存储器,工作速度接近于主存,每位成本又与辅存相近,在整机形成多层次存储系统。 (4)DMA工作方式下,在(主存与外设)之间建立了直接的数据通路...
  • 前端笔记整理(Vue)

    千次阅读 多人点赞 2021-05-21 14:03:21
    1、组件data为什么返回函数 组件的data写成函数,数据以函数返回值形式定义,复用组件时,就可以返回互不影响的份data,避免数据污染。 2、vue给对象新增属性页面没有响应 由于Vue会在初始化实例时对属性执行...
  • 今天心血来潮,准备写...启动VC6,新建个简单的基于对话框的工程,捋捋游戏流程,先写上几个功能函数的空函数,这样的好处是写代码的逻辑跟着游戏流程走,不会乱。先看一下我们都需要什么吧,头文件功能函数如下:

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 33,495
精华内容 13,398
关键字:

一次函数笔记整理