前端入门,使用Angular CLI完成增删改查页面

目录

一:环境准备

1.1下载nodejs

1.2修改模块路径和缓存路径配置

1.3环境变量配置

二:Angular安装和项目创建

2.1安装typeScript

2.2angular cli安装

2.3使用webstorm创建AngularCLI项目

三.AngularCLI增删改查页面代码

3.1angular文件目录分析

3.2angular常用语法

3.3一个增删改查demo示例

四.问题整理总结

4.1 innerHTML() is not a function

4.2 document.onclick = function(){this.submit(url)}  is not a function

4.3TSLint异常

本文代码地址https://github.com/changgongcheng00/angulardemo.git


 

最近有点前端的小任务,想想也是,总不能老靠jsp或者thymeleaf+html,前端的三驾马车咱也是能开开的。

然而我是在内心不断的骂娘中,完成这个demo的,似乎每次和前端会面都不会有好心情。

好了,闲话少说,我们开始吧。本文适合有一点点的前端基础的想要学点angular的后端从业人员

一:环境准备

nodejs安装和配置

1.1下载nodejs

中文站  http://nodejs.cn/download/

官方站  https://nodejs.org/en/download/(lts长期稳定版本current最新版本,建议下载lts)

在d盘安装nodejs

1.2修改模块路径和缓存路径配置

在nodejs文件夹里新建node_cache、node_global文件夹

打开cmd输入命令

查看npm本地配置:npm config ls

修改npm的安装路径:(默认是c盘,建议放到安装包里方便卸载)

npm config set prefix "D:\nodejs\node_global"

npm config set cache "D:\nodejs\node_cache"

修改npm镜像地址:(默认是国外镜像,不翻墙的话下载速度奇慢,改成国内阿里的镜像)
npm config set registry http://registry.npm.taobao.org

1.3环境变量配置

删除用户变量PATH中node的部分

在系统变量中,新建NODE_PATH系统变量D:\nodejs

在path中添加%NODE_PATH%\;%NODE_PATH%\node_modules;%NODE_PATH%\node_global;

使用node -v;npm -v;检验是否修改配置成功
 

二:Angular安装和项目创建

在探索学习新技术的过程中,难免会陷入囹圄不能自拔,这时就会一边骂娘一边找办法解决,为了尽可能少的出现XX和XX等不文明字眼,了解这门技术的产生背景和好处还是能舒缓下自己的郁闷的。

前端JQuery时代继承了js的自由语法,使用dom操作数据,ajax调用服务,也因此在复杂的业务场景中生产出了难以维护重用的嵌套代码。nodejs、angular、vue、react的产生就是为了解决这个问题。虽然他们的语法库不一样,但共同点都是强化了语法规范(很坑,但有必要),使用组件模块的方式开发动态页面,不过这个库真是多,多到一个字形容:乱。

2.1安装typeScript

npm install -g typescript

2.2angular cli安装

npm install -g @angular/cli
或者npm install -g @angular/cli@latest

安装完成使用该命令,若出现如下界面则说明安装成功
ng version

2.3使用webstorm创建AngularCLI项目

File-new-project-AngularCLI

好事多磨,实际创建项目时出现了上述问题。

意思很明显,创建项目的命令多了个dir(应该指代workspace的位置),但dir未定义,或者压根不存在dir这个命令。程序员可是要改变世界的啊,怎么会被这个小问题难住

点击run旁边的Terminal,输入命令 ng new angular(项目名称),选择Y,CSS 回车等待安装完毕

打开项目,找到package.json 右键show npm scripts,点击下面的start,在浏览器输入http://localhost:4200/项目启动成功,如图所示

三.AngularCLI增删改查页面代码

3.1angular文件目录分析

angular打开后有e2e、node_modules、src以及一堆文件,网上有很多关于这些文件的解释,这里我就简单刷下需要我们关注的几个地方

package.json/package-lock.json:npm的版本控制文件,相当于Mave的pom文件

