最新公告
  • 欢迎您光临码农资源网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!加入我们
  • 使用 Angular 和 Tailwind CSS 构建 URL 缩短应用程序

    使用 angular 和 tailwind css 构建 url 缩短应用程序

    在本博客中,我们将引导您完成使用 angular 作为前端并使用 tailwind css 进行样式创建 url 缩短器应用程序的过程。 url 缩短器是一个方便的工具,可以将长 url 转换为更短、更易于管理的链接。该项目将帮助您了解如何使用现代 web 开发技术构建功能齐全且美观的 web 应用程序。

    先决条件

    要学习本教程,您应该对 angular 有基本的了解,并对 tailwind css 有一定的了解。确保您的计算机上安装了 node.js 和 angular cli。

    项目设置

    1. 创建一个新的 angular 项目

    首先,通过在终端中运行以下命令来创建一个新的 angular 项目:

    ng new url-shortener-app
    cd url-shortener-app
    

    2. 安装 tailwind css

    接下来,在您的 angular 项目中设置 tailwind css。通过 npm 安装 tailwind css 及其依赖项:

    npm install -d tailwindcss postcss autoprefixer
    npx tailwindcss init
    

    通过更新 tailwind.config.js 文件来配置 tailwind css:

    module.exports = {
      content: [
        "./src/**/*.{html,ts}",
      ],
      theme: {
        extend: {},
      },
      plugins: [],
    }
    

    将 tailwind 指令添加到您的 src/styles.scss 文件中:

    @tailwind base;
    @tailwind components;
    @tailwind utilities;
    

    构建 url 缩短器

    3. 创建 url 模型

    创建 url 模型来定义 url 数据的结构。添加新文件 src/app/models/url.model.ts:

    export type urls = url[];
    
    export interface url {
      _id: string;
      originalurl: string;
      shorturl: string;
      clicks: number;
      expirationdate: string;
      createdat: string;
      __v: number;
    }
    

    4. 设置 url 服务

    创建一个服务来处理与 url 缩短相关的 api 调用。添加新文件 src/app/services/url.service.ts:

    import { httpclient } from '@angular/common/http';
    import { injectable } from '@angular/core';
    import { observable } from 'rxjs';
    import { url, urls } from '../models/url.model';
    import { environment } from '../../environments/environment';
    
    @injectable({
      providedin: 'root',
    })
    export class urlservice {
      private apiurl = environment.apiurl;
    
      constructor(private http: httpclient) {}
    
      shortenurl(originalurl: string): observable<url> {
        return this.http.post<url>(`${this.apiurl}/shorten`, { originalurl });
      }
    
      getallurls(): observable<urls> {
        return this.http.get<urls>(`${this.apiurl}/urls`);
      }
    
      getdetails(id: string): observable<url> {
        return this.http.get<url>(`${this.apiurl}/details/${id}`);
      }
    
      deleteurl(id: string): observable<url> {
        return this.http.delete<url>(`${this.apiurl}/delete/${id}`);
      }
    }
    </url></url></url></url></urls></urls></url></url>

    5. 创建缩短 url 组件

    生成一个用于缩短 url 的新组件:

    ng generate component shorten
    

    更新组件的 html (src/app/shorten/shorten.component.html) 如下所示:

    <div class="max-w-md mx-auto p-4 shadow-lg rounded-lg mt-4">
        <h2 class="text-2xl font-bold mb-2">url shortener</h2>
        <form>
            <div class="flex items-center mb-2">
                <input class="flex-1 p-2 border border-gray-300 rounded mr-4" formcontrolname="originalurl" placeholder="enter your url" required><button class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600" type="submit">
                    shorten
                </button>
            </div>
            @if (urlform.get('originalurl')?.invalid && (urlform.get('originalurl')?.dirty ||
            urlform.get('originalurl')?.touched)) {
            <div class="text-red-500" role="alert" aria-live="assertive">
                @if (urlform.get('originalurl')?.errors?.['required']) {
                url is required.
                }
                @if (urlform.get('originalurl')?.errors?.['pattern']) {
                invalid url format. please enter a valid url starting with http:// or https://.
                }
            </div>
            }
        </form>
        @if (errormsg) {
        <div class="p-4 bg-red-100 rounded mt-4">
            <p class="text-red-500">{{ errormsg }}</p>
        </div>
        }
        @if (shorturl) {
        <div class="p-4 bg-green-100 rounded">
            <p>shortened url: <a class="text-blue-500 hover:text-blue-600" shorturl target="_blank">{{ shorturl }}</a>
                <button class="ml-2 px-2 py-1 bg-gray-200 text-gray-800 border border-slate-950 rounded hover:bg-gray-300" shorturl>copy</button>
                @if (copymessage) {
                <span class="text-green ml-2">{{ copymessage }}</span>
                }
            </p>
        </div>
        }
    </div>
    
    <div class="max-w-md mx-auto mt-4 p-2">
        <h2 class="text-2xl font-bold mb-4">all urls</h2>
        @if (isloading) {
        <div class="max-w-md mx-auto p-4 shadow-lg rounded-lg">
            <div class="text-center p-4">
                loading...
            </div>
        </div>
        }
        @else if (error) {
        <div class="max-w-md mx-auto p-4 shadow-lg rounded-lg">
            <div class="text-center p-4">
                <p class="text-red-500">{{ error }}</p>
            </div>
        </div>
        }
        @else {
        @if (urls.length > 0 && !isloading && !error) {
        <ul>
            @for (url of urls; track $index) {
            <li class="p-2 border border-gray-300 rounded mb-2">
                <div class="flex justify-between items-center">
                    <div>
                        url:
                        <a class="text-blue-500 hover:text-blue-600" url.shorturl target="_blank">{{
                            url.shorturl }}</a>
                    </div>
                    <div class="flex justify-between items-center">
                        <button class="px-2 py-1 bg-blue-200 text-blue-800 rounded hover:bg-blue-300">details</button>
                        <button class="ml-2 px-2 py-1 bg-gray-200 text-gray-800 rounded hover:bg-gray-300" url.shorturl>{{
                            copyindex === $index ? 'copied' : 'copy'
                            }}</button>
                        <button class="ml-2 px-2 py-1 bg-red-200 text-red-800 rounded hover:bg-red-300">delete</button>
                    </div>
                </div>
            </li>
            }
        </ul>
        }
        @else {
        <div class="max-w-md mx-auto p-4 shadow-lg rounded-lg">
            <div class="text-center p-4">
                no urls found.
            </div>
        </div>
        }
        }
    </div>
    
    @if (showdeletemodal) {
    <div class="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50">
        <div class="bg-white p-4 rounded shadow-lg">
            <h3 class="text-xl font-bold mb-2">confirm deletion</h3>
            <p class="mb-4">are you sure you want to delete this url?</p>
            <button class="px-4 py-2 bg-red-500 text-white rounded hover:bg-red-600">yes,
                delete</button>
            <button class="px-4 py-2 bg-gray-300 text-gray-800 rounded hover:bg-gray-400 ml-2" false>cancel</button>
        </div>
    </div>
    }
    
    @if (showdetailsmodal) {
    <div class="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50">
        <div class="bg-white p-4 rounded shadow-lg">
            <h3 class="text-xl font-bold mb-2">url details</h3>
            @if (isloading) {
            <p class="mb-4">loading...</p>
            }
            @else {
            <p class="mb-4">short url: <a class="text-blue-500 hover:text-blue-600" selectedurl.shorturl target="_blank">{{ selectedurl.shorturl }}</a></p>
            <p class="mb-4">original url: <a class="text-blue-500 hover:text-blue-600" target="_blank">{{ selectedurl.originalurl }}</a></p>
            <p class="mb-4">clicks: <span class="text-green-500">{{ selectedurl.clicks }}</span></p>
            <p class="mb-4">created at: {{ selectedurl.createdat | date: 'medium' }}</p>
            <p class="mb-4">expires at: {{ selectedurl.expirationdate | date: 'medium' }}</p>
            <button class="px-4 py-2 bg-gray-300 text-gray-800 rounded hover:bg-gray-400" false>close</button>
            }
        </div>
    </div>
    }
    

    6. 向组件添加逻辑

    更新组件的 typescript 文件(src/app/shorten/shorten.component.ts)以处理表单提交和 api 交互:

    import { component, inject, oninit } from '@angular/core';
    import { urlservice } from '../services/url.service';
    import {
      formcontrol,
      formgroup,
      reactiveformsmodule,
      validators,
    } from '@angular/forms';
    import { url } from '../models/url.model';
    import { environment } from '../../environments/environment';
    import { datepipe } from '@angular/common';
    import { subject, takeuntil } from 'rxjs';
    
    @component({
      selector: 'app-shorten',
      standalone: true,
      imports: [datepipe, reactiveformsmodule],
      templateurl: './shorten.component.html',
      styleurl: './shorten.component.scss',
    })
    export class shortencomponent implements oninit {
      shorturl: string = '';
      redirecturl = environment.apiurl + '/';
      copymessage: string = '';
      copylistmessage: string = '';
      urls: url[] = [];
      showdeletemodal = false;
      showdetailsmodal = false;
      urltodelete = '';
      copyindex: number = -1;
      selectedurl: url = {} as url;
      isloading = false;
      isloading = false;
      error: string = '';
      errormsg: string = '';
      urlform: formgroup = new formgroup({});
      private unsubscribe$: subject<void> = new subject<void>();
    
      urlservice = inject(urlservice);
    
      ngoninit() {
        this.urlform = new formgroup({
          originalurl: new formcontrol('', [
            validators.required,
            validators.pattern('^(http|https)://.*$'),
          ]),
        });
        this.getallurls();
      }
    
      shortenurl() {
        if (this.urlform.valid) {
          this.urlservice.shortenurl(this.urlform.value.originalurl).pipe(takeuntil(this.unsubscribe$)).subscribe({
            next: (response) => {
              // console.log('shortened url: ', response);
              this.shorturl = response.shorturl;
              this.getallurls();
            },
            error: (error) => {
              console.error('error shortening url: ', error);
              this.errormsg = error?.error?.message || 'an error occurred!';
            },
          });
        }
      }
    
      getallurls() {
        this.isloading = true;
        this.urlservice.getallurls().pipe(takeuntil(this.unsubscribe$)).subscribe({
          next: (response) => {
            // console.log('all urls: ', response);
            this.urls = response;
            this.isloading = false;
          },
          error: (error) => {
            console.error('error getting all urls: ', error);
            this.isloading = false;
            this.error = error?.error?.message || 'an error occurred!';
          },
        });
      }
    
      showdetails(id: string) {
        this.showdetailsmodal = true;
        this.getdetails(id);
      }
    
      getdetails(id: string) {
        this.isloading = true;
        this.urlservice.getdetails(id).subscribe({
          next: (response) => {
            // console.log('url details: ', response);
            this.selectedurl = response;
            this.isloading = false;
          },
          error: (error) => {
            console.error('error getting url details: ', error);
            this.error = error?.error?.message || 'an error occurred!';
          },
        });
      }
    
      copyurl(url: string) {
        navigator.clipboard
          .writetext(url)
          .then(() => {
            // optional: display a message or perform an action after successful copy
            console.log('url copied to clipboard!');
            this.copymessage = 'copied!';
            settimeout(() => {
              this.copymessage = '';
            }, 2000);
          })
          .catch((err) => {
            console.error('failed to copy url: ', err);
            this.copymessage = 'failed to copy url';
          });
      }
    
      copylisturl(url: string, index: number) {
        navigator.clipboard
          .writetext(url)
          .then(() => {
            // optional: display a message or perform an action after successful copy
            console.log('url copied to clipboard!');
            this.copylistmessage = 'copied!';
            this.copyindex = index;
            settimeout(() => {
              this.copylistmessage = '';
              this.copyindex = -1;
            }, 2000);
          })
          .catch((err) => {
            console.error('failed to copy url: ', err);
            this.copylistmessage = 'failed to copy url';
          });
      }
    
      preparedelete(url: string) {
        this.urltodelete = url;
        this.showdeletemodal = true;
      }
    
      confirmdelete() {
        // close the modal
        this.showdeletemodal = false;
        // delete the url
        this.deleteurl(this.urltodelete);
      }
    
      deleteurl(id: string) {
        this.urlservice.deleteurl(id).subscribe({
          next: (response) => {
            // console.log('deleted url: ', response);
            this.getallurls();
          },
          error: (error) => {
            console.error('error deleting url: ', error);
            this.error = error?.error?.message || 'an error occurred!';
          },
        });
      }
    
      ngondestroy() {
        this.unsubscribe$.next();
        this.unsubscribe$.complete();
      }
    }
    
    </void></void>

    7.更新应用程序组件的html文件(src/app/app.component.html)

    <router-outlet></router-outlet>

    8.更新应用程序配置文件(src/app/app.config.ts)

    import { applicationconfig, providezonechangedetection } from '@angular/core';
    import { providerouter } from '@angular/router';
    
    import { routes } from './app.routes';
    import { providehttpclient } from '@angular/common/http';
    
    export const appconfig: applicationconfig = {
      providers: [
        providezonechangedetection({ eventcoalescing: true }),
        providerouter(routes),
        providehttpclient(),
      ],
    };
    

    9.更新应用程序路由文件(src/app/app.routes.ts)

    import { Routes } from '@angular/router';
    
    export const routes: Routes = [
      {
        path: '',
        loadComponent: () =>
          import('./shorten/shorten.component').then((m) => m.ShortenComponent),
      },
    ];
    

    结论

    您已经使用 angular 和 tailwind css 成功构建了 url 缩短器应用程序。该项目演示了如何集成现代前端技术来创建功能强大且时尚的 web 应用程序。借助 angular 的强大功能和 tailwind css 实用程序优先的方法,您可以轻松构建响应灵敏且高效的 web 应用程序。

    请随意通过添加用户身份验证等功能来扩展此应用程序。祝您编码愉快!

    立即学习前端免费学习笔记(深入)”;

    探索代码

    访问 github 存储库以详细探索代码。


    想要了解更多内容,请持续关注码农资源网,一起探索发现编程世界的无限可能!
    本站部分资源来源于网络,仅限用于学习和研究目的,请勿用于其他用途。
    如有侵权请发送邮件至1943759704@qq.com删除

    码农资源网 » 使用 Angular 和 Tailwind CSS 构建 URL 缩短应用程序
    • 7会员总数(位)
    • 25846资源总数(个)
    • 0本周发布(个)
    • 0 今日发布(个)
    • 293稳定运行(天)

    提供最优质的资源集合

    立即查看 了解详情