Ćwiczenie — zmienianie nawigacji w aplikacji Blazor przy użyciu dyrektywy @page

Ukończone

Blazor posiada narzędzie do zarządzania stanem nawigacji, które umożliwia kodowi w języku C# zarządzanie URI aplikacji. Istnieje również składnik NavLink, który jest zamiennikiem do łatwego wstawienia dla elementu <a>. Jedną z funkcji narzędzia NavLink jest dodanie aktywnej klasy do linków HTML dla menu aplikacji.

Twój zespół rozpoczął tworzenie aplikacji Blazing Pizza i opracował komponenty Blazor do reprezentacji pizzy i zamówień. Teraz aplikacja musi dodać strony finalizacji zakupów oraz inne strony związane z zamówieniem.

W tym ćwiczeniu dodasz nową stronę zamówienia, dodasz nawigację górną do aplikacji, a następnie użyjesz składnika BlazorNavLink aby poprawić swój kod.

Klonowanie istniejącej aplikacji zespołu

Uwaga

W tym module używany jest interfejs wiersza polecenia platformy .NET i program Visual Studio Code na potrzeby programowania lokalnego. Po zakończeniu tego modułu można zastosować koncepcje przy użyciu programu Visual Studio (Windows) lub Visual Studio dla komputerów Mac (macOS). W celu dalszego programowania użyj programu Visual Studio Code dla systemów Windows, Linux i macOS.

W tym module jest używany zestaw .NET 6.0 SDK. Upewnij się, że masz zainstalowany program .NET 6.0, uruchamiając następujące polecenie w preferowanym terminalu:

dotnet --list-sdks

Pojawiają się dane wyjściowe podobne do następujących:

3.1.100 [C:\program files\dotnet\sdk]
5.0.100 [C:\program files\dotnet\sdk]
6.0.100 [C:\program files\dotnet\sdk]

Upewnij się, że na liście znajduje się wersja rozpoczynająca się od 6 . Jeśli żadna nie jest wymieniona lub nie można odnaleźć polecenia, zainstaluj najnowszy zestaw SDK platformy .NET 6.0.

Jeśli wcześniej nie utworzono aplikacji Blazor, postępuj zgodnie z instrukcjami konfiguracji platformy Blazor , aby zainstalować poprawną wersję platformy .NET i sprawdzić, czy maszyna została prawidłowo skonfigurowana. Zatrzymaj się w kroku Tworzenie aplikacji .

  1. Otwórz Visual Studio Code.

  2. Otwórz zintegrowany terminal z programu Visual Studio Code, wybierając pozycję Widok. Następnie w menu głównym wybierz pozycję Terminal.

  3. W terminalu przejdź do miejsca, w którym chcesz utworzyć projekt.

  4. Sklonuj aplikację z usługi GitHub.

    git clone https://github.com/MicrosoftDocs/mslearn-blazor-navigation.git BlazingPizza
    
  5. Wybierz pozycję Plik, a następnie wybierz pozycję Otwórz folder.

  6. W oknie dialogowym Otwieranie przejdź do folderu BlazingPizza, a następnie wybierz pozycję Wybierz folder.

    Program Visual Studio Code może wyświetlić monit o nierozwiązane zależności. Wybierz przycisk Przywróć.

  7. Uruchom aplikację, aby sprawdzić, czy wszystko działa poprawnie.

  8. W programie Visual Studio Code wybierz pozycję F5. Lub w menu Uruchom wybierz pozycję Rozpocznij debugowanie.

    Zrzut ekranu przedstawiający sklonowaną wersję aplikacji Blazing Pizza.

    Skonfiguruj pizze i dodaj je do zamówienia. Wybierz Order > w dolnej części strony. Pojawi się domyślny komunikat „Błąd 404: Nie znaleziono strony”, ponieważ jeszcze nie ma strony kasy.

  9. Aby zatrzymać aplikację, wybierz pozycję Shift + F5.

