Angular25 组件的生命周期钩子
1 生命周期钩子概述
组件共有9个生命周期钩子
  
1.1 生命周期的执行顺序
技巧01:测试时父组件传递对子组件的输入属性进行初始化操作
import { Component, Input, SimpleChanges, OnInit, OnChanges, DoCheck, AfterContentChecked, AfterViewInit, AfterContentInit, AfterViewChecked, OnDestroy } from '@angular/core';
let logIndex : number = 1;
@Component({
  selector: 'life',
  templateUrl: './life.component.html',
  styleUrls: ['./life.component.scss']
})
export class LifeComponent implements OnInit, OnChanges, DoCheck,
AfterContentInit, AfterContentChecked, AfterViewInit,
AfterViewChecked, OnDestroy {
  @Input()
  name : string;
  logIt(msg : String) {
    console.log(`#${logIndex++} - ${msg}`);
  }
  constructor() {
    this.logIt("name属性在constructor里面的值为: " + this.name);
  }
  ngOnInit() {
    this.logIt("ngOnInit");
  }
  ngOnChanges(changes : SimpleChanges){
    this.logIt("name属性在ngOnChanges里面的值为: " + this.name);
  }
  ngDoCheck() {
    this.logIt("ngDoCheck");
  }
  ngAfterContentInit() {
    this.logIt("ngAfterContentInit");
  }
  ngAfterContentChecked() {
    this.logIt("ngAfterContentChecked");
  }
  ngAfterViewInit() {
    this.logIt("ngAfterViewInit");
  }
  ngAfterViewChecked() {
    this.logIt("ngAfterViewChecked");
  }
  ngOnDestroy() {
    this.logIt("ngOnDestroy");
  }
}
TS
    
2 ngOnChanges
2.1 可变对象和不可变对象
在JavaScript中string类型是不可变对象,自定义的对象是可变对象;例如:
var a = "hello"; -> 变量a中存储的是字符串“hello”对应的内存地址
a = "warrior"; -> 变量a中存储的是字符串“warrior”对应的内存地址
结论:将不同的字符串赋值给同一个变量时,变量的值会发生改变;所以string类型是不可变类型【PS: 跟Java一样】
var user : {name : string} = {name : "warrior"}; -> 变量user中存储的是对象{name : "warrior"}对应的内存地址
user.name = "fury"; -> 变量user中还是存储的对象{name : "fury”}对应的内存地址,而且{name : "warrior"}和{name : "fury”}是同一个对象,所以他们的内存地址相同,故变量user中存储的值没有发生改变,改变的仅仅是变量user所指向的那个对象中的内容而已
结论:修改一个对象的内容并不会改变这个对象的内存地址,所以对象是可变对象
2.2 ngOnChanges
当输入属性的值发生改变时就会触发ngOnChanges
技巧01:如果输入属性的类型是一个对象时,需要区分是可变对象还是不可变对象,只有不可变对象时才会触发ngOnChanges;总之记住只要输入属性的值发生改变才会触发ngOnChanges
技巧02:ngOnChanges方法需要传入一个 SimpleChanges 类型的参数,可以利用该参数来查看输入属性改变前后的值,以及是否是初次赋值
技巧03:JSON.stringfy() 方法在将数据转化成JSON时可以进行格式化,例如
  ngOnChanges(simpleChanges : SimpleChanges) {
    console.log(JSON.stringify(simpleChanges, null, 2));
  }
