Pan*_*ano 26 javascript vue.js angular
我首先学习了Vue.js,现在在Angular 4中有一个项目,所以我刚刚学习了Angular.我发现除了"计算属性"之外,一切都与Vue没有什么不同.在Vue中,我可以创建一个计算属性来侦听其他属性的更改并自动运行计算.
例如(在Vue 2中):
computed: {
name(){
return this.firstname + ' ' + this.lastname;
}
}
Run Code Online (Sandbox Code Playgroud)
name属性只会在firstname或lastname之一更改时重新计算.如何在Angular 2或4中处理此问题?
And*_*vic 41
虽然这已经得到了回答,但我认为这不是一个很好的答案,用户不应该使用getter作为角度计算属性.为什么你会问?getter只是函数的糖语法,它将被编译为普通函数,这意味着它将在每次更改检测检查时执行.这对于表现来说很糟糕,因为在任何变化时都会重新计算数百次财产.
看一下这个例子:https://plnkr.co/edit/TQMQFb?p = preview
@Component({
selector: 'cities-page',
template: `
<label>Angular computed properties are bad</label>
<ng-select [items]="cities"
bindLabel="name"
bindValue="id"
placeholder="Select city"
[(ngModel)]="selectedCityId">
</ng-select>
<p *ngIf="hasSelectedCity">
Selected city ID: {{selectedCityId}}
</p>
<p><b>hasSelectedCity</b> is recomputed <b [ngStyle]="{'font-size': calls + 'px'}">{{calls}}</b> times</p>
`
})
export class CitiesPageComponent {
cities: NgOption[] = [
{id: 1, name: 'Vilnius'},
{id: 2, name: 'Kaunas'},
{id: 3, name: 'Pabrad?'}
];
selectedCityId: any;
calls = 0;
get hasSelectedCity() {
console.log('hasSelectedCity is called', this.calls);
this.calls++;
return !!this.selectedCityId;
}
}
Run Code Online (Sandbox Code Playgroud)
如果你真的想要计算属性,你可以使用像mobx这样的状态容器
class TodoList {
@observable todos = [];
@computed get unfinishedTodoCount() {
return this.todos.filter(todo => !todo.finished).length;
}
}
Run Code Online (Sandbox Code Playgroud)
mobx具有@computed装饰器,因此只有在需要时才会缓存并重新计算getter属性
Ale*_*xei 15
我会尽力改进,Andzej Maciusovic希望得到一个规范的答案.实际上,VueJS有一个叫做计算属性的功能,可以使用一个例子快速显示:
<template>
<div>
<p>A = <input type="number" v-model="a"/></p>
<p>B = <input type="number" v-model="b"/></p>
<p>C = <input type="number" v-model="c"/></p>
<p>Computed property result: {{ product }}</p>
<p>Function result: {{ productFunc() }}</p>
</div>
</template>
<script>
export default {
data () {
return {
a: 2,
b: 3,
c: 4
}
},
computed: {
product: function() {
console.log("Product called!");
return this.a * this.b;
}
},
methods: {
productFunc: function() {
console.log("ProductFunc called!");
return this.a * this.b;
}
}
}
</script>
Run Code Online (Sandbox Code Playgroud)
每当用户更改输入值a或b,两者product并productFunc正在登录到控制台.如果用户更改c,则仅productFunc调用.
回到Angular,mobxjs真的有助于解决这个问题:
npm install --save mobx-angular mobxobservable和computed属性TS文件
import { observable, computed } from 'mobx-angular';
@Component({
selector: 'home',
templateUrl: './home.component.html',
animations: [slideInDownAnimation]
})
export class HomeComponent extends GenericAnimationContainer {
@observable a: number = 2;
@observable b: number = 3;
@observable c: number = 4;
getAB = () => {
console.log("getAB called");
return this.a * this.b;
}
@computed get AB() {
console.log("AB called");
return this.a * this.b;
}
}
Run Code Online (Sandbox Code Playgroud)
标记
<div *mobxAutorun>
<p>A = <input type="number" [(ngModel)]="a" /> </p>
<p>B = <input type="number" [(ngModel)]="b" /> </p>
<p>C = <input type="number" [(ngModel)]="c" /> </p>
<p> A * B = {{ getAB() }}</p>
<p> A * B (get) = {{ AB }}</p>
</div>
Run Code Online (Sandbox Code Playgroud)
如果a或b更改,AB则调用一次和getAB多次.如果c更改,则仅getAB调用.因此,即使必须执行计算,此解决方案也更有效.
是的你可以.
在TS文件中:
export class MyComponent {
get name() {
return this.firstname + ' ' + this.lastname;
}
}
Run Code Online (Sandbox Code Playgroud)
之后在html中:
<div>{{name}}</div>
Run Code Online (Sandbox Code Playgroud)
这是一个例子:
@Component({
selector: 'my-app',
template: `{{name}}`,
})
export class App {
i = 0;
firstN;
secondN;
constructor() {
setInterval(()=> {
this.firstN = this.i++;
this.secondN = this.i++;
}, 2000);
}
get name() {
return this.firstN + ' ' + this.secondN;
}
}
Run Code Online (Sandbox Code Playgroud)
computed Vue 中的属性有两个巨大的好处:反应性和记忆性。
在 Vue 中,我可以创建一个计算属性来监听其他属性的变化并自动运行计算。
您在这里专门询问 Angular 中的反应性系统。似乎人们已经忘记了什么是 Angular 的基石:Observables。
const {
BehaviorSubject,
operators: {
withLatestFrom,
map
}
} = rxjs;
const firstName$ = new BehaviorSubject('Larry');
const lastName$ = new BehaviorSubject('Wachowski');
const fullName$ = firstName$.pipe(
withLatestFrom(lastName$),
map(([firstName, lastName]) => `Fullname: ${firstName} ${lastName}`)
);
const subscription = fullName$.subscribe((fullName) => console.log(fullName))
setTimeout(() => {
firstName$.next('Lana');
subscription.unsubscribe();
}, 2000);Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.3/rxjs.umd.js"></script>Run Code Online (Sandbox Code Playgroud)
我的代码没有解决记忆部分,它只解决反应性。
人们给出了一些有趣的答案。虽然mobX computed属性可能(我从未使用过 mobX)更接近computedVue 中的属性,但这也意味着您正在依赖另一个您可能不感兴趣使用的库。对于您解释的特定用例,管道替代方案在这里最有趣,因为它解决了反应性和记忆化问题,但并非对所有情况都有效。
在某些情况下,使用“纯管道”可能是一个合理的选择,显然带有一些限制,但至少避免了在任何事件上执行该函数的成本。
@Pipe({ name: 'join' })
export class JoinPipe implements PipeTransform {
transform(separator: string, ...strings: string[]) {
return strings.join(separator);
}
}
Run Code Online (Sandbox Code Playgroud)
在模板中,您可以使用而不是全名属性' ' | join:firstname:lastname。很遗憾,角度的计算属性仍然不存在。