node_modules:下载的npm安装包,相当于Maven的repository仓库

src:开发包,我们的主要工作都在这里

index.html:前端默认入口

style.css:全局css

assets:静态文件目录,相当于static,放放图片什么的

app:组件目录,angular里一个组件包含了html,css和逻辑(相当于js),是一个独立的功能模块,组件之间通过服务通讯,使用HttpClientModule等工具和后台通讯

app.module.ts:模块

        declarations:声明模块里有什么东西 只能声明:组件/指令/管道

        imports:声明该模块所依赖的模块,即第三方依赖注入

        providers:声明服务

app.component.ts:组件,相当于java的类,属性和方法的集合体,修饰特定的html和css

        export class AppComponent:属性的声明和方法的实现都在这里面(较以前的js,更像java代码了)

app.component.html/app.component.css:html和css,以前怎么写还怎么写,没什么好说的

3.2angular常用语法

以下为一些基本的的语法示例,和后端的语法生态很接近

html部分:

//循环+判断+隔行换色+事件
<ul *ngIf="arr.length>0">
  <li *ngFor="let e of arr;let i = index" [ngClass]="{red:i%2==0,orange:i%2!=0}" [id]="username" (keydown)="keydown($event)" (click)="getData()">{{i}}----{{e.name}},{{e.password}},{{e.age}}</li>
</ul>
//最喜欢的style使用
<div [ngStyle]="{color:'#ccc'}">
  ngStyle演示
</div>
//if+else+switch
<ul>
  <li *ngIf="flag">正确</li>
  <li *ngIf="!flag">错误</li>
</ul>
<ul [ngSwitch]="types">
  <li *ngSwitchCase="1">大王</li>
  <li *ngSwitchCase="2">小吴</li>
  <li *ngSwitchCase="3">东神</li>
</ul>
//日期格式化
<div>{{today|date:'yyyy-MM-dd HH:mm:ss'}}</div>

 