2.2.1 子组件代码
<div class="panel panel-primary">
<div class="panel-heading">子组件</div>
<div class="panel-body">
<p>问候语:{{greeting}}</p>
<p>姓名:{{user.name}}</p>
<p>年龄:{{age}}</p>
<p>
消息:<input type="text" name="message" [(ngModel)]="message" />
</p>
</div>
<div class="panel-footer">{{currentDate | date : "yyyy-MM-dd HH:mm:ss"}}</div>
</div>
HTML
import { Component, OnInit, EventEmitter, Output, Input, OnChanges, SimpleChanges } from '@angular/core';
@Component({
  selector: 'child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.scss']
})
export class ChildComponent implements OnInit, OnChanges {
  @Input()
  greeting : string;
  @Input()
  user : {name : string};
  @Input()
  age : number;
  message : string;
  currentDate : Date;
  constructor() { }
  ngOnInit() {
    this.currentDate = new Date();
    setInterval(() => {
      this.currentDate = new Date();
    }, 1000);
  }
  ngOnChanges(simpleChanges : SimpleChanges) {
    console.log(JSON.stringify(simpleChanges, null, 2));
  }
}
TS
2.2.2 父组件代码
<div class="panel panel-primary">
<div class="panel-heading">父组件</div>
<div class="panel-body">
<p>
问候语:<input type="text" name="greeting" [(ngModel)]="greeting" />
</p>
<p>
姓名:<input type="text" name="name" [(ngModel)]="user.name" />
</p>
<p>
年龄:<input type="number" [(ngModel)]="age" />
</p>
<child [greeting]="greeting" [user]="user" [age]="age"></child>
</div>
<div class="panel-footer">{{currentDate | date : "yyyy-MM-dd HH:mm:ss"}}</div>
</div>
HTML
import { Component, OnInit } from '@angular/core';
@Component({
  selector: 'parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.scss']
})
export class ParentComponent implements OnInit {
  greeting : string = "Hello";
  user : {name : string} = {name : "王杨帅"};
  age : number = 8;
  currentDate : Date;
  constructor() { }
  ngOnInit() {
    this.currentDate = new Date();
    setInterval(() => {
      this.currentDate = new Date();
    }, 1000);
  }
}
TS
2.2.3 效果图
      
3 ngDoCheck
3.1 变更检测机制
angular中由zone.js去负责监听浏览器中所有异步事件(事件[单击、双击]、定时器、ajax)来保证模板和组件属性的变化时同步的;
只要zone.js检测到有异步事件发生时所有监测机制是默认检测机制的组件都会触发ngDoCheck
应用:当输入属性的类型是可变对象时,即使可变对象的内容发生了变化 ngOnchanges 也不会被调用,但是 ngDoCheck 会被调用;所以我们可以利用 ngDoCheck 来检测可变对象的变化
坑01:zone.js检测到任何一个组件有异步事件发生都会让所有采用默认变更检测机制的组件执行 ngDoCheck,所以 ngDoCheck 方法要慎用,而且逻辑不能太复杂,不然会影响性能
3.2 变更检测策略
3.2.1 default
angular默认的变更检测策略
如果所有的组件都是默认的变更检测策略,那么当一个组件发生改变时angular会对所有的组件进行变更检查
3.2.2 onPush
待更新...
3.3 代码汇总
3.3.1 父组件代码
<div class="panel panel-primary">
<div class="panel-heading">父组件</div>
<div class="panel-body">
<p>
问候语:<input type="text" name="greeting" [(ngModel)]="greeting" />
</p>
<p>
姓名:<input type="text" name="name" [(ngModel)]="user.name" />
</p>
<p>
年龄:<input type="number" [(ngModel)]="age" />
</p>
<child [greeting]="greeting" [user]="user" [age]="age"></child>
</div>
<div class="panel-footer">{{currentDate | date : "yyyy-MM-dd HH:mm:ss"}}</div>
</div>
HTML
import { Component, OnInit } from '@angular/core';
@Component({
  selector: 'parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.scss']
})
export class ParentComponent implements OnInit {
  greeting : string = "Hello";
  user : {name : string} = {name : "王杨帅"};
  age : number = 8;
  currentDate : Date;
  constructor() { }
  ngOnInit() {
    this.currentDate = new Date();
    // setInterval(() => {
    //   this.currentDate = new Date();
    // }, 1000);
  }
}
TS
3.3.2 子组件代码
<div class="panel panel-primary">
<div class="panel-heading">子组件</div>
<div class="panel-body">
<p>问候语:{{greeting}}</p>
<p>姓名:{{user.name}}</p>
<p>年龄:{{age}}</p>
<p>
消息:<input type="text" name="message" [(ngModel)]="message" />
</p>
</div>
<div class="panel-footer">{{currentDate | date : "yyyy-MM-dd HH:mm:ss"}}</div>
</div>
HTML
import { Component, OnInit, EventEmitter, Output, Input, OnChanges, SimpleChanges } from '@angular/core';
import { DoCheck } from '@angular/core/src/metadata/lifecycle_hooks';
@Component({
  selector: 'child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.scss']
})
export class ChildComponent implements OnInit, OnChanges, DoCheck {
  @Input()
  greeting : string;
  @Input()
  user : {name : string};
  oldName : string; // 存储上一次的值
  changeNum : number = 0; // 非本组件触发ngDoCheck方法的次数
  changeDetected : boolean; // 是否是本组件触发ngDoCheck方法
  @Input()
  age : number;
  message : string;
  currentDate : Date;
  constructor() { }
  ngOnInit() {
    this.currentDate = new Date();
    // setInterval(() => {
    //   this.currentDate = new Date();
    // }, 1000);
  }
  ngOnChanges(simpleChanges : SimpleChanges) {
    console.log(JSON.stringify(simpleChanges, null, 2));
  }
  ngDoCheck() : void {
    // 如果检测到是本组件的输入属性变化
    if (this.user.name !== this.oldName) {
      this.changeDetected = true;
      console.log("ngDoCheck: user.name 从 "+ this.oldName +" 变成了 "+ this.user.name +" ");
      this.oldName = this.user.name;
    }
    if (this.changeDetected) {
      this.changeNum = 0; // 本组件触发的ngDoCheck就进行清零操作
    } else { // 非本组件触发的ngDoCheck方法就进行加一操作
      this.changeNum = this.changeNum + 1;
      console.log("ngDoCheck: user.name没有变化,ngDoCheck方法被调用了" + this.changeNum + "次");
    }
    this.changeDetected = false;
  }
}
TS
3.3.3 效果展示
      
