-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathLearn-Angular.html
1 lines (1 loc) · 95.6 KB
/
Learn-Angular.html
1
<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=2"><meta name="theme-color" content="#222"><meta name="generator" content="Hexo 5.4.0"><link rel="apple-touch-icon" sizes="180x180" href="/images/favicon-32x32.png"><link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32.png"><link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16.png"><link rel="mask-icon" href="/images/favicon-32x32.png" color="#222"><link rel="stylesheet" href="/css/main.css"><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lato:300,300italic,400,400italic,700,700italic&display=swap&subset=latin,latin-ext"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/[email protected]/css/all.min.css" integrity="sha256-2H3fkXt6FEmrReK448mDVGKb3WW2ZZw35gI7vqHOE4Y=" crossorigin="anonymous"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/animate.min.css" integrity="sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE=" crossorigin="anonymous"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/[email protected]/dist/jquery.fancybox.min.css" integrity="sha256-Vzbj7sDDS/woiFS3uNKo8eIuni59rjyNGtXfstRzStA=" crossorigin="anonymous"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/nprogress.css" integrity="sha256-no0c5ccDODBwp+9hSmV5VvPpKwHCpbVzXHexIkupM6U=" crossorigin="anonymous"><script src="https://cdn.jsdelivr.net/npm/[email protected]/nprogress.js" integrity="sha256-a5YRB27CcBwBFcT5EF/f3E4vzIqyHrSR878nseNYw64=" crossorigin="anonymous"></script><script class="next-config" data-name="main" type="application/json">{"hostname":"www.wrysmile.cn","root":"/","images":"/images","scheme":"Gemini","version":"8.5.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":true,"bookmark":{"enable":true,"color":"#222","save":"manual"},"fancybox":true,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"prism":false,"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果:${query}","hits_time":"找到 ${hits} 个搜索结果(用时 ${time} 毫秒)","hits":"找到 ${hits} 个搜索结果"},"path":"/search.xml","localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false}}</script><script src="/js/config.js"></script><meta name="description" content="本篇是Angular开发中需要掌握的基础内容"><meta property="og:type" content="article"><meta property="og:title" content="Angular开发:基础内容"><meta property="og:url" content="https://www.wrysmile.cn/Learn-Angular.html"><meta property="og:site_name" content="Wrysmile 的博客"><meta property="og:description" content="本篇是Angular开发中需要掌握的基础内容"><meta property="og:locale" content="zh_CN"><meta property="article:published_time" content="2021-08-17T14:55:03.000Z"><meta property="article:modified_time" content="2023-01-31T10:23:56.174Z"><meta property="article:author" content="Zhang Yangeng"><meta property="article:tag" content="Angular"><meta property="article:tag" content="前端"><meta name="twitter:card" content="summary"><link rel="canonical" href="https://www.wrysmile.cn/Learn-Angular.html"><script class="next-config" data-name="page" type="application/json">{"sidebar":"","isHome":false,"isPost":true,"lang":"zh-CN","comments":true,"permalink":"https://www.wrysmile.cn/Learn-Angular.html","path":"Learn-Angular.html","title":"Angular开发:基础内容"}</script><script class="next-config" data-name="calendar" type="application/json">""</script><title>Angular开发:基础内容 | Wrysmile 的博客</title><script>!function(e,t,o,c,i,a,n){e.DaoVoiceObject=i,e[i]=e[i]||function(){(e[i].q=e[i].q||[]).push(arguments)},e[i].l=+new Date,a=t.createElement(o),n=t.getElementsByTagName(o)[0],a.async=1,a.src=c,a.charset="utf-8",n.parentNode.insertBefore(a,n)}(window,document,"script",("https:"==document.location.protocol?"https:":"http:")+"//widget.daovoice.io/widget/13e39436.js","daovoice"),daovoice("init",{app_id:"13e39436"}),daovoice("update")</script><noscript><link rel="stylesheet" href="/css/noscript.css"></noscript><link rel="alternate" href="/atom.xml" title="Wrysmile 的博客" type="application/atom+xml"></head><body itemscope itemtype="http://schema.org/WebPage" class="use-motion"><div class="headband"></div><main class="main"><header class="header" itemscope itemtype="http://schema.org/WPHeader"><div class="header-inner"><div class="site-brand-container"><div class="site-nav-toggle"><div class="toggle" aria-label="切换导航栏" role="button"><span class="toggle-line"></span> <span class="toggle-line"></span> <span class="toggle-line"></span></div></div><div class="site-meta"><a href="/" class="brand" rel="start"><i class="logo-line"></i><h1 class="site-title">Wrysmile 的博客</h1><i class="logo-line"></i></a><p class="site-subtitle" itemprop="description">欢迎来到我的个人小屋</p><img class="custom-logo-image" src="/images/favicon-32x32.png" alt="Wrysmile 的博客"></div><div class="site-nav-right"><div class="toggle popup-trigger"><i class="fa fa-search fa-fw fa-lg"></i></div></div></div><nav class="site-nav"><ul class="main-menu menu"><li class="menu-item menu-item-home"><a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a></li><li class="menu-item menu-item-about"><a href="/about/" rel="section"><i class="fa fa-user fa-fw"></i>关于</a></li><li class="menu-item menu-item-tags"><a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a></li><li class="menu-item menu-item-categories"><a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a></li><li class="menu-item menu-item-archives"><a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a></li><li class="menu-item menu-item-search"><a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索</a></li></ul></nav><div class="search-pop-overlay"><div class="popup search-popup"><div class="search-header"><span class="search-icon"><i class="fa fa-search"></i></span><div class="search-input-container"><input autocomplete="off" autocapitalize="off" maxlength="80" placeholder="搜索..." spellcheck="false" type="search" class="search-input"></div><span class="popup-btn-close" role="button"><i class="fa fa-times-circle"></i></span></div><div class="search-result-container no-result"><div class="search-result-icon"><i class="fa fa-spinner fa-pulse fa-5x"></i></div></div></div></div></div><div class="toggle sidebar-toggle" role="button"><span class="toggle-line"></span> <span class="toggle-line"></span> <span class="toggle-line"></span></div><aside class="sidebar"><div class="sidebar-inner sidebar-nav-active sidebar-toc-active"><ul class="sidebar-nav"><li class="sidebar-nav-toc">文章目录</li><li class="sidebar-nav-overview">站点概览</li></ul><div class="sidebar-panel-container"><div class="post-toc-wrap sidebar-panel"><div class="post-toc animated"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link"><span class="nav-text">基础</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-%E5%88%9B%E5%BB%BA%E9%A1%B9%E7%9B%AE"><span class="nav-text">1.创建项目</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-%E5%8D%95%E5%90%91%E7%BB%91%E5%AE%9A"><span class="nav-text">2.单向绑定</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link"><span class="nav-text">组件</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%A7%86%E5%9B%BE%E5%8C%85%E8%A3%85"><span class="nav-text">视图包装</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%BB%84%E4%BB%B6%E4%BA%A4%E4%BA%92"><span class="nav-text">组件交互</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-input"><span class="nav-text">(1).@input()</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-output"><span class="nav-text">(2).@output()</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-ViewChild"><span class="nav-text">(3).@ViewChild()</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%BB%84%E4%BB%B6%E6%A0%B7%E5%BC%8F"><span class="nav-text">组件样式</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-host"><span class="nav-text">(1).:host</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-host-content"><span class="nav-text">(2).:host-content</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%86%85%E5%AE%B9%E6%8A%95%E5%BD%B1"><span class="nav-text">内容投影</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-%E5%8D%95%E6%8F%92%E6%A7%BD%E5%86%85%E5%AE%B9%E6%8A%95%E5%BD%B1"><span class="nav-text">(1).单插槽内容投影</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-%E5%A4%9A%E6%8F%92%E6%A7%BD%E5%86%85%E5%AE%B9%E6%8A%95%E5%BD%B1"><span class="nav-text">(2).多插槽内容投影</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%8A%A8%E6%80%81%E7%BB%84%E4%BB%B6"><span class="nav-text">动态组件</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link"><span class="nav-text">指令</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-%E5%86%85%E7%BD%AE%E6%8C%87%E4%BB%A4"><span class="nav-text">1.内置指令</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-%E5%B1%9E%E6%80%A7%E5%9E%8B%E6%8C%87%E4%BB%A4"><span class="nav-text">2.属性型指令</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-%E7%BB%93%E6%9E%84%E5%9E%8B%E6%8C%87%E4%BB%A4"><span class="nav-text">3.结构型指令</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link"><span class="nav-text">服务</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-%E5%88%9B%E5%BB%BA%E6%9C%8D%E5%8A%A1"><span class="nav-text">1.创建服务</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85%A5"><span class="nav-text">2.依赖注入</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-%E6%9C%8D%E5%8A%A1%E5%B5%8C%E5%A5%97"><span class="nav-text">3.服务嵌套</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link"><span class="nav-text">路由</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-%E5%88%9B%E5%BB%BA%E8%B7%AF%E7%94%B1"><span class="nav-text">1.创建路由</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-%E9%85%8D%E7%BD%AE%E8%B7%AF%E7%94%B1%E8%A7%84%E5%88%99"><span class="nav-text">2.配置路由规则</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-%E5%9F%BA%E7%A1%80%E8%B7%AF%E7%94%B1%E9%85%8D%E7%BD%AE%E8%A7%84%E5%88%99"><span class="nav-text">(1).基础路由配置规则</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-%E9%BB%98%E8%AE%A4%E8%B7%AF%E7%94%B1%E9%85%8D%E7%BD%AE%E8%A7%84%E5%88%99"><span class="nav-text">(2).默认路由配置规则</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-%E9%80%9A%E9%85%8D%E8%B7%AF%E7%94%B1%E9%85%8D%E7%BD%AE%E8%A7%84%E5%88%99"><span class="nav-text">(3).通配路由配置规则</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-%E7%BB%84%E4%BB%B6%E6%B8%B2%E6%9F%93%E8%BE%93%E5%87%BA"><span class="nav-text">3.组件渲染输出</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#4-%E5%AF%BC%E8%88%AA"><span class="nav-text">4.导航</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#5-%E8%B7%AF%E7%94%B1%E5%B5%8C%E5%A5%97"><span class="nav-text">5.路由嵌套</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#6-%E8%B7%AF%E7%94%B1%E4%BC%A0%E5%80%BC"><span class="nav-text">6.路由传值</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-queryParams"><span class="nav-text">(1).queryParams</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-params"><span class="nav-text">(2).params</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#7-%E8%B7%AF%E7%94%B1%E9%A1%BA%E5%BA%8F"><span class="nav-text">7.路由顺序</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-%E9%BB%98%E8%AE%A4%E8%B7%AF%E5%BE%84%E8%B7%AF%E7%94%B1"><span class="nav-text">(1).默认路径路由</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-%E9%87%8D%E5%AE%9A%E5%90%91%E8%B7%AF%E7%94%B1"><span class="nav-text">(2).重定向路由</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#8-%E7%BC%96%E5%86%99%E4%BD%8D%E7%BD%AE"><span class="nav-text">8.编写位置</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-app-moudule-ts%E6%96%87%E4%BB%B6"><span class="nav-text">(1).app.moudule.ts文件</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-%E8%B7%AF%E7%94%B1%E6%A8%A1%E5%9D%97"><span class="nav-text">(2).路由模块</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#9-%E8%B7%AF%E7%94%B1%E5%AE%88%E5%8D%AB"><span class="nav-text">9.路由守卫</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%96%B9%E6%B3%95"><span class="nav-text">方法</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#10-%E8%B7%AF%E7%94%B1%E7%AD%96%E7%95%A5"><span class="nav-text">10.路由策略</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E9%BB%98%E8%AE%A4%E7%AD%96%E7%95%A5"><span class="nav-text">默认策略</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link"><span class="nav-text">表单</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%93%8D%E5%BA%94%E5%BC%8F%E8%A1%A8%E5%8D%95"><span class="nav-text">响应式表单</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%A8%A1%E6%9D%BF%E9%A9%B1%E5%8A%A8%E8%A1%A8%E5%8D%95"><span class="nav-text">模板驱动表单</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%A1%A8%E5%8D%95%E9%AA%8C%E8%AF%81"><span class="nav-text">表单验证</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E8%87%AA%E5%AE%9A%E4%B9%89%E9%AA%8C%E8%AF%81%E5%99%A8"><span class="nav-text">自定义验证器</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link"><span class="nav-text">国际化</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%AD%A5%E9%AA%A4"><span class="nav-text">步骤</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-%E6%B7%BB%E5%8A%A0-localize-%E5%8C%85"><span class="nav-text">(1).添加 localize 包</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-%E6%A0%87%E8%AE%B0%E8%A6%81%E7%BF%BB%E8%AF%91%E7%9A%84%E6%96%87%E6%9C%AC"><span class="nav-text">(2).标记要翻译的文本</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-%E6%8F%90%E5%8F%96%E6%BA%90%E8%AF%AD%E8%A8%80%E6%96%87%E4%BB%B6"><span class="nav-text">(3).提取源语言文件</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-%E7%94%9F%E6%88%90%E8%AF%AD%E8%A8%80%E6%96%87%E4%BB%B6%E5%89%AF%E6%9C%AC"><span class="nav-text">(4).生成语言文件副本</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#5-%E7%BF%BB%E8%AF%91%E8%AF%AD%E8%A8%80%E6%96%87%E4%BB%B6%E5%89%AF%E6%9C%AC"><span class="nav-text">(5).翻译语言文件副本</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#6-%E5%AE%9A%E4%B9%89%E6%9C%AC%E5%9C%B0%E7%8E%AF%E5%A2%83"><span class="nav-text">(6).定义本地环境</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#7-%E5%90%88%E5%B9%B6%E7%BF%BB%E8%AF%91%E6%96%87%E4%BB%B6"><span class="nav-text">(7).合并翻译文件</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%BC%95%E7%94%B3%EF%BC%9A%E7%94%9F%E6%88%90%E7%BF%BB%E8%AF%91%E6%96%87%E4%BB%B6%E6%97%B6%E8%87%AA%E5%8A%A8%E8%BF%BD%E5%8A%A0%E6%96%B0%E5%86%85%E5%AE%B9"><span class="nav-text">引申:生成翻译文件时自动追加新内容</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link"><span class="nav-text">动画</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%AE%80%E5%8D%95%E4%BD%BF%E7%94%A8"><span class="nav-text">简单使用</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8A%A8%E7%94%BB%E5%AE%9A%E4%B9%89"><span class="nav-text">动画定义</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8A%A8%E7%94%BB%E8%A7%A6%E5%8F%91"><span class="nav-text">动画触发</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8A%A8%E7%94%BB%E7%8A%B6%E6%80%81%E5%92%8C%E6%A0%B7%E5%BC%8F"><span class="nav-text">动画状态和样式</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8A%A8%E7%94%BB%E8%BD%AC%E5%9C%BA%E5%92%8C%E6%97%B6%E5%BA%8F"><span class="nav-text">动画转场和时序</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8A%A8%E7%94%BB%E5%B1%95%E7%A4%BA"><span class="nav-text">动画展示</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8A%A8%E7%94%BB%E7%A6%81%E7%94%A8"><span class="nav-text">动画禁用</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%BD%AC%E5%9C%BA%E4%B8%8E%E8%A7%A6%E5%8F%91%E5%99%A8"><span class="nav-text">转场与触发器</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E9%80%9A%E9%85%8D%E7%AC%A6"><span class="nav-text">通配符</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#void"><span class="nav-text">void</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%88%B6%E5%AD%90%E5%8A%A8%E7%94%BB"><span class="nav-text">父子动画</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%A4%8D%E6%9D%82%E5%BA%8F%E5%88%97"><span class="nav-text">复杂序列</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%8F%AF%E5%A4%8D%E7%94%A8%E5%8A%A8%E7%94%BB"><span class="nav-text">可复用动画</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link"><span class="nav-text">服务端渲染</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%9F%BA%E7%A1%80"><span class="nav-text">基础</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E4%BC%98%E7%82%B9"><span class="nav-text">优点</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95"><span class="nav-text">使用方法</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link"><span class="nav-text">开发技巧</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-%E6%B1%82%E6%95%B0%E7%BB%84%E4%B8%AD%E6%9C%80%E5%A4%A7%E5%80%BC"><span class="nav-text">1.求数组中最大值</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-click-%E5%A6%99%E7%94%A8"><span class="nav-text">2.(click)妙用</span></a></li></ol></li></ol></div></div><div class="site-overview-wrap sidebar-panel"><div class="site-author site-overview-item animated" itemprop="author" itemscope itemtype="http://schema.org/Person"><img class="site-author-image" itemprop="image" alt="Zhang Yangeng" src="/images/avatar.jpg"><p class="site-author-name" itemprop="name">Zhang Yangeng</p><div class="site-description" itemprop="description">保持独立思考,不卑不亢不怂,长成自己想要的样子!</div></div><div class="site-state-wrap site-overview-item animated"><nav class="site-state"><div class="site-state-item site-state-posts"><a href="/archives/"><span class="site-state-item-count">69</span> <span class="site-state-item-name">日志</span></a></div><div class="site-state-item site-state-categories"><a href="/categories/"><span class="site-state-item-count">13</span> <span class="site-state-item-name">分类</span></a></div><div class="site-state-item site-state-tags"><a href="/tags/"><span class="site-state-item-count">52</span> <span class="site-state-item-name">标签</span></a></div></nav></div><div class="links-of-author site-overview-item animated"><span class="links-of-author-item"><a href="https://github.com/zhangyangeng" title="GitHub → https://github.com/zhangyangeng" rel="external nofollow noopener noreferrer" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a> </span><span class="links-of-author-item"><a href="https://weibo.com/u/2294901673" title="weibo → https://weibo.com/u/2294901673" rel="external nofollow noopener noreferrer" target="_blank"><i class="fab fa-weibo fa-fw"></i>weibo</a></span></div><div class="cc-license site-overview-item animated" itemprop="license"><a href="https://creativecommons.org/licenses/by-nc-sa/4.0/zh-cn" class="cc-opacity" rel="external nofollow noopener noreferrer" target="_blank"><img src="https://cdn.jsdelivr.net/npm/@creativecommons/[email protected]/assets/license_badges/small/by_nc_sa.svg" alt="Creative Commons"></a></div><div class="links-of-blogroll site-overview-item animated"><div class="links-of-blogroll-title"><i class="fa fa-globe fa-fw"></i> 推荐网站</div><ul class="links-of-blogroll-list"><li class="links-of-blogroll-item"><a href="http://topbook.cc/" title="http://topbook.cc/" rel="external nofollow noopener noreferrer" target="_blank">Topbook</a></li></ul></div></div></div></div></aside><div class="sidebar-dimmer"></div></header><div class="back-to-top" role="button" aria-label="返回顶部"><i class="fa fa-arrow-up"></i> <span>0%</span></div><div class="reading-progress-bar"></div><a role="button" class="book-mark-link book-mark-link-fixed"></a><noscript><div class="noscript-warning">Theme NexT works best with JavaScript enabled</div></noscript><div class="main-inner post posts-expand"><div class="post-block"><article itemscope itemtype="http://schema.org/Article" class="post-content" lang="zh-CN"><link itemprop="mainEntityOfPage" href="https://www.wrysmile.cn/Learn-Angular.html"><span hidden itemprop="author" itemscope itemtype="http://schema.org/Person"><meta itemprop="image" content="/images/avatar.jpg"><meta itemprop="name" content="Zhang Yangeng"><meta itemprop="description" content="保持独立思考,不卑不亢不怂,长成自己想要的样子!"></span><span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization"><meta itemprop="name" content="Wrysmile 的博客"></span><header class="post-header"><h1 class="post-title" itemprop="name headline">Angular开发:基础内容</h1><div class="post-meta-container"><div class="post-meta"><span class="post-meta-item"><span class="post-meta-item-icon"><i class="far fa-calendar"></i> </span><span class="post-meta-item-text">发表于</span> <time title="创建时间:2021-08-17 22:55:03" itemprop="dateCreated datePublished" datetime="2021-08-17T22:55:03+08:00">2021-08-17</time> </span><span class="post-meta-item"><span class="post-meta-item-icon"><i class="far fa-calendar-check"></i> </span><span class="post-meta-item-text">更新于</span> <time title="修改时间:2023-01-31 18:23:56" itemprop="dateModified" datetime="2023-01-31T18:23:56+08:00">2023-01-31</time> </span><span class="post-meta-item"><span class="post-meta-item-icon"><i class="far fa-folder"></i> </span><span class="post-meta-item-text">分类于</span> <span itemprop="about" itemscope itemtype="http://schema.org/Thing"><a href="/categories/Angular%E5%BC%80%E5%8F%91/" itemprop="url" rel="index"><span itemprop="name">Angular开发</span></a> </span></span><span id="/Learn-Angular.html" class="post-meta-item leancloud_visitors" data-flag-title="Angular开发:基础内容" title="阅读次数"><span class="post-meta-item-icon"><i class="far fa-eye"></i> </span><span class="post-meta-item-text">阅读次数:</span> <span class="leancloud-visitors-count"></span></span></div><div class="post-meta"><span class="post-meta-item" title="本文字数"><span class="post-meta-item-icon"><i class="far fa-file-word"></i> </span><span class="post-meta-item-text">本文字数:</span> <span>13k</span> </span><span class="post-meta-item" title="阅读时长"><span class="post-meta-item-icon"><i class="far fa-clock"></i> </span><span class="post-meta-item-text">阅读时长 ≈</span> <span>12 分钟</span></span></div></div></header><div class="post-body" itemprop="articleBody"><center>本篇是Angular开发中需要掌握的基础内容</center><span id="more"></span><h1>基础</h1><h2 id="1-创建项目">1.创建项目</h2><p>使用 <code>ng new 项目名</code> 来创建一个新的项目</p><p>使用 <code>ng new project -S</code> 来创建一个不使用测试文件的新项目</p><p>使用 <code>ng new project --skip-install</code> 来创建一个新项目,且跳过安装依赖</p><h2 id="2-单向绑定">2.单向绑定</h2><p>绑定数据:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">// ts 中</span><br><span class="line">title: string = "标题";</span><br><span class="line">// html 中</span><br><span class="line"><div>{{title}}</div></span><br></pre></td></tr></table></figure><p>绑定属性:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">// ts 中</span><br><span class="line">msg: string = "提示信息";</span><br><span class="line">// html 中</span><br><span class="line"><div [title]="msg"></div></span><br></pre></td></tr></table></figure><p>绑定 html</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">// ts 中</span><br><span class="line">h2: string = "<h2>这是h2</h2>"</span><br><span class="line">// html 中</span><br><span class="line"><div [innerHTML]="h2"></div></span><br></pre></td></tr></table></figure><h1>组件</h1><h2 id="视图包装">视图包装</h2><p>在 Angular 中,组件的 CSS 样式被封装进了自己的视图,可以通过在组件的元数据上设置<strong>视图封装模式</strong>,你可以分别控制<strong>每个组件</strong>的封装模式</p><p>封装模式如下:</p><ul class="lvl-0"><li class="lvl-2"><p><code>ShadowDom</code>:使用浏览器原生的 Shadow DOM 来实现(不进不出,全局样式进不来,组件样式出不去)</p></li><li class="lvl-2"><p><code>Emulated</code>:默认值,通过预处理 CSS 代码来模拟 Shadow DOM 的行为(只进不出,全局样式能进来,组件样式出不去)</p></li><li class="lvl-2"><p><code>None</code>:不使用视图封装,即把 CSS 添加到全局样式中(能进能出)</p></li></ul><p>设置封装模式:组件元数据中的 <code>encapsulation</code> 属性来设置组件封装模式</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">encapsulation: ViewEncapsulation.ShadowDom</span><br></pre></td></tr></table></figure><h2 id="组件交互">组件交互</h2><h3 id="1-input">(1).@input()</h3><p>父组件通过 <code>@input()</code> 给子组件绑定属性设置输入类数据</p><p>方法如下:</p><ul class="lvl-0"><li class="lvl-2"><p>在父组件中定义一个属性</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">title: <span class="built_in">string</span> = <span class="string">"Wrysmile's Blog"</span>;</span><br></pre></td></tr></table></figure></li><li class="lvl-2"><p>在父组件的页面中给子组件传值</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">app-title</span> [<span class="attr">title</span>] = <span class="string">"title"</span>></span><span class="tag"></<span class="name">app-title</span>></span></span><br></pre></td></tr></table></figure></li><li class="lvl-2"><p>在子组件中注入该属性</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Input</span>() title?: <span class="built_in">string</span>;</span><br></pre></td></tr></table></figure></li><li class="lvl-2"><p>在子组件的页面中即可使用该属性了</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">p</span>></span>{{title}}<span class="tag"></<span class="name">p</span>></span></span><br></pre></td></tr></table></figure></li><li class="lvl-2"><p>同时也可以在父组件中修改该值,会实时同步到子组件</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">// html文件</span><br><span class="line"><span class="tag"><<span class="name">button</span> (<span class="attr">click</span>) = <span class="string">"titleChange()"</span>></span>修改<span class="tag"></<span class="name">button</span>></span></span><br></pre></td></tr></table></figure><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// ts文件</span></span><br><span class="line"><span class="function"><span class="title">titleChange</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="built_in">this</span>.title = <span class="string">"Wrysmile 的小站"</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ul><h3 id="2-output">(2).@output()</h3><p>父组件给子组件传递一个事件,子组件通过 <code>@output()</code> 弹射触发事件</p><p>@Output() 必须是 <code>EventEmitter</code> 类型的</p><p>方法如下:</p><ul class="lvl-0"><li class="lvl-2"><p>在父组件中定义属性以及触发的事件</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">list: <span class="built_in">Array</span><<span class="built_in">string</span>> = [<span class="string">"Angular"</span>];</span><br><span class="line"><span class="function"><span class="title">addList</span>(<span class="params">str: <span class="built_in">string</span></span>)</span>{</span><br><span class="line"> <span class="comment">// 将内容添加到列表中</span></span><br><span class="line"> <span class="built_in">this</span>.list?.push(str);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li class="lvl-2"><p>在父组件的页面中给子组件绑定该事件</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">p</span> *<span class="attr">ngFor</span>=<span class="string">"let item of list"</span>></span>{{item}}<span class="tag"></<span class="name">p</span>></span></span><br><span class="line"><span class="tag"><<span class="name">app-title</span> (<span class="attr">addList</span>) = <span class="string">"addList($event)"</span>></span><span class="tag"></<span class="name">app-title</span>></span></span><br></pre></td></tr></table></figure></li><li class="lvl-2"><p>在子组件中弹射触发父组件中的事件</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Output</span>() addList = <span class="keyword">new</span> EventEmitter();</span><br><span class="line"><span class="function"><span class="title">btnAdd</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="built_in">this</span>.addList.emit(<span class="string">"Vue"</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li class="lvl-2"><p>在子组件的页面中触发定义好的事件</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">button</span> (<span class="attr">click</span>) = <span class="string">"btnAdd()"</span>></span>我要学Vue<span class="tag"></<span class="name">button</span>></span></span><br></pre></td></tr></table></figure></li></ul><h3 id="3-ViewChild">(3).@ViewChild()</h3><p>通过 <code>@ViewChild()</code> 来获取子组件的实例,来获取子组件的数据</p><p>该方法需要结合第二个使用,方法如下:</p><ul class="lvl-0"><li class="lvl-2"><p>在父组件的页面中给子组件定义一个<strong>模板引用变量</strong></p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">app-title</span> #<span class="attr">titleDom</span> (<span class="attr">addList</span>) = <span class="string">"addList($event)"</span>></span><span class="tag"></<span class="name">app-title</span>></span></span><br><span class="line"><span class="tag"><<span class="name">button</span> (<span class="attr">click</span>) = <span class="string">"viewChildAdd()"</span>></span>父子组件交互<span class="tag"></<span class="name">button</span>></span></span><br></pre></td></tr></table></figure></li><li class="lvl-2"><p>在父组件中获取子组件的实例,然后就通过 <code>.child</code> 来调用子组件中的方法</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@ViewChild</span>(<span class="string">"titleDom"</span>) child: <span class="built_in">any</span>;</span><br><span class="line"><span class="function"><span class="title">viewChildAdd</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="built_in">this</span>.child.btnAdd();</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li class="lvl-2"><p>最后在子组件中弹射触发事件即可</p></li></ul><h2 id="组件样式">组件样式</h2><h3 id="1-host">(1).:host</h3><p>作用:用来选择当前组件中的子元素</p><p>场景:若想给某组件中的所有元素设置 flex 布局,可以不需要单独加一个盒子,而直接通过该伪类选择器给该组件设置 flex 布局</p><p>引申:</p><ul class="lvl-0"><li class="lvl-2"><p><code>:host(.active)</code>符合该类的组件</p></li><li class="lvl-2"><p><code>:host h2</code>组件中符合该选择器的元素</p></li></ul><h3 id="2-host-content">(2).:host-content</h3><p>作用:用来选择当前组件中的祖先节点</p><h2 id="内容投影">内容投影</h2><h3 id="1-单插槽内容投影">(1).单插槽内容投影</h3><p>使用 <code><ng-content></code> 来进行投影</p><h3 id="2-多插槽内容投影">(2).多插槽内容投影</h3><p>使用 <code><ng-content select="[question]"></code> 来进行投影</p><h2 id="动态组件">动态组件</h2><h1>指令</h1><h2 id="1-内置指令">1.内置指令</h2><p>内置属性型指令:</p><ul class="lvl-0"><li class="lvl-2"><p>NgClass:添加和删除一组 CSS 类</p></li><li class="lvl-2"><p>NgStyle:添加和删除一组 HTML 样式</p></li><li class="lvl-2"><p>NgModel:将数据双向绑定添加到 HTML 表单元素</p></li></ul><p>内置结构型指令:</p><ul class="lvl-0"><li class="lvl-2"><p>NgIf:从模板中创建和销毁子视图</p></li><li class="lvl-2"><p>NgFor:为列表中的每个条目重复渲染一个节点</p></li><li class="lvl-2"><p>NgSwitch:一组在备用视图之间切换的指令</p></li></ul><h2 id="2-属性型指令">2.属性型指令</h2><p>建立属性型指令:</p><figure class="highlight cmd"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">ng generate directive xxx</span><br><span class="line">或</span><br><span class="line">ng g d xxx</span><br></pre></td></tr></table></figure><p>应用属性型指令:只要在相应的 HTML 模板中应用指令选择器名即可</p><h2 id="3-结构型指令">3.结构型指令</h2><p>简写形式: Angular 将结构型指令前面的星号转换为围绕宿主元素及其后代的 <code><ng-template></code></p><h1>服务</h1><h2 id="1-创建服务">1.创建服务</h2><p>使用:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">ng generate service 服务名</span><br><span class="line">或</span><br><span class="line">ng g s 服务名</span><br></pre></td></tr></table></figure><p>最好在单独的文件中定义组件和服务,如果需要合并在同一个文件中,则必须<strong style="color:red">先定义服务,再定义组件</strong>(顺序不对时会返回运行时的空引用错误)</p><p>服务文件中需要 <code>@injectable()</code> 装饰器来进行配置,其中 <code>provideIn</code> 共有三个属性值,如下:</p><ul class="lvl-0"><li class="lvl-2"><p><code>root</code>:注入到 <code>app.module.ts</code> 中,所有子组件都可以是用(推荐)</p></li><li class="lvl-2"><p><code>none</code>:不设定服务作用域(不推荐)</p></li><li class="lvl-2"><p><code>组件名</code>:只作用于该组件(懒加载模式)</p></li></ul><h2 id="2-依赖注入">2.依赖注入</h2><p>需要在 <code>app.module.ts</code> 中手动进行注入</p><p>使用 <code>import</code> 引入服务,并在 <code>providers</code> 中进行注入</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> { ListService } <span class="keyword">from</span> <span class="string">'./service/list.service'</span>;</span><br><span class="line"><span class="meta">@NgModule</span>({</span><br><span class="line"> <span class="attr">declarations</span>: [</span><br><span class="line"> <span class="comment">// 组件注入</span></span><br><span class="line"> ],</span><br><span class="line"> <span class="attr">imports</span>: [</span><br><span class="line"> BrowserModule,</span><br><span class="line"> AppRoutingModule,</span><br><span class="line"> FormsModule,</span><br><span class="line"> ReactiveFormsModule</span><br><span class="line"> ],</span><br><span class="line"> <span class="attr">providers</span>: [</span><br><span class="line"> <span class="comment">// 服务注入</span></span><br><span class="line"> ListService</span><br><span class="line"> ],</span><br><span class="line"> <span class="attr">bootstrap</span>: [AppComponent]</span><br><span class="line">})</span><br></pre></td></tr></table></figure><p>依赖项注入(DI)是一种设计模式,在这种设计模式中,类会从外部源请求依赖项而不是创建它们</p><p>在组件中注入服务时需要将依赖项注入组件的 <code>constructor()</code> 中</p><h2 id="3-服务嵌套">3.服务嵌套</h2><p>当某个服务(B)依赖于另一个服务(A)时,需要在该服务(B)中注入另一个服务(A)</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> { Injectable } <span class="keyword">from</span> <span class="string">'@angular/core'</span>;</span><br><span class="line"><span class="keyword">import</span> { HEROES } <span class="keyword">from</span> <span class="string">'./mock-heroes'</span>;</span><br><span class="line"><span class="keyword">import</span> { Logger } <span class="keyword">from</span> <span class="string">'../logger.service'</span>;</span><br><span class="line"><span class="meta">@Injectable</span>({</span><br><span class="line"> <span class="attr">providedIn</span>: <span class="string">'root'</span>,</span><br><span class="line">})</span><br><span class="line"><span class="keyword">export</span> <span class="class"><span class="keyword">class</span> <span class="title">HeroService</span> </span>{</span><br><span class="line"> <span class="comment">// 注入Logger服务</span></span><br><span class="line"> <span class="function"><span class="title">constructor</span>(<span class="params"><span class="keyword">private</span> logger: Logger</span>)</span> { }</span><br><span class="line"> <span class="function"><span class="title">getHeroes</span>(<span class="params"></span>)</span> {</span><br><span class="line"> <span class="built_in">this</span>.logger.log(<span class="string">'Getting heroes ...'</span>);</span><br><span class="line"> <span class="keyword">return</span> HEROES;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1>路由</h1><p> 使用路由可以在 Angular 中实现路径的导航模式,具体表现就是不同视图的切换。在 Angular 中,组件的实例化与销毁、模块的加载、组件某些生命周期钩子的发起都与路由相关</p><p><strong>路由器</strong> 是一个调度中心,是一套规则的列表,能够查询当前 URL 对应的规则,并呈现出相关的视图</p><p><strong>路由</strong> 是列表里面的一个规则,有如下字段:</p><ul class="lvl-0"><li class="lvl-2"><p><code>path</code>:表示该路由中的 URL 路径</p></li><li class="lvl-2"><p><code>component</code>:表示与该路由相关联的组件</p></li></ul><h2 id="1-创建路由">1.创建路由</h2><p>如果使用脚手架安装时会询问是否创建路由文件,选择是时会自动生成 <code>app-routing.module.ts</code></p><p>如果使用脚手架想要跳过询问直接生成路由文件可以使用 <code>ng new 项目名 --routing</code> 来生成一个带有应用路由模块的基本项目</p><p>如果使用脚手架创建项目时没有使用默认配置创建路由器,可以使用如下命令进行创建,其中参数如下:</p><ul class="lvl-0"><li class="lvl-2"><p><code>--flat</code> 把这个文件放进了 <code>src/app</code> 中,而不是单独的目录中</p></li><li class="lvl-2"><p><code>--module=app</code> 告诉 CLI 把它注册到 <code>AppModule</code> 的 <code>imports</code> 数组中</p></li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ng generate module app-routing --flat --module=app</span><br></pre></td></tr></table></figure><p>然后用下面的代码替换生成的文件中的代码:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> { NgModule } <span class="keyword">from</span> <span class="string">'@angular/core'</span>;</span><br><span class="line"><span class="keyword">import</span> { RouterModule, Routes } <span class="keyword">from</span> <span class="string">'@angular/router'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> routes: Routes = [];</span><br><span class="line"></span><br><span class="line"><span class="meta">@NgModule</span>({</span><br><span class="line"> <span class="attr">imports</span>: [RouterModule.forRoot(routes)],</span><br><span class="line"> <span class="attr">exports</span>: [RouterModule]</span><br><span class="line">})</span><br><span class="line"><span class="keyword">export</span> <span class="class"><span class="keyword">class</span> <span class="title">AppRoutingModule</span> </span>{ }</span><br></pre></td></tr></table></figure><h2 id="2-配置路由规则">2.配置路由规则</h2><p>在路由文件中引入需要的组件,并在 <code>routes</code> 字段中配置规则</p><h3 id="1-基础路由配置规则">(1).基础路由配置规则</h3><p>即包含 URL 的路由配置,如下:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">path</span>: <span class="string">"hello"</span>,</span><br><span class="line"> <span class="attr">component</span>: HelloComponent</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="2-默认路由配置规则">(2).默认路由配置规则</h3><p>即根据端口进入页面时默认显示,如下:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">path</span>: <span class="string">""</span>,</span><br><span class="line"> <span class="attr">component</span>: HomeComponent</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>但默认配置状况下,如果地址栏输入错误,会显示项目的根目录网页,并不合适,使用 <strong>通配路由配置规则</strong> 可以解决</p><h3 id="3-通配路由配置规则">(3).通配路由配置规则</h3><p>即 URL 错误时显示该界面(此时可以配置404页面),如下;</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">path</span>: <span class="string">"*"</span>,</span><br><span class="line"> <span class="attr">component</span>: HomeComponent</span><br><span class="line">},</span><br></pre></td></tr></table></figure><h2 id="3-组件渲染输出">3.组件渲染输出</h2><p>在根页面中使用如下语句进行渲染</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">router-outlet</span>></span><span class="tag"></<span class="name">router-outlet</span>></span></span><br></pre></td></tr></table></figure><h2 id="4-导航">4.导航</h2><p>可以在 <code><a></code> 标签中进行导航</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">a</span> [<span class="attr">routerLink</span>]=<span class="string">"['/hello']"</span> <span class="attr">routerLinkActive</span>=<span class="string">"router-link-active"</span> ></span>进入hello页面<span class="tag"></<span class="name">a</span>></span></span><br></pre></td></tr></table></figure><h2 id="5-路由嵌套">5.路由嵌套</h2><p>在需要嵌套的路由规则中通过 <code>children</code> 字段来进行设置:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">path</span>: <span class="string">"home"</span>,</span><br><span class="line"> <span class="attr">component</span>: HomeComponent,</span><br><span class="line"> <span class="attr">children</span>: [</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">path</span>: <span class="string">"list"</span>,</span><br><span class="line"> <span class="attr">component</span>: ListComponent</span><br><span class="line"> }</span><br><span class="line"> ]</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>在需要嵌套的页面中进行渲染</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">a</span> [<span class="attr">routerLink</span>]=<span class="string">"['/home/list']"</span> <span class="attr">routerLinkActive</span>=<span class="string">"router-link-active"</span> ></span>进入list页面<span class="tag"></<span class="name">a</span>></span></span><br><span class="line"><span class="tag"><<span class="name">router-outlet</span>></span><span class="tag"></<span class="name">router-outlet</span>></span></span><br></pre></td></tr></table></figure><h2 id="6-路由传值">6.路由传值</h2><h3 id="1-queryParams">(1).queryParams</h3><p>在 <code><a></code> 标签中添加一个 <code>queryParams</code> 参数</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">a</span> [<span class="attr">routerLink</span>]=<span class="string">"['/home/list']"</span> [<span class="attr">queryParams</span>]=<span class="string">"{id: 1}"</span> <span class="attr">routerLinkActive</span>=<span class="string">"router-link-active"</span> ></span>进入list页面<span class="tag"></<span class="name">a</span>></span></span><br></pre></td></tr></table></figure><p>在子组件中注入 route 服务</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="title">constructor</span>(<span class="params"></span></span></span><br><span class="line"><span class="params"><span class="function"> <span class="keyword">private</span> routerInfo: ActivatedRoute</span></span></span><br><span class="line"><span class="params"><span class="function"></span>)</span> { }</span><br></pre></td></tr></table></figure><p>然后就可以通过 <code>routerInfo.snapshot.queryParams</code> 来获取传递的参数</p><h3 id="2-params">(2).params</h3><p>通过修改路由配置文件中的路径来进行传值</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">path</span>: <span class="string">"hello/:name"</span>,</span><br><span class="line"> <span class="attr">component</span>: HelloComponent</span><br><span class="line">},</span><br></pre></td></tr></table></figure><p>修改超链接中 <code>routerLink</code> 的第二个参数</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">a</span> [<span class="attr">routerLink</span>]=<span class="string">"['/hello', 'params传参']"</span> <span class="attr">routerLinkActive</span>=<span class="string">"router-link-active"</span> ></span>进入hello页面<span class="tag"></<span class="name">a</span>></span></span><br></pre></td></tr></table></figure><p>在子组件中注入 route 服务</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="title">constructor</span>(<span class="params"></span></span></span><br><span class="line"><span class="params"><span class="function"> <span class="keyword">private</span> routerInfo: ActivatedRoute</span></span></span><br><span class="line"><span class="params"><span class="function"></span>)</span> { }</span><br></pre></td></tr></table></figure><p>通过 <code>subscribe</code> 订阅的方式获取 <code>name</code> 参数</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">this</span>.routerInfo.params.subscribe(<span class="function">(<span class="params">params: Params</span>) =></span> {</span><br><span class="line"> <span class="built_in">this</span>.name = params[<span class="string">'name'</span>]</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="built_in">this</span>.name);</span><br><span class="line">})</span><br></pre></td></tr></table></figure><p><strong style="color:red">注意:使用该方式时参数位置必须对应</strong></p><h2 id="7-路由顺序">7.路由顺序</h2><p><strong>Router</strong>在匹配路由时遵循的是<strong>先到先得</strong>的策略,所以路由顺序如下:</p><ul class="lvl-0"><li class="lvl-2"><p>先配置静态路径的路由</p></li><li class="lvl-2"><p>再配置与默认路由匹配的空路径路由</p></li><li class="lvl-2"><p>最后配置通配符路径</p></li></ul><h3 id="1-默认路径路由">(1).默认路径路由</h3><p>当所请求的 URL 与任何路由器路径都不匹配时,就会选择该路由</p><p>作用:展示404页面或跳转到应用的主组件</p><p>**两个星号</p><h3 id="2-重定向路由">(2).重定向路由</h3><p>当时用重定向路由时,浏览器会默认跳转到该路由上</p><p>重定向路由需要设置以下三个参数:</p><ul class="lvl-0"><li class="lvl-2"><p><code>path</code>:重定向源</p></li><li class="lvl-2"><p><code>redirectTo</code>:重定向目标</p></li><li class="lvl-2"><p><code>pathMatch</code>:如何匹配URL(full、prefix)</p></li></ul><p>配置如下:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">path</span>: <span class="string">'home'</span>,</span><br><span class="line"> <span class="attr">component</span>: HomeComponent</span><br><span class="line">},</span><br><span class="line">{</span><br><span class="line"> <span class="attr">path</span>: <span class="string">''</span>,</span><br><span class="line"> <span class="attr">redirectTo</span>: <span class="string">'/home'</span>,</span><br><span class="line"> <span class="attr">pathMatch</span>: <span class="string">'full'</span></span><br><span class="line">},</span><br></pre></td></tr></table></figure><h2 id="8-编写位置">8.编写位置</h2><h3 id="1-app-moudule-ts文件">(1).app.moudule.ts文件</h3><p>在该文件中导入 <code>RouterModule</code>,然后在 <code>imports</code> 字段中填写如下代码,并在代码中书写需要定义的路由规则:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">RouterModule.forRoot([]),</span><br></pre></td></tr></table></figure><h3 id="2-路由模块">(2).路由模块</h3><p>使用如下命令创建一个默认路由配置文件</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">ng generate module app-routing --module app --flat</span><br><span class="line">或</span><br><span class="line">ng g m app-routing --module app --flat</span><br></pre></td></tr></table></figure><p>在 <code>app.module.ts</code> 中引入该配置文件</p><p>进入该文件,引入 <code>RouterModule</code> 以及各个组件</p><p>在 <code>imports</code> 字段中填写如下代码,并在代码中书写需要定义的路由规则:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">RouterModule.forRoot([]),</span><br></pre></td></tr></table></figure><p>在 <code>exports</code> 字段中导出 <code>RouterModule</code></p><h2 id="9-路由守卫">9.路由守卫</h2><p>路由守卫分为如下几种:</p><ul class="lvl-0"><li class="lvl-2"><p><code>CanActivate</code>:处理导航到某路由的情况</p></li><li class="lvl-2"><p><code>CanActivateChild</code>:处理导航到某子路由的情况</p></li><li class="lvl-2"><p><code>CanDeactivate</code>:处理从当前路由离开的情况</p></li><li class="lvl-2"><p><code>Resolve</code>:在路由激活之前获取路由的数据</p></li><li class="lvl-2"><p><code>CanLoad</code>:处理异步导航到某特性模块的情况</p></li></ul><h3 id="方法">方法</h3><p>为守卫创建服务,创建的时候可以选择守卫的类型</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">ng generate gurad 守卫名</span><br><span class="line">或</span><br><span class="line">ng g g 守卫名</span><br></pre></td></tr></table></figure><p>在路由配置文件中按如下配置即可:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">path</span>: <span class="string">'/your-path'</span>,</span><br><span class="line"> <span class="attr">component</span>: YourComponent,</span><br><span class="line"> <span class="attr">canActivate</span>: [YourGuard],</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="10-路由策略">10.路由策略</h2><p> 路由器导航时其中的 URL 都存在于本地,并不会请求服务器,而当前浏览器提供两种策略来展示 URL 的样式:</p><ul class="lvl-0"><li class="lvl-2"><p><code>PathLocationStrategy</code>:默认策略,支持 “HTML 5 pushState” 风格</p></li><li class="lvl-2"><p><code>HashLocationStrategy</code>:支持“hash URL”风格,即 URL 前必须加入井号才可以避免请求服务端</p></li></ul><h3 id="默认策略">默认策略</h3><p>如果使用默认策略,需要在项目的 <code>index.html</code> 中添加 <code><base href></code> 元素才可以正常工作</p><p>如果应用的根目录是 <code>app</code> 目录,那么可以设置如下:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">head</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"utf-8"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">title</span>></span>RoutingApp<span class="tag"></<span class="name">title</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">base</span> <span class="attr">href</span>=<span class="string">"/"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">name</span>=<span class="string">"viewport"</span> <span class="attr">content</span>=<span class="string">"width=device-width, initial-scale=1"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">link</span> <span class="attr">rel</span>=<span class="string">"icon"</span> <span class="attr">type</span>=<span class="string">"image/x-icon"</span> <span class="attr">href</span>=<span class="string">"favicon.ico"</span>></span></span><br><span class="line"><span class="tag"></<span class="name">head</span>></span></span><br></pre></td></tr></table></figure><h1>表单</h1><h2 id="响应式表单">响应式表单</h2><h2 id="模板驱动表单">模板驱动表单</h2><h2 id="表单验证">表单验证</h2><h3 id="自定义验证器">自定义验证器</h3><h1>国际化</h1><h2 id="步骤">步骤</h2><h3 id="1-添加-localize-包">(1).添加 localize 包</h3><p>在项目根目录中使用以下命令添加 localize 包到项目中</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ng add @angular/localize</span><br></pre></td></tr></table></figure><h3 id="2-标记要翻译的文本">(2).标记要翻译的文本</h3><p>Html 文件只需要在需要进行翻译的标签中添加 <code>i18n</code>,如下:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">h2</span> <span class="attr">i18n</span>></span>Top Heroes<span class="tag"></<span class="name">h2</span>></span></span><br></pre></td></tr></table></figure><p>TypeScript 文件只需要在构造函数中指定以下语句即可:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">title = <span class="string">'Tour of Heroes'</span>;</span><br><span class="line"><span class="function"><span class="title">constructor</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="built_in">this</span>.title = $localize <span class="string">`Tour of Heroes`</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="3-提取源语言文件">(3).提取源语言文件</h3><p>使用下面的命令将标记好的文本提取到源语言文件中</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">ng extract-i18n // 在项目的根目录中生成源语言文件</span><br><span class="line">ng extract-i18n --output-path src/locale // 修改生成地址到 src/locale</span><br></pre></td></tr></table></figure><p>参数说明:</p><ul class="lvl-0"><li class="lvl-2"><p><code>--output-path</code>:改变生成文件的位置</p></li><li class="lvl-2"><p><code>--format</code>:改变生成文件的格式(XLIFF1.2、XLIFF2、XML消息包)</p></li><li class="lvl-2"><p><code>--outFile</code>:改变生成文件的文件名</p></li></ul><h3 id="4-生成语言文件副本">(4).生成语言文件副本</h3><p>提取出来的源语言文件是一个叫做 <code>messages.xlf</code>,当有不同语言需求时需要为不同语言生成源语言文件副本</p><p>复制并重命名为 <code>messages.zh.xlf</code>,zh 即为目标语言</p><h3 id="5-翻译语言文件副本">(5).翻译语言文件副本</h3><p>交由专业的翻译人员使用 XLIFF 文件编辑器来创建和编辑翻译</p><p>打开该文件,将 <code><source></source></code> 标签复制并粘贴在其下方,改为 <code><target></target></code> 标签,然后翻译标签中的文本即可</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">source</span>></span>Dashboard<span class="tag"></<span class="name">source</span>></span></span><br><span class="line"><span class="tag"><<span class="name">target</span>></span>仪表盘<span class="tag"></<span class="name">target</span>></span></span><br></pre></td></tr></table></figure><h3 id="6-定义本地环境">(6).定义本地环境</h3><p>修改项目的 <code>Angular.json</code> 中相关配置,修改如下:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">"你的项目名"</span>: {</span><br><span class="line"> <span class="attr">"i18n"</span>: {</span><br><span class="line"> <span class="attr">"sourceLocale"</span>: <span class="string">"en-US"</span>, <span class="comment">// 当前本地环境语言,en表示语言,US表示国家,这里即美国英语区</span></span><br><span class="line"> <span class="attr">"locales"</span>: { <span class="comment">// 本地环境标识符到翻译文件的映射表</span></span><br><span class="line"> <span class="attr">"zh"</span>: <span class="string">"src/locale/messages.zh.xlf"</span></span><br><span class="line"> }</span><br><span class="line"> },</span><br><span class="line"> <span class="attr">"architect"</span>: {</span><br><span class="line"> <span class="attr">"build"</span>: {</span><br><span class="line"> <span class="attr">"options"</span>: {</span><br><span class="line"> <span class="attr">"localize"</span>: <span class="literal">true</span>, <span class="comment">// true表示为每种本地环境生成一个应用版本</span></span><br><span class="line"> <span class="attr">"aot"</span>: <span class="literal">true</span>, <span class="comment">// 本地化组件模块需要进行预先编译</span></span><br><span class="line"> }</span><br><span class="line"> <span class="string">"configurations"</span>: {</span><br><span class="line"> <span class="attr">"zh"</span>: { <span class="comment">// 使用ng serve时配置</span></span><br><span class="line"> <span class="attr">"localize"</span>: [</span><br><span class="line"> <span class="string">"zh"</span></span><br><span class="line"> ]</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="string">"serve"</span>: {</span><br><span class="line"> <span class="attr">"configurations"</span>: {</span><br><span class="line"> <span class="attr">"zh"</span>: { <span class="comment">// 使用ng serve 时配置</span></span><br><span class="line"> <span class="attr">"browserTarget"</span>: <span class="string">"你的项目名:build:zh"</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="7-合并翻译文件">(7).合并翻译文件</h3><p>构建项目时使用以下命令:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ng build --localize</span><br></pre></td></tr></table></figure><p>直接在本地运行项目时需要将上一点中后面两个进行配置后使用以下命令:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ng serve --open --configuration=zh</span><br></pre></td></tr></table></figure><h3 id="引申:生成翻译文件时自动追加新内容">引申:生成翻译文件时自动追加新内容</h3><blockquote><p>直接步骤操作时,当增加新内容时都会重新生成翻译文件,之前翻译过的内容还需重新翻译并不方便,所以可以使用插件来进行追加翻译,参考自 <a target="_blank" rel="external nofollow noopener noreferrer" href="https://www.cnblogs.com/chen8840/p/14338895.html">这里</a></p></blockquote><p>导入 <code>ngx-i18nsupport</code> 包:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install ngx-i18nsupport --save-dev</span><br></pre></td></tr></table></figure><p>在项目的根目录中新增 <code>xliffmerge.json</code> 文件,并写入如下内容:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">"xliffmergeOptions"</span>: {</span><br><span class="line"> <span class="attr">"srcDir"</span>: <span class="string">"src/locale"</span>,</span><br><span class="line"> <span class="attr">"genDir"</span>: <span class="string">"src/locale"</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>在 <code>package.json</code> 文件中添加翻译合并脚本:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">"scripts"</span>: {</span><br><span class="line"> <span class="comment">// 生成翻译文件并存放在指定目录下</span></span><br><span class="line"> <span class="attr">"extract-i18n"</span>: <span class="string">"ng extract-i18n --output-path src/locale"</span>,</span><br><span class="line"> <span class="comment">// 调用配置文件将修改追加到指定语言的翻译文件中</span></span><br><span class="line"> <span class="attr">"xliffmerge"</span>: <span class="string">"xliffmerge --profile xliffmerge.json zh"</span></span><br><span class="line">},</span><br></pre></td></tr></table></figure><p>之后在生成翻译文件时执行下面语句即可生成且追加修改了:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm run extract-i18n;npm run xliffmerge;</span><br></pre></td></tr></table></figure><p>最后合并翻译文件即可</p><h1>动画</h1><h2 id="简单使用">简单使用</h2><p>在根模块中引入 <code>BrowserAnimationsModule</code></p><p>将动画功能导入组件文件中:</p><ul class="lvl-0"><li class="lvl-2"><p>直接导入:即执行下面的动画定义即可</p></li><li class="lvl-2"><p>导入动画文件:</p><ul class="lvl-2"><li class="lvl-4">将整个触发器都定义在动画文件中</li><li class="lvl-4">在需要的组件中引入该动画文件,并引入 <code>HostBinding</code></li><li class="lvl-4">使用 <code>@HostBinding('@detailTransition') state = 'activated';</code> 来绑定动画</li><li class="lvl-4">在注入器中的 <code>animations</code> 数组中传入该动画</li></ul></li><li class="lvl-2"><p>可复用动画:见下方</p></li></ul><h3 id="动画定义">动画定义</h3><p>在组件中的 <code>@Component()</code> 装饰器的 <code>animations:</code> 属性下用代码定义你要用的动画,该属性传入的是一个数组</p><h3 id="动画触发">动画触发</h3><p>使用 <code>trigger()</code> 函数来进行触发,其包含两个参数:</p><ul class="lvl-0"><li class="lvl-2"><p>触发器的名字</p></li><li class="lvl-2"><p>数组,需要触发的动画</p></li></ul><h3 id="动画状态和样式">动画状态和样式</h3><p>在触发器的第二个参数中定义动画状态和样式</p><p>使用 <code>state()</code> 函数来进行定义,其包含两个参数:</p><ul class="lvl-0"><li class="lvl-2"><p>状态的名字</p></li><li class="lvl-2"><p>该状态的样式,使用 <code>style()</code> 函数来进行定义,其参数为一个对象,对象中传入需要设置的样式(小驼峰命名法)</p></li></ul><h3 id="动画转场和时序">动画转场和时序</h3><p>在触发器的第二个参数中定义动画转场和时序</p><p>使用 <code>transition()</code> 函数来进行定义,其包含两个参数:</p><ul class="lvl-0"><li class="lvl-2"><p>表达式,定义两个转场状态之间的方向</p></li><li class="lvl-2"><p>数组,接收一个或一系列的 <code>animate()</code> 函数,其包含3个参数</p><ul class="lvl-2"><li class="lvl-4">持续时间,纯数字表示毫秒,表示秒需要使用字符串 <code>'1s'</code></li><li class="lvl-4">延迟时间,同上</li><li class="lvl-4">速度动画:<code>ease-in/ease-out/ease-in-out</code></li></ul></li></ul><p><strong>执行顺序</strong>:上面的动画转场设置会覆盖下面的动画转场设置</p><h3 id="动画展示">动画展示</h3><p>当动画的相关配置做完以后,就可以附加到页面模板中了</p><p>给定义好的动画触发器名前面加上 @ 符号并放入方括号中,然后使用属性绑定语法来绑定到模板表达式上,如下:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"open-close-container"</span> [@<span class="attr">openClose</span>]=<span class="string">"isOpen ? 'open' : 'close'"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">p</span>></span>盒子现在是 {{isOpen ? '开启' : '关闭'}}!<span class="tag"></<span class="name">p</span>></span></span><br><span class="line"><span class="tag"></<span class="name">div</span>></span></span><br></pre></td></tr></table></figure><h3 id="动画禁用">动画禁用</h3><p>当我们想要禁用某元素及其子元素的动画时,可以给该元素绑定 <code>@.disabled</code>,当其值为 true 时会禁止渲染所有动画</p><h2 id="转场与触发器">转场与触发器</h2><h3 id="通配符">通配符</h3><p>使用 <code>*</code> 通配符表示任意状态,类似于路由,我们可以把以下状态放置到最后,当所有转场都不匹配时,就使用通配符定义的转场</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">transition(<span class="string">'* => *'</span>, [</span><br><span class="line"> animate(<span class="string">'1s'</span>)</span><br><span class="line">]),</span><br></pre></td></tr></table></figure><h3 id="void">void</h3><p><strong>场景</strong>:使用 void 状态可以为进入或离开页面配置转场</p><p><strong>使用</strong>:可以配合通配符进行使用</p><ul class="lvl-0"><li class="lvl-2"><p>当元素离开视图时,就会触发 <code>* => void(别名:leave)</code> 转场,而不管它离开前处于什么状态</p></li><li class="lvl-2"><p>当元素进入视图时,就会触发 <code>void => *(别名:enter)</code> 转场,而不管它进入时处于什么状态</p></li></ul><p><strong>注意</strong>:</p><ul class="lvl-0"><li class="lvl-2"><p>通配符状态 <code>*</code> 会匹配任何状态 —— 包括 <code>void</code></p></li><li class="lvl-2"><p>使用别名时可以与 <code>ngIf/ngFor</code> 一起使用</p></li></ul><h3 id="父子动画">父子动画</h3><p>每次在 Angular 中触发动画时,父动画始终会优先,而子动画会被阻塞</p><p>为了运行子动画,父动画必须查询出包含子动画的每个元素,然后使用 <code>animateChild()</code> 函数来运行它们</p><p>若父动画被禁用时,子动画可以使用如下方式运行:</p><ul class="lvl-0"><li class="lvl-2"><p>父动画可以使用 <code>query()</code> 函数来收集 HTML 模板中位于禁止动画区域内部的元素。这些元素仍然可以播放动画</p></li><li class="lvl-2"><p>子动画可以被父动画查询,并且之后使用 <code>animateChild()</code> 来播放它</p></li></ul><h2 id="复杂序列">复杂序列</h2><p>用于控制复杂序列的函数有:</p><ul class="lvl-0"><li class="lvl-2"><p><code>query()</code>:查找一个或多个内部 HTML 元素,其包含两个参数:</p><ul class="lvl-2"><li class="lvl-4">css 选择器</li><li class="lvl-4">数组,传入需要设置的样式和 <code>stagger()</code> 函数</li></ul></li><li class="lvl-2"><p><code>stagger()</code>:为多元素动画应用级联延迟,其包含两个参数:</p><ul class="lvl-2"><li class="lvl-4">延迟时间</li><li class="lvl-4">数组,传入一个或多个 <code>animate()</code></li></ul></li><li class="lvl-2"><p><code>group()</code>:并行执行多个动画步骤,其包含一个数组参数,传入一个或多个 <code>animate()</code></p></li><li class="lvl-2"><p><code>sequence()</code>:逐个顺序执行多个动画步骤,其包含两个参数:</p><ul class="lvl-2"><li class="lvl-4"><code>style()</code> 函数用来立即应用所指定的样式数据</li><li class="lvl-4"><code>animate()</code> 函数用来在一定的时间间隔内应用样式数据</li></ul></li></ul><h2 id="可复用动画">可复用动画</h2><p>可以将动画单独定义在一个文件中,然后在需要的组件中引入即可</p><p>使用方法如下:</p><ul class="lvl-0"><li class="lvl-2"><p>在 ts 文件中导出一个用 const 定义的变量,其包含两个参数:<code>style()</code> 和 <code>animate()</code></p></li></ul><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> transAnimation = animation([</span><br><span class="line"> style({</span><br><span class="line"> <span class="attr">height</span>: <span class="string">'{{height}}'</span>,</span><br><span class="line"> <span class="attr">opacity</span>: <span class="string">'{{opacity}}'</span>,</span><br><span class="line"> <span class="attr">backgroundColor</span>: <span class="string">'{{backgroundColor}}'</span></span><br><span class="line"> }),</span><br><span class="line"> animate(<span class="string">'{{time}}'</span>)</span><br><span class="line">]);</span><br></pre></td></tr></table></figure><ul class="lvl-0"><li class="lvl-2"><p>在组件设置的 <code>animation()</code> 函数的数组中使用 <code>useAnimation()</code> 函数来调用自定义动画,其包含两个参数:动画文件名和参数配置对象</p></li></ul><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">transition(<span class="string">'open => close'</span>, [</span><br><span class="line"> useAnimation(transAnimation, {</span><br><span class="line"> <span class="attr">params</span>: {</span><br><span class="line"> <span class="attr">height</span>: <span class="number">0</span>,</span><br><span class="line"> <span class="attr">opacity</span>: <span class="number">1</span>,</span><br><span class="line"> <span class="attr">backgroundColor</span>: <span class="string">'red'</span>,</span><br><span class="line"> <span class="attr">time</span>: <span class="string">'1s'</span></span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line">]),</span><br></pre></td></tr></table></figure><h1>服务端渲染</h1><h2 id="基础">基础</h2><p>使用 <strong>Express</strong> 来进行渲染</p><h2 id="优点">优点</h2><p>通过搜索引擎优化(SEO)来帮助网络爬虫提升在手机和低功耗设备上的性能迅速显示出第一个支持首次内容绘制(FCP)的页面</p><h2 id="使用方法">使用方法</h2><p>在项目根目录的命令行窗口使用如下命令创建 <code>app.server.module.ts</code>:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ng add @nguniversal/express-engine</span><br></pre></td></tr></table></figure><p>渲染项目:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm run dev:ssr</span><br></pre></td></tr></table></figure><h1>开发技巧</h1><h2 id="1-求数组中最大值">1.求数组中最大值</h2><p>方法如下:</p><ul class="lvl-0"><li class="lvl-2"><p>排序</p></li><li class="lvl-2"><p>使用 <code>Math.max.apply(null, arr)</code> ,apply方法可以将传入的数组展开为对应的参数,然后再执行max方法即可</p></li></ul><h2 id="2-click-妙用">2.(click)妙用</h2><p>可以直接在其中修改值,如 <code>(click)="isVisible = true;"</code></p><p>也可以传入多个事件,如 <code>(click)="clearModel();changeTab('/model/create' , 'split');"</code></p></div><footer class="post-footer"><div class="my_post_copyright"><script src="//cdn.bootcss.com/clipboard.js/1.5.10/clipboard.min.js"></script><script src="https://cdn.bootcss.com/jquery/2.0.0/jquery.min.js"></script><script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script><p><span>本文标题:</span><a href="/Learn-Angular.html">Angular开发:基础内容</a></p><p><span>文章作者:</span><a href="/" title="访问 Zhang Yangeng 的个人博客">Zhang Yangeng</a></p><p><span>发布时间:</span>2021年08月17日 - 22:08</p><p><span>最后更新:</span>2023年01月31日 - 18:01</p><p><span>许可协议:</span><i class="fab fa-creative-commons"></i> <a rel="external nofollow noopener noreferrer" href="https://creativecommons.org/licenses/by-nc-nd/4.0/" target="_blank" title="Attribution-NonCommercial-NoDerivatives 4.0 International (CC BY-NC-ND 4.0)">署名-非商业性使用-禁止演绎 4.0 国际</a></p><p><span>注意事项:</span>转载请保留原文链接及作者,请尊重作者的劳动成果</p><p><span>原始链接:</span><a href="/Learn-Angular.html" title="Angular开发:基础内容">https://www.wrysmile.cn/Learn-Angular.html</a> <span class="copy-path" title="点击复制文章链接"><i class="fa fa-clipboard" data-clipboard-text="https://www.wrysmile.cn/Learn-Angular.html" aria-label="复制成功!"></i></span></p></div><script>var clipboard=new Clipboard(".fa-clipboard");$(".fa-clipboard").click(function(){clipboard.on("success",function(){swal({title:"",text:"复制成功",icon:"success",showConfirmButton:!0})})})</script><div class="reward-container"><div>坚持原创技术分享,您的支持将是对我最大的鼓励!</div><button onclick='document.querySelector(".post-reward").classList.toggle("active")'>赞赏</button><div class="post-reward"><div><img src="https://s2.ax1x.com/2019/01/28/kKrX7T.png" alt="Zhang Yangeng 微信"> <span>微信</span></div><div><img src="https://i.loli.net/2019/01/25/5c4ac75f2e5b7.jpg" alt="Zhang Yangeng 支付宝"> <span>支付宝</span></div></div></div><div class="post-tags"><a href="/tags/Angular/" rel="tag"><i class="fa fa-tag"></i> Angular</a> <a href="/tags/%E5%89%8D%E7%AB%AF/" rel="tag"><i class="fa fa-tag"></i> 前端</a></div><div class="post-nav"><div class="post-nav-item"><a href="/Git-commit.html" rel="prev" title="如何在一台电脑上分别向 GitHub 与 GitLab 提交不同代码?"><i class="fa fa-chevron-left"></i> 如何在一台电脑上分别向 GitHub 与 GitLab 提交不同代码?</a></div><div class="post-nav-item"><a href="/Learn-ng-zorro.html" rel="next" title="学习笔记:ng-zorro">学习笔记:ng-zorro <i class="fa fa-chevron-right"></i></a></div></div></footer></article></div><div class="comments" id="lv-container" data-id="city" data-uid="MTAyMC80MjQ5Ni8xOTA0Mw=="></div></div></main><footer class="footer"><div class="footer-inner"><div class="copyright">© 2019 – <span itemprop="copyrightYear">2023</span> <span class="with-love"><i class="fa fa-heart"></i> </span><span class="author" itemprop="copyrightHolder">Wrysmile</span></div><div class="wordcount"><span class="post-meta-item"><span class="post-meta-item-icon"><i class="fa fa-chart-line"></i> </span><span>站点总字数:</span> <span title="站点总字数">413k</span> </span><span class="post-meta-item"><span class="post-meta-item-icon"><i class="fa fa-coffee"></i> </span><span>站点阅读时长 ≈</span> <span title="站点阅读时长">6:15</span></span></div><div class="busuanzi-count"><span class="post-meta-item" id="busuanzi_container_site_uv"><span class="post-meta-item-icon"><i class="fa fa-user"></i> </span><span class="site-uv" title="总访客量"><span id="busuanzi_value_site_uv"></span> </span></span><span class="post-meta-item" id="busuanzi_container_site_pv"><span class="post-meta-item-icon"><i class="fa fa-eye"></i> </span><span class="site-pv" title="总访问量"><span id="busuanzi_value_site_pv"></span></span></span></div><script color="0,0,255" opacity="0.5" zindex="-1" count="99" src="https://cdn.jsdelivr.net/npm/canvas-nest.js@1/dist/canvas-nest.js"></script><script type="text/javascript">!function(e,r){function t(){for(var e=0;e<n.length;e++)n[e].alpha<=0?(r.body.removeChild(n[e].el),n.splice(e,1)):(n[e].y--,n[e].scale+=.004,n[e].alpha-=.013,n[e].el.style.cssText="left:"+n[e].x+"px;top:"+n[e].y+"px;opacity:"+n[e].alpha+";transform:scale("+n[e].scale+","+n[e].scale+") rotate(45deg);background:"+n[e].color+";z-index:99999");requestAnimationFrame(t)}var o,n=[];e.requestAnimationFrame=e.requestAnimationFrame||e.webkitRequestAnimationFrame||e.mozRequestAnimationFrame||e.oRequestAnimationFrame||e.msRequestAnimationFrame||function(e){setTimeout(e,1e3/60)},function(t){var a=r.createElement("style");a.type="text/css";try{a.appendChild(r.createTextNode(t))}catch(e){a.styleSheet.cssText=t}r.getElementsByTagName("head")[0].appendChild(a)}(".heart{width: 10px;height: 10px;position: fixed;background: #f00;transform: rotate(45deg);-webkit-transform: rotate(45deg);-moz-transform: rotate(45deg);}.heart:after,.heart:before{content: '';width: inherit;height: inherit;background: inherit;border-radius: 50%;-webkit-border-radius: 50%;-moz-border-radius: 50%;position: fixed;}.heart:after{top: -5px;}.heart:before{left: -5px;}"),o="function"==typeof e.onclick&&e.onclick,e.onclick=function(e){var t,a;o&&o(),t=e,(a=r.createElement("div")).className="heart",n.push({el:a,x:t.clientX-5,y:t.clientY-5,scale:1,alpha:1,color:"rgb("+~~(255*Math.random())+","+~~(255*Math.random())+","+~~(255*Math.random())+")"}),r.body.appendChild(a)},t()}(window,document)</script><script type="text/javascript">var titleTime,OriginTitle=document.title;document.addEventListener("visibilitychange",function(){document.hidden?($('[rel="icon"]').attr("href","/img/TEP.ico"),document.title="╭(°A°`)╮ 页面崩溃啦 ~",clearTimeout(titleTime)):($('[rel="icon"]').attr("href","/favicon.ico"),document.title="(ฅ>ω<*ฅ) 噫又好了~"+OriginTitle,titleTime=setTimeout(function(){document.title=OriginTitle},2e3))})</script></div></footer><script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/anime.min.js" integrity="sha256-XL2inqUJaslATFnHdJOi9GfQ60on8Wx1C2H8DYiN1xY=" crossorigin="anonymous"></script><script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script><script src="https://cdn.jsdelivr.net/npm/@fancyapps/[email protected]/dist/jquery.fancybox.min.js" integrity="sha256-yt2kYMy0w8AbtF89WXb2P1rfjcP/HTHLT7097U8Y5b8=" crossorigin="anonymous"></script><script src="/js/comments.js"></script><script src="/js/utils.js"></script><script src="/js/motion.js"></script><script src="/js/next-boot.js"></script><script src="/js/bookmark.js"></script><script src="/js/third-party/search/local-search.js"></script><script class="next-config" data-name="nprogress" type="application/json">{"enable":true,"spinner":false}</script><script src="/js/third-party/nprogress.js"></script><script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script><script class="next-config" data-name="leancloud_visitors" type="application/json">{"enable":true,"app_id":"mzhbgeWR9BA3SvqtvaAJulC1-gzGzoHsz","app_key":"xcGndtx2gmyop5yrT6euUk9G","server_url":null,"security":false}</script><script src="/js/third-party/statistics/lean-analytics.js"></script><script src="/js/third-party/comments/livere.js"></script></body></html>