js部分

  //定义属性的几种方式,any代表任意类型
  public msg ="我是测试的信息";
  username:string = "张三";
  public student:any = "我是一个学生的数组";
  public arr = [{name:"a", password:"1234", age:'12'},{name:"b", password:"2134", age:'18'}];
  public today:any = new Date();
    //和后端交互的默认方式,需引入@angular/common/http
    getData(){
    let api = "localhost:8080";
    this.http.get(api).subscribe((e)=>{
      alert(e);
    })
   setData(){
    const httpOptions={ headers:new HttpHeaders({'Content-Type':'application/json'}) };
    var api = "localhost:8080";
    this.http.post(api,"data",httpOptions).subscribe(e=>{
      console.log(e)
    })
  }

3.3一个增删改查demo示例

这是前端完成版的样子,咱不是专业前端,就不强求美观了哈,代码地址会放在最后

核心代码前端部分

前端的代码主要就是table展示,和增删改的dom操作以及请求发送。本人学习了网上的viewchild试用半天发现根本不管用,索性还是用原生js来操作dom了

//构造函数,引入HttpClient
constructor(public http: HttpClient) { }
//初始化属性
  public isShow = 0;
  public httpOptions = { headers: new HttpHeaders({'Content-Type': 'application/json;charset=UTF-8'}) };
  public listUrl = 'http://localhost:8080/angular/getUser';
  public detailUrl = 'http://localhost:8080/angular/getUserDetail?id=';
  public souUrl = 'http://localhost:8080/angular/addUser';
  public removeUrl = 'http://localhost:8080/angular/removeUser?id=';
  public arr:any = new Array(); 

// 查询list,table中循环e
  getData() {
    this.http.get(this.listUrl).subscribe((e) => {
      this.arr = e;
    });
  }
//查询详情,使用<HTMLInputElement>以及const es重定义e,是因为TypeScriptLinting的语法编译不通过
  getDetail(id) {
    this.http.get(this.detailUrl + id).subscribe((e) => {
      const es: any = e;
      (<HTMLInputElement> document.getElementById('id')).value = es.id;
      (<HTMLInputElement> document.getElementById('username')).value = es.username;
      (<HTMLInputElement> document.getElementById('password')).value = es.password;
      (<HTMLInputElement> document.getElementById('tel')).value = es.tel;
      (<HTMLInputElement> document.getElementById('age')).value = es.age;
    });
  }  
// 打开新增/编辑窗口,此处新增和编辑共用一个页面,标题和保存时请求后端的url在此初始化
  addData() {
    this.isShow = 1;
    document.getElementById('formdata').innerText = '用户新增页面';
    this.souUrl = 'http://localhost:8080/angular/addUser';
  }
  editData(id) {
    this.isShow = 1;
    document.getElementById('formdata').innerText = '用户编辑页面';
    this.souUrl = 'http://localhost:8080/angular/updateUser';
    this.getDetail(id);
  }
  // 删除
  remove(id) {
    this.http.delete(this.removeUrl + id).subscribe((e) => {
      const data: any = e;
      if (data.code === 0) {
        this.ngOnInit();
      } else {
        alert(data.msg);
      }
    });
  }
  // 调用保存数据的远程方法
  setData( data) {
    this.http.post(this.souUrl, data , this.httpOptions).subscribe(e => {
      const datas: any = e;
      if (datas.code === 0) {
        this.ngOnInit();
      } else {
        alert(datas.msg);
      }
    });
  }
// 保存
  public submit() {
    const id = (<HTMLInputElement> document.getElementById('id')).value;
    const username = (<HTMLInputElement> document.getElementById('username')).value;
    const password = (<HTMLInputElement> document.getElementById('password')).value;
    const tel = (<HTMLInputElement> document.getElementById('tel')).value;
    const age = (<HTMLInputElement> document.getElementById('age')).value;
    if (username === '' || password === '' ) {
      alert('用户名密码不能为空');
      return;
    }
    const user = {
      'id': id, 'username' : username,'password': password,'tel': tel,'age': age
    };
    this.setData(user);
    this.isShow = 0;
  }
 // 页面组件初始化方法 相当于(function(){})
  ngOnInit() {
    this.getData();
  }

核心代码后端部分

普通的调用数据库增删改查接口我就不在这里写了,springboot2.x整合angular2++一个门槛的问题就是跨域,如果使用angular的HttpClient直接调用后端会报Access-Control-Allow-Origin错。

springboot的WebMvcConfigurer 接口的addCorsMappings方法专门处理跨域问题,代码写了那么多,其实就主要就是OPTIONS和.allowedHeaders("*")

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    WebInterceptor webInterceptor;

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
            .allowedOrigins("*","https://localhost/")
            .allowCredentials(true)
            .allowedMethods("GET","POST","PUT","DELETE","HEAD","OPTIONS")
            //解决angular跨域问题 Access-Control-Allow-Origin
            .allowedHeaders("*")
            .exposedHeaders("access-control-allow-headers","access-control-allow-methods",
                "access-control-allow-origin","access-control-max-age","X-Frame-Options")
            .allowCredentials(false).maxAge(3600);
    }

}

四.问题整理总结

写完后代码看着挺简单,但在实际开发过程中,真可谓步步维艰,也算是难得的学习机会,有些还记得的错误在此总结下,也算给自己个tip:在遇到困难时,不要首先认为自己是对的,把过错和责任归咎给未知

4.1 innerHTML() is not a function

在共用新增修改页面时,获取标题的值报出了上述错误,调用代码大概为:

document.getElementById('xx').innerHTML('xxx');

因为此处html默认是隐藏的,起初怀疑使用的ngStyle标签,会导致此处的页面初始化完成时不会加载而在条件触发时动态加载,使用alert(JSON.stringify(e));果然为{},然后花了大量的时间和精力去解决dom为空的问题,白折腾了。

后来使用debugger断点调试,发现dom树获取到了。dom下面只有innerHTML属性而没有函数,好吧人异常原因都告诉我了,我兜兜转转还绕了个大圈