4 ngAfterViewInit 和 ngAfterViewChecked
4.1 父组件调用子组件的方法
这两个钩子是在组件的模板已经完全组装好后才会被调用,所以在这两个钩子中不能修改和模板相关的数据信息
4.1.1 利用模板变量实现
在父组件的视图模板中为子组件添加一个模板变量,然后在父组件中就可以利用这个模板变量来调用子组件的方法了
      
4.1.2 利用子组件的实例实现
在父组件的视图模板中为子组件添加一个模板变量,然后在组件类中利用@ViewChild来实例化一个子组件实例,再通过这个实例在父组件类中调用子组件的方法
      
      
4.2 调用顺序
4.2.1 组件中这两个钩子的调用顺序
组件被加载 -> 视图初始化钩子
-> 视图变更检测钩子
-> 视图变更检测钩子
技巧01:组件被调用时先要执行视图初始化钩子,再执行视图变更检测钩子,而且视图初始化钩子只会被调用一次
4.2.2 父子组件中的调用顺序
父组件被加载 -> 子组件被加载 -> 子组件视图初始化钩子 -> 父组件视图初始化钩子
-> 子组件视图变更检测钩子 -> 父组件视图变更检测钩子
-> 子组件视图变更检测钩子 -> 父组件视图变更检测钩子
技巧01:先执行执行子父组件的视图初始化钩子 -> 再子父组件的视图变更检测钩子 -> 循环调用子父组件的视图变更检测钩子
技巧02:视图变更检测钩子的调用是先调用子组件的再调用父组件的
技巧03:视图初始化钩子的调用是先调用子组件的再调用父组件的
坑01:这两个钩子都是在视图组装好之后触发的
4.2.3 修改数据
视图初始化钩子和视图变更检测钩子中不能修改和视图相关的数据信息 -> 可以利用一个定时器来实现,因为利用定时器可以让操作在另外一个JavaScript运行周期中运行
4.2.4 代码汇总
》父组件
<div class="panel panel-primary">
<div class="panel-heading">父组件</div>
<div class="panel-body"> <child #child1></child>
<child #child2></child> <button (click)="child2.greeting('Zeus')">调用子组件child2的方法</button>
<br /> <p>{{info}}</p>
</div>
<div class="panel-footer">{{currentDate | date : "yyyy-MM-dd HH:mm:ss"}}</div>
</div>
HTML
import { Component, OnInit, ViewChild } from '@angular/core';
import { ChildComponent } from './child/child.component';
import { AfterViewInit, AfterContentChecked } from '@angular/core/src/metadata/lifecycle_hooks';
@Component({
  selector: 'parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.scss']
})
export class ParentComponent implements OnInit, AfterViewInit, AfterContentChecked {
  @ViewChild("child1")
  child1 :  ChildComponent;
  info : string;
  currentDate : Date;
  constructor() { }
  ngOnInit() {
    this.currentDate = new Date();
    // setInterval(() => {
    //   this.currentDate = new Date();
    // }, 1000);
    setInterval(() => {
      this.child1.greeting("Warrior");
    }, 5000);
  }
  ngAfterViewInit() : void {
    console.log("父组件视图初始化完毕");
    // this.info = "good boy"; // 视图初始化钩子中不能修改和视图相关的数据信息
    // setTimeout(() => { // 上面一行代码的解决办法
    //   this.info = "王杨帅";
    // }, 5000);
  }
  ngAfterContentChecked() : void {
    console.log("父组件视图变更检测完毕")
    this.info = "good boy"; // 视图变更检测钩子中可以修改和视图相关的数据信息
  }
}
TS
》子组件
<div class="panel panel-primary">
<div class="panel-heading">子组件</div>
<div class="panel-body"> </div>
<div class="panel-footer">{{currentDate | date : "yyyy-MM-dd HH:mm:ss"}}</div>
</div>
HTML
import { Component, OnInit, DoCheck, EventEmitter, Output, Input, OnChanges, SimpleChanges, AfterViewInit, AfterContentChecked } from '@angular/core';
@Component({
  selector: 'child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.scss']
})
export class ChildComponent implements OnInit, AfterViewInit, AfterContentChecked  {
  currentDate : Date;
  constructor() { }
  ngOnInit() {
    this.currentDate = new Date();
    // setInterval(() => {
    //   this.currentDate = new Date();
    // }, 1000);
  }
  greeting(info : string) : void {
    console.log("Hello " + info);
  }
  ngAfterViewInit() : void {
    console.log("子组件视图初始化完毕");
  }
  ngAfterContentChecked() : void {
    console.log("子组件视图变更检测完毕")
  }
}
TS
5 ngAfterContentInit 和 ngAfterContentChecked
5.1 内容投影
5.1.1 需求
如何将父组件的数据传递到子组件
5.1.2 方案
》利用路由解决
》利用子组件的输入属性解决
》利用服务解决
》利用投影解决 【推荐】
5.1.3 投影编程步骤
》子组件的视图
在子组件的视图中添加 ng-content 标签
》父组件视图
在父组件中添加子组件标签,并在子组件标签内编写需要进行投影的代码;当系统运行后会自动将需要投影的代码投影到子组件的 ng-content 标签里面
技巧01:ng-content 仅仅是一个占据位置的标签,系统运行后投影的内容会代替 ng-content 的位置
》如何实现多个投影
为子组件的每个 ng-content 标签添加 select 属性
技巧01: select 的属性值格式是 “.属性值”
在父组件视图中使用子组件的内部利用class为其指定投影到那个 ng-content
》代码汇总
<div class="panel panel-primary">
<div class="panel-heading">子组件</div>
<div class="panel-body">
<div style="border: 1px solid red;">
<ng-content select=".red"></ng-content>
</div>
<hr />
<div style="border: 1px solid green">
<ng-content select=".green"></ng-content>
</div>
</div>
<div class="panel-footer">{{currentDate | date : "yyyy-MM-dd HH:mm:ss"}}</div>
</div>
子组件HTML
<div class="panel panel-primary">
<div class="panel-heading">父组件</div>
<div class="panel-body"> <child>
<div class="red">
我是父组件传过来的数据【放到子组件的红框中】
</div>
<div class="green">
我是父组件传过来的数据02【放到子组件的绿框中】
</div>
</child> </div>
<div class="panel-footer">{{currentDate | date : "yyyy-MM-dd HH:mm:ss"}}</div>
</div>
父组件HTML
5.2 执行顺序
5.2.1 同一组件中这两个钩子的调用顺序
先调用投影内容初始化钩子 -> 再调用投影内容变更检测钩子
5.2.2 父子组件中的这两个钩子的调用顺序
先调用父组件中的钩子 -> 再调用子组件的的钩子
技巧01:投影内容相关的两个钩子在父子组件中的调用顺序和视图相关的两个钩子在父子组件中的调用顺序恰恰相反
5.2.3 修改数据
投影相关的两个钩子可以修改和视图相关的数据信息
愿意:投影相关的两个钩子是在视图组装完毕之前调用的,而视图相关的两个钩子是在视图组装完毕后调用的
5.2.4 代码汇总
》父组件代码
<div class="panel panel-primary">
<div class="panel-heading">父组件</div>
<div class="panel-body"> <child>
<div class="red">
我是父组件传过来的数据【放到子组件的红框中】
</div>
<div class="green">
我是父组件传过来的数据02【放到子组件的绿框中】
</div>
</child> </div>
<div class="panel-footer">{{currentDate | date : "yyyy-MM-dd HH:mm:ss"}}</div>
</div>
HTML
import { Component, OnInit, ViewChild } from '@angular/core';
import { ChildComponent } from './child/child.component';
import { AfterViewInit, AfterContentChecked, AfterContentInit, AfterViewChecked } from '@angular/core/src/metadata/lifecycle_hooks';
@Component({
  selector: 'parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.scss']
})
export class ParentComponent implements OnInit,
AfterContentInit, AfterContentChecked,
AfterViewInit, AfterViewChecked {
  @ViewChild("child1")
  child1 :  ChildComponent;
  currentDate : Date;
  constructor() { }
  ngOnInit() {
    this.currentDate = new Date();
    // setInterval(() => {
    //   this.currentDate = new Date();
    // }, 1000);
  }
  ngAfterContentInit() : void {
    console.log("父组件投影内容初始化完毕");
  }
  ngAfterContentChecked() : void {
    console.log("父组件投影内容变更检测完毕");
  }
  ngAfterViewChecked() : void {
    console.log("父组件视图内容变更检测完毕");
  }
  ngAfterViewInit() : void {
    console.log("父组件视图初始化完毕");
  }
}
TS
》子组件代码
<div class="panel panel-primary">
<div class="panel-heading">子组件</div>
<div class="panel-body">
<div style="border: 1px solid red;">
<ng-content select=".red"></ng-content>
</div>
<hr />
<div style="border: 1px solid green">
<ng-content select=".green"></ng-content>
</div>
<p>{{info}}</p>
</div>
<div class="panel-footer">{{currentDate | date : "yyyy-MM-dd HH:mm:ss"}}</div>
</div>
HTML
import { Component, OnInit, DoCheck,AfterViewChecked, EventEmitter, AfterContentInit, Output, Input, OnChanges, SimpleChanges, AfterViewInit, AfterContentChecked } from '@angular/core';
@Component({
  selector: 'child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.scss']
})
export class ChildComponent implements OnInit,
AfterContentInit, AfterContentChecked,
AfterViewInit, AfterViewChecked  {
  currentDate : Date;
  info : string;
  constructor() { }
  ngOnInit() {
    this.currentDate = new Date();
    // setInterval(() => {
    //   this.currentDate = new Date();
    // }, 1000);
  }
  ngAfterContentInit() : void {
    console.log("子组件投影内容初始化完毕");
    // this.info = "warrior"; // 投影内容初始化完毕时可以修改视图相关数据信息
  }
  ngAfterContentChecked() : void {
    console.log("子组件投影内容变更检测完毕");
    this.info = "fury"; // 投影内容变更检测完毕时可以修改视图相关数据信息
  }
  ngAfterViewChecked() : void {
    console.log("子组件视图内容变更检测完毕");
    // this.info = "warrior";
  }
  ngAfterViewInit() : void {
    console.log("子组件视图初始化完毕");
  }
}
TS
5.2.5 效果展示
      
