Modern front-end development has produced many excellent JavaScript frameworks, each with its own characteristics in terms of performance and efficiency, and each front-end team has its own development framework that is comfortable to use. This article introduces a new front-end framework, Mithril. Js, which is a high-performance JavaScript framework whose size and speed make it a good choice for view-model needs. Most of the work in Mithril.js is pure JavaScript. In addition, Mithril. Js is a great tutorial for learning functional programming. This article builds a simple application that displays the list of posts and implements CRUD operations in simple steps:

  • Project initialization
  • Setting Application Components
  • Set routes between pages
  • The implementation of listing
  • Implement create/update forms
  • Add delete button
  • The Bootstrap beautify UI

If you need to see the final result, you can find it on GitHub.

Mithril. Js official website: mithril.js.org/

Project initialization

The front-end project framework is usually introduced by referring to the core Mithril. Js file on the public CDN, by NPM install or by other scaffolding. In this paper, the scaffolding Vite. TypeScript will be used in this application.

First, create the base application and install the dependencies, here naming the project mithril-Study, then use the Vite template Vane-ts.

npm init vite@latest ./ --template
Copy the code

Install dependencies:

npm install mithril -- save
npm install bootstrap --save
npm install @types/mithril -- save-dev
Copy the code

Setting Application Components

Now create an application component that renders the root element of the application (

) and will become a container for all other components in the application. Replace the SRC >main.ts code with:

import "./style.css"; import m from "mithril"; function App(): m.Component { return { view: () => m( "div.app", m("header", "Mithril Study"), m("main", "[main content]"), m( "footer", "Mithril is simple yet powerful, a simple yet powerful front-end framework "),}; } m.mount(document.body, App);Copy the code

So what’s going on here?

  • Install dependenciesMithril.jsIt’s all in the foldernode_modulesIn the applicationimportImport, and give it a short namemTo facilitate subsequent calls.
  • Defines a functionApp, it returns oneMithrilComponents. Defines a returnMithrilComponent functionsAppMithrilA component is any object that has view methods. byAppThe component returned by the function will be called from hereappComponents.
  • The view method willmAs a function call, its first argument looks like a CSS selectordiv.app. This is going to appear to be<div class="app"></div>. rightmMultiple calls are added as arguments to the first call, which is rendered as nested elements.
  • Finally, tellMithrilApply colours to a drawingAppWhatever the function returns and renders todocument.bodyElement.

Now run NPM run dev in terminal to run Vite, then navigate to the application as follows:

Open the file index.html in the root directory and remove the div with the ID app, because the project’s render root is Document.body.

Set routes between pages

Add the following three functions to SRC >main.ts before setting the route:

function GetList(): m.Component { return { view: () => "Get List", }; } function PostForm(): m.Component { return { view: () => "Post Form", }; } function setupRouting(root: Element): void { m.route.prefix = ""; {m.r oute (root, "/", "/" : the GetList, / / access list "/ posts" : PostForm, / / send data/posts / : "id" : PostForm, / / update the data}); }Copy the code

The first two are component functions, so the convention is that component functions are named with a capital letter, just like App functions, and need to render some virtual text.

The setupRouting function does the following:

  • First, it takes an HTML element from the DOM as input.
  • By putting them.route.prefixSet to an empty string that defines how the route should be resolved from the browser URL. If I ignore it,MithrilWill use stroke point hashes just like any other front-end framework#!That would provide something similarhttp://localhost:3000/#! /posts/1The URL. Change the URL format to the following by setting it to an empty stringhttp://localhost:3000/posts/1.
  • callm.route(...)Function to set three parameters, the first being an HTML element that acts as a routing container, in which all the routing content will be displayed. The second parameter is the fallback route to use when the browser navigates to a URL that has no route defined. The third parameter is an object that maps the route (URL path) to the component function.
  • Finally, look at the route/posts/:id. This route maps a portion of the URL to a variableid. You can check the route parameter in the component.

You need to call setupRouting from somewhere to provide it with an HTML element. In the App function, place m(“main”…) The line changes to the following:

m("main", {
    oncreate: (vnode: m.VnodeDOM) => setupRouting(vnode.dom),
})
Copy the code

When the second argument to M is a non-component object, it is used to configure the element created by the first argument. In this case, one of Mithril’s lifecycle hooks is used: onCreate. This hook is called when Mithril creates an element in the DOM and exposes a virtual node (an internal representation of the element) with the DOM element attached. Supply the DOM element to setupRouting.

Now the browser type http://localhost:3000 to see the contents of the main elements to Get the List, then enter http://localhost:3000/posts as you can see the main content into a Post Form.

Implementing real lists

The previous list was just text content; now it’s time to get the list data through Ajax. To implement the GetList component, add the following interface and update the GetList function:

interface IPost { userId: number; id: number; title: string; body: string; } function GetList(): const posts: IPost[] = [{userId: 1, id: 1, title: "Array of JavaScript data structures ", body: In JavaScript, arrays are modified objects. Unlike other languages, each slot in an array can store any type of data. This means you can create an array whose first element is a string, the second element is a number, and the third element is an object. 2, title: "JavaScript data structure Object", body: "Object is one of the most commonly used data types in ECMAScript and is ideal for storing and interacting data between applications. Object defines an unordered collection of properties, which can be thought of as a hash table. return { view: () => m( "section.post-list", m( "ul", posts.map((post) => m( "li", m( m.route.Link, { href: ` / posts / ${post. Id} `,}, post. The title)))), m (m.r oute. Link, {href: "/ posts", the className: "button,"}, "new")),}; }Copy the code

The above code does the following:

  • First defines the data structure of the article, namely the interfaceIPostAnd define the article dataposts
  • inviewMethod to create a list (ul), and set a CSS class for it;
  • Add onenewConnection button of

View the running result, as shown below:

Next, go back to GetList to increment the actual interface call data, and insert the following code before return:

m.request<IPost[]>({ method: "GET", url: "https://jsonplaceholder.typicode.com/posts", }).then((data) => posts.push(... data));Copy the code

Call m.test and insert the response data into the posts variable. With TypeScript, add a type parameter to m.test

to predict what type the response data will be.
[]>

Implement the Create/edit page

The PostForm function will be updated and a function will be added to hold the article data:

function savePost(post: IPost, callback: Function): void { const isCreate = post.id === -1; const url = "https://jsonplaceholder.typicode.com/posts" + (isCreate ? "" : `/${post.id}`); m.request<IPost>({ method: isCreate ? "POST" : "PUT", url, body: post, }).then((data) => callback(data)); } function PostForm(): m.Component { let post: IPost = { userId: -1, id: -1, title: "", body: "", }; const id = m.route.param("id"); if (id) { m.request<IPost>({ method: "GET", url: `https://jsonplaceholder.typicode.com/posts/${id}`, }).then((data) => (post = data)); } return {view: (a) = > m (" form ", m (" div ", m (" label ", "the title:"), m (' input [type = "text"] ', {value: the post title, onchange: (e: Event) => (post.title = (e.target as HTMLInputElement).value),})), m(" div", m("label", "contents: "), m('textarea[rows="5"]', { value: post.body, onchange: (e: Event) => (post.body = ( e.target as HTMLTextAreaElement ).value), }) ), m( "div", m("label", ""), M ('button.button[type=" button.button "]', {onclick: () => savePost(post, () => {console.log(" save operation completed "); }),}, "Save now"))),}; }Copy the code

Then click on the article to see the following effect:

Add delete button

As the last CRUD operation, this is where the delete function is implemented. Go back to the GetList function and add a delete button to each list item and bind the button with a click event to send a delete request to the API.

function deletePost(postId: number): void {
    m.request({
        method: "DELETE",
        url: `https://jsonplaceholder.typicode.com/posts/${postId}`,
    });
}
Copy the code

Bootstrap

Now use Bootstrap to make simple adjustments to the interface. The specific code is not shown here, but can be viewed on GitHub. The final result is as follows:

conclusion

At this point, a simple CRUD application is built. Mithril takes care of rendering, routing, and HTTP requests, while pure JavaScript takes care of the rest. So far, you can see the simplicity of Mithril building applications. Because it is a learning nature, some interactions are incomplete, such as the operation after a successful save or delete is not implemented, including subsequent logical updates. If you are interested, please refer to the official documentation: mithril.js.org/