正确写法是innerHTML = "xxx";

4.2 document.onclick = function(){this.submit(url)}  is not a function

这个问题和4.1其实是同时发生的,也因此更容易迷惑人。

此处最初的设想是对表单的button设定onclick监控事件,在onclick的function里执行submit方法,动态传入新增/修改的url,结果怎么改都提示submit方法不是函数,这特么是我自己写的方法,而且其他地方调用也没异常,就这儿不行,截止目前仍然没找到原因,郁闷的一场。

替代解决方案是在button上定义onclick事件,把请求url设为全局变量,在打开新增修改页面时,修改url的值

4.3TSLint异常

这个异常最郁闷,项目开发完了运行正常,在单独打包测试时发现编译不通过,localhost:4300无法访问,大约3分钟后又提示编译成功可以访问。

浏览器提示异常信息如下:

Refused to load the image 'http://localhost:4200/favicon.ico' because it violates the following Content Security Policy directive: "default-src 'none'". Note that 'img-src' was not explicitly set, so 'default-src' is used as a fallback.

用这个提示信息去百度Google了半天毫无进展,查看控制台报大量的异常错误,但除了开始的3分钟,浏览器都能正常运行和访问后台,仔细检查核心错误代码如下

Property 'value' does not exist on type 'HTMLElement'

以及Object(就是e)里没有id等属性的错,虽然编译报错,但值正常获取到,难道这么几行代码的程序也要启动3分钟么。

最终在https://stackoverflow.com/questions/53634133/property-value-does-not-exist-on-type-htmlelement?answertab=oldest#tab-top中大致确定了是TSlinting的问题

参考https://stackoverflow.com/questions/12989741/the-property-value-does-not-exist-on-value-of-type-htmlelementhttps://www.cnblogs.com/limbobark/p/10043769.html

修正了代码
 

 

本文代码地址https://github.com/changgongcheng00/angulardemo.git

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是使用AngularJS实现增删的示例代码: HTML模板: ```html <div ng-app="myApp" ng-controller="myCtrl"> <h2>用户列表</h2> <table> <thead> <tr> <th>姓名</th> <th>年龄</th> <th>操作</th> </tr> </thead> <tbody> <tr ng-repeat="user in users"> <td>{{user.name}}</td> <td>{{user.age}}</td> <td> <button ng-click="editUser(user)">编辑</button> <button ng-click="deleteUser(user)">删除</button> </td> </tr> </tbody> </table> <h2>添加/编辑用户</h2> <form ng-submit="saveUser()"> <label>姓名:</label> <input type="text" ng-model="currentUser.name" required /> <br /> <label>年龄:</label> <input type="number" ng-model="currentUser.age" required /> <br /> <button type="submit">保存</button> </form> </div> ``` AngularJS控制器: ```javascript var app = angular.module('myApp', []); app.controller('myCtrl', function($scope) { $scope.users = [ { name: '张三', age: 20 }, { name: '李四', age: 25 }, { name: '王五', age: 30 } ]; $scope.currentUser = {}; $scope.editUser = function(user) { $scope.currentUser = angular.copy(user); }; $scope.saveUser = function() { if ($scope.currentUser.name && $scope.currentUser.age) { if ($scope.currentUser.hasOwnProperty('$index')) { $scope.users[$scope.currentUser.$index] = angular.copy($scope.currentUser); } else { $scope.users.push(angular.copy($scope.currentUser)); } $scope.currentUser = {}; } }; $scope.deleteUser = function(user) { var index = $scope.users.indexOf(user); if (index > -1) { $scope.users.splice(index, 1); } }; }); ``` 上述代码实现了一个简单的用户列表,包含姓名和年龄字段。用户可以添加、编辑和删除用户信息。使用ng-repeat指令在表格中显示用户列表,通过ng-click指令调用相应的方法进行编辑和删除操作,ng-model指令绑定用户输入的数据。保存时,根据当前用户是否包含索引属性来判断是新增还是编辑操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值