Angular25 组件的生命周期钩子的更多相关文章
- Vue_(组件)实例生命周期钩子
		
Vue生命周期中文文档 传送门 Vue生命周期:Vue实例从创建到销毁的过程,称为Vue的生命周期: Vue生命周期钩子:又称为Vue生命周期钩子方法/函数,是Vue为开发者提供的方法,我们可以通过这 ...
 - 通俗易懂了解Vue组件的生命周期
		
1.前言 在使用vue2.0进行日常开发中,我们总有这样的需求,我就想在页面刚一加载出这个表格组件时就发送请求去后台拉取数据,亦或者我想在组件加载前显示个loading图,当组件加载出来就让这个loa ...
 - Vue项目的创建、路由、及生命周期钩子
		
目录 一.Vue项目搭建 1.环境搭建 2.项目的创建 3.pycharm配置并启动vue项目 4.vue项目目录结构分析 5.Vue根据配置重新构建依赖 二.Vue项目创建时发生了什么 三.项目初始 ...
 - [Vuejs] 组件 v-if 和 v-show 切换时生命周期钩子的执行
		
v-if 初始渲染 初始值为 false 组件不会渲染,生命周期钩子不会执行,v-if 的渲染是惰性的. 初始值为 true 时,组件会进行渲染,并依次执行 beforeCreate,created, ...
 - Angular组件生命周期——生命周期钩子
		
