欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

宁皓网 Angular :起步 2 有大用

继续了解 Angular 框架的基础。

来自  https://ninghao.net/course/7655#info


一)

# ng generate  component  modules/post/components/post-item         #生成组件

CREATE src/app/modules/post/components/post-item/post-item.component.html (24 bytes)

CREATE src/app/modules/post/components/post-item/post-item.component.spec.ts (614 bytes)

CREATE src/app/modules/post/components/post-item/post-item.component.ts (286 bytes)

CREATE src/app/modules/post/components/post-item/post-item.component.css (0 bytes)

UPDATE src/app/modules/post/post.module.ts (477 bytes)


# ng generate component modules/post/componets/post-details         #生成组件

CREATE src/app/modules/post/componets/post-details/post-details.component.html (27 bytes)

CREATE src/app/modules/post/componets/post-details/post-details.component.spec.ts (635 bytes)

CREATE src/app/modules/post/componets/post-details/post-details.component.ts (298 bytes)

CREATE src/app/modules/post/componets/post-details/post-details.component.css (0 bytes)

UPDATE src/app/modules/post/post.module.ts (591 bytes)


# ng generate service modules/post/services/post        #生成服务

CREATE src/app/modules/post/services/post.service.spec.ts (347 bytes)

CREATE src/app/modules/post/services/post.service.ts (133 bytes)






Angular is running in development mode. Call enableProdMode() to enable production mode.

image.png



介绍与准备

1)介绍(起步 2)

在组件里添加 Input 属性,这样在组件的父组件那里可以给它传递需要的数据。在子组件上发生的事情,可以通过自定义事件通知组件的父组件。也就是在组件的父组件那里可以监听组件上发生的自定义事件。

我们可以在应用里定义一些路由,路由都有一个地址,还有一个对应的组件,访问路由地址,可以打开对应的组件显示内容。

服务可以帮助组件去做一些事情,也就是在服务里面可以添加一些方法,在组件里可以使用这些方法去做一些事情。

来自  https://ninghao.net/video/7657#info


2)VSCode:配置 TypeScript 的自动导入使用相对路径


VSCode 会自动帮我们导入需要的模块,比如这里添加一个 AppRoutingModule,编辑器会提示这个模块的位置,按一下回车或者 Tab 键,会自动在文件的顶部导入这个模块。

注意导入的时候用的是一个绝对路径,如果你想使用相对的路径需要再去配置一下,打开编辑器的配置,

image.png

image.png

然后搜索一下 import module。

修改一下 TypeScript 的 Import Module Specifier,现在是 auto ,可以把它换成 relative,相对。

回到之前的文件,先删除掉自动导入的这行代码,然后重新再输入需要的 AppRoutingModule,按一下回车或 Tab,编辑器自动导入了这个模块,不过这次导入的时候,使用的路径是相对的。

来自  https://ninghao.net/video/7658#info


基础

3)Input:父组件给子组件传递数据

在页面上显示的这组内容列表是在 Post 组件里要显示的东西。回到项目,打开 Post 组件的视图,这里这个 post works 可以删除掉 .. 这样界面上就不会再显示这个段落文字了。

应用里的 Post 组件,里面渲染了一组内容列表,现在我想把列表项目单独放在一个组件里。在终端给项目生成一个组件,ng generate 一个 component ,放在 modules/post/components 里面,名字是 post-item 。

# ng g c modules/post/components/post-item  ( #ng generate component modules/post/components/post-item )

回到项目,先打开 Post 组件的模板文件,剪切一下 ul 元素里包装的这个 li 元素,这里可以换成刚才我们创建的 app-post-item 组件。

打开 PostItem 组件的模板文件,把刚才剪切的视图粘贴到这里,去掉 li 元素上的 ngFor 指令。这个组件里需要一个 entity 数据,它的值应该就是要显示的内容,里面有 title 还有 body 属性。

这个 entity 数据要在使用了 PostItem 组件的父辈那里绑定。打开 PostItem 组件,在组件里要添加一个 Input 属性,用一下 @Input 这个装饰器,它来自 @angular/core 这个包。

装饰的属性的名字可以是 entity,这样在使用这个组件的时候,可以给这个组件绑定一个 entity 属性。

属性的值的类型可以再设置一下,在 post 目录里面,新建一个 models 目录,里面添加一个 post.model.ts ,在这个文件里 export 一个 class ,名字叫 Post ,在类里添加一个构造方法,里面添加两个参数属性。public title ,类型是 string,public body,类型也是 string 。