Dodaj stronę kasy

  1. W programie Visual Studio Code w eksploratorze plików wybierz pozycję App.razor.

    <Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true">
        <Found Context="routeData">
            <RouteView RouteData="@routeData" />
        </Found>
        <NotFound>
            <LayoutView>
                <p>Sorry, there's nothing at this address.</p>
            </LayoutView>
        </NotFound>
    </Router>
    

    Blok <NotFound> kodu jest tym, co klienci widzą, jeśli próbują przejść do strony, która nie istnieje.

  2. W Eksploratorze plików rozwiń węzeł Strony, kliknij prawym przyciskiem myszy folder i wybierz pozycję Nowy plik.

  3. Nadaj nowej nazwie plik Checkout.razor. W tym pliku napisz następujący kod:

    @page "/checkout"
    @inject OrderState OrderState
    @inject HttpClient HttpClient
    @inject NavigationManager NavigationManager
    
    <div class="top-bar">
        <a class="logo" href="">
            <img src="img/logo.svg" />
        </a>
    
        <a href="" class="nav-tab">
            <img src="img/pizza-slice.svg" />
            <div>Get Pizza</div>
        </a>
    
    </div>
    
    <div class="main">
        <div class="checkout-cols">
            <div class="checkout-order-details">
                <h4>Review order</h4>
                @foreach (var pizza in Order.Pizzas)
                {
                    <p>
                        <strong>
                            @(pizza.Size)"
                            @pizza.Special.Name
                            (£@pizza.GetFormattedTotalPrice())
                        </strong>
                    </p>
                }
    
                <p>
                    <strong>
                        Total price:
                        £@Order.GetFormattedTotalPrice()
                    </strong>
                </p>
            </div>
        </div>
    
        <button class="checkout-button btn btn-warning">
            Place order
        </button>
    </div>
    
    @code {
        Order Order => OrderState.Order;
    }
    

    Ta strona jest oparta na bieżącej aplikacji i korzysta ze stanu aplikacji zapisanego w programie OrderState. Pierwszy div to nowa nawigacja nagłówka aplikacji. Dodajmy go do strony indeksu.

  4. W Eksploratorze plików rozwiń folder Pages, a następnie wybierz pozycję index.razor.

  5. Nad klasą <div class="main">top-bar dodaj kod HTML.

    <div class="top-bar">
        <a class="logo" href="">
            <img src="img/logo.svg" />
        </a>
    
        <a href="" class="nav-tab" >
            <img src="img/pizza-slice.svg" />
            <div>Get Pizza</div>
        </a>
    
    </div>
    

    Kiedy jesteśmy na tej stronie, dobrze byłoby wyróżnić link, aby pokazać go klientom. Zespół utworzył już klasę active css, więc dodaj active do atrybutu class , który już zawiera nav-tab styl.

    <div class="top-bar">
        <a class="logo" href="">
            <img src="img/logo.svg" />
        </a>
    
        <a href="" class="nav-tab active" >
            <img src="img/pizza-slice.svg" />
            <div>Get Pizza</div>
        </a>
    
    </div>
    
  6. W programie Visual Studio Code wybierz pozycję F5. Lub w menu Uruchom wybierz pozycję Rozpocznij debugowanie.

    Aplikacja ma teraz ładny pasek menu u góry, który zawiera logo firmy. Dodaj kilka pizz i przejdź do realizacji zamówienia na stronie realizacji zamówienia. Widzisz, że pizze są wymienione, a w menu brakuje aktywnego wskaźnika.

    Zrzut ekranu przedstawiający stronę kasy z kilkoma pizzami.

  7. Aby zatrzymać aplikację, wybierz pozycję Shift + F5.

Zezwalaj klientom na składania zamówienia

