Upgrade to Pro — share decks privately, control downloads, hide ads and more …

How to make front-end / How to make front-end

nrs
August 31, 2019

How to make front-end / How to make front-end

builderscon 2019 にて発表したスライドです。
フロントエンドなどの GUI プログラミングにおけるシンプルなコードを達成するためのセオリーについてお話しています。
補足解説: https://nrslib.com/how-to-make-front-end/

# URL
HomePage: https://nrslib.com
Twitter: https://twitter.com/nrslib

nrs

August 31, 2019
Tweet

More Decks by nrs

Other Decks in Programming

Transcript

  1. 2

  2. 3

  3. 10

  4. 12

  5. 13

  6. 49

  7. 68

  8. 69

  9. 74

  10. Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: naruse

    Twitter: @nrslib Modal Name: nrs 79
  11. Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: nrs

    Twitter: @nrslib Modal Name: nrs 80
  12. Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: nrs

    Twitter: @nrslib Update Name: nrs 82
  13. Id: 1 Name: nrs Twitter: @nrslib Id: 1 Name: nrs

    Twitter: @nrslib どこが悪いか もう一度 85
  14. 86

  15. Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: naruse

    Twitter: @nrslib Modal Name: nrs 92
  16. Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: nrs

    Twitter: @nrslib Modal Name: nrs 93
  17. Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: nrs

    Twitter: @nrslib 一時的な データ不整合 96
  18. Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: nrs

    Twitter: @nrslib 一時的な データ不整合 たとえるなら 97
  19. 98

  20. 100

  21. Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: naruse

    Twitter: @nrslib Modal Name: nrs 105
  22. Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: naruse

    Twitter: @nrslib Modal Name: nrs Update Name: nrs 106
  23. Id: 1 Name: nrs Twitter: @nrslib Id: 1 Name: naruse

    Twitter: @nrslib Modal Name: nrs 107
  24. Id: 1 Name: nrs Twitter: @nrslib Id: 1 Name: naruse

    Twitter: @nrslib Modal Name: nrs Id: 1 Name: nrs Twitter: @nrslib 108
  25. Id: 1 Name: nrs Twitter: @nrslib Id: 1 Name: nrs

    Twitter: @nrslib Modal Name: nrs 109
  26. 112

  27. 114

  28. Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: nrs

    Twitter: @nrslib Update Name: nrs 120
  29. Id: 1 Name: nrs Twitter: @nrslib Id: 1 Name: nrs

    Twitter: @nrslib Id: 1 Name: nrs Twitter: @nrslib 121
  30. Id: 1 Name: nrs Twitter: @nrslib Id: 1 Name: nrs

    Twitter: @nrslib Id: 1 Name: nrs Twitter: @nrslib あくまでサーバのデータで フロントを更新する 122
  31. Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: nrs

    Twitter: @nrslib Update Name: nrs 123
  32. Id: 1 Name: naruse Twitter: @nrslib Id: 1 Name: nrs

    Twitter: @nrslib Update Name: nrs 124
  33. Id: 1 Name: naruse Twitter: @nrs Id: 1 Name: nrs

    Twitter: @nrslib Update Name: nrs Id: 1 Name: naruse Twitter: @nrs 125
  34. Id: 1 Name: naruse Twitter: @nrs Id: 1 Name: nrs

    Twitter: @nrslib Id: 1 Name: naruse Twitter: @nrs Id: 1 Name: nrs Twitter: @nrs 126
  35. Id: 1 Name: naruse Twitter: @nrs Id: 1 Name: nrs

    Twitter: @nrs Id: 1 Name: naruse Twitter: @nrs Id: 1 Name: nrs Twitter: @nrs 127
  36. Id: 1 Name: naruse Twitter: @nrs Id: 1 Name: nrs

    Twitter: @nrs Id: 1 Name: naruse Twitter: @nrs Id: 1 Name: nrs Twitter: @nrs 信頼たるデータを 信頼しよう 128
  37. 153

  38. 159

  39. Mail: [email protected] Name: naruse Password: ******** duplicated-email, duplicated-username duplicated-email だからメール欄に

    エラー表示して duplicated-username だからユーザ名欄に エラー表示して 163
  40. 166

  41. 167

  42. 170

  43. export default class Apios { public static post<T>(url: string, data?:

    any, params?: { onError?: IErrorNotifier; unexpectedErrorHandler?: Handler<T>; config?: AxiosRequestConfig; } ): Promise<ApiosResponse<T>> { const onError = this._selectErrorNote(params.onError); ... return new Promise<ApiosResponse<T>>((resolve, reject) => { Axios.post(url, data, { headers: { token: token } }) .then((res) => { const response = this._convertErrorMessage(res.data); if (this.isIResponse(response)) { if (response.errors.length > 0) { onError(response); } } const apiosResponse = new ApiosResponse(false, response); resolve(apiosResponse); }) .catch((e: AxiosError) => { unexpectedErrorHandler<T>(resolve, reject, e, onError); }); }); 178
  44. export default class Apios { public static post<T>(url: string, data?:

    any, params?: { onError?: IErrorNotifier; unexpectedErrorHandler?: Handler<T>; config?: AxiosRequestConfig; } ): Promise<ApiosResponse<T>> { const onError = this._selectErrorNote(params.onError); ... return new Promise<ApiosResponse<T>>((resolve, reject) => { Axios.post(url, data, { headers: { token: token } }) .then((res) => { const response = this._convertErrorMessage(res.data); if (this.isIResponse(response)) { if (response.errors.length > 0) { onError(response); } } const apiosResponse = new ApiosResponse(false, response); resolve(apiosResponse); }) .catch((e: AxiosError) => { unexpectedErrorHandler<T>(resolve, reject, e, onError); }); }); 179
  45. export default class Apios { public static post<T>(url: string, data?:

    any, params?: { onError?: IErrorNotifier; unexpectedErrorHandler?: Handler<T>; config?: AxiosRequestConfig; } ): Promise<ApiosResponse<T>> { const onError = this._selectErrorNote(params.onError); ... return new Promise<ApiosResponse<T>>((resolve, reject) => { Axios.post(url, data, { headers: { token: token } }) .then((res) => { const response = this._convertErrorMessage(res.data); if (this.isIResponse(response)) { if (response.errors.length > 0) { onError(response); } } const apiosResponse = new ApiosResponse(false, response); resolve(apiosResponse); }) .catch((e: AxiosError) => { unexpectedErrorHandler<T>(resolve, reject, e, onError); }); }); 180
  46. export default class Apios { public static post<T>(url: string, data?:

    any, params?: { onError?: IErrorNotifier; unexpectedErrorHandler?: Handler<T>; config?: AxiosRequestConfig; } ): Promise<ApiosResponse<T>> { const onError = this._selectErrorNote(params.onError); ... return new Promise<ApiosResponse<T>>((resolve, reject) => { Axios.post(url, data, { headers: { token: token } }) .then((res) => { const response = this._convertErrorMessage(res.data); if (this.isIResponse(response)) { if (response.errors.length > 0) { onError(response); } } const apiosResponse = new ApiosResponse(false, response); resolve(apiosResponse); }) .catch((e: AxiosError) => { unexpectedErrorHandler<T>(resolve, reject, e, onError); }); }); 181
  47. const notifyErrorToMessageService: IErrorNotifier = (response: IResponse) => { response.errors .map(x

    => x.message) .forEach(message => messageService.addMessage(MessageType.Error, message) ); }; 182
  48. const notifyErrorToMessageService: IErrorNotifier = (response: IResponse) => { response.errors .map(x

    => x.message) .forEach(message => messageService.addMessage(MessageType.Error, message) ); }; 183
  49. <template> <div v-if="hasAnyMessage"> {{head}} <template v-for="tailMessage in tail"> <br> {{tailMessage}}

    </template> </div> </template> ... @Component export default class NotifyMessage extends Vue { ... public get hasAnyMessage(): boolean { return this.messageService.hasAnyMessage; } public get head(): string { return this.messageService.headMessage; } public get tail(): string[] { return this.messageService.tailMessages; } } 184
  50. <template> <div v-if="hasAnyMessage"> {{head}} <template v-for="tailMessage in tail"> <br> {{tailMessage}}

    </template> </div> </template> ... @Component export default class NotifyMessage extends Vue { ... public get hasAnyMessage(): boolean { return this.messageService.hasAnyMessage; } public get head(): string { return this.messageService.headMessage; } public get tail(): string[] { return this.messageService.tailMessages; } } 185
  51. export default class Apios { public static post<T>(url: string, data?:

    any, params?: { onError?: IErrorNotifier; unexpectedErrorHandler?: Handler<T>; config?: AxiosRequestConfig; } ): Promise<ApiosResponse<T>> { const onError = this._selectErrorNote(params.onError); ... return new Promise<ApiosResponse<T>>((resolve, reject) => { Axios.post(url, data, { headers: { token: token } }) .then((res) => { const response = this._convertErrorMessage(res.data); if (this.isIResponse(response)) { if (response.errors.length > 0) { onError(response); } } const apiosResponse = new ApiosResponse(false, response); resolve(apiosResponse); }) .catch((e: AxiosError) => { unexpectedErrorHandler<T>(resolve, reject, e, onError); }); }); 188
  52. export default class Apios { public static post<T>(url: string, data?:

    any, params?: { onError?: IErrorNotifier; unexpectedErrorHandler?: Handler<T>; config?: AxiosRequestConfig; } ): Promise<ApiosResponse<T>> { const onError = this._selectErrorNote(params.onError); ... return new Promise<ApiosResponse<T>>((resolve, reject) => { Axios.post(url, data, { headers: { token: token } }) .then((res) => { const response = this._convertErrorMessage(res.data); if (this.isIResponse(response)) { if (response.errors.length > 0) { onError(response); } } const apiosResponse = new ApiosResponse(false, response); resolve(apiosResponse); }) .catch((e: AxiosError) => { unexpectedErrorHandler<T>(resolve, reject, e, onError); }); }); 189
  53. export default class Apios { public static post<T>(url: string, data?:

    any, params?: { onError?: IErrorNotifier; unexpectedErrorHandler?: Handler<T>; config?: AxiosRequestConfig; } ): Promise<ApiosResponse<T>> { const onError = this._selectErrorNote(params.onError); ... return new Promise<ApiosResponse<T>>((resolve, reject) => { Axios.post(url, data, { headers: { token: token } }) .then((res) => { const response = this._convertErrorMessage(res.data); if (this.isIResponse(response)) { if (response.errors.length > 0) { onError(response); } } const apiosResponse = new ApiosResponse(false, response); resolve(apiosResponse); }) .catch((e: AxiosError) => { unexpectedErrorHandler<T>(resolve, reject, e, onError); }); }); 呼び出し側がエラーハンドラを 設定できるように受け口を用意 190
  54. できごと ハンドリング 成功 Callback 失敗 しない or Callback 例外 しない

    or Callback セッション切れ 権限変更 (パーミッション変更) 198
  55. できごと ハンドリング 成功 Callback 失敗 しない or Callback 例外 しない

    or Callback セッション切れ ログイン画面へ 権限変更 (パーミッション変更) 199
  56. できごと ハンドリング 成功 Callback 失敗 しない or Callback 例外 しない

    or Callback セッション切れ ログイン画面へ 権限変更 (パーミッション変更) しない(権限エラー通知) 200
  57. できごと ハンドリング 成功 Callback 失敗 しない or Callback 例外 しない

    or Callback セッション切れ ログイン画面へ 権限変更 (パーミッション変更) しない(権限エラー通知) 201
  58. public static post<T>(url: string, data?: any, onSuccess: T => void,

    params?: { onError?: IErrorNotifier; unexpectedErrorHandler?: Handler<T>; config?: AxiosRequestConfig; } ) できごと ハンドリング 成功 Callback 失敗 しない or Callback 例外 しない or Callback セッション切れ ログイン画面へ 権限変更 (パーミッション変更) しない(権限エラー通知) 202
  59. public static post<T>(url: string, data?: any, onSuccess: T => void,

    params?: { onError?: IErrorNotifier; unexpectedErrorHandler?: Handler<T>; config?: AxiosRequestConfig; } ) できごと ハンドリング 成功 Callback 失敗 しない or Callback 例外 しない or Callback セッション切れ ログイン画面へ 権限変更 (パーミッション変更) しない(権限エラー通知) 203
  60. class ObjectA { private objectB = new ObjectB(this); public method()

    { this.objectB.methodForA(); } public methodForB() { ... } } class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { ... this.objectA.methodForB(); } 215
  61. class ObjectA { private objectB = new ObjectB(this); public method()

    { this.objectB.methodForA(); } public methodForB() { ... } } class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { ... this.objectA.methodForB(); } 216
  62. class ObjectA { private objectB = new ObjectB(this); public method()

    { this.objectB.methodForA(); } public methodForB() { ... } } class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { ... this.objectA.methodForB(); } 217
  63. class ObjectA { private objectB = new ObjectB(this); public method()

    { this.objectB.methodForA(); } public methodForB() { ... } } class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { ... this.objectA.methodForB(); } 相互参照 218
  64. class ObjectA { private objectB = new ObjectB(this); public method()

    { this.objectB.methodForA(); } public methodForB() { ... } } class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { ... this.objectA.methodForB(); } 相互参照 コンストラクタに this を渡してると 大抵ヤバイ 219
  65. class ObjectA { private objectB = new ObjectB(this); public method()

    { this.objectB.methodForA(); } public methodForB() { ... } } class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { ... this.objectA.methodForB(); } 220
  66. class ObjectA { private objectB = new ObjectB(this); public method()

    { this.objectB.methodForA(); } public methodForB() { ... } } class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { ... this.objectA.methodForB(); } 221
  67. class ObjectA { private objectB = new ObjectB(this); public method()

    { this.objectB.methodForA(); } public methodForB() { ... } } class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { ... this.objectA.methodForB(); } 222
  68. class ObjectA { private objectB = new ObjectB(this); public method()

    { this.objectB.methodForA(); } public methodForB() { ... } } class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { ... this.objectA.methodForB(); } 223
  69. class ObjectA { private objectB = new ObjectB(this); public method()

    { this.objectB.methodForA(); } public methodForB() { ... } } class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { ... this.objectA.methodForB(); } 224
  70. class ObjectA { private objectB = new ObjectB(this); public method()

    { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 226
  71. class ObjectA { private objectB = new ObjectB(this); public method()

    { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 227
  72. class ObjectA { private objectB = new ObjectB(this); public method()

    { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 228
  73. class ObjectA { private objectB = new ObjectB(this); public method()

    { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 229
  74. class ObjectA { private objectB = new ObjectB(this); public method()

    { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 230
  75. class ObjectA { private objectB = new ObjectB(this); public method()

    { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 231
  76. class ObjectA { private objectB = new ObjectB(this); public method()

    { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 232
  77. class ObjectA { private objectB = new ObjectB(this); public method()

    { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 233
  78. class ObjectA { private objectB = new ObjectB(this); public method()

    { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 234
  79. class ObjectA { private objectB = new ObjectB(this); public method()

    { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 235
  80. class ObjectA { private objectB = new ObjectB(this); public method()

    { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 236
  81. class ObjectA { private objectB = new ObjectB(this); public method()

    { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 237
  82. class ObjectA { private objectB = new ObjectB(this); public method()

    { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 238
  83. class ObjectA { private objectB = new ObjectB(this); public method()

    { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 239
  84. class ObjectA { private objectB = new ObjectB(this); public method()

    { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 240
  85. class ObjectA { private objectB = new ObjectB(this); public method()

    { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 241
  86. class ObjectA { private objectB = new ObjectB(this); public method()

    { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 242
  87. class ObjectA { private objectB = new ObjectB(this); public method()

    { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 243
  88. class ObjectA { private objectB = new ObjectB(this); public method()

    { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 244
  89. class ObjectA { private objectB = new ObjectB(this); public method()

    { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 245
  90. class ObjectA { private objectB = new ObjectB(this); public method()

    { this.objectB.methodForA(); } public methodForB() { ... } public methodForB2() { ... this.objectB.methodForA2(); } public methodForB3() { this.objectB.methodForA3(); ... this.objectB.methodForA4(); } public methodForB4() { ... class ObjectB { public constructor( private readonly objectA: ObjectA) { } public method() { this.objectA.methodForB(); } public methodForA() { this.objectA.methodForB(); ... this.objectA.methodForB2(); } public methodForA2() { ... this.objectA.methodForB3(); } public methodForA3() { ... } public methodForA4() { 動作順序 把握できました? 246
  91. class Parent { private readonly objectA = new ObjectA(); private

    readonly objectB = new ObjectB(); public method() { this.objectB.methodForA(); this.objectA.methodForB(); this.objectA.methodForB2(); this.objectB.methodForA2(); this.objectA.methodForB3(); this.objectB.methodForA3(); this.objectB.methodForA4(); } } 252
  92. class Parent { private readonly objectA = new ObjectA(); private

    readonly objectB = new ObjectB(); public method() { this.objectB.methodForA(); this.objectA.methodForB(); this.objectA.methodForB2(); this.objectB.methodForA2(); this.objectA.methodForB3(); this.objectB.methodForA3(); this.objectB.methodForA4(); } } class ObjectA { public methodForB() { ... } public methodForB2() { ... } public methodForB3() { ... } public methodForB4() { ... } } class ObjectB { public methodForA() { ... } public methodForA2() { ... } public methodForA3() { ... } public methodForA4() { ... } } 253
  93. class Parent { private readonly objectA = new ObjectA(); private

    readonly objectB = new ObjectB(); public method() { this.objectB.methodForA(); this.objectA.methodForB(); this.objectA.methodForB2(); this.objectB.methodForA2(); this.objectA.methodForB3(); this.objectB.methodForA3(); this.objectB.methodForA4(); } } class ObjectA { public methodForB() { ... } public methodForB2() { ... } public methodForB3() { ... } public methodForB4() { ... } } class ObjectB { public methodForA() { ... } public methodForA2() { ... } public methodForA3() { ... } public methodForA4() { ... } } オブジェクトは シンプルに 254
  94. class Parent { private readonly objectA = new ObjectA(); private

    readonly objectB = new ObjectB(); public method() { this.objectB.methodForA(); this.objectA.methodForB(); this.objectA.methodForB2(); this.objectB.methodForA2(); this.objectA.methodForB3(); this.objectB.methodForA3(); this.objectB.methodForA4(); } } 255
  95. class Parent { private readonly objectA = new ObjectA(); private

    readonly objectB = new ObjectB(); public method() { this.objectB.methodForA(); this.objectA.methodForB(); this.objectA.methodForB2(); this.objectB.methodForA2(); this.objectA.methodForB3(); this.objectB.methodForA3(); this.objectB.methodForA4(); } } コードを見れば 一目瞭然 256
  96. TabButton TabButton TabButton TabButton TabContent TabButtonGroup Tab Select (B) Select

    メソッド Vue などでは これをバインディングで 実現する 292
  97. <template> <button @click="onClick"> <slot /> {{selected}} </button> </template> <script lang="ts">

    import {Component, Emit, Prop, Vue} from "vue-property-decorator"; @Component export default class TabButton extends Vue { @Prop() public selected!: boolean; @Emit('click') public onClick() { } } </script> 294
  98. <template> <button @click="onClick"> <slot /> {{selected}} </button> </template> <script lang="ts">

    import {Component, Emit, Prop, Vue} from "vue-property-decorator"; @Component export default class TabButton extends Vue { @Prop() public selected!: boolean; @Emit('click') public onClick() { } } </script> 295
  99. <template> <button @click="onClick"> <slot /> {{selected}} </button> </template> <script lang="ts">

    import {Component, Emit, Prop, Vue} from "vue-property-decorator"; @Component export default class TabButton extends Vue { @Prop() public selected!: boolean; @Emit('click') public onClick() { } } </script> 296
  100. <template> <ul> <TabButton v-for="param in parameters" :key="param.id" :selected="isSelected(param.id)" @click="onTabButtonClick(param.id)"> {{param.title}}

    </TabButton> </ul> </template> <script lang="ts"> ... export default class TabButtonGroup extends Vue { @Prop() public selectedTabId!: string; @Prop() public parameters!: ITabButtonParameter[]; @Emit('tabButtonClick') public onTabButtonClick(id: string) { } public isSelected(id: string) { return id === this.selectedTabId; } } 297
  101. <template> <ul> <TabButton v-for="param in parameters" :key="param.id" :selected="isSelected(param.id)" @click="onTabButtonClick(param.id)"> {{param.title}}

    </TabButton> </ul> </template> <script lang="ts"> ... export default class TabButtonGroup extends Vue { @Prop() public selectedTabId!: string; @Prop() public parameters!: ITabButtonParameter[]; @Emit('tabButtonClick') public onTabButtonClick(id: string) { } public isSelected(id: string) { return id === this.selectedTabId; } } 298
  102. <template> <ul> <TabButton v-for="param in parameters" :key="param.id" :selected="isSelected(param.id)" @click="onTabButtonClick(param.id)"> {{param.title}}

    </TabButton> </ul> </template> <script lang="ts"> ... export default class TabButtonGroup extends Vue { @Prop() public selectedTabId!: string; @Prop() public parameters!: ITabButtonParameter[]; @Emit('tabButtonClick') public onTabButtonClick(id: string) { } public isSelected(id: string) { return id === this.selectedTabId; } } 299
  103. <template> <div> <TabButtonGroup :selectedTabId="selectedTabId" :parameters="tabContents" @tabButtonClick="onTabGroupTabButtonClick" /> <slot :selectedTabId="selectedTabId" />

    </div> </template> <script lang="ts"> ... export default class Tab extends Vue { public tabContents: TabContent[] = []; public selectedTab: TabContent | null = null; @Prop() public selectedTabId!: string; public mounted() { const tabContents = this.$slots.default .filter(x => x.componentInstance) .map(x => x.componentInstance) .map(x => x as TabContent); this.tabContents = tabContents; this.onTabGroupTabButtonClick(this.tabContents[0].id); } @Emit('tabButtonClick') public onTabGroupTabButtonClick(id: string) { } 300
  104. <template> <div> <TabButtonGroup :selectedTabId="selectedTabId" :parameters="tabContents" @tabButtonClick="onTabGroupTabButtonClick" /> <slot :selectedTabId="selectedTabId" />

    </div> </template> <script lang="ts"> ... export default class Tab extends Vue { public tabContents: TabContent[] = []; public selectedTab: TabContent | null = null; @Prop() public selectedTabId!: string; public mounted() { const tabContents = this.$slots.default .filter(x => x.componentInstance) .map(x => x.componentInstance) .map(x => x as TabContent); this.tabContents = tabContents; this.onTabGroupTabButtonClick(this.tabContents[0].id); } @Emit('tabButtonClick') public onTabGroupTabButtonClick(id: string) { } 301
  105. <template> <div> <TabButtonGroup :selectedTabId="selectedTabId" :parameters="tabContents" @tabButtonClick="onTabGroupTabButtonClick" /> <slot :selectedTabId="selectedTabId" />

    </div> </template> <script lang="ts"> ... export default class Tab extends Vue { public tabContents: TabContent[] = []; public selectedTab: TabContent | null = null; @Prop() public selectedTabId!: string; public mounted() { const tabContents = this.$slots.default .filter(x => x.componentInstance) .map(x => x.componentInstance) .map(x => x as TabContent); this.tabContents = tabContents; this.onTabGroupTabButtonClick(this.tabContents[0].id); } @Emit('tabButtonClick') public onTabGroupTabButtonClick(id: string) { } 302
  106. <template> <div class="home"> <img alt="Vue logo" src="../assets/logo.png"> <Tab :selectedTabId="selectedTabId" @tabButtonClick="onTabButtonClick">

    <TabContent title="first" :active="isActive('first')"> ContentsFirst </TabContent> <TabContent title="second" :active="isActive('second')"> ContentsSecond </TabContent> ... </Tab> </div> </template> <script lang="ts"> ... export default class Home extends Vue { public selectedTabId: string = "first"; public onTabButtonClick(id: string) { this.selectedTabId = id; } public isActive(id: string) { return id === this.selectedTabId; } } </script> 303
  107. <template> <div class="home"> <img alt="Vue logo" src="../assets/logo.png"> <Tab :selectedTabId="selectedTabId" @tabButtonClick="onTabButtonClick">

    <TabContent title="first" :active="isActive('first')"> ContentsFirst </TabContent> <TabContent title="second" :active="isActive('second')"> ContentsSecond </TabContent> ... </Tab> </div> </template> <script lang="ts"> ... export default class Home extends Vue { public selectedTabId: string = "first"; public onTabButtonClick(id: string) { this.selectedTabId = id; } public isActive(id: string) { return id === this.selectedTabId; } } </script> 304
  108. <template> <div class="home"> <img alt="Vue logo" src="../assets/logo.png"> <Tab :selectedTabId="selectedTabId" @tabButtonClick="onTabButtonClick">

    <TabContent title="first" :active="isActive('first')"> ContentsFirst </TabContent> <TabContent title="second" :active="isActive('second')"> ContentsSecond </TabContent> ... </Tab> </div> </template> <script lang="ts"> ... export default class Home extends Vue { public selectedTabId: string = "first"; public onTabButtonClick(id: string) { this.selectedTabId = id; } public isActive(id: string) { return id === this.selectedTabId; } } </script> 305
  109. <template> <div class="home"> <img alt="Vue logo" src="../assets/logo.png"> <Tab :selectedTabId="selectedTabId" @tabButtonClick="onTabButtonClick">

    <TabContent title="first" :active="isActive('first')"> ContentsFirst </TabContent> <TabContent title="second" :active="isActive('second')"> ContentsSecond </TabContent> ... </Tab> </div> </template> <script lang="ts"> ... export default class Home extends Vue { public selectedTabId: string = "first"; public onTabButtonClick(id: string) { this.selectedTabId = id; } public isActive(id: string) { return id === this.selectedTabId; } } </script> 306
  110. <template> <div class="home"> <img alt="Vue logo" src="../assets/logo.png"> <Tab :selectedTabId="selectedTabId" @tabButtonClick="onTabButtonClick">

    <TabContent title="first" :active="isActive('first')"> ContentsFirst </TabContent> <TabContent title="second" :active="isActive('second')"> ContentsSecond </TabContent> ... </Tab> </div> </template> <script lang="ts"> ... export default class Home extends Vue { public selectedTabId: string = "first"; public onTabButtonClick(id: string) { this.selectedTabId = id; } public isActive(id: string) { return id === this.selectedTabId; } } </script> 307
  111. <template> <div class="home"> <img alt="Vue logo" src="../assets/logo.png"> <Tab :selectedTabId="selectedTabId" @tabButtonClick="onTabButtonClick">

    <TabContent title="first" :active="isActive('first')"> ContentsFirst </TabContent> <TabContent title="second" :active="isActive('second')"> ContentsSecond </TabContent> ... </Tab> </div> </template> <script lang="ts"> ... export default class Home extends Vue { public selectedTabId: string = "first"; public onTabButtonClick(id: string) { this.selectedTabId = id; } public isActive(id: string) { return id === this.selectedTabId; } } </script> 308
  112. <template> <div class="home"> <img alt="Vue logo" src="../assets/logo.png"> <Tab :selectedTabId="selectedTabId" @tabButtonClick="onTabButtonClick">

    <TabContent title="first" :active="isActive('first')"> ContentsFirst </TabContent> <TabContent title="second" :active="isActive('second')"> ContentsSecond </TabContent> ... </Tab> </div> </template> <script lang="ts"> ... export default class Home extends Vue { public selectedTabId: string = "first"; public onTabButtonClick(id: string) { this.selectedTabId = id; } public isActive(id: string) { return id === this.selectedTabId; } } </script> 子コンポーネント同士の 取り回しはあくまでも それを保持する親コンポーネントが 責任をもっておこなう 309
  113. <template> <div class="home"> <img alt="Vue logo" src="../assets/logo.png"> <Tab :selectedTabId="selectedTabId" @tabButtonClick="onTabButtonClick">

    <TabContent title="first" :active="isActive('first')"> ContentsFirst </TabContent> <TabContent title="second" :active="isActive('second')"> ContentsSecond </TabContent> ... </Tab> </div> </template> <script lang="ts"> ... export default class Home extends Vue { public selectedTabId: string = "first"; public onTabButtonClick(id: string) { this.selectedTabId = id; } public isActive(id: string) { return id === this.selectedTabId; } } </script> 子コンポーネント同士が 勝手に反応しない ようにすること 310
  114. <input v-model="message"> <p>Message is: {{ message }}</p> Component Input message

    Event モデルバインディングは シンタックスシュガー 347
  115. 350