回到 PostItem 组件,设置一下 entity 这个属性的类型,可以用一下 Post,这个东西来自刚才我们定义的 Post 类。

然后打开 Post 组件,在这个组件里用了一下 PostItem 组件,在组件上用一个 *ngFor,循环一下 Post 组件里的 entities 这组数据, let entity of entities。

PostItem 组件的模板里需要 entity 数据,这个属性我们已经在 PostItem 里面设置成了一个 Input 属性,所以在这里可以绑定一个 entity 属性,它的值就是每次循环的时候当前项目的名字,也就是 entity 。

回到浏览器再预览一下,现在页面上仍然会显示一组内容列表。

来自  https://ninghao.net/video/7660#info


4)Output:父组件监听在子组件上发生的事情

按一下这个内容列表某个项目里的 Remove 按钮,暂时这个按钮还不能做什么。按了这个按钮以后,可以让 PostItem 组件触发一个自定义的事件,父组件可以监听这个事件去做一些事情。

回到项目,打开 PostItem 组件,在这个组件里先添加一个 Output 属性,用 @Output 这个装饰器装饰一下,它来自@angular/core 这个包。属性的名字可以叫做 remove,它的值新建一个 EventEmitter,这个 EventEmitter 也来自 @angular/core 。

点击了内容列表里的 Remove 按钮以后,可以触发一个 remove 事件。在组件里添加一个方法,名字可以叫 onClick,方法接收一个 entity 参数,类型是 Post。

方法里面用一下 this.remove 上的 emit 触发一下这个 remove 事件,发生这个事情的时候带着一个 entity,这样监听这个事件的地方就可以得到 entity 的值。这里这个 entity 表示的就是发生这个事件的内容项目。

视图

下面再打开这个组件的视图,找到 Remove 按钮,在按钮上绑定一个 click 事件,发生点击事件,执行一下组件里的 onClick 方法,带着 entity 数据。这样 onClick 方法里面会触发一个 remove 事件。

Post 视图

然后去处理一下 Post 组件,打开它的模板文件,在这里用了 PostItem 组件,使用它的时候可以绑定一个自定义的事件,名字是 remove,当这个 PostItem 组件上发生这个自定义事件的时候,用 Post 组件的 removeItem 方法来处理,方法接收一个 $event 参数,它的值就是触发这个事件的时候带的数据。

Post 组件

打开 Post 组件,组件里之前我们已经添加了一个 removeItem 方法,现在这个方法接收的 item 参数,它的类型可以设置成 Post。可以再修改一下 entities 这个数据,在每个数据项目里面,再添加一个 id 属性,它的值是一个 id 号,类型是数字。

这样 Post Model 也需要改一下,打开它,在构造方法里,再添加一个 public id 类型是 number。

回到 Post 组件,继续再修改一下 removeItem 方法,方法里重新设置 this.entities 的值,用一下 this.entities.filter,提供的方法参数接收一个 entity 参数,方法 return 的是 entity 的 id 不等于 item.id 。

预览

回到浏览器,再试一下,按一下列表项目里的 remove 方法,可以在列表中移除掉当前这个内容项目。

来自  https://ninghao.net/video/7661#info



5)路由(Routes)


在地址栏里输入了对应的地址,或者点击了某个链接,可以打开应用对应的页面,这就是路由的主要功能。在用 ng new 命令创建项目的时候,我选择了使用路由功能。

回到项目,先打开 app.module ,你会发现在这个模块的 imports 里面导入了一个 AppRoutingModule 模块,这个模块是在 app-routing.module.ts 文件里定义的。 打开这个文件。

在这个模块的 imports 里面,用了一个 RouterModule,这个模块是在 @angular/router 里的东西。这里用了一下 forRoot 方法配置了一下 RouterMoudle 模块。 给这个 forRoot 方法提供了一个 routes,这个 routes 的类型是 Routes,它也来自 @angular/router 。

在这个 routes 里面,可以定义一些路由。每个路由的定义可以是一个对象,里面先用 path 属性设置一下路由的地址,比如 posts,然后再用 component 属性设置一下对应的组件,也就是访问 posts 这个地址的时候,要在页面上显示哪个组件,这里用一下 PostComponent 这个组件,注意在文件的顶部要导入这个组件。

在 AppModule 模块里导入了 AppRoutingModule 模块,因为在这个 AppRoutingModule 模块里,exports 里面,导出了 RouterMoudle,所以,在 AppModule 模块里,也就可以使用在 AppRoutingModule 模块里导出的这个 RouterModule,这样应用也就可以知道我们在这个模块里定义的路由了。