Obecnie strona kasy nie zezwala klientom na składanie zamówień. Logika aplikacji musi przechowywać zamówienie do wysłania do kuchni. Po wysłaniu zamówienia przekierowujmy klientów z powrotem na stronę główną.

  1. W Eksploratorze Plików rozwiń Pages i wybierz Checkout.razor.

  2. Zmodyfikuj element przycisku za pomocą wywołania PlaceOrder metody . Dodaj atrybuty @onclick i disabled tak, jak pokazano.

    <button class="checkout-button btn btn-warning" @onclick="PlaceOrder" disabled=@isSubmitting>
      Place order
    </button>
    

    Nie chcemy, aby klienci składali zduplikowane zamówienia, dlatego wyłączamy przycisk Składanie zamówienia do momentu przetworzenia zamówienia.

  3. W bloku @code dodaj ten kod pod kodem Order Order => OrderState.Order;.

    bool isSubmitting;
    
    async Task PlaceOrder()
    {
        isSubmitting = true;
        var response = await HttpClient.PostAsJsonAsync(NavigationManager.BaseUri + "orders", OrderState.Order);
        var newOrderId= await response.Content.ReadFromJsonAsync<int>();
        OrderState.ResetOrder();
        NavigationManager.NavigateTo("/");
    }
    

    Powyższy kod wyłącza przycisk Umieść zamówienie, publikuje JSON i dodaje go do pizza.db, anuluje zamówienie i używa NavigationManager do przekierowania klientów do strony głównej.

    Aby obsłużyć zamówienie, musisz dodać kod. Dodaj klasę OrderController dla tego zadania. Jeśli spojrzysz na PizzaStoreContext.cs, zobaczysz tylko obsługę bazy danych platformy entity framework dla programu PizzaSpecials. Naprawmy to najpierw.

Dodanie obsługi Entity Framework dla zamówień i pizzy

  1. W Eksploratorze plików wybierz pozycję PizzaStoreContext.cs.

  2. Zastąp klasę PizzaStoreContext następującym kodem:

      public class PizzaStoreContext : DbContext
      {
            public PizzaStoreContext(
                DbContextOptions options) : base(options)
            {
            }
    
            public DbSet<Order> Orders { get; set; }
    
            public DbSet<Pizza> Pizzas { get; set; }
    
            public DbSet<PizzaSpecial> Specials { get; set; }
    
            public DbSet<Topping> Toppings { get; set; }
    
            protected override void OnModelCreating(ModelBuilder modelBuilder)
            {
                base.OnModelCreating(modelBuilder);
    
                // Configuring a many-to-many special -> topping relationship that is friendly for serialization
                modelBuilder.Entity<PizzaTopping>().HasKey(pst => new { pst.PizzaId, pst.ToppingId });
                modelBuilder.Entity<PizzaTopping>().HasOne<Pizza>().WithMany(ps => ps.Toppings);
                modelBuilder.Entity<PizzaTopping>().HasOne(pst => pst.Topping).WithMany();
            }
    
      }
    

    Ten kod dodaje wsparcie dla platformy Entity Framework dla klas zamówień i pizzy aplikacji.

  3. W programie Visual Studio Code w menu wybierz pozycję Plik>nowy plik tekstowy.

  4. Wybierz język C#, a następnie wprowadź następujący kod:

    using Microsoft.AspNetCore.Mvc;
    using Microsoft.EntityFrameworkCore;
    
    namespace BlazingPizza;
    
    [Route("orders")]
    [ApiController]
    public class OrdersController : Controller
    {
        private readonly PizzaStoreContext _db;
    
        public OrdersController(PizzaStoreContext db)
        {
            _db = db;
        }
    
        [HttpGet]
        public async Task<ActionResult<List<OrderWithStatus>>> GetOrders()
        {
            var orders = await _db.Orders
            .Include(o => o.Pizzas).ThenInclude(p => p.Special)
            .Include(o => o.Pizzas).ThenInclude(p => p.Toppings).ThenInclude(t => t.Topping)
            .OrderByDescending(o => o.CreatedTime)
            .ToListAsync();
    
            return orders.Select(o => OrderWithStatus.FromOrder(o)).ToList();
        }
    
        [HttpPost]
        public async Task<ActionResult<int>> PlaceOrder(Order order)
        {
            order.CreatedTime = DateTime.Now;
    
            // Enforce existence of Pizza.SpecialId and Topping.ToppingId
            // in the database - prevent the submitter from making up
            // new specials and toppings
            foreach (var pizza in order.Pizzas)
            {
                pizza.SpecialId = pizza.Special.Id;
                pizza.Special = null;
            }
    
            _db.Orders.Attach(order);
            await _db.SaveChangesAsync();
    
            return order.OrderId;
        }
    }
    

    Powyższy kod umożliwia naszej aplikacji pobranie wszystkich bieżących zamówień i umieszczenie zamówienia. Atrybut [Route("orders")] Blazor umożliwia tej klasie obsługę przychodzących żądań HTTP dla /orders i /orders/{orderId}.

  5. Zapisz zmiany za pomocą Ctrl+S.

  6. W przypadku nazwy pliku użyj OrderController.cs. Upewnij się, że plik został zapisany w tym samym katalogu co OrderState.cs.

  7. W Eksploratorze plików wybierz pozycję OrderState.cs.

  8. W dolnej części klasy w metodzie RemoveConfiguredPizza zmodyfikuj ResetOrder() , aby zresetować kolejność:

    public void ResetOrder()
    {
        Order = new Order();
    }
    

