angularjs1.3.0源码解析之directive
前言
angular之所以使用起来很方便,是因为通常我们只需要在html里面引入一个或多个(自定义或内置的)指令就可以完成一个特定的功能(这也是angular推荐的方式),比如:一个简单的双向绑定(用ng-model指令),或者模板循环渲染(用ng-repeat指令),又或者是模板是否显示(用ng-if指令),而对于这些指令的内部实现一般我们无需太多关心(除非你想深入了解),我们更乐意于把侧重点放在指令如何使用(即API)上。
我们知道一个应用是由多个功能组成的,而在angular应用中,一个功能又是由一个或多个指令所完成,那么我们可以认为angular应用被很多指令所驱动着,当我们给angular应用添加了所有我们需要的指令后,angular内部则会负责帮我们编译和运行所有指令,从而完成特定功能的实现。
那么,对于指令,我们自然会有以下的疑问: 1. 指令是什么? 2. 指令如何定义存储? 3. 指令如何编译运行?
带着疑问,我们慢慢一步一步深入到源码compile.js中。
指令
指令从html的角度,可以认为指令名字是一个标识符,可以作为元素名(E),元素属性(A),注释(M),类名(C)出现在html中;而从javascript的角度,则可以认为是返回的一个规范化的有特殊意义的指令对象。
听起来有点抽象,简而言之一切都得从自定义一个简单指令开始:
html
<body ng-app="myApp">
<div my-directive></div>
</body>
js
angular.module('myApp', [])
.directive('myDirective', function() {
// 返回一个对象(暂且称之为指令对象)
return {
restrict: 'A',
replace: true,
scope: true,
template: '<span>hello world</span>',
compile: function (tElement) {
console.log('complile: ', tElement);
return function (scope, elem) {
console.log('link: ', elem);
}
}
}
});
上面的代码,大家肯定都很熟悉,就是利用定义好的模块对象myApp调用它的directive()方法,成功注册了一个名字叫做myDirective的指令,然后在html中便可以将my-directive作为元素属性的方式调用这个指令(这里只是简单的模板替换和打印日志)。
这里其实我们关注的其实有两点:
directive方法的实现
返回的指令对象(暂且这样称呼)每个字段的含义
指令定义
module对象的directive方法的实质
首先我们得知道模块对象是什么?不清楚的可以看下这篇文章angular指令流程提到的setupModuleLoader函数。
其实模块对象的directive方法只是一个link,并没有真正的指令注册,这是什么意思呢?
先来看看它的定义:
directive: invokeLater('$compileProvider', 'directive')
再看看invokeLater方法的实现:
function invokeLater(provider, method, insertMethod, queue) {
if (!queue) queue = invokeQueue;
return function() {
queue[insertMethod || 'push']([provider, method, arguments]);
return moduleInstance;
};
}
这样其实就很明了了,module对象的directive方法当调用时实质上只是做一个队列(invokeQueue)的存储,并没有正真意义上的指令注册。
就拿myDirective指令来说,存储的就是[217;$compileProvider217;, 216;directive217;, [217;myDirective217;, function() {230;}]]这样一个数据元单位。
那么真正的指令注册是在什么时候呢,以及怎么注册的呢?在angular指令流程源码注释里也提到过:
当angular执行bootstrap()方法时,内部会调用loadModules()这个方法,来加载所有的module对象(这里就包括了myApp模块对象),模块加载的实质其中就包括遍历当前模块对象上的invokeQueue队列这一项,取出每一个数据元单位,然后执行对应服务的对应方法,所以这里的指令注册便会link到$compileProvider服务的directive()方法。
于是乎,便可以总结了:module.directive()方法只是指令的存储,指令的注册是在angular应用bootstrap()后,通过调用$compileProvider.directive()方法实现的。
其实module对象的其它方法也都是像这样延后执行(invokeLater)的(例如:module.config(),module.controller(),module.provider()等),这样的好处我认为是基于模块化的思想,即我们的指令(directive),控制器(controller),服务(service)等都是基于模块(module)的,angular程序的启动可以有选择性地加载想要的模块(即拥有了挂载在模块上的指令,控制器和服务等),这也是angular的第三方插件经常做的事情,声明一个自己的模块(如:ui.router),然后在(依赖)模块之上注册各种服务(如:$UrlRouterProvider)等供外界调用.
ok,当我们知道了指令注册的实质,我们便可以这样注册myDirective指令:
angular.module('myApp', [])
.config(['$compileProvider', function ($compileProvider) {
$compileProvider.directive('myDirective', function() {
return {
restrict: 'A',
replace: true,
scope: true,
template: '<span>hello world</span>',
compile: function (tElement) {
console.log('complile: ', tElement);
return function (scope, elem) {
console.log('link: ', elem);
}
}
}
});
}]);
不过,显然还是第一种方式来的更简便,也是推荐的使用方式。
$compileProvider服务directive方法的实现
上面我们知道了指令注册的实质是$compileProvider.directive(),那就赶紧来看看它源代码实现吧:
// 指令存储容器,一个指令可以有多个指令工厂函数(即多个指令对象)
// 格式如下:
// {
// directive1: [fn1, fn2,..],
// directive2: [fn3, fn4,..]
// ...
// }
var hasDirectives = {};
this.directive = function registerDirective(name, directiveFactory) {
assertNotHasOwnProperty(name, 'directive');
// 单个指令注册
if (isString(name)) {
assertArg(directiveFactory, 'directiveFactory');
// 如果该指令还没有任何一个指令工厂
if (!hasDirectives.hasOwnProperty(name)) {
// 先初始化
hasDirectives[name] = [];
// 将该指令注册为服务,也就是说当我们通过$injector服务来获取该服务返回的指令对象集合(注意:是有缓存的单例哦)
$provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
function($injector, $exceptionHandler) {
// 指令对象集合
var directives = [];
// 循环遍历指令工厂集合,并收集每个工厂函数返回的指令对象
forEach(hasDirectives[name], function(directiveFactory, index) {
try {
// 调用工厂函数,注意这里用的是$injector,所以工厂函数也可以是一个拥有依赖注入的函数或数组
var directive = $injector.invoke(directiveFactory);
// 如果返回的directive是函数,那么被认为是指令对象的compile字段,
// 该函数返回的结果将作为指令对象的link字段
if (isFunction(directive)) {
directive = { compile: valueFn(directive) };
// 其他的则认为directive是指令对象
// 如果compile字段不存在,link字段存在的情况
} else if (!directive.compile && directive.link) {
directive.compile = valueFn(directive.link);
}
// 下面是指令对象的字段一些默认值设置,这些字段的含义之后再说
directive.priority = directive.priority || 0;
directive.index = index;
directive.name = directive.name || name;
directive.require = directive.require || (directive.controller && directive.name);
directive.restrict = directive.restrict || 'EA';
// 存储到指令对象集合中
directives.push(directive);
} catch (e) {
$exceptionHandler(e);
}
});
// 返回到指令对象集合
return directives;
}]);
}
// 存储当前指令工厂
hasDirectives[name].push(directiveFactory);
// 多个指令对象的形式注册,如:{'d1': function(){}, d2: ['$injector', function($injector) {}]}
} else {
forEach(name, reverseParams(registerDirective));
}
// 提供链式调用
return this;
};
ok,结合上面的源代码加注释,其实可以知道一下几点:
注册指令时,注册的是工厂函数(支持依赖注入),它负责返回指令对象
一个指令可以注册多个工厂函数,就意味着将对应多个指令对象(即指令对象集合),其实多个指令对象之间是有一些冲突的,比如只能拥有有一个模板,拥有一个孤立作用域等
一个指令对应的指令对象集合是通过注册为服务的方式被外界获取的,比如我们可以这样获取上面例子中的myDirective指令集合(代码在这里):
angular.module('myApp').run(['$injector', function($injector) {
console.log($injector.get('myDirective' + 'Directive'));
}]);
另外,工厂函数是支持依赖注入的,所以我们注册指令的形式就可以有那么几种:
// 普通的指令
app.directive('myDirective', function () {
return function () {
console.log('postLink1');
}
});
// 隐式注入
app.directive('myDirective', function ($injector) {
return function () {
console.log('postLink2: ', $injector);
}
});
// 显式注入
app.directive('myDirective', ['$injector', function ($injector) {
return function () {
console.log('postLink3: ', $injector);
}
}]);
指令对象的各个字段
作为使用者,在创建指令的时候,我们其实只要关注工厂函数返回的那个对象(我们称之为指令对象)就可以了,因为在指令编译的时候,它的每个字段将决定着你创建的指令会拥有哪些特性。
对于这些字段含义,打算在后面的编译指令时结合源码,举例讲解会比较清楚些。
指令详解
不知道大家是否还记得angular开始编译的入口,在scope原理的开头有提到过:
injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
function bootstrapApply(scope, element, compile, injector) {
scope.$apply(function() {
element.data('$injector', injector);
compile(element)(scope); // 这里这里开始编译
});
}]
);
在所有module都装载完毕在之后,compile(element)(scope);这句开始编译和链接整个dom树(其实就是调用dom上出现的指令)。
这里$compile是$CompileProvider服务返回的函数单例。
第一步:传递应用根节点给$compile函数,开始编译,返回link函数。
第二步:传递根作用域给link函数,开始链接(每个指令分为pre link 和 post link两个过程)
指令的link和compile
angular在解析指令的时候,其实会先按一定的顺序执行所有指令的compile函数,然后执行所有指令的preLink函数(如果存在的话),最后执行所有指令的postLink函数。
指令对象有两个重要字段,分别是compile和link,其中compile函数的返回值会被用作link字段(函数或者对象如:{pre: function() {}, post: function() {}}),所以有下面几种情况:
当compile字段存在时,link字段将被忽略,compile函数的返回值将作为link字段。
当compile不存在,link字段存在时,angular通过这样directive.compile = valueFn(directive.link);包装一层,使用用户定义定义的link字段
我们说了,link分为preLink和posLink两个阶段,这在哪里体现出来呢,是这样的:link字段或者compile函数的返回值(将作为link字段)可以有两个情况:
如果是函数,那么这样的link,会被认为是postLink
如果是对象,那么link.pre作为preLink函数,link.post作为postLink函数,像这样:
app.directive('myDirective', function () {
return {
compile: function () {
return {
pre: function () {
console.log('preLink');
},
post: function () {
console.log('postLink');
}
}
}
}
});
还有种情况,我们的指令工厂返回的是一个函数,那么angular通过这样的包装directive = { compile: valueFn(directive) },即该函数将作为指令对象的postLink函数,像这样:
app.directive('myDirective', function () {
return function () {
console.log('postLink');
}
});
为了看清angular编译链接指令的顺序,我用以下代码输出日志的方式来说明(代码在这里):
html
<body ng-app="myApp">
<A a1>
<B b1 b2></B>
<C>
<E e1></E>
<F>
<G></G>
</F>
</C>
<D d1></D>
</A>
</body>
js
var app = angular.module('myApp', []);
var names = ['a1', 'b1', 'b2', 'e1', 'd1'];
names.forEach(function (name) {
app.directive(name, function () {
return {
compile: function () {
console.log(name + ' compile');
return {
pre: function () {
console.log(name + ' preLink');
},
post: function () {
console.log(name + ' postLink');
}
};
}
};
});
});
控制台输出:
a1 compile
b1 compile
b2 compile
e1 compile
d1 compile
a1 preLink
b1 preLink
b2 preLink
b2 postLink
b1 postLink
e1 preLink
e1 postLink
d1 preLink
d1 postLink
a1 postLink
可以看出:
所有的指令都是先compile,然后preLink,然后postLink。
节点指令的preLink是在所有子节点指令preLink,postLink之前,所以一般这里就可以通过scope给子节点传递一定的信息。
节点指令的postLink是在所有子节点指令preLink,postLink完毕之后,也就意味着,当父节点指令执行postLink时,子节点postLink已经都完成了,此时子dom树已经稳定,所以我们大部分dom操作,访问子节点都在这个阶段。
指令在link的过程,其实是一个深度优先遍历的过程,postLink的执行其实是一个回溯的过程。
节点上的可能有若干指令,在搜集的时候就会按一定顺序排列(通过byPriority排序),执行的时候,preLinks是正序执行,而postLinks则是倒序执行。
来一张清晰的流程图:
compile-link
大都数情况下,我们编写指令的时候大部分情况会用到postLink(link字段如果是函数而非对象,默认情况下也是postLink)
那我们来看看preLink的应用场景(找到一个例子),代码在这里:
html
<body ng-app="myApp">
<my-parent></my-parent>
</body>
js
var app = angular.module('myApp', []);
app.directive('myParent', function () {
return {
restrict: 'EA',
template: '<div>{{greeting}}{{name}}'+
'<my-child></my-child>'+
'</div>',
link: function(scope,elem,attr){
scope.name = 'Lovesueee';
scope.greeting = 'Hey, I am ';
}
};
});
app.directive('myChild', function () {
return {
restrict: 'EA',
template: '<div>{{says}}</div>',
link: function(scope,elem,attr){
scope.says = 'Hey, I am child, and my parent is ' + scope.name;
}
};
});
页面显示:
Hey, I am Lovesueee
Hey, I am child, and my parent is undefined
这里父指令模板里面嵌套一个子指令(子指令继承了父指令的作用域),我们在子指令中有一个模板变量{{says}},它的值我们在link函数中引用了scope.name,因为我们认为子作用域继承了父作用域,但是结果却显示为undefined。
问题在哪里?我们按顺序来,当link开始时,首先是myParent指令,先preLink(这里没有),此时发现存在子指令myChild,那么对子指令进行preLink(也没有),230;,之后再对子指令进行postLink,注意此时scope.name为undefined,(myParent的postLink还未执行),所以子指令的scope.says的取值就是:Hey, I am child, and my parent is undefined,最后才会执行myParent指令的postLink。
所以说,由于父指令的postLink总是在子指令的preLink和postLink之后执行,而父指令的preLink总是在子指令的preLink和postLink之前执行,所以当父指令要通过scope传递数据数据给子指令(或者说子指令想要访问父指令的作用域数据)时,我们便可以通过preLink函数给scope赋值,像这样改造上面的例子,代码在这里:
app.directive('myParent', function () {
return {
restrict: 'EA',
template: '<div>{{greeting}}{{name}}'+
'<my-child></my-child>'+
'</div>',
link: {
pre: function(scope,elem,attr){
scope.name = 'Lovesueee';
scope.greeting = 'Hey, I am ';
}
}
};
});
页面显示:
Hey, I am Lovesueee
Hey, I am child, and my parent is Lovesueee
指令的scope
在scope原理中,就说明了一点:指令的编译过程中伴随着作用域的创建,这个作用域是跟指令相关的(比较熟悉的内置指令:ngController创建scope)。
在scope原理中也说过,作用域是可继承的,也有孤立作用域的存在,那么在指令中,我们通过指定scope字段来利用这些特点:
scope: true(非空),创建一个继承自父作用域的子作用域,这就意味着,子指令拥有了自己的作用域,同时可以访问父指令的作用域数据。
scope: false(空值),不创建任何作用域,将父作用域当做当前作用域,这意味着,子指令对数据的任何修改都会影响父作用域。
scope: {230;}(对象),创建孤立作用域,这就意味着,与父作用域没有任何联系。
对于前两点,没啥需要解释的,来看看第三点孤立作用域:
我们知道孤立作用域,是单独存在的一个作用域,没继承关系,也不直接引用父作用域,那么问题来了:如果想要访问父作用域的数据,该怎么办?
angular帮我们解决了这个问题,通过将当前节点的属性做为数据传递桥梁,父作用域可以传递数据给节点属性,孤立作用域便可通过一个映射关系来访问这个节点属性来获取数据,从而达到访问父作用域的目的。
问:还记得指令创建孤立作用域的的条件是什么吗?
答:scope是必须是一个对象。
问:那么这个对象有什么用?
答:这是孤立作用域跟父作用域的数据通信的关键,其实是一个孤立作用域字段跟节点属性的映射,这样的映射有三种形式,决定着跟父作用域数据的读(写)关系。
三种访问父作用域的方式:
@attrName : 单向绑定,这就意味着,孤立作用域的任何改变都不会影响到父作用域,父作用域的改变则影响着孤立作用域。
=attrName : 双向绑定,这就意味着,孤立作用域和它的父作用域的任何改变都会影响着对方。
&attrName: 函数绑定,其实就是指定调用父作用域的哪个方法。
类似于这样的映射结构:
scope: {
name: "@", // 单向绑定,孤立作用域的name字段对应着节点的的name属性,其实我们也可以改变属性名:name: @parentName,这样它对应的节点属性就是parent-name
color: "=", // 双向绑定,孤立作用域的color字段对应着节点的的color属性
reverse: "&" // 函数绑定,孤立作用域的reverse字段对应着节点的的reverse属性
}
这里有一个例子,很好地说明了这三种绑定,代码在这里。
接下来我们需要探究的是孤立作用域如何通过这个映射做到数据传递的?
1.单向绑定
case '@':
attrs.$observe(attrName, function(value) {
isolateBindingContext[scopeName] = value;
});
attrs.$$observers[attrName].$$scope = scope;
if( attrs[attrName] ) {
isolateBindingContext[scopeName] = $interpolate(attrs[attrName])(scope);
}
angular内部有一个Attribute类,用来管理节点的属性,angular利用attrs.$observe方法,监测节点属性值是否变化,变化了则改变孤立作用域对应的scopeName的值。
2.双向绑定
case '=':
// 该属性绑定是否可选
if (optional && !attrs[attrName]) {
return;
}
// 父作用域的读
parentGet = $parse(attrs[attrName]);
//...省略不重要代码
// 父作用域的写
parentSet = parentGet.assign || function() {
lastValue = isolateBindingContext[scopeName] = parentGet(scope);
throw $compileMinErr('nonassign',
"Expression '{0}' used with directive '{1}' is non-assignable!",
attrs[attrName], newIsolateScopeDirective.name);
};
// 记录孤立作用域修改之前的值
lastValue = isolateBindingContext[scopeName] = parentGet(scope);
var unwatch = scope.$watch($parse(attrs[attrName], function parentValueWatch(parentValue) {
// 父作用域数据与孤立作用域数据不同
if (!compare(parentValue, isolateBindingContext[scopeName])) {
// 父作用域的数据变化,那么同步孤立作用域数据
if (!compare(parentValue, lastValue)) {
isolateBindingContext[scopeName] = parentValue;
} else {
// 孤立作用域的数据变化,那么同步子作用域数据
parentSet(scope, parentValue = isolateBindingContext[scopeName]);
}
}
return lastValue = parentValue;
}), null, parentGet.literal);
上面的scope是父作用域,isolateBindingContext可认为孤立作用域(也可以是controller实例),parentGet和parentSet是对父作用域的读和写操作。
利用父作用域的scope.$watch添加对属性值的监听,每一次digest,函数parentValueWatch都会执行
如果父作用域数据(parentValue)与孤立作用域数据不同,那么就有两种情况:
孤立作用域的数据变化,那么执行parentSet(scope, parentValue = isolateBindingContext[scopeName]);,同步设置父作用域的值
父作用域的数据变化,那么执行isolateBindingContext[scopeName] = parentValue;,同步设置孤立作用域的值
这样就可以达到双向绑定的作用了。
3.函数绑定
case '&':
parentGet = $parse(attrs[attrName]);
isolateBindingContext[scopeName] = function(locals) {
return parentGet(scope, locals);
};
代码很简单,其实就是包装了一个函数,利用$parse服务解析到的parentGet函数和父作用域scope,调用父作用域的对应函数。
指令的controller
提到controller,大家肯定会想到定义controller(像:myModule.controller(230;)),我们经常会在controller里面注入$scope当前作用域,然后往$scope里面设置值或者函数,那样我们就可以在html中引用这个controller,然后调用$scope里的值或者函数,但是这里我们要谈到的是directive中的controller,到底有啥不同点和相同点?
首先说说,我们通常在指令中如何定义controller?
第一种:通过controller名,引用已定义的controller,代码在这里
app.controller('myController', function ($scope) {
$scope.name = 'Lovesueee'; // 给$scope赋值
this.name = 'maxin'; // 给controller实例赋值
});
app.directive('myDirective', function () {
return {
controller: 'myController',
link: function (scope, elem, attrs, ctrl) {
console.log(ctrl, scope);
}
}
});
我们自定义一个controller叫做myController(存储在controllers集合里),然后在指令myDirective中,通过字符串'myController'引用这个定义好的controller,最后在link函数中第四个参数便可以调用到这个controller实例(打开控制台看下输出日志)
它的查找原理是什么?
angular会首先会从所有定义好的controllers集合(就像directives集合一样)里面找名字叫做'myController'的controller(这里就是这样的),如果存在则返回这个contructor,不存在则会从当前$scope里面查找同名的controller,如果还不存在且设置准许全局查找,则会在全局里面查找同名的controller,它的实现:
expression = controllers.hasOwnProperty(constructor)
? controllers[constructor]
: getter(locals.$scope, constructor, true) ||
(globals ? getter($window, constructor, true) : undefined);
试一试从当前作用域里查找controller,代码在这里
var app = angular.module('myApp', []).run(function ($rootScope) {
// 将controller存在$scope中
$rootScope.myController = function () {
this.name = 'maxin';
}
});
app.directive('myDirective', function () {
return {
controller: 'myController',
link: function (scope, elem, attrs, ctrl) {
console.log(ctrl);
}
}
});
除了上述的controller: 'myController'这种字符串引用定义好的controller,我们当然也可以直接在指令中用函数(可以依赖注入哦)定义一个匿名controller,修改之前的例子:
第二种:通过直接定义匿名controllerh函数,代码在这里
app.directive('myDirective', function () {
return {
controller: function ($scope) {
$scope.name = 'Lovesueee';
this.name = 'maxin';
},
link: function (scope, elem, attrs, ctrl) {
console.log(scope, ctrl);
}
}
});
再说说ng-controller指令,实质就是和定义其他指令一样,它的实现:
var ngControllerDirective = [function() {
return {
restrict: 'A',
scope: true,
controller: '@',
priority: 500
};
}];
scope: true创建了一个继承作用域,定义了controller: @字段,这里的@的表示controller字段的真正取值来自于ng-controller="myController"中的myController,那么接下来的情况就和第一种情况类似了,只不过,我们大部分情况下,在使用ng-controller指令时没有用controller的实例,而是创建一个继承了父作用域的$scope,然后向$scope里面赋值来完成模板渲染或者回调,像这样:
html
<div ng-controller="MyController">
<button ng-click="show()">{{text}}</button>
</div>
js
app.controller("MyController", ['$scope',function(scope) {
scope.text = "点我";
scope.show = function () {
console.log(scope.text);
}
}]);
倘若我要使用实例化的controller实例呢?angular可以通过as来让我们调用,我们修改代码,代码在这里:
html
<div ng-controller="MyController as ctrl">
<button ng-click="ctrl.show()">{{ctrl.text}}</button>
</div>
js
app.controller("MyController", ['$scope',function(scope) {
this.text = "点我";
this.show = function () {
console.log(this.text);
}
}]);
我们在controller的构造函数中我们不再使用$scope而是this(代表controller实例),在html中通过MyController as ctrl关键字来引用controller实例,所以这里的程序功能和上一个例子没啥区别,只是使用方式不同。
那么在directive中,我们知道link函数的第四个参数其实就是controller实例,所以如果我们要通过controller传递数据时,就要用this变量,另外指令中的controller实例是可以被其它指令所调用的,这就涉及到指令中的require参数,后面讲到。
来说说上述as关键字实现的原理:
我们知道模板的渲染肯定离开不了$scope这个变量,我们通过MyController as ctrl这一句便可在模板中随意使用ctrl这个变量名当做controller实例使用,完全可以猜想到$scope.ctrl其实已经被赋值引用了当前的controller实例,看下angular如何实现的:
function addIdentifier(locals, identifier, instance, name) {
if (!(locals && isObject(locals.$scope))) {
throw minErr('$controller')('noscp',
"Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.",
name, identifier);
}
locals.$scope[identifier] = instance;
}
identifier是别名,instance是controller实例,locals.$scope[identifier] = instance;这一句便是实现这一个功能的核心(另外:指令中还可以通过controllerAs设置指令的默认别名)。
最后:
说到controller,可以说下bindToController,这个指令字段可能大家很少使用,当我们使用孤立作用域的时候,可能会使用到它:
我们知道孤立作用域的数据通过scope: {...}与父作用域进行关联,如果我们想在孤立作用域的使用controller, 那么就涉及到:controller实例的数据通过scope: {...}与父作用域进行关联的问题,bindToController: trur就是用来解决这个问题的(这里就不细讲了,可以看下这个例子)。
指令中的require
前面提到了controller,其实当一个指令被link之前,controller构造函数会被执行,创建controller实例,此时做的很重要的一点是:
$element.data('$' + directive.name + 'Controller', controllerInstance.instance);
这一句将该controller实例通过data方法存储到对应的dom上。
先举个例子,代码在这里:
html
<body ng-app="myApp">
<my-parent></my-parent>
</body>
js
app.directive('myParent', function () {
return {
restrict: 'EA',
template: '<div>{{greeting}}{{name}}'+
'<my-child></my-child>'+
'</div>',
controller: function(){
this.name = 'Lovesueee';
},
link: function(scope,elem,attr,ctrl){
scope.name = ctrl.name;
scope.greeting = 'Hey, I am ';
}
};
});
app.directive('myChild', function () {
return {
restrict: 'EA',
require: '^myParent', // 引用父指令的controller
template: '<div>{{says}}</div>',
link: function(scope,elem,attr,ctrl){
scope.says = 'Hey, I am child, and my parent is '+ ctrl.name;
}
};
});
上面的例子我们在父指令中myParent定义了controller(angularjs会自动加上为她require: 'myParent'),它的实例除了在自身的link函数中引用以外,在子指令myChild的link函数中也有引用,这都归功于require: '^myParent'这一句,意思是说,将在link函数中引用myParent指令中的controller实例,整体地从这个例子来看,这其实就是一种父作用域向子作用域数据传递的方式。
那么是如何做到引用controller实例呢?
前面说了,controller实例是通过data方法被存储在对应指令的dom元素上的,那么要想获得这样的实例,当然就得从dom元素上再次通过data方法取出来,如果是父指令的controller实例,那么就需要在dom.parent()上通过data方法取,如果是祖先指令的controller实例,则需要一直向上遍历并通过data方法取,直到根元素为止(为此angularjs封装了一个可以向祖先元素通过data方法取数据的方法,叫做inheritedData)。
而到底要不要选择向祖先元素获取controller实例,是由require的值决定的:
require: 216;myParent217; 表示只从当前节点上获取myParent指令的controller实例。
require: 217;^myParent217; 表示从当前节点上获取myParent指令的controller实例开始,如果获取不到则一直从parent节点上取。
require: 217;?myParent217;,217;^?myParent217; 或者 217;?^myParent217; 加上问号,表示获取不到controller实例也不会报错。
注意:require的值可以是一个数组,来引用多个controller实例。
指令编译源码分析图
指令的编译其实是一个复杂的递归过程(毕竟dom树),为了描述的更清楚些,我还是画了一个有点复杂思维导图(原图):
指令编译流程
这里,我们做一个简单假设:
根节点是节点A
节点C,F,G没有指令,其他节点都有一个或多个指令。
源引:http://www.html-js.com/article/2447
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
相关文章
- 吉大一院哪家双眼皮做的好吗
...
2024/4/21 6:09:29 - angular 指令 要点解析
指令可以删繁就简前端的js代码,杜绝重复的js代码和html代码。 下面就对指令的重要属性进行罗列 一、restrict 定义指令的出现形式 可以定义为多种形式,比如 restrict AE 标识可以是属性,也可以是元素。restrict AECM 则标识支持下面所有…...
2024/4/21 6:09:29 - Vue源码解析——响应式篇
文章来源:我的博客 概述 这里的响应式,是指作为现在 MVVM 主流思想下的前端框架采用的一种数据驱动视图的方案,即对数据监测,来进行相应的 DOM 更新。而 Vue 实现的方案也是比较特别的,其很巧妙的借助 JS 原生的对对象…...
2024/4/28 13:15:01 - ROS move_base 源码解析
一、move_base.h #ifndef NAV_MOVE_BASE_ACTION_H_ #define NAV_MOVE_BASE_ACTION_H_#include <vector> #include <string>#include <ros/ros.h>#include <actionlib/server/simple_action_server.h> #include <move_base_msgs/MoveBaseAction.h&g…...
2024/4/20 19:11:51 - 双眼皮开的一个大一个小
...
2024/4/20 8:34:19 - 试读angular源码第二章:引导模块bootstrapModule
直接看人话总结 前言 今天 angularv8的正式版发了,但是除了路由懒加载那里没觉得有啥大变化,有点小失望 承接上一章 项目地址 文章地址 angular 版本:8.0.0-rc.4 欢迎看看我的类angular框架 文章列表 试读angular源码第一章:开场与…...
2024/5/6 18:58:23 - 试读angular源码第四章:angular模块及JIT编译模块
直接看人话总结 前言 承接上一章 该文章项目地址 文章地址 angular 版本:8.0.0-rc.4 欢迎看看我的类angular框架 文章列表 试读angular源码第一章:开场与platformBrowserDynamic 试读angular源码第二章:引导模块bootstrapModule 试读angular源…...
2024/4/21 6:09:27 - AngularJS源码解析1:angular自启动过程
angularJS加载进来后,会有一个立即执行函数调用,在源代码的最下面是angular初始化的地方。代码展示: bindJQuery();publishExternalAPI(angular);jqLite(document).ready(function() {angularInit(document, bootstrap); }); bindJQuery方法的…...
2024/4/21 6:09:26 - Vue set方法使用及源码解析
使用场景: 动态添加一个响应式属性 实例创建之后添加新的属性到实例上,它不会触发视图更新。 由于 JavaScript 的限制,Vue 不能检测以下变动的数组。 通过数组的下标去修改数组的值,数据已经被修改了,但是不触发updated函数,视图不更新, v…...
2024/4/21 6:09:25 - 爱思特程旭双眼皮案例
...
2024/4/21 6:09:24 - ui.router源码解析
http://www.html-js.com/article/Front-end-source-code-analysis-original-uirouter-source-code-analysisangular路由路由(route),几乎所有的MVC(VM)框架都应该具有的特性,因为它是前端构建单页面应用(SPA)必不可少的组成部分。那么,对于an…...
2024/4/21 6:09:23 - React setState 源码解析
React setState 不知道什么时候开始,很多人开始认为setState是异步操作,所谓的异步操作,就是我们在执行了setState之后,立即通过this.state.xxx不能拿到更新之后的值。这样的认知其实有一种先入为主的意识,也许是受到很…...
2024/4/21 6:09:22 - 【笔记-react】《imooc-React源码深度解析 高级前端工程师必备技能》
第01章 课程导学 01-01 课程导学 一、UIfn(x) 核心api:setState 没有directive双向绑定 二、vue,angular更新大版本,需要调整兼容 三、react,引入fiber,从根本上解决了,js单线程运行,如果计算…...
2024/4/21 6:09:21 - @angular/forms 源码解析之双向绑定
我们知道,Angular 的 angular/forms 包提供了 NgModel 指令,来实现双向绑定,即把一个 JS 变量(假设为 name)与一个 DOM 元素(假设为 input 元素)进行绑定,这样 name 的值发生变化&am…...
2024/4/21 6:09:20 - 做双眼皮失败修复手术哪里好
...
2024/5/3 9:37:58 - 做双眼皮切开法好不好
...
2024/4/21 6:09:18 - 电凝刀做双眼皮切开手术过程
...
2024/4/26 13:01:36 - 成都华西医院割完双眼皮宽度
...
2024/4/21 6:09:17 - 如何创建angular项目
准备工作 1.下载安装mode.js 2.打开cmd执行命令npm install -g angular/cli安装angular/cli(只需要安装一次) 创建angular项目 1.创建一个文件目录,并且在cmd中进入这个目录,然后执行代码ng new angulardemo01(angular…...
2024/4/21 6:09:15 - 埋线双眼皮的线会断吗
...
2024/5/7 3:39:47
最新文章
- 重写muduo之EPollPoller
1、EPollPoller.h EPollPoller的主要实现:作为poller的派生类,把基类给派生类保留的这些纯虚函数的接口实现出来。 override表示在派生类里面,这些方法是覆盖方法。必须由编译器来保证在基类里面一定有这些函数的接口的声明。在派生类要重写…...
2024/5/7 4:06:23 - 梯度消失和梯度爆炸的一些处理方法
在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言,在此感激不尽。 权重和梯度的更新公式如下: w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...
2024/5/6 9:38:23 - 设计模式——责任链模式13
责任链模式 每个流程或事物处理 像一个链表结构处理。场景由 多层部门审批,问题分级处理等。下面体现的是 不同难度的问题由不同人进行解决。 设计模式,一定要敲代码理解 传递问题实体 /*** author ggbond* date 2024年04月10日 07:48*/ public class…...
2024/5/6 8:43:06 - Linux——gdb
gdb调试 (1)debug版本: 在编译阶段会加入某些调试信息; 调试信息是在编译的过程中加入到中间文件.o文件的; gcc -c main.c -g:生成包含调试信息的中间文件 gcc -o main main.o 一步执行:gcc -o main main.c -g (1) (2)release版本: 发行版本,没有调试信息; gcc默认生成relea…...
2024/5/5 19:46:47 - R语言做两次分类,再做两两T检验,最终输出均值和pvalue
1.输入文件: 2.代码: setwd("E:/R/Rscripts/rG4相关绘图")# 加载所需的库 library(tidyverse)# 读取CSV文件 data <- read.csv("box-cds-ABD-不同类型rg4-2.csv", stringsAsFactors FALSE)# 组合Type1和Type2:通过…...
2024/5/6 17:20:45 - 【外汇早评】美通胀数据走低,美元调整
原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...
2024/5/4 23:54:56 - 【原油贵金属周评】原油多头拥挤,价格调整
原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...
2024/5/4 23:54:56 - 【外汇周评】靓丽非农不及疲软通胀影响
原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...
2024/5/4 23:54:56 - 【原油贵金属早评】库存继续增加,油价收跌
原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...
2024/5/6 9:21:00 - 【外汇早评】日本央行会议纪要不改日元强势
原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...
2024/5/4 23:54:56 - 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响
原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...
2024/5/4 23:55:05 - 【外汇早评】美欲与伊朗重谈协议
原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...
2024/5/4 23:54:56 - 【原油贵金属早评】波动率飙升,市场情绪动荡
原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...
2024/5/4 23:55:16 - 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试
原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...
2024/5/4 23:54:56 - 【原油贵金属早评】市场情绪继续恶化,黄金上破
原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...
2024/5/6 1:40:42 - 【外汇早评】美伊僵持,风险情绪继续升温
原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...
2024/5/4 23:54:56 - 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势
原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...
2024/5/4 23:55:17 - 氧生福地 玩美北湖(上)——为时光守候两千年
原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...
2024/5/4 23:55:06 - 氧生福地 玩美北湖(中)——永春梯田里的美与鲜
原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...
2024/5/4 23:54:56 - 氧生福地 玩美北湖(下)——奔跑吧骚年!
原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...
2024/5/4 23:55:06 - 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!
原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...
2024/5/5 8:13:33 - 「发现」铁皮石斛仙草之神奇功效用于医用面膜
原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...
2024/5/4 23:55:16 - 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者
原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...
2024/5/4 23:54:58 - 广州械字号面膜生产厂家OEM/ODM4项须知!
原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...
2024/5/6 21:42:42 - 械字号医用眼膜缓解用眼过度到底有无作用?
原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...
2024/5/4 23:54:56 - 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...
解析如下:1、长按电脑电源键直至关机,然后再按一次电源健重启电脑,按F8健进入安全模式2、安全模式下进入Windows系统桌面后,按住“winR”打开运行窗口,输入“services.msc”打开服务设置3、在服务界面,选中…...
2022/11/19 21:17:18 - 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。
%读入6幅图像(每一幅图像的大小是564*564) f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...
2022/11/19 21:17:16 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...
win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面,在等待界面中我们需要等待操作结束才能关机,虽然这比较麻烦,但是对系统进行配置和升级…...
2022/11/19 21:17:15 - 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...
有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows,请勿关闭计算机”的提示,要过很久才能进入系统,有的用户甚至几个小时也无法进入,下面就教大家这个问题的解决方法。第一种方法:我们首先在左下角的“开始…...
2022/11/19 21:17:14 - win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...
置信有很多用户都跟小编一样遇到过这样的问题,电脑时发现开机屏幕显现“正在配置Windows Update,请勿关机”(如下图所示),而且还需求等大约5分钟才干进入系统。这是怎样回事呢?一切都是正常操作的,为什么开时机呈现“正…...
2022/11/19 21:17:13 - 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...
Win7系统开机启动时总是出现“配置Windows请勿关机”的提示,没过几秒后电脑自动重启,每次开机都这样无法进入系统,此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一:开机按下F8,在出现的Windows高级启动选…...
2022/11/19 21:17:12 - 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...
有不少windows10系统用户反映说碰到这样一个情况,就是电脑提示正在准备windows请勿关闭计算机,碰到这样的问题该怎么解决呢,现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法:1、2、依次…...
2022/11/19 21:17:11 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...
今天和大家分享一下win7系统重装了Win7旗舰版系统后,每次关机的时候桌面上都会显示一个“配置Windows Update的界面,提示请勿关闭计算机”,每次停留好几分钟才能正常关机,导致什么情况引起的呢?出现配置Windows Update…...
2022/11/19 21:17:10 - 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...
只能是等着,别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚,只能是考虑备份数据后重装系统了。解决来方案一:管理员运行cmd:net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...
2022/11/19 21:17:09 - 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?
原标题:电脑提示“配置Windows Update请勿关闭计算机”怎么办?win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢?一般的方…...
2022/11/19 21:17:08 - 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...
关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!关机提示 windows7 正在配…...
2022/11/19 21:17:05 - 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...
钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...
2022/11/19 21:17:05 - 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...
前几天班里有位学生电脑(windows 7系统)出问题了,具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面,长时间没反应,无法进入系统。这个问题原来帮其他同学也解决过,网上搜了不少资料&#x…...
2022/11/19 21:17:04 - 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...
本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法,并在最后教给你1种保护系统安全的好方法,一起来看看!电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中,添加了1个新功能在“磁…...
2022/11/19 21:17:03 - 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...
许多用户在长期不使用电脑的时候,开启电脑发现电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机。。.这要怎么办呢?下面小编就带着大家一起看看吧!如果能够正常进入系统,建议您暂时移…...
2022/11/19 21:17:02 - 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...
配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!配置windows update失败 还原更改 请勿关闭计算机&#x…...
2022/11/19 21:17:01 - 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...
不知道大家有没有遇到过这样的一个问题,就是我们的win7系统在关机的时候,总是喜欢显示“准备配置windows,请勿关机”这样的一个页面,没有什么大碍,但是如果一直等着的话就要两个小时甚至更久都关不了机,非常…...
2022/11/19 21:17:00 - 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...
当电脑出现正在准备配置windows请勿关闭计算机时,一般是您正对windows进行升级,但是这个要是长时间没有反应,我们不能再傻等下去了。可能是电脑出了别的问题了,来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...
2022/11/19 21:16:59 - 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...
我们使用电脑的过程中有时会遇到这种情况,当我们打开电脑之后,发现一直停留在一个界面:“配置Windows Update失败,还原更改请勿关闭计算机”,等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢࿰…...
2022/11/19 21:16:58 - 如何在iPhone上关闭“请勿打扰”
Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...
2022/11/19 21:16:57