视图

打开 AppComponent 组件的模板文件,去掉在这里添加 app-post 元素,换成一个 router-outlet,意思就是在这里输出路由对应的组件的内容。

预览

回到浏览器可以预览一下,现在应用的首页上除了标题以后,不会显示其它的东西。在地址里输入一个 /posts,这个是我们定义的一条路由的地址,打开以后,在 AppComponent 的模板里的 router-outlet 元素的地方,就会显示这个路由对应的组件,这里就是 PostComponent 这个组件。

来自  https://ninghao.net/video/7662#info


6)路由:定义带参数的路由

访问 posts 斜线,加上一个具体的内容 id,可以打开内容的详情页面。先在终端用命令生成一个组件,执行 ng generate 生成一个 component ,放在 modules/post/components 的下面,名字是 post-details 。

# ng g c modules/post/components/post-details  ( ng generate component modules/post/components/post-details ) 

定义路由

打开 AppRoutingModule 模块,在这个模块的 routes 里面,再定义一条路由,路由的 path,也就是地址是 posts/:id,这里的 :id 是这个地址里的一个参数,也就是它的值是会发生变化的。

再用 component 设置一下对应的组件,用一下刚才我们创建的 PostDetailsComponent 组件,注意要在文件顶部导入这个组件。

预览

回到浏览器,访问一下 posts 斜线,后面加上一个内容的 id 号,

http://localhost:4200/posts/1

页面上显示的就是 PostDetails 组件里的内容。现在不管 id 是多少,都会显示同样的内容。在后面我们会根据地址里的这个 id 参数的值,在 PostDetails 组件里显示对应的文章内容。

来自  https://ninghao.net/video/7663#info

7)routerLink:路由链接

点击内容列表的标题,可以打开对应的内容地址。回到项目,我们要处理的是 PostItem 组件的视图,打开它的模板文件。然后在这个 a 元素里面,绑定一个 routerLink,它的值是一组方括号,里面先添加一个 /posts,第二个项目是路由的对应的参数的值,这里可以用一下 entity 的 id 属性。

现在编辑器会提示 a 元素上没有 routerLink 属性,这是因为 routerLink 是 RouterModule 模块提供的东西。所以我们需要在这个 PostItem 组件所属的模块里面,导入 RouterModule 模块。

打开 PostModule 模块,在 imports 里面,可以添加一个 RouterModule ,或者添加一个 AppRoutingModule,因为在这个模块里导出了 RouterModule 模块。

回到 PostItem 组件的视图,现在绑定 routerLink 的地方就不会再出现警告了。

预览

回到浏览器,预览一下。先打开 posts 这个地址,然后按一下内容列表的标题链接,会打开对应的内容页面。

来自  https://ninghao.net/video/7664#info


8)在组件中获取路由参数的值(paramMap)


在 PostDetails 组件里,我们需要动态的获取到路由地址里的 id 参数的值,这样就可以根据这个 id 的值得到对应要显示的内容数据了。Angular 里的 ActivatedRoute 里面包含了路由相关的信息。

打开 PostDetails 组件,先把 ActivatedRoute 作为这个类的依赖注入进来,在类的构造方法里面,添加一个 private route,类型是 ActivatedRoute。这样在这个类里面会添加一个 route 属性,它的值就是一个 ActivatedRoute。 ActivatedRoute 来自 @angular/router 这个包。要在文件的顶部导入它。

然后在这个组件的 ngOnInit 方法里面,可以去做一些事情, ngOnInit 是组件的一个生命周期方法,组件在初始化的时候会执行它。

用一下 this.route 上的 paramMap,这个 paramMap 是个 Observable,可以订阅一下这个 Observable,使用 subscribe 方法,给它提供一个方法,这个方法会在 Observable 上有数据的时候执行。

方法接收一个 params 参数,在方法里面,得到对应的路由参数可以使用 params 上的 get 方法。先添加一个 postId ,用一下 params 上的 get 方法,要得到的参数的名字叫 id 。获取到的这个值会是字符串类型的,把它转换成数字类型的值,可以在前面加上一个加号。(就是把字符串转换成数字类型的)

在控制台上输出 postId 的值。用一个 console.log 输出 postId 。

预览

回到浏览器预览一下,点击内容列表项目的标题,路由地址里的参数值会有变化,在控制台上会输出路由地址里的 id 参数的值。

来自  https://ninghao.net/video/7665#info


9)利用路由地址参数