Testowanie funkcjonalności procesu zakupu

  1. W programie Visual Studio Code wybierz pozycję F5. Lub w menu Uruchom wybierz pozycję Rozpocznij debugowanie.

    Aplikacja powinna się skompilować, ale jeśli utworzysz zamówienie i spróbujesz dokonać zakupu, pojawi się błąd środowiska uruchomieniowego. Ten błąd występuje, ponieważ nasza baza danych pizza.db SQLLite została utworzona przed utworzeniem obsługi zamówień i pizz. Musimy usunąć plik, aby można było poprawnie utworzyć nową bazę danych.

  2. Aby zatrzymać aplikację, wybierz pozycję Shift + F5.

  3. W Eksploratorze plików usuń plik pizza.db .

  4. Wybierz F5. Lub w menu Uruchom wybierz pozycję Rozpocznij debugowanie.

    W ramach testu dodaj pizze, przejdź do kasy i złożyć zamówienie. Nastąpi przekierowanie do strony głównej i zobaczysz, że zamówienie jest teraz puste.

  5. Aby zatrzymać aplikację, wybierz pozycję Shift + F5.

Aplikacja się poprawia. Mamy konfigurację pizzy i proces zakupu. Chcemy zezwolić klientom na sprawdzenie stanu zamówienia pizzy po jego złożenia.

Dodawanie strony zamówień

  1. W Eksploratorze plików rozwiń węzeł Strony, kliknij prawym przyciskiem myszy folder i wybierz pozycję Nowy plik.

  2. Nadaj nowemu plikowi nazwę MyOrders.razor. W tym pliku napisz następujący kod:

    @page "/myorders"
    @inject HttpClient HttpClient
    @inject NavigationManager NavigationManager
    
    <div class="top-bar">
        <a class="logo" href="">
            <img src="img/logo.svg" />
        </a>
    
        <a href="" class="nav-tab">
            <img src="img/pizza-slice.svg" />
            <div>Get Pizza</div>
        </a>
    
        <a href="myorders" class="nav-tab active">
            <img src="img/bike.svg" />
            <div>My Orders</div>
        </a>
    </div>
    
    <div class="main">
        @if (ordersWithStatus == null)
        {
            <text>Loading...</text>
        }
        else if (!ordersWithStatus.Any())
        {
            <h2>No orders placed</h2>
            <a class="btn btn-success" href="">Order some pizza</a>
        }
        else
        {
            <div class="list-group orders-list">
                @foreach (var item in ordersWithStatus)
                {
                    <div class="list-group-item">
                        <div class="col">
                            <h5>@item.Order.CreatedTime.ToLongDateString()</h5>
                            Items:
                            <strong>@item.Order.Pizzas.Count()</strong>;
                            Total price:
                            <strong>£@item.Order.GetFormattedTotalPrice()</strong>
                        </div>
                        <div class="col">
                            Status: <strong>@item.StatusText</strong>
                        </div>
                        @if (@item.StatusText != "Delivered")
                        {
                            <div class="col flex-grow-0">
                                <a href="myorders/" class="btn btn-success">
                                    Track &gt;
                                </a>
                            </div>
                        }
                    </div>
                }
            </div>
        }
    </div>
    
    @code {
        List<OrderWithStatus> ordersWithStatus = new List<OrderWithStatus>();
    
        protected override async Task OnParametersSetAsync()
        {
          ordersWithStatus = await HttpClient.GetFromJsonAsync<List<OrderWithStatus>>(
              $"{NavigationManager.BaseUri}orders");
        }
    }
    

    Nawigacja musi zostać zmieniona na wszystkich stronach, które obecnie posiadamy, aby zawierała link do nowej strony Moje zamówienia. Otwórz plik Checkout.razor i Index.razor i zastąp nawigację następującym kodem:

    <div class="top-bar">
        <a class="logo" href="">
            <img src="img/logo.svg" />
        </a>
    
        <a href="" class="nav-tab active" >
            <img src="img/pizza-slice.svg" />
            <div>Get Pizza</div>
        </a>
    
        <a href="myorders" class="nav-tab" >
            <img src="img/bike.svg" />
            <div>My orders</div>
        </a>
    
    </div>
    

    Za pomocą <a> elementów możemy ręcznie zarządzać aktywną stroną, dodając klasę active css. Zaktualizujmy całą nawigację, aby użyć zamiast tego składnika NavLink.

  3. Na wszystkich trzech stronach z nawigacją (Index.razor, Checkout.razor i MyOrders.razor) użyj tego samego kodu Blazor do nawigacji:

    <div class="top-bar">
        <a class="logo" href="">
            <img src="img/logo.svg" />
        </a>
    
        <NavLink href="" class="nav-tab" Match="NavLinkMatch.All">
            <img src="img/pizza-slice.svg" />
            <div>Get Pizza</div>
        </NavLink>
    
        <NavLink href="myorders" class="nav-tab">
            <img src="img/bike.svg" />
            <div>My Orders</div>
        </NavLink>
    </div>
    

    Klasa active css jest teraz automatycznie dodawana do stron przez składnik NavLink . Nie musisz pamiętać, aby zrobić to na każdej stronie, na której znajduje się nawigacja.

  4. Ostatnim krokiem jest zmiana NavigationManager na przekierowanie do strony myorders po złożeniu zamówienia. W Eksploratorze plików rozwiń folder Pages, a następnie wybierz Checkout.razor.

  5. Zmień metodę PlaceOrder, aby przekierować do poprawnej strony, przekazując /myorders do NavigationManager.NavigateTo().

    async Task PlaceOrder()
    {
        isSubmitting = true;
        var response = await HttpClient.PostAsJsonAsync($"{NavigationManager.BaseUri}orders", OrderState.Order);
        var newOrderId = await response.Content.ReadFromJsonAsync<int>();
        OrderState.ResetOrder();
        NavigationManager.NavigateTo("/myorders");
    } 
    
  6. W programie Visual Studio Code wybierz pozycję F5. Lub w menu Uruchom wybierz pozycję Rozpocznij debugowanie.

    Zrzut ekranu przedstawiający stronę zamówienia.

    Powinno być możliwe zamawianie pizzy, a następnie wyświetlanie zamówień aktualnie w bazie danych.

  7. Zatrzymaj aplikację, wybierając pozycję Shift + F5.