生命周期钩子介绍: 1.ngOnChange:响应组件输入值发生变化时触发的事件. 2.ngOnInit:用于数据绑定输入属性之后初始化组件,在第一次ngOnChange之后被调用. a. 组件构造后 ...
 - Vue ---- 组件文件分析 组件生命周期钩子 路由 跳转 传参
		
目录 Vue组件文件微微细剖 Vue组件生命周期钩子 Vue路由 1.touter下的index.js 2.路由重定向 3.路由传参数 补充:全局样式导入 路由跳转 1. router-view标签 ...
 - Vue 组件生命周期钩子
		
Vue 组件生命周期钩子 # 1)一个组件从创建到销毁的整个过程,就称之为组件的生命周期 # 2)在组件创建到销毁的过程中,会出现众多关键的时间节点, 如: 组件要创建了.组件创建完毕了.组件数据渲染 ...
 - 简单记录一下vue生命周期及 父组件和子组件生命周期钩子执行顺序
		
首先,vue生命周期可以用下图来简单理解 当然这也是官方文档的图片,详细的vue周期详解请参考这里 然而当同时存在父子组件的时候生命周期钩子是如何执行的呢? 请看下文: 加载渲染过程父beforeCr ...
 - Vue生命周期 钩子函数和组件传值
		
Vue生命周期 钩子函数 每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听.编译模板.将实例挂载到 DOM 并在数据变化时更新 DOM 等. 同时在这个过程中也会运行一 ...
 
随机推荐
- Python 字符串相似性的几种度量方法
			
字符串的相似性比较应用场合很多,像拼写纠错.文本去重.上下文相似性等. 评价字符串相似度最常见的办法就是:把一个字符串通过插入.删除或替换这样的编辑操作,变成另外一个字符串,所需要的最少编辑次数,这种 ...
 - Windows GVLK密钥对照表(KMS激活专用
			
以下key来源于微软官网:https://technet.microsoft.com/en-us/library/jj612867.aspx Windows Server 2016 操作系统 KMS激 ...
 - win10 135/445端口关闭
			
135端口关闭 见[在 Windows 下关闭135/139/445端口的图文方法] 445端口关闭 打开控制面板-->网络和共享中心-->更改适配器设置-->右键点击正在使用的网卡 ...
 - 【MFC】SetWindowPos函数使用详解
			
摘自: http://wenku.baidu.com/link?url=hYKs20rYA13TTdMl9gJ378GNOsxH1DPZPkYZVEIcipATlVBMLzjWdpd2-29fm-tq ...
 - 【解题报告】[动态规划]RQNOJ PID2 / 开心的金明
			
原题地址:http://www.rqnoj.cn/problem/2 解题思路:背包问题. 状态转移方程:DP[i][j]=max(DP[i-v[j]][j-1]+p[j]*v[j],DP[i][j- ...
 - CodeForces - 662A:Gambling Nim (求有多少个子集其异或为S)(占位)
			
As you know, the game of "Nim" is played with n piles of stones, where the i-th pile initi ...
 - JavaScript 与 Java、PHP 的比较
			
网站开发的实践从设计方面开始,包括客户端编程语言.大体上说,在网页设计中使用了三种语言:HTML,CSS和Java.自从网站发明以来,HTML和CSS已经成为网页设计的基础,但是Java被用于添加网站 ...
 - 因实现本地浏览器访问nginx修改配置文件后,安装vsftpd失败
			
解决方法如下(修改dns配置) vi /etc/resolv.conf 在此文件最后加入:nameserver 8.8.8.8 如果没有vi编辑器可用: echo "nameserver 8 ...
 - 在Spring中通过构造自动装配--constructor
			
在Spring中,可以使用“通过构造自动装配”,实际上是按构造函数的参数类型自动装配. 这意味着,如果一个bean的数据类型与其他bean的构造器参数的数据类型是相同的,那么将自动装配. packag ...
 - Linux多进程多线程例子
			
看了apue3,关于进程线程和进程间通信写了一个例子,方便自己理解相关知识,备忘. #include <stdlib.h> #include <stdio.h> #includ ...