打开 PostComponent 组件,在这个组件里我们之前直接添加了一组 entities 数据,剪切一下这组数据,可以把它单独放在一个文件里。这个 entities 的类型是一组 Post。

下面在 post 目录的下面,新建一个文件,名字是 posts.ts,文件里导出一个 const ,名字可以叫 posts,把刚刚剪切的内容列表数据粘贴到这里。

然后回到 PostComponent,在组件的构造方法里面,设置一下 entities 属性的值,让它等于 posts,注意要在文件顶部从 posts 里面导入这个 posts 。

现在这个 this.entities 会出现一个警告,打开 post/models 里的 post.model.ts,可以把 body 标记成可选的,加上一个问号。

这是因为在 posts 里面,最后这个数据项目里并没有 body 属性,所以可以把 Post 里的 body 标记成一个可选的属性。这样这个 this.entities 就不会再出现警告了。

PostDetailsComponent

打开 PostDetails 组件,先在这个组件里添加一个属性,名字可以叫 entity,它的类型是 Post。然后修改一下订阅 paramMap 提供的方法。

设置一下 this.entity 属性的值,它的值是 posts,注意在文件顶部要导入这个 posts,用一下 posts 数组上的 find ,提供一个方法参数,接收一个 post 参数,方法返回的是 post.id 等于 postId 的项目。

这样组件里的 entity 属性的值就会是这个组件要显示的内容数据。

打开这个组件对应的模板文件,删除掉里面的东西,然后添加一个标题元素,里面绑定输出 entity 里的 title 属性的值。下面再添加一个段落标签,里面再绑定输出 entity 的 body 属性的值。

因为有的数据项目可能里面没有 body 属性,所以在这个段落元素上可以用一个 *ngIf,条件是 entity 的 body,就是如果数据里面有 body 就显示这个元素,没有就不显示。

预览

回到浏览器再预览一下,现在页面的地址是 posts/3 ,页面上会显示一个标题,因为这个数据项目里面没有 body 属性。返回内容列表,打开列表里的一个其它的项目,页面上会显示对应的内容。

来自  https://ninghao.net/video/7666#info

10)服务(Services)

在 Angular 应用里可以使用服务帮组件去做一些事情,在终端先去生成一个服务,ng generate 一个 service ,放在 modules/post/services 里面,名字叫 post 。

# ng g s modules/post/service/post    (  ng generate service modules/post/service/post )

回到项目,找到刚才生成的这个 post.service,服务是个类,这个类要用 Injectable 装饰一下,给这个装饰器提供的对象参数里面,有个 providedIn,值是 root,这样这个服务就可以在任何地方使用。

在这个服务里,添加一个 entities,类型是一组 Post,然后在这个类的构造方法里面,设置一下 this.entities 的值,让它等于 posts,这个 posts 要在文件顶部导入。

然后在服务里添加两个方法,先添加一个 index 方法,这个方法做的事情就是 return this.entities 。下面再添加一个方法,名字叫 show,它可以返回指定的文章内容,接收一个 id 参数,类型是 number。

方法 return 的是,用一下 this.entities.find,提供一个方法参数,有个 post 参数,返回的是 post.id 等于 id 的数据项目。

使用服务

要在组件里使用服务需要把它注入到组件里面,先打开 PostComponent,在组件的构造方法里设置了一下组件里的 entities 的值,现在这个值可以使用 PostService 服务提供的方法得到。

先把这个服务作为这个组件的依赖注入进来,在组件的构造方法的参数里面,添加一个 private postService,类型是 PostService,这样这个 postService 属性就是一个 PostService 服务。

这样这个 this.entities 的值,现在可以是 this.postService 用一下它上面的 index 方法,这个方法会返回一组内容。

文件顶部导入的这个 posts 现在就可以去掉了。

再打开 PostDetails 组件,先把 PostService 作为这个组件的依赖注入进来,在构造方法的参数里,添加一个 private postService 类型是 PostService 。

在订阅 paramMap 的方法里,this.entity 的值,现在就可以用一下 this.postService 上的 show,把 postId 交给这个方法。

文件顶部导入的 posts 现在可以去掉了。

预览

回到浏览器预览一下,打开内容列表,页面上仍然会显示一组内容,这些要显示的内容数据,现在是用 PostService 里的 index 方法获取到的。再打开一个内容项目,页面上会显示对应的内容,这个页面上显示的内容数据现在是用 PostService 上的 show 方法获取到的。

来自   https://ninghao.net/video/7667





普通分类: