mirror of
https://github.com/yewstack/yew.git
synced 2025-12-08 21:26:25 +00:00
Versioned docs (#1499)
* Setup versioned docs * Create docs version 0.17.3 * Add translated versioned docs
This commit is contained in:
parent
f470df5cec
commit
0220506b74
2
.github/workflows/autopublish.yml
vendored
2
.github/workflows/autopublish.yml
vendored
@ -23,6 +23,6 @@ jobs:
|
||||
- name: Deploy to Firebase
|
||||
uses: w9jds/firebase-action@master
|
||||
with:
|
||||
args: deploy --only hosting --public website/build/docs
|
||||
args: deploy --only hosting
|
||||
env:
|
||||
FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"hosting": {
|
||||
"public": "website/build/docs",
|
||||
"public": "website/build/yew",
|
||||
"ignore": [
|
||||
"firebase.json",
|
||||
"**/.*",
|
||||
|
||||
@ -101,6 +101,97 @@
|
||||
},
|
||||
"SUMMARY": {
|
||||
"title": "SUMMARY"
|
||||
},
|
||||
"version-0.17.3/advanced-topics/version-0.17.3-how-it-works": {
|
||||
"title": "How it works"
|
||||
},
|
||||
"version-0.17.3/advanced-topics/version-0.17.3-optimizations": {
|
||||
"title": "Optimizations & Best Practices",
|
||||
"sidebar_label": "Optimizations"
|
||||
},
|
||||
"version-0.17.3/concepts/version-0.17.3-agents": {
|
||||
"title": "Agents"
|
||||
},
|
||||
"version-0.17.3/concepts/version-0.17.3-components": {
|
||||
"title": "Introduction"
|
||||
},
|
||||
"version-0.17.3/concepts/components/version-0.17.3-callbacks": {
|
||||
"title": "Callbacks"
|
||||
},
|
||||
"version-0.17.3/concepts/components/version-0.17.3-properties": {
|
||||
"title": "Properties"
|
||||
},
|
||||
"version-0.17.3/concepts/components/version-0.17.3-refs": {
|
||||
"title": "Refs"
|
||||
},
|
||||
"version-0.17.3/concepts/version-0.17.3-html": {
|
||||
"title": "html!",
|
||||
"sidebar_label": "Introduction"
|
||||
},
|
||||
"version-0.17.3/concepts/html/version-0.17.3-components": {
|
||||
"title": "Components"
|
||||
},
|
||||
"version-0.17.3/concepts/html/version-0.17.3-elements": {
|
||||
"title": "Elements"
|
||||
},
|
||||
"version-0.17.3/concepts/html/version-0.17.3-lists": {
|
||||
"title": "Lists"
|
||||
},
|
||||
"version-0.17.3/concepts/html/version-0.17.3-literals-and-expressions": {
|
||||
"title": "Literals and Expressions"
|
||||
},
|
||||
"version-0.17.3/concepts/version-0.17.3-router": {
|
||||
"title": "Router"
|
||||
},
|
||||
"version-0.17.3/concepts/version-0.17.3-services": {
|
||||
"title": "Services",
|
||||
"sidebar_label": "Overview"
|
||||
},
|
||||
"version-0.17.3/concepts/services/version-0.17.3-format": {
|
||||
"title": "Format"
|
||||
},
|
||||
"version-0.17.3/getting-started/version-0.17.3-build-a-sample-app": {
|
||||
"title": "Build a sample app"
|
||||
},
|
||||
"version-0.17.3/getting-started/version-0.17.3-choose-web-library": {
|
||||
"title": "Choosing a web library"
|
||||
},
|
||||
"version-0.17.3/getting-started/version-0.17.3-examples": {
|
||||
"title": "Examples"
|
||||
},
|
||||
"version-0.17.3/getting-started/version-0.17.3-project-setup": {
|
||||
"title": "Project Setup",
|
||||
"sidebar_label": "Introduction"
|
||||
},
|
||||
"version-0.17.3/getting-started/project-setup/version-0.17.3-using-cargo-web": {
|
||||
"title": "Using cargo-web"
|
||||
},
|
||||
"version-0.17.3/getting-started/project-setup/version-0.17.3-using-wasm-bindgen": {
|
||||
"title": "Using wasm-bindgen"
|
||||
},
|
||||
"version-0.17.3/getting-started/project-setup/version-0.17.3-using-wasm-pack": {
|
||||
"title": "Using wasm-pack"
|
||||
},
|
||||
"version-0.17.3/getting-started/version-0.17.3-starter-templates": {
|
||||
"title": "Starter templates"
|
||||
},
|
||||
"version-0.17.3/version-0.17.3-intro": {
|
||||
"title": "Introduction"
|
||||
},
|
||||
"version-0.17.3/more/version-0.17.3-css": {
|
||||
"title": "CSS"
|
||||
},
|
||||
"version-0.17.3/more/version-0.17.3-debugging": {
|
||||
"title": "Debugging"
|
||||
},
|
||||
"version-0.17.3/more/version-0.17.3-external-libs": {
|
||||
"title": "External libraries"
|
||||
},
|
||||
"version-0.17.3/more/version-0.17.3-roadmap": {
|
||||
"title": "Roadmap"
|
||||
},
|
||||
"version-0.17.3/more/version-0.17.3-testing": {
|
||||
"title": "Testing apps"
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
{
|
||||
"_comment": "This file is auto-generated by write-translations.js",
|
||||
"localized-strings": {
|
||||
"next": "Next",
|
||||
"previous": "Previous",
|
||||
@ -101,6 +100,97 @@
|
||||
},
|
||||
"SUMMARY": {
|
||||
"title": "SUMMARY"
|
||||
},
|
||||
"version-0.17.3-advanced-topics/how-it-works": {
|
||||
"title": "How it works"
|
||||
},
|
||||
"version-0.17.3-advanced-topics/optimizations": {
|
||||
"title": "Optimizations & Best Practices",
|
||||
"sidebar_label": "Optimizations"
|
||||
},
|
||||
"version-0.17.3-concepts/agents": {
|
||||
"title": "Agents"
|
||||
},
|
||||
"version-0.17.3-concepts/components": {
|
||||
"title": "Introduction"
|
||||
},
|
||||
"version-0.17.3-concepts/components/callbacks": {
|
||||
"title": "Callbacks"
|
||||
},
|
||||
"version-0.17.3-concepts/components/properties": {
|
||||
"title": "Properties"
|
||||
},
|
||||
"version-0.17.3-concepts/components/refs": {
|
||||
"title": "Refs"
|
||||
},
|
||||
"version-0.17.3-concepts/html": {
|
||||
"title": "html!",
|
||||
"sidebar_label": "Introduction"
|
||||
},
|
||||
"version-0.17.3-concepts/html/components": {
|
||||
"title": "Components"
|
||||
},
|
||||
"version-0.17.3-concepts/html/elements": {
|
||||
"title": "Elements"
|
||||
},
|
||||
"version-0.17.3-concepts/html/lists": {
|
||||
"title": "Lists"
|
||||
},
|
||||
"version-0.17.3-concepts/html/literals-and-expressions": {
|
||||
"title": "Literals and Expressions"
|
||||
},
|
||||
"version-0.17.3-concepts/router": {
|
||||
"title": "Router"
|
||||
},
|
||||
"version-0.17.3-concepts/services": {
|
||||
"title": "Services",
|
||||
"sidebar_label": "Overview"
|
||||
},
|
||||
"version-0.17.3-concepts/services/format": {
|
||||
"title": "Format"
|
||||
},
|
||||
"version-0.17.3-getting-started/build-a-sample-app": {
|
||||
"title": "Build a sample app"
|
||||
},
|
||||
"version-0.17.3-getting-started/choose-web-library": {
|
||||
"title": "Choosing a web library"
|
||||
},
|
||||
"version-0.17.3-getting-started/examples": {
|
||||
"title": "Examples"
|
||||
},
|
||||
"version-0.17.3-getting-started/project-setup": {
|
||||
"title": "Project Setup",
|
||||
"sidebar_label": "Introduction"
|
||||
},
|
||||
"version-0.17.3-getting-started/project-setup/using-cargo-web": {
|
||||
"title": "Using cargo-web"
|
||||
},
|
||||
"version-0.17.3-getting-started/project-setup/using-wasm-bindgen": {
|
||||
"title": "Using wasm-bindgen"
|
||||
},
|
||||
"version-0.17.3-getting-started/project-setup/using-wasm-pack": {
|
||||
"title": "Using wasm-pack"
|
||||
},
|
||||
"version-0.17.3-getting-started/starter-templates": {
|
||||
"title": "Starter templates"
|
||||
},
|
||||
"version-0.17.3-intro": {
|
||||
"title": "Introduction"
|
||||
},
|
||||
"version-0.17.3-more/css": {
|
||||
"title": "CSS"
|
||||
},
|
||||
"version-0.17.3-more/debugging": {
|
||||
"title": "Debugging"
|
||||
},
|
||||
"version-0.17.3-more/external-libs": {
|
||||
"title": "External libraries"
|
||||
},
|
||||
"version-0.17.3-more/roadmap": {
|
||||
"title": "Roadmap"
|
||||
},
|
||||
"version-0.17.3-more/testing": {
|
||||
"title": "Testing apps"
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
{
|
||||
"_comment": "This file is auto-generated by write-translations.js",
|
||||
"localized-strings": {
|
||||
"next": "Next",
|
||||
"previous": "Previous",
|
||||
@ -95,6 +94,103 @@
|
||||
},
|
||||
"more/testing": {
|
||||
"title": "测试"
|
||||
},
|
||||
"README": {
|
||||
"title": "README"
|
||||
},
|
||||
"SUMMARY": {
|
||||
"title": "SUMMARY"
|
||||
},
|
||||
"version-0.17.3-advanced-topics/how-it-works": {
|
||||
"title": "How it works"
|
||||
},
|
||||
"version-0.17.3-advanced-topics/optimizations": {
|
||||
"title": "Optimizations & Best Practices",
|
||||
"sidebar_label": "Optimizations"
|
||||
},
|
||||
"version-0.17.3-concepts/agents": {
|
||||
"title": "Agents"
|
||||
},
|
||||
"version-0.17.3-concepts/components": {
|
||||
"title": "Introduction"
|
||||
},
|
||||
"version-0.17.3-concepts/components/callbacks": {
|
||||
"title": "Callbacks"
|
||||
},
|
||||
"version-0.17.3-concepts/components/properties": {
|
||||
"title": "Properties"
|
||||
},
|
||||
"version-0.17.3-concepts/components/refs": {
|
||||
"title": "Refs"
|
||||
},
|
||||
"version-0.17.3-concepts/html": {
|
||||
"title": "html!",
|
||||
"sidebar_label": "Introduction"
|
||||
},
|
||||
"version-0.17.3-concepts/html/components": {
|
||||
"title": "Components"
|
||||
},
|
||||
"version-0.17.3-concepts/html/elements": {
|
||||
"title": "Elements"
|
||||
},
|
||||
"version-0.17.3-concepts/html/lists": {
|
||||
"title": "Lists"
|
||||
},
|
||||
"version-0.17.3-concepts/html/literals-and-expressions": {
|
||||
"title": "Literals and Expressions"
|
||||
},
|
||||
"version-0.17.3-concepts/router": {
|
||||
"title": "Router"
|
||||
},
|
||||
"version-0.17.3-concepts/services": {
|
||||
"title": "Services",
|
||||
"sidebar_label": "Overview"
|
||||
},
|
||||
"version-0.17.3-concepts/services/format": {
|
||||
"title": "Format"
|
||||
},
|
||||
"version-0.17.3-getting-started/build-a-sample-app": {
|
||||
"title": "Build a sample app"
|
||||
},
|
||||
"version-0.17.3-getting-started/choose-web-library": {
|
||||
"title": "Choosing a web library"
|
||||
},
|
||||
"version-0.17.3-getting-started/examples": {
|
||||
"title": "Examples"
|
||||
},
|
||||
"version-0.17.3-getting-started/project-setup": {
|
||||
"title": "Project Setup",
|
||||
"sidebar_label": "Introduction"
|
||||
},
|
||||
"version-0.17.3-getting-started/project-setup/using-cargo-web": {
|
||||
"title": "Using cargo-web"
|
||||
},
|
||||
"version-0.17.3-getting-started/project-setup/using-wasm-bindgen": {
|
||||
"title": "Using wasm-bindgen"
|
||||
},
|
||||
"version-0.17.3-getting-started/project-setup/using-wasm-pack": {
|
||||
"title": "Using wasm-pack"
|
||||
},
|
||||
"version-0.17.3-getting-started/starter-templates": {
|
||||
"title": "Starter templates"
|
||||
},
|
||||
"version-0.17.3-intro": {
|
||||
"title": "Introduction"
|
||||
},
|
||||
"version-0.17.3-more/css": {
|
||||
"title": "CSS"
|
||||
},
|
||||
"version-0.17.3-more/debugging": {
|
||||
"title": "Debugging"
|
||||
},
|
||||
"version-0.17.3-more/external-libs": {
|
||||
"title": "External libraries"
|
||||
},
|
||||
"version-0.17.3-more/roadmap": {
|
||||
"title": "Roadmap"
|
||||
},
|
||||
"version-0.17.3-more/testing": {
|
||||
"title": "Testing apps"
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
{
|
||||
"_comment": "This file is auto-generated by write-translations.js",
|
||||
"localized-strings": {
|
||||
"next": "Next",
|
||||
"previous": "Previous",
|
||||
@ -101,6 +100,97 @@
|
||||
},
|
||||
"SUMMARY": {
|
||||
"title": "SUMMARY"
|
||||
},
|
||||
"version-0.17.3-advanced-topics/how-it-works": {
|
||||
"title": "How it works"
|
||||
},
|
||||
"version-0.17.3-advanced-topics/optimizations": {
|
||||
"title": "Optimizations & Best Practices",
|
||||
"sidebar_label": "Optimizations"
|
||||
},
|
||||
"version-0.17.3-concepts/agents": {
|
||||
"title": "Agents"
|
||||
},
|
||||
"version-0.17.3-concepts/components": {
|
||||
"title": "Introduction"
|
||||
},
|
||||
"version-0.17.3-concepts/components/callbacks": {
|
||||
"title": "Callbacks"
|
||||
},
|
||||
"version-0.17.3-concepts/components/properties": {
|
||||
"title": "Properties"
|
||||
},
|
||||
"version-0.17.3-concepts/components/refs": {
|
||||
"title": "Refs"
|
||||
},
|
||||
"version-0.17.3-concepts/html": {
|
||||
"title": "html!",
|
||||
"sidebar_label": "Introduction"
|
||||
},
|
||||
"version-0.17.3-concepts/html/components": {
|
||||
"title": "Components"
|
||||
},
|
||||
"version-0.17.3-concepts/html/elements": {
|
||||
"title": "Elements"
|
||||
},
|
||||
"version-0.17.3-concepts/html/lists": {
|
||||
"title": "Lists"
|
||||
},
|
||||
"version-0.17.3-concepts/html/literals-and-expressions": {
|
||||
"title": "Literals and Expressions"
|
||||
},
|
||||
"version-0.17.3-concepts/router": {
|
||||
"title": "Router"
|
||||
},
|
||||
"version-0.17.3-concepts/services": {
|
||||
"title": "Services",
|
||||
"sidebar_label": "Overview"
|
||||
},
|
||||
"version-0.17.3-concepts/services/format": {
|
||||
"title": "Format"
|
||||
},
|
||||
"version-0.17.3-getting-started/build-a-sample-app": {
|
||||
"title": "Build a sample app"
|
||||
},
|
||||
"version-0.17.3-getting-started/choose-web-library": {
|
||||
"title": "Choosing a web library"
|
||||
},
|
||||
"version-0.17.3-getting-started/examples": {
|
||||
"title": "Examples"
|
||||
},
|
||||
"version-0.17.3-getting-started/project-setup": {
|
||||
"title": "Project Setup",
|
||||
"sidebar_label": "Introduction"
|
||||
},
|
||||
"version-0.17.3-getting-started/project-setup/using-cargo-web": {
|
||||
"title": "Using cargo-web"
|
||||
},
|
||||
"version-0.17.3-getting-started/project-setup/using-wasm-bindgen": {
|
||||
"title": "Using wasm-bindgen"
|
||||
},
|
||||
"version-0.17.3-getting-started/project-setup/using-wasm-pack": {
|
||||
"title": "Using wasm-pack"
|
||||
},
|
||||
"version-0.17.3-getting-started/starter-templates": {
|
||||
"title": "Starter templates"
|
||||
},
|
||||
"version-0.17.3-intro": {
|
||||
"title": "Introduction"
|
||||
},
|
||||
"version-0.17.3-more/css": {
|
||||
"title": "CSS"
|
||||
},
|
||||
"version-0.17.3-more/debugging": {
|
||||
"title": "Debugging"
|
||||
},
|
||||
"version-0.17.3-more/external-libs": {
|
||||
"title": "External libraries"
|
||||
},
|
||||
"version-0.17.3-more/roadmap": {
|
||||
"title": "Roadmap"
|
||||
},
|
||||
"version-0.17.3-more/testing": {
|
||||
"title": "Testing apps"
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
|
||||
110
website/pages/en/versions.js
Normal file
110
website/pages/en/versions.js
Normal file
@ -0,0 +1,110 @@
|
||||
/**
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
const React = require('react');
|
||||
|
||||
const CompLibrary = require('../../core/CompLibrary');
|
||||
|
||||
const Container = CompLibrary.Container;
|
||||
|
||||
const CWD = process.cwd();
|
||||
|
||||
const versions = require(`${CWD}/versions.json`);
|
||||
|
||||
function Versions(props) {
|
||||
const {config: siteConfig} = props;
|
||||
const latestVersion = versions[0];
|
||||
const repoUrl = `https://github.com/${siteConfig.organizationName}/${siteConfig.projectName}`;
|
||||
return (
|
||||
<div className="docMainWrapper wrapper">
|
||||
<Container className="mainContainer versionsContainer">
|
||||
<div className="post">
|
||||
<header className="postHeader">
|
||||
<h1>{siteConfig.title} Versions</h1>
|
||||
</header>
|
||||
<h3 id="latest">Current version (Stable)</h3>
|
||||
<table className="versions">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>{latestVersion}</th>
|
||||
<td>
|
||||
{/* You are supposed to change this href where appropriate
|
||||
Example: href="<baseUrl>/docs(/:language)/:id" */}
|
||||
<a
|
||||
href={`${siteConfig.baseUrl}${siteConfig.docsUrl}/${
|
||||
props.language ? props.language + '/' : ''
|
||||
}intro`}>
|
||||
Documentation
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="https://github.com/yewstack/yew/releases">Release Notes</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3 id="rc">Pre-release versions</h3>
|
||||
<table className="versions">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>master</th>
|
||||
<td>
|
||||
{/* You are supposed to change this href where appropriate
|
||||
Example: href="<baseUrl>/docs(/:language)/next/:id" */}
|
||||
<a
|
||||
href={`${siteConfig.baseUrl}${siteConfig.docsUrl}/${
|
||||
props.language ? props.language + '/' : ''
|
||||
}next/intro`}>
|
||||
Documentation
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href={repoUrl}>Source Code</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3 id="archive">Past Versions</h3>
|
||||
<p>Here you can find previous versions of the documentation.</p>
|
||||
<table className="versions">
|
||||
<tbody>
|
||||
{versions.map(
|
||||
version =>
|
||||
version !== latestVersion && (
|
||||
<tr key={version}>
|
||||
<th>{version}</th>
|
||||
<td>
|
||||
{/* You are supposed to change this href where appropriate
|
||||
Example: href="<baseUrl>/docs(/:language)/:version/:id" */}
|
||||
<a
|
||||
href={`${siteConfig.baseUrl}${siteConfig.docsUrl}/${
|
||||
props.language ? props.language + '/' : ''
|
||||
}${version}/intro`}>
|
||||
Documentation
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href={`${repoUrl}/releases/tag/v${version}`}>
|
||||
Release Notes
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
),
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
<p>
|
||||
You can find past versions of this project on{' '}
|
||||
<a href={repoUrl}>GitHub</a>.
|
||||
</p>
|
||||
</div>
|
||||
</Container>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = Versions;
|
||||
@ -18,7 +18,7 @@ const siteConfig = {
|
||||
// baseUrl: '/test-site/',
|
||||
|
||||
// Used for publishing and more
|
||||
projectName: 'docs',
|
||||
projectName: 'yew',
|
||||
organizationName: 'yewstack',
|
||||
// For top-level user or org sites, the organization is still the same.
|
||||
// e.g., for the https://JoelMarcey.github.io site, it would be set like...
|
||||
|
||||
44
website/translated_docs/ja/version-0.17.3/SUMMARY.md
Normal file
44
website/translated_docs/ja/version-0.17.3/SUMMARY.md
Normal file
@ -0,0 +1,44 @@
|
||||
# Table of contents
|
||||
|
||||
* [はじめに](intro.md)
|
||||
|
||||
## 始める
|
||||
|
||||
* [プロジェクトの準備](getting-started/project-setup.md)
|
||||
* [wasm-packを使う](getting-started/project-setup/using-wasm-pack.md)
|
||||
* [wasm-bindgenを使う](getting-started/project-setup/using-wasm-bindgen.md)
|
||||
* [cargo-webを使う](getting-started/project-setup/using-cargo-web.md)
|
||||
* [入門用テンプレート](getting-started/starter-templates.md)
|
||||
* [サンプルアプリを作る](getting-started/build-a-sample-app.md)
|
||||
* [web-sysかstdweb選ぶ](getting-started/choose-web-library.md)
|
||||
* [例から学ぶ](getting-started/examples.md)
|
||||
|
||||
## 基本となる概念 <a id="concepts"></a>
|
||||
|
||||
* [html!を使う](concepts/html.md)
|
||||
* [リスト](concepts/html/lists.md)
|
||||
* [要素](concepts/html/elements.md)
|
||||
* [リテラルと式](concepts/html/literals-and-expressions.md)
|
||||
* [コンポーネント](concepts/html/components.md)
|
||||
* [コンポーネント (Components)](concepts/components.md)
|
||||
* [属性 (Properties)](concepts/components/properties.md)
|
||||
* [コールバック (Callbacks)](concepts/components/callbacks.md)
|
||||
* [参照 (Refs)](concepts/components/refs.md)
|
||||
* [Agents](concepts/agents.md)
|
||||
* [Services](concepts/services.md)
|
||||
* [Format](concepts/services/format.md)
|
||||
* [ルータ](concepts/router.md)
|
||||
|
||||
## 高度な内容
|
||||
|
||||
* [最適化とベストプラクティス](advanced-topics/optimizations.md)
|
||||
* [低レベルなライブラリの中身](advanced-topics/how-it-works.md)
|
||||
|
||||
## 更なる内容
|
||||
|
||||
* [CSS](more/css.md)
|
||||
* [ロードマップ](more/roadmap.md)
|
||||
* [テスト](more/testing.md)
|
||||
* [デバッグ](more/debugging.md)
|
||||
* [外部ライブラリ](more/external-libs.md)
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
---
|
||||
title: How it works
|
||||
description: Low level details about the framework
|
||||
---
|
||||
|
||||
# 低レベルなライブラリの中身
|
||||
|
||||
コンポーネントのライフサイクルの状態機械、VDOMの異なるアルゴリズム
|
||||
|
||||
@ -0,0 +1,186 @@
|
||||
---
|
||||
title: Optimizations
|
||||
description: Make your app faster
|
||||
---
|
||||
|
||||
# 最適化とベストプラクティス
|
||||
|
||||
## neq\_assign
|
||||
|
||||
親コンポーネントからpropsを受け取った際、`change`メソッドが呼ばれます。
|
||||
これはコンポーネントの状態を更新することができるのに加え、コンポーネントがpropsが変わった際に再レンダリングするかどうかを決める
|
||||
`ShouldRender`という真偽値を返すことができます。
|
||||
|
||||
再レンダリングはコストがかかるもので、もし避けられるのであれば避けるべきです。
|
||||
一般的なルールとしてpropsが実際に変化した際にのみ再レンダリングすれば良いでしょう。
|
||||
以下のコードブロックはこのルールを表しており、propsが前と変わったときに`true`を返します。
|
||||
|
||||
```rust
|
||||
use yew::ShouldRender;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
struct ExampleProps;
|
||||
|
||||
struct Example {
|
||||
props: ExampleProps,
|
||||
};
|
||||
|
||||
impl Example {
|
||||
fn change(&mut self, props: ExampleProps) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
しかし我々は先に進んでいけます!
|
||||
この6行のボイラープレードは`PartialEq`を実装したものにトレイトとブランケットを用いることで1行のコードへと落とし込むことができます。
|
||||
[こちら](https://docs.rs/yewtil/*/yewtil/trait.NeqAssign.html)にて`yewtil`クレートの`NewAssign`トレイトを見てみてください。
|
||||
|
||||
## 効果的にスマートポインタを使う
|
||||
|
||||
**注意: このセクションで使われている用語がわからなければRust bookは
|
||||
[スマートポインタについての章](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)
|
||||
があり、非常に有用です。**
|
||||
|
||||
再レンダリングの際にpropsを作るデータを大量にコピーしないために、スマートポインタを用いてデータ自体ではなくデータへの参照だけを
|
||||
コピーできます。
|
||||
propsや子コンポーネントで関連するデータに実データではなく参照を渡すと、子コンポーネントでデータを変更する必要がなければ
|
||||
データのコピーを避けることができます。
|
||||
その際、`Rc::make_mut`によって変更したいデータの変更可能な参照を得ることができます。
|
||||
|
||||
これにより、propsが変更されたときにコンポーネントが再レンダリングされるかどうかを決めるかで`Component::change`に更なる恩恵があります。
|
||||
なぜなら、データの値を比較する代わりに元々のポインタのアドレス (つまりデータが保管されている機械のメモリの場所) を比較できるためです。
|
||||
2つのポインターが同じデータを指す場合、それらのデータの値は同じでなければならないのです。
|
||||
ただし、その逆は必ずしも成り立たないことに注意してください!
|
||||
もし2つのポインタが異なるのであれば、そのデータは同じである可能性があります。
|
||||
この場合はデータを比較するべきでしょう。
|
||||
|
||||
この比較においては`PartialEq`ではなく`Rc::ptr_eq`を使う必要があります。
|
||||
`PartialEq`は等価演算子`==`を使う際に自動的に使われます。
|
||||
Rustのドキュメントには[`Rc::ptr_eq`についてより詳しく書いてあります](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.ptr_eq)。
|
||||
|
||||
この最適化は`Copy`を実装していないデータの型に対して極めて有効なものです。
|
||||
もしデータを簡単に変更できるのであれば、スマートポインタに取り換える必要はありません。
|
||||
しかし`Vec`や`HashMap`、`String`などのような重たいデータの構造体に対してはスマートポインタを使うことで
|
||||
パフォーマンスを改善することができるでしょう。
|
||||
|
||||
この最適化は値がまだ一度も子によって更新されていない場合に極めて有効で、親からほとんど更新されない場合においてもかなり有効です。
|
||||
これにより、`Rc<_>s`が純粋なコンポーネントに対してプロパティの値をラップする良い一手となります。
|
||||
|
||||
## View関数
|
||||
|
||||
コードの可読性の理由から`html!`の部分を関数へと移植するのは意味があります。
|
||||
これは、インデントを減らすのでコードを読みやすくするだけでなく、良いデザインパターンを産むことにも繋がるのです。
|
||||
これらの関数は複数箇所で呼ばれて書くべきコード量を減らせるため、分解可能なアプリケーションを作ることができるのです。
|
||||
|
||||
## 純粋なコンポーネント
|
||||
|
||||
純粋なコンポーネントは状態を変化せず、ただ中身を表示してメッセージを普通の変更可能なコンポーネントへ渡すコンポーネントのことです。
|
||||
View関数との違いとして、純粋なコンポーネントは式の構文\(`{some_view_function()}`\)ではなく
|
||||
コンポーネントの構文\(`<SomePureComponent />`\)を使うことで`html!`マクロの中で呼ばれる点、
|
||||
そして実装次第で記憶され (つまり、一度関数が呼ばれれば値は"保存"され、
|
||||
同じ引数でもう一度呼ばれても値を再計算する必要がなく最初に関数が呼ばれたときの保存された値を返すことができる)、
|
||||
先述の`neq_assign`ロジックを使う別々のpropsで再レンダリングを避けられる点があります。
|
||||
|
||||
Yewは純粋な関数やコンポーネントをサポートしていませんが、外部のクレートを用いることで実現できます。
|
||||
|
||||
## 関数型コンポーネント (a.k.a フック)
|
||||
|
||||
関数型コンポーネントはまだ開発中です!
|
||||
開発状況については[プロジェクトボード](https://github.com/yewstack/yew/projects/3)に詳しく書いてあります。
|
||||
|
||||
## キー付きDOMノード
|
||||
|
||||
## ワークスペースでコンパイル時間を減らす
|
||||
|
||||
間違いなくYewを使う上での最大の欠点はコンパイルに時間がかかる点です。
|
||||
プロジェクトのコンパイルにかかる時間は`html!`マクロに渡されるコードの量に関係しています。
|
||||
これは小さなプロジェクトにはそこまで問題ないようですが、大きなアプリではコードを複数クレートに分割することでアプリに変更が加られた際に
|
||||
コンパイラの作業量を減らすのが有効です。
|
||||
|
||||
一つ可能なやり方として、ルーティングとページ洗濯を担当するメインのクレートを作り、それぞれのページに対して別のクレートを作ることです。
|
||||
そうして各ページは異なるコンポーネントか、`Html`を生成する大きな関数となります。
|
||||
アプリの異なる部分を含むクレート同士で共有されるコードはプロジェクト全体で依存する分離したクレートに保存されます。
|
||||
理想的には1回のコンパイルでコード全てを再ビルドせずメインのクレートかどれかのページのクレートを再ビルドするだけにすることです。
|
||||
最悪なのは、"共通"のクレートを編集して、はじめに戻ってくることです:
|
||||
共有のクレートに依存している全てのコード、恐らく全てのコードをコンパイルすることです。
|
||||
|
||||
もしメインのクレートが重たすぎる、もしくは深くネストしたページ (例えば別ページのトップでレンダリングされるページ)
|
||||
で速く繰り返したい場合、クレートの例を用いてメインページの実装をシンプルにしたりトップで動かしているコンポーネントをレンダリングできます。
|
||||
|
||||
## バイナリサイズを小さくする
|
||||
|
||||
* Rustのコードを最適化する
|
||||
* `wee_alloc` \( tiny allocatorを使用 \)
|
||||
* `cargo.toml` \( release profileを定義 \)
|
||||
* `wasm-opt`を用いてwasmのコードを最適化する
|
||||
|
||||
**注意: バイナリサイズを小さくするのについては[Rust Wasm Book](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)に詳しく書いてあります。**
|
||||
|
||||
### wee\_alloc
|
||||
|
||||
[wee\_alloc](https://github.com/rustwasm/wee_alloc)は小さなアロケーターで、Rustのバイナリで使用される通常のものより遥かに小さなものです。
|
||||
デフォルトのアロケーターと置き換えることで、WASMファイルをより小さくすることができ、速度とメモリのオーバーヘッドを軽減できます。
|
||||
|
||||
デフォルトのアロケータを含めないことによるサイズの増加と比較して、速度とメモリのオーバーヘッドが悪くなります。
|
||||
ファイルサイズが小さいことで、ページの読み込みが速くなります。
|
||||
そのため、アロケーションのタスクが非常に多い場合でなければデフォルトのものではなくtiny allocatorを利用することが一般的に推奨されています。
|
||||
|
||||
```rust
|
||||
// `wee_alloc`を使用する。
|
||||
#[global_allocator]
|
||||
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
|
||||
```
|
||||
|
||||
### Cargo.toml
|
||||
|
||||
`Cargo.toml`で`[profile.release]`のセクションに設定を書き込むことでリリースビルドを小さくすることが可能です。
|
||||
|
||||
```text
|
||||
[profile.release]
|
||||
# バイナリに含むコードを少なくする
|
||||
panic = 'abort'
|
||||
# コードベース全体での最適化 ( 良い最適化だがビルドが遅くなる)
|
||||
codegen-units = 1
|
||||
# サイズの最適化( よりアグレッシブに )
|
||||
opt-level = 'z'
|
||||
# サイズの最適化
|
||||
# opt-level = 's'
|
||||
# プログラム全体の分析によるリンク時最適化
|
||||
lto = true
|
||||
```
|
||||
|
||||
### wasm-opt
|
||||
|
||||
更に`wasm`のコードのサイズを最適化することができます。
|
||||
|
||||
The Rust Wasm BookにはWASMバイナリのサイズを小さくすることについてのセクションがあります:
|
||||
[Shrinking .wasm size](https://rustwasm.github.io/book/game-of-life/code-size.html)
|
||||
|
||||
* `wasm-pack`でデフォルトの`wasm`のコードをリリースビルド時に最適化する
|
||||
* `wasm-opt`によって直接`wasm`ファイルを最適化する
|
||||
|
||||
```text
|
||||
wasm-opt wasm_bg.wasm -Os -o wasm_bg_opt.wasm
|
||||
```
|
||||
|
||||
#### yew/examples/にある例を小さなサイズでビルドする
|
||||
|
||||
注意: `wasm-pack`はRustとWasmのコードへの最適化を組み合わせます。`wasm-bindgen`はこの例ではRustのサイズ最適化を用いていません。
|
||||
|
||||
| 使用したツール | サイズ |
|
||||
| :--- | :--- |
|
||||
| wasm-bindgen | 158KB |
|
||||
| wasm-bindgen + wasm-opt -Os | 116KB |
|
||||
| wasm-pack | 99 KB |
|
||||
|
||||
## 参考文献:
|
||||
* [The Rust Bookのスマートポインタに関する章](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)
|
||||
* [the Rust Wasm Bookでのバイナリサイズを小さくすることについて](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)
|
||||
* [Rust profilesについてのドキュメント](https://doc.rust-lang.org/cargo/reference/profiles.html)
|
||||
* [binaryenプロジェクト](https://github.com/WebAssembly/binaryen)
|
||||
56
website/translated_docs/ja/version-0.17.3/concepts/agents.md
Normal file
56
website/translated_docs/ja/version-0.17.3/concepts/agents.md
Normal file
@ -0,0 +1,56 @@
|
||||
---
|
||||
title: Agents
|
||||
description: Yew's Actor System
|
||||
---
|
||||
|
||||
エージェントはAngularの[サービス](https://angular.io/guide/architecture-services)に似ており\(ただし依存性インジェクションはありません\)、
|
||||
[アクターモデル](https://en.wikipedia.org/wiki/Actor_model)を提供します。
|
||||
エージェントはコンポーネント階層のどこに位置するかに関わらず、コンポーネント間でメッセージをルーティングしたり、共有状態を作成したり、UIをレンダリングするメインスレッドから計算量の多いタスクをオフロードするために使用することができます。
|
||||
また、Yew アプリケーションがタブをまたいで通信できるようにするためのエージェントのサポートも\(将来的には\)計画されています。
|
||||
|
||||
エージェントが並行に動くようにYewは[web-workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers)を使用しています。
|
||||
|
||||
## ライフサイクル
|
||||
|
||||

|
||||
|
||||
## エージェントの種類
|
||||
|
||||
### Reaches
|
||||
|
||||
* Context - Contextエージェントのインスタンスは、常に最大1つ存在します。
|
||||
Bridgesは、UIスレッド上で既にスポーンされたエージェントをスポーンするか、接続します。
|
||||
これは、コンポーネントまたは他のエージェント間の状態を調整するために使用することができます。
|
||||
このエージェントにBridgesが接続されていない場合、このエージェントは消滅します。
|
||||
|
||||
* Job - 新しいブリッジごとにUIスレッド上で新しいエージェントをスポーンします。
|
||||
これは、ブラウザと通信する共有されているが独立した動作をコンポーネントの外に移動させるのに適しています。
|
||||
(TODO 確認) タスクが完了すると、エージェントは消えます。
|
||||
|
||||
* Public - Contextと同じですが、独自のweb workerで動作します。
|
||||
|
||||
* Private - Jobと同じですが、独自のweb workerで動作します。
|
||||
|
||||
* Global \(WIP\)
|
||||
|
||||
## エージェントとコンポーネントのやり取り
|
||||
|
||||
### Bridges
|
||||
|
||||
Bridgeは、エージェントとコンポーネント間の双方向通信を可能にします。
|
||||
また、Bridgeはエージェント同士の通信を可能にします。
|
||||
|
||||
### Dispatchers
|
||||
|
||||
Dispatcherは、コンポーネントとエージェント間の一方向通信を可能にします。
|
||||
Dispatcherは、コンポーネントがエージェントにメッセージを送信することを可能にします。
|
||||
|
||||
## オーバーヘッド
|
||||
|
||||
独自の独立したweb worker(プライベートとパブリック)にあるエージェントは、送受信するメッセージにシリアライズするオーバーヘッドが発生します。
|
||||
他のスレッドとの通信には[bincode](https://github.com/servo/bincode)を使用するので、関数を呼び出すよりもコストはかなり高くなります。
|
||||
計算コストがメッセージの受け渡しコストを上回る場合を除き、ロジックを UI スレッドエージェント\(JobまたはContext\)に格納する必要があります。
|
||||
|
||||
## 参考資料
|
||||
|
||||
* [pub\_sub](https://github.com/yewstack/yew/tree/master/examples/pub_sub)の例でコンポーネントがどのようにエージェントと通信させているかがわかります。
|
||||
197
website/translated_docs/ja/version-0.17.3/concepts/components.md
Normal file
197
website/translated_docs/ja/version-0.17.3/concepts/components.md
Normal file
@ -0,0 +1,197 @@
|
||||
---
|
||||
title: Introduction
|
||||
description: Components and their lifecycle hooks
|
||||
---
|
||||
## コンポーネントとは?
|
||||
|
||||
コンポーネントはYewを構成するブロックです。
|
||||
コンポーネントは状態を管理し、自身をDOMへレンダリングすることができます。
|
||||
コンポーネントはライフサイクルの機能がある`Component`トレイトを実装することによって作られます。
|
||||
|
||||
## ライフサイクル
|
||||
|
||||
:::important contribute
|
||||
`Contribute to our docs:` [Add a diagram of the component lifecycle](https://github.com/yewstack/docs/issues/22)
|
||||
:::
|
||||
|
||||
## ライフサイクルのメソッド
|
||||
|
||||
### Create
|
||||
|
||||
コンポーネントが作られると、`ComponentLink`と同様に親コンポーネントからプロパティを受け取ります。
|
||||
プロパティはコンポーネントの状態を初期化するのに使われ、"link"はコールバックを登録したりコンポーネントにメッセージを送るのに使われます。
|
||||
|
||||
propsとlinkをコンポーネント構造体に格納するのが一般的です。
|
||||
例えば:
|
||||
|
||||
```rust
|
||||
pub struct MyComponent {
|
||||
props: Props,
|
||||
link: ComponentLink<Self>,
|
||||
}
|
||||
|
||||
impl Component for MyComponent {
|
||||
type Properties = Props;
|
||||
// ...
|
||||
|
||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
MyComponent { props, link }
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### View
|
||||
|
||||
コンポーネントは`view()`メソッドによってレイアウトを宣言します。
|
||||
Yewは`html!`マクロによってHTMLとSVGノード、リスナー、子コンポーネントを宣言できます。
|
||||
マクロはReactのJSXのような動きをしますが、JavaScriptの代わりにRustの式を用います。
|
||||
|
||||
```rust
|
||||
impl Component for MyComponent {
|
||||
// ...
|
||||
|
||||
fn view(&self) -> Html {
|
||||
let onclick = self.link.callback(|_| Msg::Click);
|
||||
html! {
|
||||
<button onclick=onclick>{ self.props.button_text }</button>
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
使い方については[`html!`ガイド](html.md)をご確認ください。
|
||||
|
||||
### Rendered
|
||||
|
||||
`rendered()`コンポーネントのライフサイクルのメソッドは`view()`が処理されたてYewがコンポーネントをレンダリングした後、
|
||||
ブラウザがページを更新する前に呼ばれます。
|
||||
コンポーネントは、コンポーネントが要素をレンダリングした後にのみ実行できるアクションを実行するため、このメソッドを実装したい場合があります。
|
||||
コンポーネントが初めてレンダリングされたかどうかは `first_render` パラメータで確認できます。
|
||||
|
||||
```rust
|
||||
use stdweb::web::html_element::InputElement;
|
||||
use stdweb::web::IHtmlElement;
|
||||
use yew::prelude::*;
|
||||
|
||||
pub struct MyComponent {
|
||||
node_ref: NodeRef,
|
||||
}
|
||||
|
||||
impl Component for MyComponent {
|
||||
// ...
|
||||
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<input ref=self.node_ref.clone() type="text" />
|
||||
}
|
||||
}
|
||||
|
||||
fn rendered(&mut self, first_render: bool) {
|
||||
if first_render {
|
||||
if let Some(input) = self.node_ref.try_into::<InputElement>() {
|
||||
input.focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::tip note
|
||||
ライフサイクルメソッドは実装の必要がなく、デフォルトでは何もしません。
|
||||
:::
|
||||
|
||||
### Update
|
||||
|
||||
コンポーネントは動的で、非同期メッセージを受信するために登録することができます。
|
||||
ライフサイクルメソッド `update()` はメッセージごとに呼び出されます。
|
||||
これにより、コンポーネントはメッセージが何であったかに基づいて自身を更新し、自身を再レンダリングする必要があるかどうかを判断することができます。
|
||||
メッセージは、HTML要素リスナーによってトリガーされたり、子コンポーネント、エージェント、サービス、またはFuturesによって送信されたりします。
|
||||
|
||||
`update()`がどのようなのかについての例は以下の通りです:
|
||||
|
||||
```rust
|
||||
pub enum Msg {
|
||||
SetInputEnabled(bool)
|
||||
}
|
||||
|
||||
impl Component for MyComponent {
|
||||
type Message = Msg;
|
||||
|
||||
// ...
|
||||
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
match msg {
|
||||
Msg::SetInputEnabled(enabled) => {
|
||||
if self.input_enabled != enabled {
|
||||
self.input_enabled = enabled;
|
||||
true // Re-render
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Change
|
||||
|
||||
コンポーネントは親によって再レンダリングされることがあります。
|
||||
このような場合、新しいプロパティを受け取り、再レンダリングを選択する可能性があります。
|
||||
この設計では、プロパティを変更することで、親から子へのコンポーネントの通信が容易になります。
|
||||
|
||||
典型的な実装例は以下の通りです:
|
||||
|
||||
```rust
|
||||
impl Component for MyComponent {
|
||||
// ...
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Destroy
|
||||
|
||||
コンポーネントが DOM からアンマウントされた後、Yew は `destroy()` ライフサイクルメソッドを呼び出し、必要なクリーンアップ操作をサポートします。
|
||||
このメソッドはオプションで、デフォルトでは何もしません。
|
||||
|
||||
## Associated Types
|
||||
|
||||
`Component`トレイトは2つの関連型があります: `Message`と`Properties`です。
|
||||
|
||||
```rust
|
||||
impl Component for MyComponent {
|
||||
type Message = Msg;
|
||||
type Properties = Props;
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
`Message`はコンポーネントによって処理され、何らかの副作用を引き起こすことができるさまざまなメッセージを表します。
|
||||
例えば、APIリクエストをトリガーしたり、UIコンポーネントの外観を切り替えたりする `Click` メッセージがあります。
|
||||
コンポーネントのモジュールで `Msg` という名前の列挙型を作成し、それをコンポーネントのメッセージ型として使用するのが一般的です。
|
||||
"message"を"msg"と省略するのも一般的です。
|
||||
|
||||
```rust
|
||||
enum Msg {
|
||||
Click,
|
||||
}
|
||||
```
|
||||
|
||||
`Properties`は、親からコンポーネントに渡される情報を表します。
|
||||
この型はProperties traitを実装していなければならず\(通常はこれを派生させることで\)、特定のプロパティが必須かオプションかを指定することができます。
|
||||
この型は、コンポーネントの作成・更新時に使用されます。
|
||||
コンポーネントのモジュール内に `Props` という構造体を作成し、それをコンポーネントの `Properties` 型として使用するのが一般的です。
|
||||
”Properties”を"props"に短縮するのが一般的です。
|
||||
Propsは親コンポーネントから継承されるので、アプリケーションのルートコンポーネントは通常`()`型の`Properties`を持ちます。
|
||||
ルートコンポーネントのプロパティを指定したい場合は、`App::mount_with_props`メソッドを利用します。
|
||||
@ -0,0 +1,34 @@
|
||||
---
|
||||
title: Callbacks
|
||||
description: ComponentLink and Callbacks
|
||||
---
|
||||
”リンク”コンポーネントはコンポーネントがコールバックを登録できて自身を更新することができるメカニズムです。
|
||||
|
||||
## ComponentLink API
|
||||
|
||||
### callback
|
||||
|
||||
実行時にコンポーネントの更新メカニズムにメッセージを送信するコールバックを登録します。
|
||||
これは、渡されたクロージャから返されるメッセージで `send_self` を呼び出します。
|
||||
`Fn(IN) -> Vec<COMP::Message>`が渡され、`Callback<IN>`が返されます。
|
||||
|
||||
### send\_message
|
||||
|
||||
現在のループが終了した直後にコンポーネントにメッセージを送信し、別の更新ループを開始します。
|
||||
|
||||
### send\_message\_batch
|
||||
|
||||
実行時に一度に多数のメッセージを一括して送信するコールバックを登録します。
|
||||
メッセージによってコンポーネントが再レンダリングされる場合、バッチ内のすべてのメッセージが処理された後、コンポーネントは再レンダリングされます。
|
||||
`Fn(IN) -> COMP::Message`が渡され、`Callback<IN>`が返されます。
|
||||
|
||||
## コールバック
|
||||
|
||||
_\(This might need its own short page.\)_
|
||||
|
||||
コールバックは、Yew 内のサービス、エージェント、親コンポーネントとの通信に使われます。
|
||||
これらは単に `Fn` を `Rc` でラップしただけであり、クローンを作成できるようにするためのものです。
|
||||
|
||||
これらの関数には `emit` 関数があり、`<IN>` 型を引数に取り、それをアドレスが欲しいメッセージに変換します。
|
||||
親からのコールバックが子コンポーネントにpropsで提供されている場合、子は `update` ライフサイクルフックで `emit` をコールバックに呼び出して親にメッセージを返すことができます。
|
||||
マクロ内でpropsとして提供されたクロージャや関数は自動的にコールバックに変換されます。
|
||||
@ -0,0 +1,85 @@
|
||||
---
|
||||
title: Properties
|
||||
description: Parent to child communication
|
||||
---
|
||||
プロパティは、子コンポーネントと親コンポーネントが互いに通信できるようにします。
|
||||
|
||||
## マクロの継承
|
||||
|
||||
`Properties`を自分で実装しようとせず、代わりに`#[derive(Properties)]`を使ってください。
|
||||
|
||||
:::note
|
||||
`Properties`を継承した型は`Clone`を実装していなければいけません。
|
||||
これは`#[derive(Properties, Clone)`か`Clone`を手で実装することで可能です。
|
||||
:::
|
||||
|
||||
### 必要な属性
|
||||
|
||||
デフォルトでは、`Properties` を導出する構造体内のフィールドは必須です。
|
||||
フィールドが欠落していて `html!` マクロでコンポーネントが作成された場合、コンパイラエラーが返されます。
|
||||
オプションのプロパティを持つフィールドについては、`#[prop_or_default]` 属性を使用して、propが指定されていない場合はその型のデフォルト値を使用します。
|
||||
値を指定するには `#[prop_or(value)]` 属性を用います。
|
||||
ここでvalueはプロパティのデフォルト値、あるいは代わりに `#[prop_or_else(function)]` を使用して、`function` はデフォルト値を返します。
|
||||
例えば、ブール値のデフォルトを `true` とするには、属性 `#[prop_or(true)]` を使用します。オプションのプロパティでは、デフォルト値 `None` を持つ `Option` 列挙型を使うのが一般的です。
|
||||
|
||||
### PartialEq
|
||||
|
||||
もし可能ならpropsで `PartialEq` を継承するのが良いかもしれません。
|
||||
`PartialEq`を使うことで、不必要な再レンダリングを避けることができます
|
||||
(これについては、**最適化とベストプラクティス**のセクションで説明しています)。
|
||||
|
||||
## プロパティを使用する際のメモリと速度のオーバーヘッド
|
||||
|
||||
`Compoenent::view`ではコンポーネントの状態への参照を取り、それを使って `Html` を作成します。
|
||||
しかし、プロパティは自身の値です。
|
||||
つまり、それらを作成して子コンポーネントに渡すためには、`view` 関数で提供される参照を所有する必要があるのです。
|
||||
これは所有する値を取得するためにコンポーネントに渡される参照を暗黙のうちにクローンすることで行われます。
|
||||
|
||||
|
||||
これは、各コンポーネントが親から受け継いだ状態の独自のコピーを持っていることを意味し、コンポーネントを再レンダリングするときはいつでも、再レンダリングしたコンポーネントのすべての子コンポーネントのpropsがクローンされなければならないことを意味します。
|
||||
|
||||
このことの意味するところは、もしそうでなければ_大量の_データ \(10KBもあるような文字列\) をpropsとして渡してしまうのであれば、子コンポーネントを親が呼び出す `Html` を返す関数にすることを考えた方がいいかもしれないということです。
|
||||
|
||||
propsを介して渡されたデータを変更する必要がない場合は、実際のデータそのものではなく、データへの参照カウントされたポインタのみが複製されるように `Rc` でラップすることができます。
|
||||
|
||||
## 例
|
||||
|
||||
```rust
|
||||
use std::rc::Rc;
|
||||
use yew::Properties;
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum LinkColor {
|
||||
Blue,
|
||||
Red,
|
||||
Green,
|
||||
Black,
|
||||
Purple,
|
||||
}
|
||||
|
||||
impl Default for LinkColor {
|
||||
fn default() -> Self {
|
||||
// The link color will be blue unless otherwise specified.
|
||||
LinkColor::Blue
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Properties, Clone, PartialEq)]
|
||||
pub struct LinkProps {
|
||||
/// The link must have a target.
|
||||
href: String,
|
||||
/// If the link text is huge, this will make copying the string much cheaper.
|
||||
/// This isn't usually recommended unless performance is known to be a problem.
|
||||
text: Rc<String>,
|
||||
/// Color of the link.
|
||||
#[prop_or_default]
|
||||
color: LinkColor,
|
||||
/// The view function will not specify a size if this is None.
|
||||
#[prop_or_default]
|
||||
size: Option<u32>,
|
||||
/// When the view function doesn't specify active, it defaults to true.
|
||||
#[prop_or(true)]
|
||||
active: bool,
|
||||
}
|
||||
```
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
---
|
||||
title: Refs
|
||||
description: Out-of-band DOM access
|
||||
---
|
||||
|
||||
`ref`は、任意のHTML要素やコンポーネントの内部で、割り当てられているDOM`Element`を取得するために使用することができます。
|
||||
これは、`view` ライフサイクルメソッドの外でDOMに変更を加えるために使用できます。
|
||||
|
||||
これは、キャンバスの要素を取得したり、ページの異なるセクションにスクロールしたりするのに便利です。
|
||||
|
||||
構文は以下の通りです:
|
||||
|
||||
```rust
|
||||
// In create
|
||||
self.node_ref = NodeRef::default();
|
||||
|
||||
// In view
|
||||
html! {
|
||||
<div ref=self.node_ref.clone()></div>
|
||||
}
|
||||
|
||||
// In update
|
||||
let has_attributes = self.node_ref.try_into::<Element>().has_attributes();
|
||||
```
|
||||
|
||||
21
website/translated_docs/ja/version-0.17.3/concepts/html.md
Normal file
21
website/translated_docs/ja/version-0.17.3/concepts/html.md
Normal file
@ -0,0 +1,21 @@
|
||||
---
|
||||
title: Introduction
|
||||
description: The procedural macro for generating HTML and SVG
|
||||
---
|
||||
|
||||
`html!`マクロによってHTMLとSVGのコードを宣言的に書くことができます。
|
||||
JSX \(HTMLのようなコードをJavaScript内部に書くことができるJavaScriptの拡張\) に似ています。
|
||||
|
||||
**重要な注意**
|
||||
|
||||
1. `html!`マクロはルートのHTMLノードのみ受け付けます \([フラグメントかイテレータを使う](html/lists.md)ことでやり取りできます\)
|
||||
2. 空の`html! {}`の呼び出しは可能ですが何もレンダリングしません
|
||||
3. リテラルはクオーテーションがつけられ、ブレースで囲う必要があります: `html! { "Hello, World" }`
|
||||
|
||||
:::note
|
||||
`html!`マクロはコンパイラのデフォルトの再帰の上限に簡単に達してしまいます。
|
||||
もしコンパイラエラーに遭遇した場合はその値を押し出すといいかもしれません。
|
||||
クレートのルート\(つまり、`lib.rs`か`main.rs`\)で`#![recursion_limit="1024"]`のような属性を使えば解決します。
|
||||
|
||||
詳しくは[公式ドキュメント](https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute)と[Stack Overflowの質問](https://stackoverflow.com/questions/27454761/what-is-a-crate-attribute-and-where-do-i-add-it)を見てみてください。
|
||||
:::
|
||||
@ -0,0 +1,105 @@
|
||||
---
|
||||
title: Components
|
||||
description: Create complex layouts with component hierarchies
|
||||
---
|
||||
## 基本
|
||||
|
||||
`Component`を実装しているあらゆる型は`html!`マクロの中で使えます:
|
||||
|
||||
```rust
|
||||
html!{
|
||||
<>
|
||||
// No properties
|
||||
<MyComponent />
|
||||
|
||||
// With Properties
|
||||
<MyComponent prop1="lorem" prop2="ipsum" />
|
||||
|
||||
// With the whole set of props provided at once
|
||||
<MyComponent with props />
|
||||
</>
|
||||
}
|
||||
```
|
||||
|
||||
## ネスト
|
||||
|
||||
`children`フィールドが`Properties`の中にある場合はコンポーネントは子に渡されます。
|
||||
|
||||
```rust title="parent.rs"
|
||||
html! {
|
||||
<Container>
|
||||
<h4>{ "Hi" }</h4>
|
||||
<div>{ "Hello" }</div>
|
||||
</Container>
|
||||
}
|
||||
```
|
||||
|
||||
```rust title="container.rs"
|
||||
pub struct Container(Props);
|
||||
|
||||
#[derive(Properties, Clone)]
|
||||
pub struct Props {
|
||||
pub children: Children,
|
||||
}
|
||||
|
||||
impl Component for Container {
|
||||
type Properties = Props;
|
||||
|
||||
// ...
|
||||
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<div id="container">
|
||||
{ self.0.children.render() }
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::note
|
||||
`Properties`を継承した型は`Clone`を実装していなければいけません。
|
||||
これは`#[derive(Properties, Clone)]`を使うか手で`Clone`を実装すれば良いです。
|
||||
:::
|
||||
|
||||
## Propsとネストした子コンポーネント
|
||||
|
||||
ネストしたコンポーネントのプロパティは格納しているコンポーネントの型が子である場合はアクセス可能、または変更可能です。
|
||||
以下の例では`List`コンポーネントは`ListItem`コンポーネントをラップできています。
|
||||
実際の使用においてこのパターンの例については`yew-router`のソースコードを確認してみてください。
|
||||
より進んだ例としてはYewのメインのリポジトリにある`nested-list`を確認してみてください。
|
||||
|
||||
```rust title="parent.rs"
|
||||
html! {
|
||||
<List>
|
||||
<ListItem value="a" />
|
||||
<ListItem value="b" />
|
||||
<ListItem value="c" />
|
||||
</List>
|
||||
}
|
||||
```
|
||||
|
||||
```rust title="list.rs"
|
||||
pub struct List(Props);
|
||||
|
||||
#[derive(Properties, Clone)]
|
||||
pub struct Props {
|
||||
pub children: ChildrenWithProps<ListItem>,
|
||||
}
|
||||
|
||||
impl Component for List {
|
||||
type Properties = Props;
|
||||
|
||||
// ...
|
||||
|
||||
fn view(&self) -> Html {
|
||||
html!{{
|
||||
for self.0.children.iter().map(|mut item| {
|
||||
item.props.value = format!("item-{}", item.props.value);
|
||||
item
|
||||
})
|
||||
}}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -0,0 +1,360 @@
|
||||
---
|
||||
title: Elements
|
||||
description: Both HTML and SVG elements are supported
|
||||
---
|
||||
## タグ構造
|
||||
|
||||
要素のタグは`<... />`のような自己完結タグか、開始タグに対応した終了タグを持っている必要があります。
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--Open - Close-->
|
||||
```rust
|
||||
html! {
|
||||
<div id="my_div"></div>
|
||||
}
|
||||
```
|
||||
<!--Invalid-->
|
||||
```rust
|
||||
html! {
|
||||
<div id="my_div"> // <- MISSING CLOSE TAG
|
||||
}
|
||||
```
|
||||
|
||||
<!--Self-closing-->
|
||||
```rust
|
||||
html! {
|
||||
<input id="my_input" />
|
||||
}
|
||||
```
|
||||
|
||||
<!--Invalid-->
|
||||
```rust
|
||||
html! {
|
||||
<input id="my_input"> // <- MISSING SELF-CLOSE
|
||||
}
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
:::note
|
||||
便利さのために、_普通は_終了タグを必要とする要素は自己完結タグとすることが**できます**。
|
||||
例えば`html! { <div class="placeholder" /> }`と書くのは有効です。
|
||||
:::
|
||||
|
||||
## 子
|
||||
|
||||
複雑にネストしたHTMLやSVGのレイアウトを書くのには以下のようにするのが楽です:
|
||||
**
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--HTML-->
|
||||
|
||||
```rust
|
||||
html! {
|
||||
<div>
|
||||
<div data-key="abc"></div>
|
||||
<div class="parent">
|
||||
<span class="child" value="anything"></span>
|
||||
<label for="first-name">{ "First Name" }</label>
|
||||
<input type="text" id="first-name" value="placeholder" />
|
||||
<input type="checkbox" checked=true />
|
||||
<textarea value="write a story" />
|
||||
<select name="status">
|
||||
<option selected=true disabled=false value="">{ "Selected" }</option>
|
||||
<option selected=false disabled=true value="">{ "Unselected" }</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
```
|
||||
|
||||
<!--SVG-->
|
||||
|
||||
```rust
|
||||
html! {
|
||||
<svg width="149" height="147" viewBox="0 0 149 147" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M60.5776 13.8268L51.8673 42.6431L77.7475 37.331L60.5776 13.8268Z" fill="#DEB819"/>
|
||||
<path d="M108.361 94.9937L138.708 90.686L115.342 69.8642" stroke="black" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<g filter="url(#filter0_d)">
|
||||
<circle cx="75.3326" cy="73.4918" r="55" fill="#FDD630"/>
|
||||
<circle cx="75.3326" cy="73.4918" r="52.5" stroke="black" stroke-width="5"/>
|
||||
</g>
|
||||
<circle cx="71" cy="99" r="5" fill="white" fill-opacity="0.75" stroke="black" stroke-width="3"/>
|
||||
<defs>
|
||||
<filter id="filter0_d" x="16.3326" y="18.4918" width="118" height="118" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feGaussianBlur stdDeviation="2"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
|
||||
</filter>
|
||||
</defs>
|
||||
</svg>
|
||||
}
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## クラス
|
||||
|
||||
要素へのクラスを特定する便利なやり方はたくさんあります:
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--Literal-->
|
||||
```rust
|
||||
html! {
|
||||
<div class="container"></div>
|
||||
}
|
||||
```
|
||||
|
||||
<!--Multiple-->
|
||||
```rust
|
||||
html! {
|
||||
<div class="container center-align"></div>
|
||||
}
|
||||
```
|
||||
|
||||
<!--Interpolated-->
|
||||
```rust
|
||||
html! {
|
||||
<div class=format!("{}-container", size)></div>
|
||||
}
|
||||
```
|
||||
|
||||
<!--Expression-->
|
||||
```rust
|
||||
html! {
|
||||
<div class=self.classes()></div>
|
||||
}
|
||||
```
|
||||
|
||||
<!--Tuple-->
|
||||
```rust
|
||||
html! {
|
||||
<div class=("class-1", "class-2")></div>
|
||||
}
|
||||
```
|
||||
|
||||
<!--Vector-->
|
||||
```rust
|
||||
html! {
|
||||
<div class=vec!["class-1", "class-2"]></div>
|
||||
}
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## リスナー
|
||||
|
||||
リスナー属性はクロージャのラッパーである`Callback`に渡される必要があります。
|
||||
コールバックをどのように作るかはアプリをリスナーイベントにどう反応させたいかによります。
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--Component handler-->
|
||||
```rust
|
||||
struct MyComponent {
|
||||
link: ComponentLink<Self>,
|
||||
}
|
||||
|
||||
enum Msg {
|
||||
Click,
|
||||
}
|
||||
|
||||
impl Component for MyComponent {
|
||||
type Message = Msg;
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
MyComponent { link }
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
match msg {
|
||||
Msg::Click => {
|
||||
// Handle Click
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
// Create a callback from a component link to handle it in a component
|
||||
let click_callback = self.link.callback(|_: ClickEvent| Msg::Click);
|
||||
html! {
|
||||
<button onclick=click_callback>
|
||||
{ "Click me!" }
|
||||
</button>
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<!--Agent Handler-->
|
||||
|
||||
```rust
|
||||
struct MyComponent {
|
||||
worker: Dispatcher<MyWorker>,
|
||||
}
|
||||
|
||||
impl Component for MyComponent {
|
||||
type Message = ();
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {
|
||||
MyComponent {
|
||||
worker: MyWorker::dispatcher()
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, _: Self::Message) -> ShouldRender {
|
||||
false
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
// Create a callback from a worker to handle it in another context
|
||||
let click_callback = self.worker.callback(|_: ClickEvent| WorkerMsg::Process);
|
||||
html! {
|
||||
<button onclick=click_callback>
|
||||
{ "Click me!" }
|
||||
</button>
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<!--Other Cases-->
|
||||
```rust
|
||||
struct MyComponent;
|
||||
|
||||
impl Component for MyComponent {
|
||||
type Message = ();
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {
|
||||
MyComponent
|
||||
}
|
||||
|
||||
fn update(&mut self, _: Self::Message) -> ShouldRender {
|
||||
false
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
// Create an ephemeral callback
|
||||
let click_callback = Callback::from(|| {
|
||||
ConsoleService::new().log("clicked!");
|
||||
});
|
||||
|
||||
html! {
|
||||
<button onclick=click_callback>
|
||||
{ "Click me!" }
|
||||
</button>
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## イベントの型
|
||||
|
||||
:::note
|
||||
以下のテーブルでは`yew`を`web-sys`と使う場合 (デフォルトでは使うようになっている) `web-sys`のイベントの型が使われるべきです。
|
||||
`yew-stdweb`クレートを使う場合は`stdweb`のイベントの型を使用してください。
|
||||
詳細については[`web-sys`と`stdweb`をどちらを使うべきかについてのドキュメント](https://yew.rs/docs/getting-started/choose-web-library)をご確認ください。
|
||||
:::
|
||||
|
||||
:::note
|
||||
以下のテーブルにある全てのイベントの型は`yew::events`で再エクスポートされています。
|
||||
All the event types mentioned in the following table are re-exported under `yew::events`. Using the types from
|
||||
`yew::events` makes it easier to ensure version compatibility than if you were to manually include `web-sys`
|
||||
or `stdweb` as dependencies in your crate because you won't end up using a version which conflicts with
|
||||
the version Yew specifies.
|
||||
:::
|
||||
|
||||
| イベント名 | `web_sys` イベント型 | `stdweb` イベント型 |
|
||||
| ----------- | -------------------- | ------------------ |
|
||||
| `onabort` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | [ResourceAbortEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.ResourceAbortEvent.html) |
|
||||
| `onauxclick` | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html) | [AuxClickEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.AuxClickEvent.html) |
|
||||
| `onblur` | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html) | [BlurEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.BlurEvent.html) |
|
||||
| `oncancel` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | サポート無し |
|
||||
| `oncanplay` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | サポート無し |
|
||||
| `oncanplaythrough` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | サポート無し |
|
||||
| `onchange` | [ChangeData](https://docs.rs/yew/latest/yew/events/enum.ChangeData.html) | [ChangeData](https://docs.rs/yew-stdweb/latest/yew_stdweb/events/enum.ChangeData.html) |
|
||||
| `onclick` | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html) | [ClickEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.ClickEvent.html) |
|
||||
| `onclose` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | サポート無し |
|
||||
| `oncontextmenu` | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html) | [ContextMenuEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.ContextMenuEvent.html) |
|
||||
| `oncuechange` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | サポート無し |
|
||||
| `ondblclick` | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html) | [DoubleClickEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.DoubleClickEvent.html) |
|
||||
| `ondrag` | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html) | [DragEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.DragEvent.html) |
|
||||
| `ondragend` | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html) | [DragEndEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.DragEndEvent.html) |
|
||||
| `ondragenter` | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html) | [DragEnterEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.DragEnterEvent.html) |
|
||||
| `ondragexit` | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html) | [DragExitEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.DragExitEvent.html) |
|
||||
| `ondragleave` | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.htmk) | [DragLeaveEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.DragLeaveEvent.html) |
|
||||
| `ondragover` | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html) | [DragOverEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.DragOverEvent.html) |
|
||||
| `ondragstart` | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html) | [DragStartEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.DragStartEvent.html) |
|
||||
| `ondrop` | [DragEvent](https://docs.rs/web-sys/latest/web_sys/struct.DragEvent.html) | [DragDropEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.DragDropEvent.html) |
|
||||
| `ondurationchange` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | サポート無し |
|
||||
| `onemptied` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | サポート無し |
|
||||
| `onended` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | サポート無し |
|
||||
| `onerror` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | [ResourceErrorEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.ResourceErrorEvent.html) |
|
||||
| `onfocus` | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html) | [FocusEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.FocusEvent.html) |
|
||||
| `onformdata` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | サポート無し |
|
||||
| `oninput` | [InputData](https://docs.rs/yew/latest/yew/events/struct.InputData.html) | [InputData](https://docs.rs/yew-stdweb/latest/yew_stdweb/events/struct.InputData.html) |
|
||||
| `oninvalid` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | サポート無し |
|
||||
| `onkeydown` | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html) | [KeyDownEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.KeyDownEvent.html) |
|
||||
| `onkeypress` | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html) | [KeyPressEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.KeyPressEvent.html) |
|
||||
| `onkeyup` | [KeyboardEvent](https://docs.rs/web-sys/latest/web_sys/struct.KeyboardEvent.html) | [KeyUpEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.KeyUpEvent.html) |
|
||||
| `onload` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | [ResourceLoadEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.ResourceLoadEvent.html) |
|
||||
| `onloadeddata` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | サポート無し |
|
||||
| `onloadedmetadata` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | サポート無し |
|
||||
| `onloadstart` | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html) | [LoadStartEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.LoadStartEvent.html) |
|
||||
| `onmousedown` | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html) | [MouseDownEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.MouseDownEvent.html) |
|
||||
| `onmouseenter` | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html) | [MouseEnterEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.MouseEnterEvent.html) |
|
||||
| `onmouseleave` | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html) | [MouseLeaveEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.MouseLeaveEvent.html) |
|
||||
| `onmousemove` | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html) | [MouseMoveEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.MouseMoveEvent.html) |
|
||||
| `onmouseout` | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html) | [MouseOutEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.MouseOutEvent.html) |
|
||||
| `onmouseover` | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html) | [MouseOverEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.MouseOverEvent.html) |
|
||||
| `onmouseup` | [MouseEvent](https://docs.rs/web-sys/latest/web_sys/struct.MouseEvent.html) | [MouseUpEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.MouseUpEvent.html) |
|
||||
| `onpause` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | サポート無し |
|
||||
| `onplay` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | サポート無し |
|
||||
| `onplaying` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | サポート無し |
|
||||
| `onprogress` | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html) | [ProgressEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.ProgressEvent.html) |
|
||||
| `onratechange` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | サポート無し |
|
||||
| `onreset` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | サポート無し |
|
||||
| `onresize` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | [ResizeEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.ResizeEvent.html) |
|
||||
| `onscroll` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | [ScrollEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.ScrollEvent.html) |
|
||||
| `onsecuritypolicyviolation` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | サポート無し |
|
||||
| `onseeked` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | サポート無し |
|
||||
| `onseeking` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | サポート無し |
|
||||
| `onselect` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | サポート無し |
|
||||
| `onslotchange` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | [SlotChangeEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.SlotChangeEvent.html) |
|
||||
| `onstalled` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | サポート無し |
|
||||
| `onsubmit` | [FocusEvent](https://docs.rs/web-sys/latest/web_sys/struct.FocusEvent.html) | [SubmitEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.SubmitEvent.html) |
|
||||
| `onsuspend` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | サポート無し |
|
||||
| `ontimeupdate` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | サポート無し |
|
||||
| `ontoggle` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | サポート無し |
|
||||
| `onvolumechange` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | サポート無し |
|
||||
| `onwaiting` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | サポート無し |
|
||||
| `onwheel` | [WheelEvent](https://docs.rs/web-sys/latest/web_sys/struct.WheelEvent.html) | [MouseWheelEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.MouseWheelEvent.html) |
|
||||
| `oncopy` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | サポート無し |
|
||||
| `oncut` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | サポート無し |
|
||||
| `onpaste` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | サポート無し |
|
||||
| `onanimationcancel` | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html) | サポート無し |
|
||||
| `onanimationend` | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html) | サポート無し |
|
||||
| `onanimationiteration` | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html) | サポート無し |
|
||||
| `onanimationstart` | [AnimationEvent](https://docs.rs/web-sys/latest/web_sys/struct.AnimationEvent.html) | サポート無し |
|
||||
| `ongotpointercapture` | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html) | [GotPointerCaptureEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.GotPointerCaptureEvent.html) |
|
||||
| `onloadend` | [ProgressEvent](https://docs.rs/web-sys/latest/web_sys/struct.ProgressEvent.html) | [LoadEndEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.LoadEndEvent.html) |
|
||||
| `onlostpointercapture` | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html) | [LostPointerCaptureEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.LostPointerCaptureEvent.html) |
|
||||
| `onpointercancel` | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html) | [PointerCancelEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.PointerCancelEvent.html) |
|
||||
| `onpointerdown` | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html) | [PointerDownEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.PointerDownEvent.html) |
|
||||
| `onpointerenter` | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html) | [PointerEnterEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.PointerEnterEvent.html) |
|
||||
| `onpointerleave` | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html) | [PointerLeaveEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.PointerLeaveEvent.html) |
|
||||
| `onpointerlockchange` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | [PointerLockChangeEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.PointerLockChangeEvent.html) |
|
||||
| `onpointerlockerror` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | [PointerLockErrorEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.PointerLockErrorEvent.html) |
|
||||
| `onpointermove` | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html) | [PointerMoveEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.PointerMoveEvent.html) |
|
||||
| `onpointerout` | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html) | [PointerOutEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.PointerOutEvent.html) |
|
||||
| `onpointerover` | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html) | [PointerOverEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.PointerOverEvent.html) |
|
||||
| `onpointerup` | [PointerEvent](https://docs.rs/web-sys/latest/web_sys/struct.PointerEvent.html) | [PointerUpEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.PointerUpEvent.html) |
|
||||
| `onselectionchange` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | [SelectionChangeEvent](https://docs.rs/stdweb/latest/stdweb/web/event/struct.SelectionChangeEvent.html) |
|
||||
| `onselectstart` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | サポート無し |
|
||||
| `onshow` | [Event](https://docs.rs/web-sys/latest/web_sys/struct.Event.html) | サポート無し |
|
||||
| `ontouchcancel` | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html) | [TouchCancel](https://docs.rs/stdweb/latest/stdweb/web/event/struct.TouchCancel.html) |
|
||||
| `ontouchend` | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html) | [TouchEnd](https://docs.rs/stdweb/latest/stdweb/web/event/struct.TouchEnd.html) |
|
||||
| `ontouchmove` | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html) | [TouchMove](https://docs.rs/stdweb/latest/stdweb/web/event/struct.TouchMove.html) |
|
||||
| `ontouchstart` | [TouchEvent](https://docs.rs/web-sys/latest/web_sys/struct.TouchEvent.html) | [TouchStart](https://docs.rs/stdweb/latest/stdweb/web/event/struct.TouchStart.html) |
|
||||
| `ontransitioncancel` | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) | サポート無し |
|
||||
| `ontransitionend` | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) | サポート無し |
|
||||
| `ontransitionrun` | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) | サポート無し |
|
||||
| `ontransitionstart` | [TransitionEvent](https://docs.rs/web-sys/latest/web_sys/struct.TransitionEvent.html) | サポート無し |
|
||||
@ -0,0 +1,55 @@
|
||||
---
|
||||
title: Lists
|
||||
---
|
||||
|
||||
## フラグメント
|
||||
|
||||
`html!`マクロは常にルートノードが1つであることを要求します。
|
||||
この制限のために、空のタグを使って内容をラップすると良いでしょう。
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--Valid-->
|
||||
```rust
|
||||
html! {
|
||||
<>
|
||||
<div></div>
|
||||
<p></p>
|
||||
</>
|
||||
}
|
||||
```
|
||||
|
||||
<!--Invalid-->
|
||||
```rust
|
||||
/* error: only one root html element allowed */
|
||||
|
||||
html! {
|
||||
<div></div>
|
||||
<p></p>
|
||||
}
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
|
||||
## イテレータ
|
||||
|
||||
YewはイテレータからHTMLをビルドするのに2つの方法をサポートしています。
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--Syntax Type 1-->
|
||||
```rust
|
||||
html! {
|
||||
<ul class="item-list">
|
||||
{ self.props.items.iter().map(renderItem).collect::<Html>() }
|
||||
</ul>
|
||||
}
|
||||
```
|
||||
|
||||
<!--Syntax Type 2-->
|
||||
```rust
|
||||
html! {
|
||||
<ul class="item-list">
|
||||
{ for self.props.items.iter().map(renderItem) }
|
||||
</ul>
|
||||
}
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
@ -0,0 +1,59 @@
|
||||
---
|
||||
title: Literals and Expressions
|
||||
---
|
||||
## リテラル
|
||||
|
||||
式が`Display`を実装した型を解決する場合、文字列に変換されてDOMに[Text](https://developer.mozilla.org/en-US/docs/Web/API/Text)ノードとして挿入されます。
|
||||
|
||||
テキストは式として処理されるため、全ての表示される内容は`{}`ブロックによって囲まれる必要があります。
|
||||
これはYewのアプリと通常のHTMLの構文で最も異なる点です。
|
||||
|
||||
```rust
|
||||
let text = "lorem ipsum";
|
||||
html!{
|
||||
<>
|
||||
<div>{text}</div>
|
||||
<div>{"dolor sit"}</div>
|
||||
<span>{42}</span>
|
||||
</>
|
||||
}
|
||||
```
|
||||
|
||||
## 式
|
||||
|
||||
HTMLに`{}`ブロックを使って式を挿入することができます。
|
||||
|
||||
```rust
|
||||
html! {
|
||||
<div>
|
||||
{
|
||||
if show_link {
|
||||
html! {
|
||||
<a href="https://example.com">{"Link"}</a>
|
||||
}
|
||||
} else {
|
||||
html! {}
|
||||
}
|
||||
}
|
||||
</div>
|
||||
}
|
||||
```
|
||||
|
||||
式を関数やクロージャに分離するのはコードの可読性の観点から有効なことがあります。
|
||||
|
||||
```rust
|
||||
let show_link = true;
|
||||
let maybe_display_link = move || -> Html {
|
||||
if show_link {
|
||||
html! {
|
||||
<a href="https://example.com">{"Link"}</a>
|
||||
}
|
||||
} else {
|
||||
html! {}
|
||||
}
|
||||
};
|
||||
|
||||
html! {
|
||||
<div>{maybe_display_link()}</div>
|
||||
}
|
||||
```
|
||||
94
website/translated_docs/ja/version-0.17.3/concepts/router.md
Normal file
94
website/translated_docs/ja/version-0.17.3/concepts/router.md
Normal file
@ -0,0 +1,94 @@
|
||||
---
|
||||
title: Router
|
||||
description: Yew's official router
|
||||
---
|
||||
|
||||
[crates.ioにあるルータ](https://crates.io/crates/yew-router)
|
||||
|
||||
シングルページアプリケーション\(SPA\)におけるルータはURLよってページを出し分けます。
|
||||
リンクがクリックされたときに異なるリソースを要求するというデフォルトの動作の代わりに、ルータはアプリケーション内の有効なルートを指すように URL をローカルに設定します。
|
||||
ルータはこの変更を検出してから、何をレンダリングするかを決定します。
|
||||
|
||||
## コアとなる要素
|
||||
|
||||
### `Route`
|
||||
|
||||
URL内のドメインの後のすべてを表す文字列と、オプションでhistory APIに保存されている状態を含みます。
|
||||
|
||||
### `RouteService`
|
||||
|
||||
ブラウザとやりとりしてルーティングを決めます。
|
||||
|
||||
### `RouteAgent`
|
||||
|
||||
RouteService を所有し、ルートが変更された際の更新を調整するために使用します。
|
||||
|
||||
### `Switch`
|
||||
|
||||
`Switch`トレイトは`Route`をトレイトの実装する側の間で変換するために用いられます。
|
||||
|
||||
### `Router`
|
||||
|
||||
RouterコンポーネントはRouteAgentとやり取りし、エージェントがどうスイッチするかRoutesを自動的に解決します。
|
||||
これは、結果として得られるスイッチがどのようにHtmlに変換されるかを指定できるようにするため、propsを介して公開されます。
|
||||
|
||||
## ルータをどのように使うか
|
||||
|
||||
まず、アプリケーションのすべての状態を表す型を作成します。
|
||||
これは通常は列挙型ですが、構造体もサポートされており、`Switch` を実装した他のアイテムを内部に入れ子にすることができることに注意してください。
|
||||
|
||||
次に、`Switch`を型に継承させなければいけません。
|
||||
列挙型の場合は全てのvariantは`#[to = "/some/route"]`とアノテーションされている必要があり、代わり構造体を用いている場合は構造体宣言が外部から見えるようにしてなければいけません。
|
||||
|
||||
```rust
|
||||
#[derive(Switch)]
|
||||
enum AppRoute {
|
||||
#[to="/login"]
|
||||
Login,
|
||||
#[to="/register"]
|
||||
Register,
|
||||
#[to="/delete_account"]
|
||||
Delete,
|
||||
#[to="/posts/{id}"]
|
||||
ViewPost(i32),
|
||||
#[to="/posts/view"]
|
||||
ViewPosts,
|
||||
#[to="/"]
|
||||
Home
|
||||
}
|
||||
```
|
||||
|
||||
:::caution
|
||||
`Switch`用の派生マクロによって生成された実装は、各variantを最初から最後までの順にマッチさせようとするので、指定した`to`アノテーションのうち 2 つのルートにマッチする可能性がある場合は、最初のルートがマッチし、2 つ目のルートは試行されないことに注意してください。例えば、以下の`Switch`を定義した場合、マッチするルートは`AppRoute::Home`だけになります。
|
||||
|
||||
```rust
|
||||
#[derive(Switch)]
|
||||
enum AppRoute {
|
||||
#[to="/"]
|
||||
Home,
|
||||
#[to="/login"]
|
||||
Login,
|
||||
#[to="/register"]
|
||||
Register,
|
||||
#[to="/delete_account"]
|
||||
Delete,
|
||||
#[to="/posts/{id}"]
|
||||
ViewPost(i32),
|
||||
#[to="/posts/view"]
|
||||
ViewPosts,
|
||||
}
|
||||
```
|
||||
:::
|
||||
|
||||
また、`#[to = ""]`アノテーションの中で`{}`のバリエーションを使ってセクションをキャプチャすることもできます。
|
||||
`{}`は、次の区切り文字\(コンテキストに応じて "/", "?", "&", "#" のいずれか\) までのテキストをキャプチャします。
|
||||
`{*}`は、次の文字が一致するまでテキストをキャプチャすることを意味します。
|
||||
`{<number>}`は、指定した数の区切り文字が見つかるまでテキストをキャプチャすることを意味します
|
||||
\(例: `{2}`は区切り文字が2つ見つかるまでキャプチャします\)。
|
||||
|
||||
名前付きフィールドを持つ構造体や列挙型の場合は、キャプチャグループ内で以下のようにフィールドの名前を指定する必要があります。
|
||||
`{user_name}` または `{*:age}` のように、キャプチャグループ内でフィールドの名前を指定しなければなりません。
|
||||
|
||||
Switchトレイトは文字列よりも構造化されたキャプチャグループで動作します。
|
||||
`Switch`を実装した任意の型を指定することができます。
|
||||
そのため、キャプチャグループが `usize` であることを指定することができ、URLのキャプチャ部分がそれに変換できない場合、variantはマッチしません。
|
||||
@ -0,0 +1,10 @@
|
||||
---
|
||||
title: Introduction
|
||||
description: Yew's glue to browser APIs
|
||||
---
|
||||
|
||||
# サービス
|
||||
|
||||
:::note
|
||||
このセクションはまだWIPです。
|
||||
:::
|
||||
@ -0,0 +1,7 @@
|
||||
---
|
||||
title: Format
|
||||
---
|
||||
|
||||
:::important contribute
|
||||
`Contribute to our docs:` [Explain the format module in depth](https://github.com/yewstack/docs/issues/24)
|
||||
:::
|
||||
@ -0,0 +1,127 @@
|
||||
---
|
||||
title: Build a sample app
|
||||
---
|
||||
|
||||
はじめに、Rustの新規ライブラリを作りましょう(**重要:** `--lib`フラグを渡すことで_バイナリ_ではなく_ライブラリ_を作ってください)
|
||||
|
||||
```bash
|
||||
cargo new --lib yew-app && cd yew-app
|
||||
```
|
||||
|
||||
依存ライブラリに`yew`と`wasm-bindgen`を追加してください \(最新バージョンについては[こちら](https://docs.rs/yew)を参照してください\)
|
||||
|
||||
```toml title="Cargo.toml"
|
||||
[package]
|
||||
name = "yew-app"
|
||||
version = "0.1.0"
|
||||
authors = ["Yew App Developer <name@example.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
yew = "0.17"
|
||||
wasm-bindgen = "0.2"
|
||||
```
|
||||
|
||||
以下のテンプレートを `src/lib.rs`ファイルにコピーしてください:
|
||||
|
||||
```rust title="src/lib.rs"
|
||||
use wasm_bindgen::prelude::*;
|
||||
use yew::prelude::*;
|
||||
|
||||
struct Model {
|
||||
link: ComponentLink<Self>,
|
||||
value: i64,
|
||||
}
|
||||
|
||||
enum Msg {
|
||||
AddOne,
|
||||
}
|
||||
|
||||
impl Component for Model {
|
||||
type Message = Msg;
|
||||
type Properties = ();
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
Self {
|
||||
link,
|
||||
value: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
match msg {
|
||||
Msg::AddOne => self.value += 1
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
// Should only return "true" if new properties are different to
|
||||
// previously received properties.
|
||||
// This component has no properties so we will always return "false".
|
||||
false
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<button onclick=self.link.callback(|_| Msg::AddOne)>{ "+1" }</button>
|
||||
<p>{ self.value }</p>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen(start)]
|
||||
pub fn run_app() {
|
||||
App::<Model>::new().mount_to_body();
|
||||
}
|
||||
```
|
||||
|
||||
このテンプレートはルートに`Component`をセットアップし、`Model`と呼ばれるクリックしたら更新するボタンを作ります。
|
||||
`main()`の中にある`App::<Model>::new().mount_to_body()`がアプリをスタートしてページの`<body>`タグをマウントすることに特に注意してください。
|
||||
動的なプロパティでアプリをスタートしたい場合は代わりに`App::<Model>::new().mount_to_body_with_props(..)`を使うことで実現できます。
|
||||
|
||||
最後に、アプリの中の`static`という名前のフォルダに`index.html`ファイルを追加してください。
|
||||
|
||||
```bash
|
||||
mkdir static
|
||||
```
|
||||
|
||||
```markup title="index.html"
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Yew Sample App</title>
|
||||
<script type="module">
|
||||
import init from "./wasm.js"
|
||||
init()
|
||||
</script>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
||||
```
|
||||
|
||||
## アプリを動かす!
|
||||
|
||||
[`wasm-pack`](https://rustwasm.github.io/docs/wasm-pack/)を使うのがアプリを動かすのに推奨される方法です。
|
||||
まだ`wasm-pack`をインストールしていない場合、`cargo install wasm-pack`でインストールして開発サーバーを動かしてみましょう:
|
||||
|
||||
```bash
|
||||
wasm-pack build --target web --out-name wasm --out-dir ./static
|
||||
```
|
||||
|
||||
`wasm-pack`はコンパイルされたWebAssemblyとJavaScriptラッパーをまとめたものを`./static`ディレクトリに作り、
|
||||
アプリのWebAssemblyバイナリを読み込んで動かします。
|
||||
|
||||
そして、`./static`以下で好きなサーバーをファイルをサーブしてみましょう。
|
||||
例えば:
|
||||
|
||||
```bash
|
||||
cargo +nightly install miniserve
|
||||
miniserve ./static --index index.html
|
||||
```
|
||||
|
||||
@ -0,0 +1,123 @@
|
||||
---
|
||||
title: Choosing a web library
|
||||
---
|
||||
## はじめに
|
||||
|
||||
Yewアプリは[`web-sys`](https://docs.rs/web-sys)か[`stdweb`](https://docs.rs/stdweb)で作ることができます。
|
||||
これらのクレートはRustとWeb APIのバインディングを提供しています。
|
||||
Cargoの依存クレートに`yew`を追加する際はどちらかを選ばなければいけません:
|
||||
|
||||
```toml
|
||||
# Choose `web-sys`
|
||||
yew = "0.17"
|
||||
|
||||
# Choose `stdweb`
|
||||
yew = { version = "0.17", package = "yew-stdweb" }
|
||||
```
|
||||
|
||||
[Rust / Wasm 活動チーム](https://rustwasm.github.io/)のサポートがある`web-sys`が推奨です。
|
||||
|
||||
## 使用例
|
||||
|
||||
```rust
|
||||
// web-sys
|
||||
let window: web_sys::Window = web_sys::window().expect("window not available");
|
||||
window.alert_with_message("hello from wasm!").expect("alert failed");
|
||||
|
||||
// stdweb
|
||||
let window: stdweb::web::Window = stdweb::web::window();
|
||||
window.alert("hello from wasm!");
|
||||
|
||||
// stdweb with js! macro
|
||||
use stdweb::js;
|
||||
use stdweb::unstable::TryFrom;
|
||||
use stdweb::web::Window;
|
||||
|
||||
let window_val: stdweb::Value = js!{ return window; }; // <- JS syntax inside!
|
||||
let window = Window::try_from(window_val).expect("conversion to window failed");
|
||||
window.alert("hello from wasm!");
|
||||
```
|
||||
|
||||
2つのクレートのAPIはわずかに異なりますが、だいたい同じ目的で似た機能が提供されています。
|
||||
|
||||
## 一方を選ぶ
|
||||
|
||||
アプリに`web-sys`と`stdweb`のどちらを選ぶかにおいてはいくつかの見方があります。
|
||||
注意として、一つのアプリに両方を用いることができるのですが、クレートをコンパイルした際にバイナリのサイズを小さくするには
|
||||
一方だけを使用するのが良いです。
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="text-align:left"></th>
|
||||
<th style="text-align:left"><code>web-sys</code>
|
||||
</th>
|
||||
<th style="text-align:left"><code>stdweb</code>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="text-align:left">プロジェクトの進捗状況</td>
|
||||
<td style="text-align:left">
|
||||
<a href="https://rustwasm.github.io/">Rust / Wasm 活動チーム</a>により活発にメンテナンスされている
|
||||
</td>
|
||||
<td style="text-align:left">GitHubで8ヶ月間動きなし</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">Web API のカバー</td>
|
||||
<td style="text-align:left">RustのAPIはWeb IDLスペックから自動的に生成される。</td>
|
||||
<td style="text-align:left">Browser APIはコミュニティにより追加。</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">RustのAPIのデザイン</td>
|
||||
<td style="text-align:left">
|
||||
ほとんどのAPIコールおいて<code>Result</code>が返ってくるよう保守的なアプローチがとられている。
|
||||
</td>
|
||||
<td style="text-align:left">しばしば<code>Result</code>を返さずpanicするようになっている。例えば <code>stdweb::web::window()</code>ワーカーの中で呼ばれるパニックする。</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">サポートされているビルドツール</td>
|
||||
<td style="text-align:left">
|
||||
<p></p>
|
||||
<ul>
|
||||
<li><code>wasm-bindgen</code>
|
||||
</li>
|
||||
<li><code>wasm-pack</code>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td style="text-align:left">
|
||||
<p></p>
|
||||
<ul>
|
||||
<li><code>cargo-web</code>
|
||||
</li>
|
||||
<li><code>wasm-bindgen</code>
|
||||
</li>
|
||||
<li><code>wasm-pack</code>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">サポートされているターゲット</td>
|
||||
<td style="text-align:left">
|
||||
<ul>
|
||||
<li><code>wasm32-unknown-unknown</code>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td style="text-align:left">
|
||||
<ul>
|
||||
<li><code>wasm32-unknown-unknown</code>
|
||||
</li>
|
||||
<li><code>wasm32-unknown-emscripten</code>
|
||||
</li>
|
||||
<li><code>asmjs-unknown-emscripten</code>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@ -0,0 +1,15 @@
|
||||
---
|
||||
title: Examples
|
||||
---
|
||||
|
||||
Yewのリポジトリは[例](https://github.com/yewstack/yew/tree/v0.17/examples)がたくさんあります
|
||||
\(メンテナンス状況は様々\)。
|
||||
様々なフレームワークの機能の使い方を知るのにはそれらの例に取り組むのを勧めます。
|
||||
プルリクエストやIssueはウェルカムです。
|
||||
|
||||
* [**Todoアプリ** ](https://github.com/yewstack/yew/tree/v0.17/examples/todomvc)
|
||||
* [**カスタムコンポーネント**](https://github.com/yewstack/yew/tree/v0.17/examples/custom_components)
|
||||
* [**マルチスレッド\(エージェント\)**](https://github.com/yewstack/yew/tree/v0.17/examples/multi_thread)
|
||||
* [**タイマーサービス**](https://github.com/yewstack/yew/tree/v0.17/examples/timer)
|
||||
* [**ネストしたコンポーネント**](https://github.com/yewstack/yew/tree/v0.16.0/examples/nested_list)
|
||||
|
||||
@ -0,0 +1,142 @@
|
||||
---
|
||||
title: Introduction
|
||||
description: Set yourself up for success
|
||||
---
|
||||
|
||||
# 始める
|
||||
|
||||
## Rust
|
||||
|
||||
まずはじめにRustが必要です。Rustとビルドツールの`cargo`をインストールするために、以下の[公式サイト](https://www.rust-lang.org/tools/install)
|
||||
を見てください。
|
||||
|
||||
## **Wasm ビルドツール**
|
||||
|
||||
WebAssemblyとJavaScriptの互換を持たせるために他にツールが必要です。さらに、選んだツールに応じてブラウザでアプリから`.wasm`ファイルを実行するのに
|
||||
必要なJavaScriptラッパーのコードを生成し、これによってデプロイやパッケージ化での頭痛の種を軽減させるのに役立ちます。
|
||||
|
||||
### [**`wasm-pack`**](https://rustwasm.github.io/docs/wasm-pack/)
|
||||
|
||||
Rust / Wasm活動チームによって開発されているCLIツールで、WebAssemblyをパッケージ化することができます。
|
||||
Webpackには[`wasm-pack-plugin`](https://github.com/wasm-tool/wasm-pack-plugin)が最もよく使われています。
|
||||
|
||||
[`wasm-pack`で始める](project-setup/using-wasm-pack.md)
|
||||
|
||||
### [**`wasm-bindgen`**](https://rustwasm.github.io/docs/wasm-bindgen/)
|
||||
|
||||
Rust/Wasm活動チームによって開発されているライブラリとCLIツールで、JS / WebAssemblyの互換性を持たせるための低レベルなツールです
|
||||
(`wasm-pack`で内部的に使われています)。
|
||||
`wasm-bindgen`は手書きのJavaScriptでWebAssemblyのバイナリを使う必要があるため、直接使うのは非推奨です。
|
||||
しかし、詳細な情報については[**`wasm-bindgen` ガイド**](https://rustwasm.github.io/docs/wasm-bindgen/)から得られます。
|
||||
|
||||
[`wasm-bindgen`で始める。](project-setup/using-wasm-bindgen.md)
|
||||
|
||||
### [**`cargo-web`**](https://github.com/koute/cargo-web)
|
||||
|
||||
`wasm-pack`と`wasm-bindgen`を導入する前は好まれたWebワークフローツールです。
|
||||
`wasm-pack`がサポートされていないサンプルを動かすのにインストールする価値があり、依然として**最もお手軽に**始められる方法です。
|
||||
|
||||
[`cargo web`で始める](project-setup/using-cargo-web.md)
|
||||
|
||||
### 比較
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="text-align:left"></th>
|
||||
<th style="text-align:left"><code>wasm-pack</code>
|
||||
</th>
|
||||
<th style="text-align:left"><code>wasm-bindgen</code>
|
||||
</th>
|
||||
<th style="text-align:left"><code>cargo-web</code>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="text-align:left">プロジェクトの進行状況</td>
|
||||
<td style="text-align:left"><a href="https://rustwasm.github.io/">Rust / Wasm活動チーム</a>により活発にメンテナンス
|
||||
</td>
|
||||
<td style="text-align:left"><a href="https://rustwasm.github.io/">Rust / Wasm 活動チーム</a>により活発にメンテナンス
|
||||
</td>
|
||||
<td style="text-align:left">6ヶ月間GitHubでの活発な活動無し</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">開発体験</td>
|
||||
<td style="text-align:left">ほぼ大丈夫! <code>webpack</code>があればなお良い。</td>
|
||||
<td
|
||||
style="text-align:left">だいたい大丈夫。開発においては少し流れを書かないといけない。</td>
|
||||
<td style="text-align:left">しっかり動く!完結していて、外部ライブラリに頼る必要無し。</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">ローカルサーバー</td>
|
||||
<td style="text-align:left"><code>webpack</code>プラグインによるサポートあり</td>
|
||||
<td style="text-align:left">サポート無し</td>
|
||||
<td style="text-align:left">サポートあり</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">ローカル環境での変更による自動再ビルド</td>
|
||||
<td style="text-align:left"><code>webpack</code>プラグインによるサポートあり</td>
|
||||
<td style="text-align:left">サポート無し</td>
|
||||
<td style="text-align:left">サポートあり</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">ヘッドレスブラウザテスト</td>
|
||||
<td style="text-align:left"><a href="https://rustwasm.github.io/docs/wasm-pack/commands/test.html">サポートあり</a>
|
||||
</td>
|
||||
<td style="text-align:left"><a href="https://rustwasm.github.io/docs/wasm-bindgen/wasm-bindgen-test/index.html">サポートあり</a>
|
||||
</td>
|
||||
<td style="text-align:left"><a href="https://github.com/koute/cargo-web#features">サポートあり</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">サポートされているターゲット</td>
|
||||
<td style="text-align:left">
|
||||
<ul>
|
||||
<li><code>wasm32-unknown-unknown</code>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td style="text-align:left">
|
||||
<ul>
|
||||
<li><code>wasm32-unknown-unknown</code>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td style="text-align:left">
|
||||
<ul>
|
||||
<li><code>wasm32-unknown-unknown</code>
|
||||
</li>
|
||||
<li><code>wasm32-unknown-emscripten</code>
|
||||
</li>
|
||||
<li><code>asmjs-unknown-emscripten</code>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left"><code>web-sys</code></td>
|
||||
<td style="text-align:left">互換性あり</td>
|
||||
<td style="text-align:left">互換性あり</td>
|
||||
<td style="text-align:left">互換性無し</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left"><code>stdweb</code></td>
|
||||
<td style="text-align:left">互換性あり</td>
|
||||
<td style="text-align:left">互換性あり</td>
|
||||
<td style="text-align:left">互換性あり</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">使用例</td>
|
||||
<td style="text-align:left"><a href="https://github.com/yewstack/yew-wasm-pack-minimal">入門用テンプレート</a>
|
||||
</td>
|
||||
<td style="text-align:left">
|
||||
Yewで<a href="https://github.com/yewstack/yew/blob/master/examples/build.sh">作る例</a>
|
||||
</td>
|
||||
<td style="text-align:left">
|
||||
Yewで<a href="https://www.github.com/yewstack/yew/tree/master/yew-stdweb/examples">作る例</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
---
|
||||
title: Using cargo-web
|
||||
---
|
||||
|
||||
Cargo webはクライアントWebアプリを作るためのCargoサブコマンドです。
|
||||
これによりWebアプリのビルドとデプロイを驚くほど簡単にできます。
|
||||
そして同時にEmscriptenがターゲットなのを唯一サポートしているツールチェーンです。
|
||||
詳しくは[こちら](https://github.com/koute/cargo-web)。
|
||||
|
||||
**インストール**
|
||||
|
||||
```bash
|
||||
cargo install cargo-web
|
||||
```
|
||||
|
||||
## ビルド
|
||||
|
||||
```bash
|
||||
cargo web build
|
||||
```
|
||||
|
||||
## 動かす
|
||||
|
||||
```bash
|
||||
cargo web start
|
||||
```
|
||||
|
||||
## サポートされているターゲット
|
||||
|
||||
* `wasm32-unknown-unknown`
|
||||
* `wasm32-unknown-emscripten`
|
||||
* `asmjs-unknown-emscripten`
|
||||
|
||||
:::注意
|
||||
`*-emscripten`をターゲットにする場合、Emscripten SDKをインストールする必要があります。
|
||||
:::
|
||||
@ -0,0 +1,51 @@
|
||||
---
|
||||
title: Using wasm-bindgen
|
||||
---
|
||||
|
||||
## インストール
|
||||
|
||||
```bash
|
||||
cargo install wasm-bindgen-cli
|
||||
```
|
||||
|
||||
## ビルド
|
||||
|
||||
はじめに、Wasmファイルを生成するアプリをビルドしましょう。
|
||||
[サンプルアプリをビルド](../build-a-sample-app.md)のアプリをビルドしたいとします。
|
||||
生成されたファイルのパスは`target/wasm32-unknown-unknown/debug/yew-app.wasm`にあるはずです。
|
||||
もしクレートに何か別の名前をつけた場合、Wasmファイルの名前は`yew-app.wasm`ではなく、`Cargo.toml`ファイルに
|
||||
`package.name`として名前をつけたものになるでしょう。
|
||||
|
||||
```bash
|
||||
cargo build --target wasm32-unknown-unknown
|
||||
```
|
||||
|
||||
次に、wasm-bindgenのCLIを動かしましょう。
|
||||
このコマンドは`--out-dir`のディレクトリにいくつかのファイルを生成し、その中にはWasmバイナリを読み込んで動かすための
|
||||
コンパイルされたWebAssemblyとJavaScriptのラッパーが入っています。
|
||||
現在のブラウザは直接WebAssemblyファイルを読み込むことができないため、代わりにJavaScript経由で読み込まれるなければならず、
|
||||
そのためにこれらのラッパーが必要となります。
|
||||
[サンプルアプリを作る(../build-a-sample-app.md)の例では`static`フォルダにファイルが生成されるようにしており
|
||||
(そのために`wasm-bindgen`へ`--out-dir static`と渡す必要があります)、
|
||||
`wasm.js`と`wasm_bg.wasm`という名前になります(`wasm-bindgen`へ`--out-name wasm`と渡すことで実現できます)
|
||||
|
||||
```bash
|
||||
wasm-bindgen --target web --out-dir static --out-name wasm target/wasm32-unknown-unknown/debug/appname.wasm --no-typescript
|
||||
```
|
||||
|
||||
## アプリをサーブする
|
||||
|
||||
好きなサーバーを使ってください。
|
||||
ここではシンプルなPythonのサーバーを使います。
|
||||
|
||||
```bash
|
||||
python -m http.server 8000
|
||||
```
|
||||
|
||||
## サポートされているターゲット
|
||||
|
||||
* `wasm32-unknown-unknown`
|
||||
|
||||
## 参考ドキュメント
|
||||
|
||||
* [The `wasm-bindgen` docs](https://rustwasm.github.io/docs/wasm-bindgen/)
|
||||
@ -0,0 +1,49 @@
|
||||
---
|
||||
title: Using wasm-pack
|
||||
---
|
||||
|
||||
このツールはRust / Wasm活動チームによって開発され、WebAssemblyのアプリを作るのに使われれるツールで最も活発に開発されているものです。
|
||||
コードを`npm`モジュールへパッケージ化するのをサポートし、既存のJavaScriptのアプリと簡単に統合できる
|
||||
[Webpack plugin](https://github.com/wasm-tool/wasm-pack-plugin)がついています。
|
||||
詳しい情報は[the `wasm-pack` documentation](https://rustwasm.github.io/docs/wasm-pack/introduction.html)にあります。
|
||||
|
||||
:::注意
|
||||
`wasm-pack`を使う際は`Cargo.toml`のcrate-typeは`cdylib`である必要があります。
|
||||
:::
|
||||
|
||||
## インストール
|
||||
|
||||
```bash
|
||||
cargo install wasm-pack
|
||||
```
|
||||
|
||||
## ビルド
|
||||
|
||||
このコマンドはJavaScriptラッパーとアプリのWebAssemblyをまとめたものを`./pkg`ディレクトリに生成し、アプリをスタートすることができます。
|
||||
This command will produce a bundle in the `./pkg` directory with your app's compiled WebAssembly
|
||||
along with a JavaScript wrapper which can be used to start your application.
|
||||
|
||||
```bash
|
||||
wasm-pack build --target web
|
||||
```
|
||||
|
||||
## バンドル
|
||||
|
||||
ロールアップにについては詳しくは[ガイド](https://rollupjs.org/guide/en/#quick-start)をご覧ください。
|
||||
|
||||
```bash
|
||||
rollup ./main.js --format iife --file ./pkg/bundle.js
|
||||
```
|
||||
|
||||
## サーブ
|
||||
|
||||
好きなサーバーを使ってください。
|
||||
ここではシンプルなPythonのサーバーを使ってアプリをサーブします。
|
||||
|
||||
```bash
|
||||
python -m http.server 8000
|
||||
```
|
||||
|
||||
## サポートされているターゲット
|
||||
|
||||
* `wasm32-unknown-unknown`
|
||||
@ -0,0 +1,42 @@
|
||||
---
|
||||
title: Starter templates
|
||||
---
|
||||
|
||||
## `wasm-pack`
|
||||
|
||||
* [ミニマルテンプレート](https://github.com/yewstack/yew-wasm-pack-minimal) - アプリをビルドするのに `wasm-pack`と
|
||||
|
||||
`rollup`を使い、サーバーはアプリをサーブします. ベルや笛はここにはありません。
|
||||
|
||||
* [Webpackテンプレート](https://github.com/yewstack/yew-wasm-pack-template) - `wasm-pack`と
|
||||
|
||||
[`wasm-pack-plugin`](https://github.com/wasm-tool/wasm-pack-plugin)を使い、Webpackが開発を滑らかにします。
|
||||
|
||||
これらのテンプレートを使うのと`cargo-web`を使用するのと重要な違いは、このアプローチは`bin`クレートではなく`lib`クレートを用いて
|
||||
`#[wasm_bindgen]`によってエントリーポイントを指定できる点です。
|
||||
|
||||
また、`Cargo.toml`はクレートの種類が"cdylib"であると特定できるようにしましょう。
|
||||
|
||||
```text title="Cargo.toml"
|
||||
[package]
|
||||
name = "yew-app"
|
||||
version = "0.1.0"
|
||||
authors = ["Yew App Developer <name@example.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
# for web_sys
|
||||
yew = "0.17"
|
||||
# or for stdweb
|
||||
# yew = { version = "0.17", package = "yew-stdweb" }
|
||||
wasm-bindgen = "0.2"
|
||||
```
|
||||
|
||||
## その他のテンプレート
|
||||
|
||||
* [Parcel Template](https://github.com/spielrs/yew-parcel-template) - コミュニティのメンバーによって開発され、
|
||||
Parcel](https://parceljs.org/)を使っています。
|
||||
|
||||
64
website/translated_docs/ja/version-0.17.3/intro.md
Normal file
64
website/translated_docs/ja/version-0.17.3/intro.md
Normal file
@ -0,0 +1,64 @@
|
||||
---
|
||||
title: Introduction
|
||||
---
|
||||
|
||||
## Yewとは?
|
||||
|
||||
**Yew** は [WebAssembly](https://webassembly.org/) によってマルチスレッドなWebアプリのフロントエンドを作ることができる、モダンな [Rust](https://www.rust-lang.org/) のフレームワークです。
|
||||
|
||||
* インタラクティブなUIを簡単に作ることができる、**コンポーネントベース** のフレームワークです. [React](https://reactjs.org/) や [Elm](https://elm-lang.org/) のようなフレームワークを使用したことがある開発者はYewを違和感なく使うことができるでしょう。
|
||||
* DOMのAPIを呼び出すのを最小化し、開発者がWebワーカーによって簡単に処理を軽量化できることで **素晴らしいパフォーマンス** を発揮します。
|
||||
* **JavaScriptとの互換性** をサポートし、開発者はnpmのパッケージを活用し既存のJavaScriptアプリと統合させることができます。
|
||||
|
||||
### コミュニティに参加する 😊
|
||||
|
||||
* [GitHub issues page](https://github.com/yewstack/yew/issues) でバグを報告したり機能について議論できます。
|
||||
* プルリクエストはぜひウェルカムです。ご協力いただけるなら [good first issues](https://github.com/yewstack/yew/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) をご確認ください。
|
||||
* 私たちの [Discord chat](https://discord.gg/VQck8X4) はとても活発で質問するのに良い場所です。
|
||||
|
||||
### 始める準備はいいですか?
|
||||
|
||||
以下のリンクをクリックして初めてのYewアプリの作り方を学び、コミュニティのプロジェクト例を見てみましょう。
|
||||
|
||||
[始める](getting-started/project-setup.md)
|
||||
|
||||
### まだ満足していませんか?
|
||||
|
||||
このプロジェクトは先進的な技術によって成り立っており、これからの基礎となるプロジェクトを作っていきたい開発者にとっては素晴らしいものです。
|
||||
ここではYewのようなフレームワークがどうしてWeb開発における未来となると考えられるかについての理由を述べていきます。
|
||||
|
||||
#### 待って、どうしてWebAssembly?
|
||||
|
||||
WebAssembly _\(Wasm\)_ はRustがコンパイル可能な軽量で低レベルな言語です。
|
||||
WebAssemblyはブラウザでネイティブ並の速度で動き、JavaScriptと互換性があり、そして全ての主要なブラウザでサポートされています。
|
||||
アプリでWebAssemblyをどう使いこなすかについては [use cases](https://webassembly.org/docs/use-cases/) のリストをご確認ください。
|
||||
|
||||
気をつけなければいけないこととして、Wasmは\(まだ\)Webアプリのパフォーマンスを改善する銀の弾丸ではありません。
|
||||
現時点では、DOMのAPIをWebAssemblyから使うのはまだJavaScriptから直接呼ぶよりも遅いのです。
|
||||
これは [WebAssembly Interface Types](https://github.com/WebAssembly/interface-types/blob/master/proposals/interface-types/Explainer.md) が解決しようとしている今のところの課題です。
|
||||
詳しい情報についてはMozillaの提案が書いてある [excellent article](https://hacks.mozilla.org/2019/08/webassembly-interface-types/)
|
||||
をご確認ください。
|
||||
|
||||
#### わかった、でもどうしてRust?
|
||||
|
||||
Rustは目まぐるしいほど高速に動作し、素晴らしい型と所有権モデルによって信頼性があります。
|
||||
Rustには厳しい学習曲線がありますが、努力するだけの十分な価値があります。
|
||||
RustはStack OverFlowによる開発者調査で5年連続で最も愛されている言語に選ばれています:
|
||||
[2016](https://insights.stackoverflow.com/survey/2016#technology-most-loved-dreaded-and-wanted),
|
||||
[2017](https://insights.stackoverflow.com/survey/2017#most-loved-dreaded-and-wanted),
|
||||
[2018](https://insights.stackoverflow.com/survey/2018#technology-_-most-loved-dreaded-and-wanted-languages),
|
||||
[2019](https://insights.stackoverflow.com/survey/2019#technology-_-most-loved-dreaded-and-wanted-languages),
|
||||
[2020](https://insights.stackoverflow.com/survey/2020#most-loved-dreaded-and-wanted).
|
||||
|
||||
同時にRustは素晴らしい型システムと所有権モデルによって開発者がより安全なコードを書くようサポートしてくれます。
|
||||
JavaScriptでの追跡するのが難しいバグよ、さよなら!
|
||||
実際にRustではコードを走らせるまでもなくコンパイラによってバグのほとんどは捕捉されます。
|
||||
そして心配することなかれ、アプリを走らせてエラーになったとしてもブラウザのコンソールでRustのコードを完全に追跡することができます。
|
||||
|
||||
#### 代わりは?
|
||||
|
||||
私たちは喜んで他のプロジェクトのアイデアを共有し、このワクワクする新たな技術のあらゆる可能性を実現できるよう皆が互いに助け合えると信じています。
|
||||
もしYewがグッとこない場合は以下のプロジェクトがいいかもしれません。
|
||||
|
||||
* [Percy](https://github.com/chinedufn/percy) - _"RustとWebAssemblyで同一なWebアプリを作る組み立てツール"_
|
||||
* [Seed](https://github.com/seed-rs/seed) - _"Webアプリを作るためのRustフレームワーク"_
|
||||
18
website/translated_docs/ja/version-0.17.3/more/css.md
Normal file
18
website/translated_docs/ja/version-0.17.3/more/css.md
Normal file
@ -0,0 +1,18 @@
|
||||
---
|
||||
title: CSS
|
||||
---
|
||||
|
||||
# CSS
|
||||
|
||||
<TODO>
|
||||
|
||||
統合的なCSSサポートについての提案はこちらにあります: [https://github.com/yewstack/yew/issues/533](https://github.com/yewstack/yew/issues/533)
|
||||
|
||||
## スタイルフレームワーク:
|
||||
|
||||
今のところ、コミュニティメンバーは以下のスタイルフレームワークを開発しています。
|
||||
|
||||
* [yew_styles](https://github.com/spielrs/yew_styles) - JavaScriptに依存しないYewのスタイルフレームワーク
|
||||
* [yew-mdc](https://github.com/Follpvosten/yew-mdc) - マテリアルデザインのコンポーネント
|
||||
* [muicss-yew](https://github.com/AlephAlpha/muicss-yew) - MUIのCSSコンポーネント
|
||||
* [Yewtify](https://github.com/yewstack/yewtify) – YewでVuetifyフレームワークで提供されている機能の実装
|
||||
58
website/translated_docs/ja/version-0.17.3/more/debugging.md
Normal file
58
website/translated_docs/ja/version-0.17.3/more/debugging.md
Normal file
@ -0,0 +1,58 @@
|
||||
---
|
||||
title: Debugging
|
||||
---
|
||||
|
||||
# デバッグ
|
||||
|
||||
## パニック
|
||||
|
||||
Rustシンボルで良いスタックトレースをするには
|
||||
[`console_error_panic`](https://github.com/rustwasm/console_error_panic_hook)クレートを使用してください。
|
||||
注意として、`cargo-web`でビルドされたものとは互換性がありません。
|
||||
|
||||
## コンソールでのログ
|
||||
|
||||
一般的に、WasmのWebアプリはブラウザのAPIと連携することができ、`console.log`のAPIも例外ではありません。
|
||||
いつくかの選択肢があります:
|
||||
|
||||
### [`wasm-logger`](https://crates.io/crates/wasm-logger)
|
||||
|
||||
このクレートはRustの`log`クレートと親和性があります。
|
||||
|
||||
```rust
|
||||
// セットアップ
|
||||
fn main() {
|
||||
wasm_logger::init(wasm_logger::Config::default());
|
||||
}
|
||||
|
||||
// 使用方法
|
||||
log::info!("Update: {:?}", msg);
|
||||
```
|
||||
|
||||
### [`ConsoleService`](https://docs.rs/yew/latest/yew/services/console/struct.ConsoleService.html)
|
||||
|
||||
このサービスはYewに含まれており、`"services"`の機能が有効化されている場合は利用可能です。
|
||||
|
||||
```rust
|
||||
// 使用方法
|
||||
ConsoleService::new()::info(format!("Update: {:?}", msg));
|
||||
```
|
||||
|
||||
## ソースマップ
|
||||
|
||||
今のところはRust/WasmのWebアプリにはソースマップへの第一級のサポートがありません。
|
||||
もちろん、これは変更される可能性があります。これが当てはまらない場合、または進捗が見られる場合は、変更を提案してください!
|
||||
|
||||
### 最新情報
|
||||
|
||||
\[2019年12月\] [Chrome DevTools update](https://developers.google.com/web/updates/2019/12/webassembly#the_future)
|
||||
|
||||
> やらなければいけないことがまだたくさんあります。例えばツール側ではEmscripten\(Binaryen\)とwasm-pack\(wasm-bindgen\)がそれらが実行する変換に関するDWARF情報の更新をまだサポートしていません。
|
||||
|
||||
\[2020\] [Rust Wasm デバッグガイド](https://rustwasm.github.io/book/reference/debugging.html#using-a-debugger)
|
||||
|
||||
> 残念なことに、WebAssemblyのデバッグの物語はまだ未成熟です。ほとんどのUnixのシステムでは[DWARF](http://dwarfstd.org/)は実行中のプログラムをソースレベルで検査するためにデバッガに必要な情報をエンコードするために使用されます。Windowsには同様の情報をエンコードする代替形式があります。現在、WebAssemblyに相当するものはありません。
|
||||
|
||||
\[2019\] [Rust Wasm ロードマップ](https://rustwasm.github.io/rfcs/007-2019-roadmap.html#debugging)
|
||||
|
||||
> デバッグはトリッキーです。なぜなら、多くの話はこの活動チームの手の届かないところにあり、WebAssembly の標準化団体とブラウザ開発者ツールを実装している人たちの両方に依存しているからです。
|
||||
@ -0,0 +1,27 @@
|
||||
---
|
||||
title: External libraries
|
||||
description: Libraries that can help with yew development
|
||||
---
|
||||
|
||||
# 外部ライブラリ
|
||||
|
||||
### Yewtil
|
||||
|
||||
YewtilはYewのプログラムを書きやすくするユーティリティ集です。
|
||||
含まれているのは:
|
||||
|
||||
* NeqAssign - 先述の通り、再レンダリングを最小化するようpropsを割り当てる方法です
|
||||
* PureComponents - 状態を更新しないコンポーネント。NeqAssignを使用するとマクロの中から通常のコンポーネントのように呼び出される関数がメモ化されます。
|
||||
|
||||
* Lrc - リンクされたリストは、`Rc`のようにカウントされたスマートポインタ関数を参照しますが、新しいデータ更新パターンを可能にします。
|
||||
* Mrc/Irc - Mutable/Immutable 参照カウントのスマートポインタは `Rc` のように機能しますが、`Mrc` に対して `DerefMut` と `BorrowMut` を実装しているため、Yew の中でより使いやすくなっています。これにより、`Mrc` を `NeqAssign` と一緒に使うことができます。`Irc` はデータに対する不変のビューとして機能するので、表示のみのタスクで使用されるデータを保持するのに理想的です。
|
||||
|
||||
* History - `VecDeque` を用いて、表示した過去の値を保持する履歴追跡ラッパーです。
|
||||
* Futures - コンポーネントの更新ループにメッセージを送信するのをサポートします。
|
||||
* Fetch - `web_sys` と前述のfuturesの機能を用いたフェッチリクエストを処理するための抽象化です。
|
||||
|
||||
## お探しのものは
|
||||
|
||||
エコシステムが必要なライブラリですが、まだありません。
|
||||
|
||||
Bootstrap/MaterialUi/arbitraryといったCSSフレームワークのコンポーネントのラッパー。
|
||||
46
website/translated_docs/ja/version-0.17.3/more/roadmap.md
Normal file
46
website/translated_docs/ja/version-0.17.3/more/roadmap.md
Normal file
@ -0,0 +1,46 @@
|
||||
---
|
||||
title: Roadmap
|
||||
description: The planned feature roadmap for the Yew framework
|
||||
---
|
||||
|
||||
# ロードマップ
|
||||
|
||||
## 優先順位
|
||||
|
||||
フレームワークの今後の機能やフォーカスの優先順位は、コミュニティによって決定されます。2020年の春には、プロジェクトの方向性についてのフィードバックを集めるために開発者アンケートが行われました。その概要は [Yew Wiki](https://github.com/yewstack/yew/wiki/Dev-Survey-%5BSpring-2020%5D) で見ることができます。
|
||||
|
||||
:::note
|
||||
主要な取り組みの状況は、YewのGithubの[Project board](https://github.com/yewstack/yew/projects)で確認できます。
|
||||
:::
|
||||
|
||||
## 焦点
|
||||
|
||||
1. Top Requested Features
|
||||
2. Production Readiness
|
||||
3. Documentation
|
||||
4. Pain Points
|
||||
|
||||
### Top Requested Features
|
||||
|
||||
1. [関数型コンポーネント](https://github.com/yewstack/yew/projects/3)
|
||||
2. [Componentライブラリ](https://github.com/yewstack/yew/projects/4)
|
||||
3. より良い状態管理
|
||||
4. [サーバーサイドでのレンダリング](https://github.com/yewstack/yew/projects/5)
|
||||
|
||||
### Production Readiness
|
||||
|
||||
* テストカバレッジの向上
|
||||
* バイナリサイズ
|
||||
* [ベンチマークのパフォーマンス](https://github.com/yewstack/yew/issues/5)
|
||||
|
||||
### Documentation
|
||||
|
||||
* チュートリアルを作る
|
||||
* プロジェクトのセットアップをシンプルにする
|
||||
|
||||
### Pain Points
|
||||
|
||||
* [Componentのボイラープレート](https://github.com/yewstack/yew/issues/830)
|
||||
* Fetch API
|
||||
* [エージェント](https://github.com/yewstack/yew/projects/6)
|
||||
|
||||
12
website/translated_docs/ja/version-0.17.3/more/testing.md
Normal file
12
website/translated_docs/ja/version-0.17.3/more/testing.md
Normal file
@ -0,0 +1,12 @@
|
||||
---
|
||||
title: Testing apps
|
||||
description: Testing your app
|
||||
---
|
||||
|
||||
# Testing
|
||||
|
||||
<TODO>
|
||||
|
||||
## wasm\_bindgen\_test
|
||||
|
||||
Rust Wasm ワーキンググループは wasm_bindgen_test というフレームワークをメンテナンスしており、組み込みの #[test] プロシージャルマクロの動作と同様の方法でブラウザでテストを実行することができます。詳細は、[Rust WASM 活動グループのドキュメント](https://rustwasm.github.io/docs/wasm-bindgen/wasm-bindgen-test/index.html)に記載されています。
|
||||
44
website/translated_docs/zh-CN/version-0.17.3/SUMMARY.md
Normal file
44
website/translated_docs/zh-CN/version-0.17.3/SUMMARY.md
Normal file
@ -0,0 +1,44 @@
|
||||
# Table of contents
|
||||
|
||||
* [简介](README.md)
|
||||
|
||||
## 从零开始 <a id="getting-started"></a>
|
||||
|
||||
* [项目设置](getting-started/project-setup.md)
|
||||
* [使用 wasm-pack](getting-started/project-setup/using-wasm-pack.md)
|
||||
* [使用 wasm-bindgen](getting-started/project-setup/using-wasm-bindgen.md)
|
||||
* [使用 cargo-web](getting-started/project-setup/using-cargo-web.md)
|
||||
* [新手模板](getting-started/starter-templates.md)
|
||||
* [第一个简单的 App](getting-started/build-a-sample-app.md)
|
||||
* [选择 web-sys 还是 stdweb](getting-started/choose-web-library.md)
|
||||
* [通过例子学习](getting-started/examples.md)
|
||||
|
||||
## 核心概念 <a id="concepts"></a>
|
||||
|
||||
* [使用 html! 宏](concepts/html.md)
|
||||
* [列表](concepts/html/lists.md)
|
||||
* [元素](concepts/html/elements.md)
|
||||
* [常量和表达式](concepts/html/literals-and-expressions.md)
|
||||
* [组件](concepts/html/components.md)
|
||||
* [组件(Components)](concepts/components.md)
|
||||
* [属性(Properties)](concepts/components/properties.md)
|
||||
* [回调(Callbacks)](concepts/components/callbacks.md)
|
||||
* [Refs](concepts/components/refs.md)
|
||||
* [Agents](concepts/agents.md)
|
||||
* [Services](concepts/services.md)
|
||||
* [Format](concepts/services/format.md)
|
||||
* [Router](concepts/router.md)
|
||||
|
||||
## 高级主题 <a id="advanced-topics"></a>
|
||||
|
||||
* [性能优化与最佳实践](advanced-topics/optimizations.md)
|
||||
* [底层库的内部细节](advanced-topics/how-it-works.md)
|
||||
|
||||
## 更多 <a id="more"></a>
|
||||
|
||||
* [CSS](more/css.md)
|
||||
* [路线图](more/roadmap.md)
|
||||
* [测试](more/testing.md)
|
||||
* [Debugging](more/debugging.md)
|
||||
* [外部库](more/external-libs.md)
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
---
|
||||
description: 有关框架的底层细节
|
||||
---
|
||||
|
||||
# 底层库的内部细节
|
||||
|
||||
组件生命周期状态机,虚拟 dom diff 算法。
|
||||
|
||||
@ -0,0 +1,104 @@
|
||||
---
|
||||
description: 加速你的应用程序
|
||||
---
|
||||
|
||||
# 性能优化与最佳实践
|
||||
|
||||
## neq\_assign
|
||||
|
||||
当组件从它的父组件接收 props 时,`change` 方法将被调用。除了允许你更新组件的状态,还允许你返回一个布尔类型的值 `ShouldRender` 来指示组件是否应该响应 props 的更改而重新渲染自身。
|
||||
|
||||
重新渲染的开销很大,你应该尽量避免。一个通用的法则是,你只应该在 props 实际更改时重新渲染。以下代码块展示了此法则,如果 props 和先前的 props 不同,则返回 `true`:
|
||||
|
||||
```rust
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != &props {
|
||||
*self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
但是我们可以更进一步!对于任何实现了 `PartialEq` 的项,可以使用一个 trait 和一个 blanket implementation 将这六行样板代码减少到一行。
|
||||
|
||||
{% code title="neq\_assign.rs" %}
|
||||
```rust
|
||||
pub trait NeqAssign {
|
||||
fn neq_assign(&mut self, new: Self) -> ShouldRender;
|
||||
}
|
||||
impl<T: PartialEq> NeqAssign for T {
|
||||
fn neq_assign(&mut self, new: T) -> ShouldRender {
|
||||
if self != &new {
|
||||
*self = new;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ...
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
self.props.neq_assign(props)
|
||||
}
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
该 trait 称为 `NeqAssign` 是因为如果目标值和新值不相等,它将赋为新值。
|
||||
|
||||
这比简单的实现还要短:
|
||||
|
||||
```rust
|
||||
// 不要这样做,除非你无法避免。
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
self.props = props;
|
||||
true
|
||||
}
|
||||
```
|
||||
|
||||
你不仅限在 `change` 函数中使用它。通常,在 `update` 函数中执行此操作也是有意义的,尽管性能提升在那里不太明显。
|
||||
|
||||
## wee\_alloc
|
||||
|
||||
[wee\_alloc](https://github.com/rustwasm/wee_alloc) 是一个比 Rust 二进制文件中通常使用的分配器还小得多的微型分配器。用这个分配器来替代默认的分配器将使 WASM 文件体积更小,但会牺牲速度和内存开销。
|
||||
|
||||
对比不包含默认分配器换取的体积大小,牺牲的速度和内存开销是微不足道的。较小的文件体积意味着你的页面将加载更快,因此通常建议使用此分配器而不是默认分配器,除非你的应用程序会执行一些繁重的内存分配任务。
|
||||
|
||||
```rust
|
||||
// 将 `wee_alloc` 作为全局分配器
|
||||
#[global_allocator]
|
||||
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
|
||||
```
|
||||
|
||||
## RC
|
||||
|
||||
为了避免在重新渲染时为了创建 props 而克隆大块数据,我们可以使用智能指针来只克隆指针。如果在 props 和子组件中使用 `Rc<_>` 而不是普通未装箱的值,则可以延迟克隆直到需要修改子组件中的数据为止,在该组件中可以使用 `Rc::make_mut` 来对要更改数据进行克隆和获取可变引用。通过在要修改前不进行克隆,子组件可以在几乎没有性能成本的情况下拒绝与它们在 `Component::change` 中拥有状态的 props 相同的 props,这与数据本身需要先复制到父级 props 结构体中,然后在子级中进行比较和拒绝的情况相反。
|
||||
|
||||
对于不是 `Copy` 类型的数据,这种优化是最有用的。如果你能轻松地拷贝数据,那么将其放入智能指针中可能是不值得的。对于可以包含大量数据的结构,例如 `Vec`,`HashMap` 和 `String`,这种优化应该是值得的。
|
||||
|
||||
如果子组件从不更新组件的值,则这种优化效果最好,如果父组件很少更新组件的值,则效果更好。这使得 `Rc<_>s` 是包装纯组件属性值的不错选择。
|
||||
|
||||
## 视图函数
|
||||
|
||||
出于代码可读性的原因,将 `html!` 各个部分的代码迁移到他们自己的函数中通常是有意义的,这样就可以避免在深层嵌套的 HTML 中出现代码块向右偏移。
|
||||
|
||||
## 纯组件 / 函数式组件
|
||||
|
||||
纯组件是不会修改它们状态的组件,它们仅展示内容和向普通可变组件传递消息。它们与视图函数不同之处在于他们可以使用组件语法(`<SomePureComponent />`)而不是表达式语法(`{some_view_function()}`)来在 `html!` 宏中使用,并且根据它们的实现,它们可以被记忆化 - 使用前面提到的 `neq_assign` 逻辑来防止因为相同的 props 而重新渲染。
|
||||
|
||||
Yew 没有原生支持纯组件或者函数式组件,但是可以通过外部库获取它们。
|
||||
|
||||
函数式组件尚不存在,但是从理论上来讲,可以通过使用 proc 宏和标注函数生成纯组件。
|
||||
|
||||
## Keyed DOM nodes when they arrive
|
||||
|
||||
## 使用 Cargo Workspaces 进行编译速度优化
|
||||
|
||||
可以说,使用 Yew 的最大缺点是编译时间长。编译时间似乎与 `html!` 宏块中的代码量相关。对于较小的项目,这通常不是什么大问题,但是对于跨多个页面的 web 应用程序,将代码拆分为多个 crates 以最大程度地减少编译器要做的工作通常是有意义的。
|
||||
|
||||
你应该尝试让主 crate 处理路由和页面选择,将所有公用的代码移动到另一个 crate,然后为每一个页面创建一个不同的 crate,其中每个页面可能是一个不同的组件,或者只是一个产生 `Html` 的大函数。在最好的情况下,你将从重新构建所有代码到只重新构建主 crate 和一个页面的 crate。在最糟糕的情况下,当你在“公共” crate 中编辑内容时,你将回到起点:编译所有依赖此公用 crate 的代码,这可能就是除此之外的所有代码。
|
||||
|
||||
如果你的主 crate 过于庞大,或者你想在深层嵌套的页面(例如,在另一个页面顶部渲染的页面)中快速迭代,则可以使用一个示例 crate 创建一个更简单的主页面实现并在之上渲染你正在开发的组件。
|
||||
|
||||
@ -0,0 +1,41 @@
|
||||
---
|
||||
title: Agents
|
||||
description: Yew 的 Actor 系统
|
||||
---
|
||||
|
||||
Agents 和 Angular 的 [Services](https://angular.io/guide/architecture-services) 相似(但没有依赖注入),给 Yew 提供了 [Actor 模型](https://en.wikipedia.org/wiki/Actor_model)。Agents 可以用于在组件之间路由消息,而与它们在组件层次结构中的位置无关,或者可以用于协调全局状态,或者可以用于从主 UI 线程上卸载计算密集型任务,或者在不同的标签页间通信(在未来)。
|
||||
|
||||
Agents 使用 [web-workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers) 同时运行来实现并发。
|
||||
|
||||
## 生命周期
|
||||
|
||||

|
||||
|
||||
## Agents 的类型
|
||||
|
||||
#### Reaches
|
||||
|
||||
* Job - 在 UI 线程上为每个新的 Bridge 生成一个新的 Agent。这对于将与浏览器通信的共享但独立的行为移出组件是很有用的。(待验证)任务完成后,Agent 将消失。
|
||||
* Context - Bridges 将生成或连接到 UI 线程上的 agent。这可用于在组件和其它 Agents 之间协调状态。当没有 Bridge 连接到该 Agent 时,Agent 将消失。
|
||||
* Private - 与 Job 相同,但运行在自己的 web worker 中。
|
||||
* Public - 与 Context 相同,但运行在自己的 web worker 中。
|
||||
* Global \(WIP\)
|
||||
|
||||
## Agent 通信
|
||||
|
||||
### Bridges
|
||||
|
||||
Bridges 将连接到一个 Agent 并且允许双向通信。
|
||||
|
||||
### Dispatchers
|
||||
|
||||
Dispatchers 和 Bridges 类似,但是他们只能发送消息给 Agents。
|
||||
|
||||
## 开销
|
||||
|
||||
Agents 通过使用二进制码 bincode 序列化其消息来进行通信。因此,存在比仅调用函数相比更高的性能消耗。除非计算成本或者在任意组件间协调的需求超过消息传递的成本,否则你应该尽可能地在函数中包含你的应用逻辑。
|
||||
|
||||
## Further reading
|
||||
|
||||
* The [pub\_sub](https://github.com/yewstack/yew/tree/master/examples/pub_sub) example shows how components can use agents to communicate with each other.
|
||||
|
||||
@ -0,0 +1,171 @@
|
||||
---
|
||||
description: 组件及其生命周期钩子
|
||||
---
|
||||
|
||||
# 组件(Components)
|
||||
|
||||
## 组件是什么?
|
||||
|
||||
组件是 Yew 的基石。它们管理自己的状态,并可以渲染为 DOM。组件是通过实现描述组件生命周期的 `Component` trait 来创建的。
|
||||
|
||||
## 生命周期
|
||||
|
||||
:::note
|
||||
`为我们的文档做出贡献:`[添加组件的生命周期图示](https://github.com/yewstack/docs/issues/22)
|
||||
:::
|
||||
|
||||
## 生命周期方法
|
||||
|
||||
### Create
|
||||
|
||||
当一个组件被创建时,它会从其父组件以及一个 `ComponentLink` 接收属性(properties)。属性(properties)可用于初始化组件的状态,“link”可用于注册回调或向组件发送消息。
|
||||
|
||||
通常将 props 和 link 存储在组件的结构体中,如下所示:
|
||||
|
||||
```rust
|
||||
pub struct MyComponent {
|
||||
props: Props,
|
||||
link: ComponentLink<Self>,
|
||||
}
|
||||
|
||||
impl Component for MyComponent {
|
||||
type Properties = Props;
|
||||
// ...
|
||||
|
||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
MyComponent { props, link }
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### View
|
||||
|
||||
组件在 `view()` 方法中声明它的布局。Yew 提供了 `html!` 宏来声明 HTML 和 SVG 节点和它们的监听器及其子组件。这个宏的行为很像 React 中的 JSX,但是使用的是 Rust 表达式而不是 JavaScript。
|
||||
|
||||
```rust
|
||||
impl Component for MyComponent {
|
||||
// ...
|
||||
|
||||
fn view(&self) -> Html {
|
||||
let onclick = self.link.callback(|_| Msg::Click);
|
||||
html! {
|
||||
<button onclick=onclick>{ self.props.button_text }</button>
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
有关用法的详细信息,请查看 [`html!` 宏指南](html.md)]
|
||||
|
||||
### Mounted
|
||||
|
||||
`mounted()` 组件生命周期方法调用是在 `view()` 被处理并且 Yew 已经把组件挂载到 DOM 上之后,浏览器刷新页面之前。组件通常希望实现此方法以执行只能在组件渲染元素之后才能执行的操作。如果你想在做出一些更改后重新渲染组件,返回 `true` 就可以了。
|
||||
|
||||
```rust
|
||||
use stdweb::web::html_element::InputElement;
|
||||
use stdweb::web::IHtmlElement;
|
||||
use yew::prelude::*;
|
||||
|
||||
pub struct MyComponent {
|
||||
node_ref: NodeRef,
|
||||
}
|
||||
|
||||
impl Component for MyComponent {
|
||||
// ...
|
||||
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<input ref=self.node_ref.clone() type="text" />
|
||||
}
|
||||
}
|
||||
|
||||
fn mounted(&mut self) -> ShouldRender {
|
||||
if let Some(input) = self.node_ref.cast::<InputElement>() {
|
||||
input.focus();
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::note
|
||||
请注意,此生命周期方法不要求必须实现,默认情况下不会执行任何操作。
|
||||
:::
|
||||
|
||||
### Update
|
||||
|
||||
组件是动态的,可以注册以接收异步信息。`update()` 生命周期方法对于每个消息都会被调用。这使得组件可以根据消息的内容来更新自身,并决定是否需要重新渲染自己。消息可以由 HTML 元素监听器触发,或者由子组件,Agents,Services 或 Futures 发送。
|
||||
|
||||
`update()` 可能看起来像下面这个例子:
|
||||
|
||||
```rust
|
||||
pub enum Msg {
|
||||
SetInputEnabled(bool)
|
||||
}
|
||||
|
||||
impl Component for MyComponent {
|
||||
type Message = Msg;
|
||||
|
||||
// ...
|
||||
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
match msg {
|
||||
Msg::SetInputEnabled(enabled) => {
|
||||
if self.input_enabled != enabled {
|
||||
self.input_enabled = enabled;
|
||||
true // 重新渲染
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Change
|
||||
|
||||
组件可能被其父节点重新渲染。发生这种情况时,它们可以接收新的属性(properties)并选择重新渲染。这种设计通过更改属性(properties)来促进父子组件之间的通信。你不是必须实现 `change()`,但是如果想在组件被创建后通过 props 来更新组件,则可能要这么做。
|
||||
|
||||
一个原始的实现可能看起来像:
|
||||
|
||||
```rust
|
||||
impl Component for MyComponent {
|
||||
// ...
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
self.props = props;
|
||||
true // 当提供了新的 props 将始终重新渲染。
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Destroy
|
||||
|
||||
组件从 DOM 上被卸载后,Yew 调用 `destroy()` 生命周期方法来支持任何必要的清理操作。这个方法是可选的,默认情况下不执行任何操作。
|
||||
|
||||
## 关联类型
|
||||
|
||||
`Component` trait 有两个关联类型:`Message` 和 `Properties`。
|
||||
|
||||
```rust
|
||||
impl Component for MyComponent {
|
||||
type Message = Msg;
|
||||
type Properties = Props;
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
`Message` 表示组件可以处理以触发某些副作用的各种消息。例如,你可能有一条 `Click` 消息,该消息触发 API 请求或者切换 UI 组件的外观。通常的做法是在组件模块中创建一个叫做 `Msg` 的枚举并将其用作组件中的消息类型。通常将“message”缩写为“msg”。
|
||||
|
||||
```rust
|
||||
enum Msg {
|
||||
Click,
|
||||
}
|
||||
```
|
||||
|
||||
`Properties` 表示从父级传递到组件的信息。此类型必须实现 `Properties` trait(通常通过派生),并且可以指定某些属性(properties)是必需的还是可选的。创建和更新组件时使用此类型。通常的做法是在组件模块中创建一个叫做 `Props` 的结构体并将其用作组件的 `Properties` 类型。通常将“properties”缩写为“props”。由于 props 是从父组件传递下来的,因此应用程序的根组件通常有一个类型为 `()` 的 `Properties`。如果你希望为根组件指定属性(properties),请使用 `App::mount_with_props` 方法。
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
---
|
||||
description: ComponentLink 和 Callbacks.
|
||||
---
|
||||
|
||||
# 回调(Callbacks)
|
||||
|
||||
组件“link”是一种机制,通过该机制,组件可以注册回调并自行更新。
|
||||
|
||||
## ComponentLink API
|
||||
|
||||
### callback
|
||||
|
||||
注册一个回调,该回调将在执行时将消息发送到组件的更新机制。在内部,它将使用提供的闭包返回的消息调用 `send_self`。提供 `Fn(IN) -> Vec<COMP::Message>`,返回 `Callback<IN>`。
|
||||
|
||||
### send\_message
|
||||
|
||||
当前循环结束后立即向组件发送消息,导致另一个更新循环启动。
|
||||
|
||||
### send\_message\_batch
|
||||
|
||||
注册一个回调,该回调在执行时立即发送一批消息。如果其中任何一个消息将导致组件重新渲染,那么组件会在该批次所有消息被处理后重新渲染。提供 `Fn(IN) -> COMP::Message`,返回 `Callback<IN>`。
|
||||
|
||||
## Callbacks
|
||||
|
||||
Callbacks 用于与 Yew 中的 services,agents 和父组件进行通信。它们仅仅是个 `Fn`,并由 `Rc` 包裹以允许被克隆。
|
||||
|
||||
它们有一个 `emit` 函数,该函数将它的 `<IN>` 类型作为参数并将其转换为目标所期望的消息。如果一个回调从父组件中通过 props 提供给子组件,则子组件可以在其 `update` 生命周期钩子中对该回调调用 `emit`,以将消息发送回父组件。在 `html!` 宏内被提供作为 props 的闭包或函数会自动转换为 Callbacks。
|
||||
|
||||
@ -0,0 +1,73 @@
|
||||
---
|
||||
description: 父组件到子组件的通信
|
||||
---
|
||||
|
||||
# 属性(Properties)
|
||||
|
||||
如“组件(Components)”页面所述,Properties 用于父级到子组件的通信。
|
||||
|
||||
## 派生宏
|
||||
|
||||
不要尝试自己去实现 `Properties`,而是通过使用 `#[derive(Properties)]` 来派生它。
|
||||
|
||||
### 必需属性
|
||||
|
||||
默认情况下,实现了 `Properties` 的结构体中的字段是必需的。当缺少了该字段并且在 `html!` 宏中创建了组件时,将返回编译错误。对于具有可选属性的字段,使用 `#[prop_or_default]` 来使用该类型的默认值。要指定一个值,请使用 `#[prop_or_else(value)]`,其中 value 是该属性的默认值。例如,要将一个布尔值的默认值设置为 `true`,请使用属性 `#[prop_or_else(true)]`。可选属性通常使用 `Option`,其默认值为 `None`。
|
||||
|
||||
### PartialEq
|
||||
|
||||
如果可以的话,在你的 props 上派生 `PartialEq` 通常是很有意义的。这使用了一个**性能优化与最佳实践**部分解释了的技巧,可以更轻松地避免重新渲染。
|
||||
|
||||
## Properties 的内存/速度开销
|
||||
|
||||
记住组件的 `view` 函数签名:
|
||||
|
||||
```rust
|
||||
fn view(&self) -> Html
|
||||
```
|
||||
|
||||
你对组件的状态取了一个引用,并用来创建 `Html`。但是 properties 是有所有权的值(owned values)。这意味着为了创造它们并且将它们传递给子组件,我们需要获取 `view` 函数里提供的引用的所有权。这是在将引用传递给组件时隐式克隆引用完成的,以获得构成其 props 的有所有权的值。
|
||||
|
||||
这意味着每个组件都有从其父级传递来的状态的独特副本,而且,每当你重新渲染一个组件时,该重新渲染组件的所有子组件的 props 都将被克隆。
|
||||
|
||||
这意味着如果你将 _大量_ 数据作为 props(大小为 10 KB 的字符串)向下传递,则可能需要考虑将子组件转换为在父级运行返回 `Html` 的函数,因为这样就不会被强制克隆你的数据。
|
||||
|
||||
另外,如果你不需要修改作为 props 传递的大数据,而只需要显示它,则可以将其包装在 `Rc` 中,以便仅克隆一个引用计数的指针,而不是数据本身。
|
||||
|
||||
## 示例
|
||||
|
||||
```rust
|
||||
pub struct LinkColor {
|
||||
Blue,
|
||||
Red,
|
||||
Green,
|
||||
Black,
|
||||
Purple,
|
||||
}
|
||||
|
||||
impl Default for LinkColor {
|
||||
fn default() -> Self {
|
||||
// 除非另有说明,否则链接的颜色将为蓝色
|
||||
LinkColor::Blue
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Properties, PartialEq)]
|
||||
pub struct LinkProps {
|
||||
/// 链接必须有一个目标地址
|
||||
href: String,
|
||||
/// 如果链接文本很大,这将使得复制字符串开销更小
|
||||
/// 除非有性能问题,否则通常不建议这么做
|
||||
text: Rc<String>,
|
||||
/// 链接的颜色
|
||||
#[prop_or_default]
|
||||
color: LinkColor,
|
||||
/// 如果为 None,则 view 函数将不指定大小
|
||||
#[prop_or_default]
|
||||
size: Option<u32>
|
||||
/// 当 view 函数没有指定 active,其默认为 true
|
||||
#[prop_or_else(true)]
|
||||
active: bool,
|
||||
}
|
||||
```
|
||||
|
||||
@ -0,0 +1,23 @@
|
||||
---
|
||||
title: Refs
|
||||
description: 超出界限的 DOM 访问
|
||||
---
|
||||
|
||||
`ref` 关键词可被用在任何 HTML 元素或组件内部以获得该项所附加到的 DOM 元素。这可被用于在 `view` 生命周期方法之外来对 DOM 进行更改。
|
||||
|
||||
这对于获取 canvas 元素或者滚动到页面的不同部分是有用的。
|
||||
|
||||
语法如下:
|
||||
|
||||
```rust
|
||||
// 在 create 中
|
||||
self.node_ref = NodeRef::default();
|
||||
|
||||
// 在 view 中
|
||||
html! {
|
||||
<div ref=self.node_ref.clone()></div>
|
||||
}
|
||||
|
||||
// 在 update 中
|
||||
let has_attributes = self.node_ref.cast::<Element>().unwrap().has_attributes();
|
||||
```
|
||||
@ -0,0 +1,13 @@
|
||||
---
|
||||
description: 用于生成 HTML 和 SVG 的宏程序
|
||||
---
|
||||
|
||||
# 使用 html! 宏
|
||||
|
||||
`html!` 宏允许你为组件编写声明式的 HTML 和 SVG。如果你使用过 React 的 JSX,将会感觉到非常熟悉。
|
||||
|
||||
**重要提示**
|
||||
|
||||
1. `html!` 宏调用中只能有一个根节点
|
||||
2. 空的 `html! {}` 宏调用是有效的但不会渲染任何内容
|
||||
3. 常量必须始终被引号括起来并被包含在大括号里:`html! { "Hello, World" }`
|
||||
@ -0,0 +1,107 @@
|
||||
---
|
||||
description: 使用具有层次结构的组件来创建复杂的布局
|
||||
---
|
||||
|
||||
# 组件
|
||||
|
||||
## 基础
|
||||
|
||||
任何实现了 `Component` trait 的类型都可被用在 `html!` 宏中:
|
||||
|
||||
```rust
|
||||
html!{
|
||||
<>
|
||||
// 没有属性
|
||||
<MyComponent />
|
||||
|
||||
// 具有属性
|
||||
<MyComponent prop1="lorem" prop2="ipsum" />
|
||||
|
||||
// 同时提供全套的 props
|
||||
<MyComponent with props />
|
||||
</>
|
||||
}
|
||||
```
|
||||
|
||||
## 嵌套
|
||||
|
||||
如果组件的 `Properties` 中有 `children` 字段,则可以被传递子组件。
|
||||
|
||||
{% code title="parent.rs" %}
|
||||
```rust
|
||||
html! {
|
||||
<Container>
|
||||
<h4>{ "Hi" }</h4>
|
||||
<div>{ "Hello" }</div>
|
||||
</Container>
|
||||
}
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
{% code title="container.rs" %}
|
||||
```rust
|
||||
pub struct Container(Props);
|
||||
|
||||
#[derive(Properties)]
|
||||
pub struct Props {
|
||||
pub children: Children,
|
||||
}
|
||||
|
||||
impl Component for Container {
|
||||
type Properties = Props;
|
||||
|
||||
// ...
|
||||
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<div id="container">
|
||||
{ self.0.children.render() }
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
## 拥有 Props 的嵌套子组件
|
||||
|
||||
如果包含组件标注了 children 的类型,则可以访问和更改嵌套组件的属性。在下面的示例中,`List` 组件可以包含 `ListItem` 组件。有关此模式的真实示例,请查看 `yew-router` 的源码。有关更高级的示例,请在 yew 主仓库中查看 `nested-list` 示例代码。
|
||||
|
||||
{% code title="parent.rs" %}
|
||||
```rust
|
||||
html! {
|
||||
<List>
|
||||
<ListItem value="a" />
|
||||
<ListItem value="b" />
|
||||
<ListItem value="c" />
|
||||
</List>
|
||||
}
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
{% code title="list.rs" %}
|
||||
```rust
|
||||
pub struct List(Props);
|
||||
|
||||
#[derive(Properties)]
|
||||
pub struct Props {
|
||||
pub children: ChildrenWithProps<ListItem>,
|
||||
}
|
||||
|
||||
impl Component for List {
|
||||
type Properties = Props;
|
||||
|
||||
// ...
|
||||
|
||||
fn view(&self) -> Html {
|
||||
html!{{
|
||||
for self.0.children.iter().map(|mut item| {
|
||||
item.props.value = format!("item-{}", item.props.value);
|
||||
item
|
||||
})
|
||||
}}
|
||||
}
|
||||
}
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
@ -0,0 +1,246 @@
|
||||
---
|
||||
description: HTML 和 SVG 元素均受支持
|
||||
---
|
||||
|
||||
# 元素
|
||||
|
||||
## 标签结构
|
||||
|
||||
元素标签必须是自闭合的 `<... />`,或是每个标签都有一个对应的闭合标签。
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--标签 - 闭合标签-->
|
||||
```rust
|
||||
html! {
|
||||
<div id="my_div"></div>
|
||||
}
|
||||
```
|
||||
|
||||
<!--无效-->
|
||||
```rust
|
||||
html! {
|
||||
<div id="my_div"> // <- 缺少闭合标签
|
||||
}
|
||||
```
|
||||
|
||||
<!--自闭合-->
|
||||
```rust
|
||||
html! {
|
||||
<input id="my_input" />
|
||||
}
|
||||
```
|
||||
|
||||
<!--无效-->
|
||||
```rust
|
||||
html! {
|
||||
<input id="my_input"> // <- 没有自闭合
|
||||
}
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
:::note
|
||||
为方便起见,一些 _通常_ 需要闭合标签的元素是被**允许**自闭合的。例如,`html! { <div class="placeholder" /> }` 这样写是有效的。
|
||||
:::
|
||||
|
||||
## Children
|
||||
|
||||
轻松创建复杂的嵌套 HTML 和 SVG 布局:
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--HTML-->
|
||||
```rust
|
||||
html! {
|
||||
<div>
|
||||
<div data-key="abc"></div>
|
||||
<div class="parent">
|
||||
<span class="child" value="anything"></span>
|
||||
<label for="first-name">{ "First Name" }</label>
|
||||
<input type="text" id="first-name" value="placeholder" />
|
||||
<input type="checkbox" checked=true />
|
||||
<textarea value="write a story" />
|
||||
<select name="status">
|
||||
<option selected=true disabled=false value="">{ "Selected" }</option>
|
||||
<option selected=false disabled=true value="">{ "Unselected" }</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
```
|
||||
|
||||
<!--SVG-->
|
||||
```rust
|
||||
html! {
|
||||
<svg width="149" height="147" viewBox="0 0 149 147" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M60.5776 13.8268L51.8673 42.6431L77.7475 37.331L60.5776 13.8268Z" fill="#DEB819"/>
|
||||
<path d="M108.361 94.9937L138.708 90.686L115.342 69.8642" stroke="black" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<g filter="url(#filter0_d)">
|
||||
<circle cx="75.3326" cy="73.4918" r="55" fill="#FDD630"/>
|
||||
<circle cx="75.3326" cy="73.4918" r="52.5" stroke="black" stroke-width="5"/>
|
||||
</g>
|
||||
<circle cx="71" cy="99" r="5" fill="white" fill-opacity="0.75" stroke="black" stroke-width="3"/>
|
||||
<defs>
|
||||
<filter id="filter0_d" x="16.3326" y="18.4918" width="118" height="118" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feGaussianBlur stdDeviation="2"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
|
||||
</filter>
|
||||
</defs>
|
||||
</svg>
|
||||
}
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## Classes
|
||||
|
||||
有许多方便的选项可用于元素指定 classes:
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--常量-->
|
||||
```rust
|
||||
html! {
|
||||
<div class="container"></div>
|
||||
}
|
||||
```
|
||||
|
||||
<!--多个属性-->
|
||||
```rust
|
||||
html! {
|
||||
<div class="container center-align"></div>
|
||||
}
|
||||
```
|
||||
|
||||
<!--插值-->
|
||||
```rust
|
||||
html! {
|
||||
<div class=format!("{}-container", size)></div>
|
||||
}
|
||||
```
|
||||
|
||||
<!--表达式-->
|
||||
```rust
|
||||
html! {
|
||||
<div class=self.classes()></div>
|
||||
}
|
||||
```
|
||||
|
||||
<!--元组-->
|
||||
```rust
|
||||
html! {
|
||||
<div class=("class-1", "class-2")></div>
|
||||
}
|
||||
```
|
||||
|
||||
<!--Vector-->
|
||||
```rust
|
||||
html! {
|
||||
<div class=vec!["class-1", "class-2"]></div>
|
||||
}
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## 监听器
|
||||
|
||||
监听器属性需要传递一个由闭包包裹的 `Callback`。创建回调的方式取决于你希望你的应用程序如何响应监听器事件:
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--Component 处理器-->
|
||||
```rust
|
||||
struct MyComponent {
|
||||
link: ComponentLink<Self>,
|
||||
}
|
||||
|
||||
enum Msg {
|
||||
Click,
|
||||
}
|
||||
|
||||
impl Component for MyComponent {
|
||||
type Message = Msg;
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
MyComponent { link }
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
match msg {
|
||||
Msg::Click => {
|
||||
// 处理 Click
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
// 从组件 link 中创建回调来在组件中处理它
|
||||
let click_callback = self.link.callback(|_: ClickEvent| Msg::Click);
|
||||
html! {
|
||||
<button onclick=click_callback>
|
||||
{ "Click me!" }
|
||||
</button>
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<!--Agent 处理器-->
|
||||
```rust
|
||||
struct MyComponent {
|
||||
worker: Dispatcher<MyWorker>,
|
||||
}
|
||||
|
||||
impl Component for MyComponent {
|
||||
type Message = ();
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {
|
||||
MyComponent {
|
||||
worker: MyWorker::dispatcher()
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, _: Self::Message) -> ShouldRender {
|
||||
false
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
// 从 worker 中创建回调来在另一个上下文中处理它
|
||||
let click_callback = self.worker.callback(|_: ClickEvent| WorkerMsg::Process);
|
||||
html! {
|
||||
<button onclick=click_callback>
|
||||
{ "Click me!" }
|
||||
</button>
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<!--其他情况-->
|
||||
```rust
|
||||
struct MyComponent;
|
||||
|
||||
impl Component for MyComponent {
|
||||
type Message = ();
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {
|
||||
MyComponent
|
||||
}
|
||||
|
||||
fn update(&mut self, _: Self::Message) -> ShouldRender {
|
||||
false
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
// 创建一个短暂的回调
|
||||
let click_callback = Callback::from(|| {
|
||||
ConsoleService::new().log("clicked!");
|
||||
});
|
||||
|
||||
html! {
|
||||
<button onclick=click_callback>
|
||||
{ "Click me!" }
|
||||
</button>
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
@ -0,0 +1,52 @@
|
||||
# 列表
|
||||
|
||||
## Fragments
|
||||
|
||||
`html!` 宏总是要求一个单一的根节点。为了绕开这个限制,把内容包裹在一个空标签内是有效的:
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--有效-->
|
||||
```rust
|
||||
html! {
|
||||
<>
|
||||
<div></div>
|
||||
<p></p>
|
||||
</>
|
||||
}
|
||||
```
|
||||
|
||||
<!--无效-->
|
||||
```rust
|
||||
/* 错误:只允许一个 html 根元素 */
|
||||
|
||||
html! {
|
||||
<div></div>
|
||||
<p></p>
|
||||
}
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## 迭代器
|
||||
|
||||
Yew 支持两种从迭代器构建 html 的语法:
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--语法类型 1-->
|
||||
```rust
|
||||
html! {
|
||||
<ul class="item-list">
|
||||
{ self.props.items.iter().map(renderItem).collect::<Html>() }
|
||||
</ul>
|
||||
}
|
||||
```
|
||||
|
||||
<!--语法类型 2-->
|
||||
```rust
|
||||
html! {
|
||||
<ul class="item-list">
|
||||
{ for self.props.items.iter().map(renderItem) }
|
||||
</ul>
|
||||
}
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
@ -0,0 +1,58 @@
|
||||
# 常量和表达式
|
||||
|
||||
## 常量
|
||||
|
||||
如果一个表达式的类型本身实现了 `Display` (一个标准库中的 Trait),他们将会被转化成字符串并且作为一个 [Text](https://developer.mozilla.org/en-US/docs/Web/API/Text) 节点插入 DOM 中。
|
||||
|
||||
所有的需要显示的文本必须被 `{}` 块包含,因为这些文本会被当做一个 Rust 表达式来处理。这一点上,Yew 中使用 HTML 的方式和正常 HTML 语法有巨大的区别。
|
||||
|
||||
```rust
|
||||
let text = "lorem ipsum";
|
||||
html!{
|
||||
<>
|
||||
<div>{text}</div>
|
||||
<div>{"dolor sit"}</div>
|
||||
<span>{42}</span>
|
||||
</>
|
||||
}
|
||||
```
|
||||
|
||||
## 表达式
|
||||
|
||||
你可以在 HTML 中使用 `{}` 块来插入 Rust 表达式,只要这些表达式最终可以被解析成 `Html`
|
||||
|
||||
```rust
|
||||
html! {
|
||||
<div>
|
||||
{
|
||||
if show_link {
|
||||
html! {
|
||||
<a href="https://example.com">{"Link"}</a>
|
||||
}
|
||||
} else {
|
||||
html! {}
|
||||
}
|
||||
}
|
||||
</div>
|
||||
}
|
||||
```
|
||||
|
||||
通常我们会把这些表达式写进函数或者闭包中来增加可读性:
|
||||
|
||||
```rust
|
||||
let show_link = true;
|
||||
let maybe_display_link = move || -> Html {
|
||||
if show_link {
|
||||
html! {
|
||||
<a href="https://example.com">{"Link"}</a>
|
||||
}
|
||||
} else {
|
||||
html! {}
|
||||
}
|
||||
};
|
||||
|
||||
html! {
|
||||
<div>{maybe_display_link()}</div>
|
||||
}
|
||||
```
|
||||
|
||||
@ -0,0 +1,46 @@
|
||||
---
|
||||
description: Yew 的官方 Router
|
||||
---
|
||||
|
||||
# Router
|
||||
|
||||
[https://crates.io/crates/yew-router](https://crates.io/crates/yew-router)
|
||||
|
||||
Routers 在单页应用(SPA)中根据 URL 的不同显示不同的页面。当点击一个链接时,Router 在本地设置 URL 以指向应用程序中有效的路由,而不是默认请求一个不同的远程资源。然后 Router 检测到此更改后决定要渲染的内容。
|
||||
|
||||
## 核心元素
|
||||
|
||||
### Route
|
||||
|
||||
包含一个字符串,该字符串表示网址中域名之后的所有内容,还可以选择表示存储在 history api 中的状态。
|
||||
|
||||
### RouteService
|
||||
|
||||
与浏览器通信以获取和设置路由。
|
||||
|
||||
### RouteAgent
|
||||
|
||||
拥有一个 RouteService,并用于当路由改变时协调更新,无论更新是来自应用程序自身逻辑还是来自浏览器触发的事件。
|
||||
|
||||
### Switch
|
||||
|
||||
`Switch` trait 用于在该 trait 的实现者之间转换 `Route`。
|
||||
|
||||
### Router
|
||||
|
||||
Router 组件同 `RouterAgent` 进行通信,并将自动把它从 Agent 那里获得的 Routes 解析为 Switches,并通过 `render` 属性暴露该 Switch,该属性允许指定将生成的 Switch 转换为 `HTML` 的方式。
|
||||
|
||||
## 如何使用 Router
|
||||
|
||||
首先,你要创建一个表征你的应用程序所有状态的类型。请注意,虽然这通常是一个枚举,但也支持结构体,并且你可以在内部嵌套实现了 `Switch` trait 的其他项。
|
||||
|
||||
然后你应该为了你创建的类型派生 `Switch`。对于枚举,每一个成员都必须用 `#[to = "/some/route"]` 进行标注,如果你使用结构体,则标注必须出现在结构体声明之外。
|
||||
|
||||
请注意,由派生宏为 `Switch` 生成的实现,将尝试从头到尾依次创建每个成员,因此,如果任何路由可能与你指定的两个 `to` 标注相匹配,那么第一个会被匹配,第二个将永远不会被尝试。
|
||||
|
||||
你还可以在 `#[to = ""]` 标注中使用 `{}` 的变体来捕获片段。`{}` 表示捕获文本直到下一个分隔符(根据上下文可能是"/","?","&" 或 "\#")。`{*}` 表示捕获文本直到后续字符匹配为止,如果不存在任何字符,则它将匹配任何内容。`{<number>}` 表示捕获文本直到遇到指定数目的分隔符为止(例如:`{2}` 将一直捕获文本直到遇到两个分隔符为止)。
|
||||
|
||||
对于具有命名字段的结构体和枚举,你必须在捕获组中指定字段的名称,例如:`{user_name}` 或 `{*:age}`。
|
||||
|
||||
Switch trait 适用于比字符串更结构化的捕获组。你可以指定实现了 `Switch` trait 的任何类型。因此,你可以指定捕获组为 `usize`,并且如果 URL 的捕获部分无法转换为它,则该成员不会被匹配。
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
---
|
||||
description: Yew's glue to browser APIs.
|
||||
---
|
||||
|
||||
# Services
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
# Format
|
||||
|
||||
:::note
|
||||
`Contribute to our docs:` [Explain the format module in depth](https://github.com/yewstack/docs/issues/24)
|
||||
:::
|
||||
|
||||
@ -0,0 +1,84 @@
|
||||
# 第一个简单的 App
|
||||
|
||||
首先创建一个二进制项目:
|
||||
|
||||
```bash
|
||||
cargo new --bin yew-app && cd yew-app
|
||||
```
|
||||
|
||||
添加 `yew` 到你的依赖库中([这里](https://docs.rs/yew) 可以查看最新版本的 Yew)
|
||||
|
||||
{% code title="Cargo.toml" %}
|
||||
```text
|
||||
[package]
|
||||
name = "yew-app"
|
||||
version = "0.1.0"
|
||||
authors = ["Yew App Developer <name@example.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
yew = { version = "0.14.3", features = ["std_web"] }
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
将这份代码复制到你的 `src/main.rs` 文件中:
|
||||
|
||||
{% code title="src/main.rs" %}
|
||||
```rust
|
||||
use yew::prelude::*;
|
||||
|
||||
struct Model {
|
||||
link: ComponentLink<Self>,
|
||||
value: i64,
|
||||
}
|
||||
|
||||
enum Msg {
|
||||
AddOne,
|
||||
}
|
||||
|
||||
impl Component for Model {
|
||||
type Message = Msg;
|
||||
type Properties = ();
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
Self {
|
||||
link,
|
||||
value: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
match msg {
|
||||
Msg::AddOne => self.value += 1
|
||||
}
|
||||
true // 指示组件应该重新渲染
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<button onclick=self.link.callback(|_| Msg::AddOne)>{ "+1" }</button>
|
||||
<p>{ self.value }</p>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
yew::initialize();
|
||||
App::<Model>::new().mount_to_body();
|
||||
}
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
这份代码将构建你的称为 `Model` 的 `Component` 根组件,它会显示一个按钮,当你点击它时,`Model` 将会更新自己的状态。特别注意 `main()` 中的 `App::<Model>::new().mount_to_body()`,它会启动你的应用并将其挂载到页面的 `<body>` 标签中。如果你想使用任何动态属性来启动应用程序,则可以使用 `App::<Model>::new().mount_to_body_with_props(..)`。
|
||||
|
||||
## 运行你的应用程序!
|
||||
|
||||
启动并运行你的应用的最快方式就是使用 [`cargo-web`](https://github.com/koute/cargo-web)。如果你还没有的话,请用 `cargo install cargo-web` 命令来安装这个工具然后通过运行下述命令来构建和启动一个开发服务器:
|
||||
|
||||
```bash
|
||||
cargo web start
|
||||
```
|
||||
|
||||
`cargo-web` 将会自动为你添加 `wasm32-unknown-unknown` 作为目标代码,然后构建你的应用,你的应用将默认在 [http://\[::1\]:8000](http://[::1]:8000) 被访问。可以通过 `cargo web start --help` 命令来获取更多选项和帮助。
|
||||
|
||||
@ -0,0 +1,121 @@
|
||||
# 选择 web-sys 还是 stdweb
|
||||
|
||||
## 简介
|
||||
|
||||
Yew 应用程序可以通过 [`web-sys`](https://docs.rs/web-sys) 或者 [`stdweb`](https://docs.rs/stdweb) 来构建。这两个 crates 提供了 Rust 和 Web API 之间的绑定。当把 `yew` 添加到你的 cargo 依赖时,你需要选择它们其中之一:
|
||||
|
||||
{% code title="Cargo.toml" %}
|
||||
```rust
|
||||
# 选择 `web-sys`
|
||||
yew = { version = "0.13", features = ["web_sys"] }
|
||||
|
||||
# 选择 `stdweb`
|
||||
yew = { version = "0.13", features = ["std_web"] }
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
我们建议选择 `web-sys`,因为它是由 [Rust / Wasm 工作组](https://rustwasm.github.io/) 提供支持。
|
||||
|
||||
## 示例用法
|
||||
|
||||
```rust
|
||||
// web-sys
|
||||
let window: web_sys::Window = web_sys::window().expect("window not available");
|
||||
window.alert_with_message("hello from wasm!").expect("alert failed");
|
||||
|
||||
// stdweb
|
||||
let window: stdweb::web::Window = stdweb::web::window();
|
||||
window.alert("hello from wasm!");
|
||||
|
||||
// stdweb 搭配 js! 宏
|
||||
use stdweb::js;
|
||||
use stdweb::unstable::TryFrom;
|
||||
use stdweb::web::Window;
|
||||
|
||||
let window_val: stdweb::Value = js!{ return window; }; // <- 里面使用 JS 语法
|
||||
let window = Window::try_from(window_val).expect("conversion to window failed");
|
||||
window.alert("hello from wasm!");
|
||||
```
|
||||
|
||||
两个 crate 的 API 略有不用,但他们的目标大致相同,功能相似。
|
||||
|
||||
## 选择其中之一
|
||||
|
||||
当为你的应用程序选择使用 `web-sys` 还是 `stdweb` 时,有几个不同的角度需要考虑。注意,可以在一个应用程序中同时使用两者,但是为了最小化编译的 `.wasm` 二进制体积,最好选择其中之一。
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="text-align:left"></th>
|
||||
<th style="text-align:left"><code>web-sys</code>
|
||||
</th>
|
||||
<th style="text-align:left"><code>stdweb</code>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="text-align:left">项目状态</td>
|
||||
<td style="text-align:left">由<a href="https://rustwasm.github.io/">Rust / Wasm 工作组</a>积极维护</td>
|
||||
<td
|
||||
style="text-align:left">超过四个月没有 Github 活动</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">Web API 覆盖率</td>
|
||||
<td style="text-align:left">Rust API 是从 Web IDL 规范自动生成,因此理论上有
|
||||
100% 的覆盖率。</td>
|
||||
<td style="text-align:left">浏览器 API 是根据需求由社区添加</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">Rust API 设计</td>
|
||||
<td style="text-align:left">采取保守的方法,为大多数
|
||||
API 调用返回 <code>Result</code>
|
||||
</td>
|
||||
<td style="text-align:left">通常拒绝返回 <code>Result</code> 而更倾向于使用
|
||||
panic。例如,在 worker 中调用 <code>stdweb::web::window()</code> 将
|
||||
panic。</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">支持的构建工具</td>
|
||||
<td style="text-align:left">
|
||||
<ul>
|
||||
<li><code>wasm-bindgen</code>
|
||||
</li>
|
||||
<li><code>wasm-pack</code>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td style="text-align:left">
|
||||
<ul>
|
||||
<li><code>cargo-web</code>
|
||||
</li>
|
||||
<li><code>wasm-bindgen</code>
|
||||
</li>
|
||||
<li><code>wasm-pack</code>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">支持生成的目标代码</td>
|
||||
<td
|
||||
style="text-align:left">
|
||||
<ul>
|
||||
<li><code>wasm32-unknown-unknown</code>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td style="text-align:left">
|
||||
<ul>
|
||||
<li><code>wasm32-unknown-unknown</code>
|
||||
</li>
|
||||
<li><code>wasm32-unknown-emscripten</code>
|
||||
</li>
|
||||
<li><code>asmjs-unknown-emscripten</code>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>有关更多挑选构建工具的信息,请参阅 [Wasm 构建工具](project-setup/#wasm-build-tools) 指南。
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
# 通过例子学习
|
||||
|
||||
Yew 的 github 项目中就包含了各种各样的示例(这些项目在不同程度的维护中)。我们建议仔细地学习它们, 了解如何使用不同的框架特性. 我们在书中有纰漏和错误的时候也欢迎 pull-requests 和提交 issues ♥️
|
||||
|
||||
* [**Todo App(代办事项)\(stdweb\)**](https://github.com/yewstack/yew/tree/v0.14.0/examples/std_web/todomvc)
|
||||
* [**Todo App(代办事项)\(web\_sys\)**](https://github.com/yewstack/yew/tree/v0.14.0/examples/web_sys/todomvc)
|
||||
* [**Custom Components(自定义 Component 组件)**](https://github.com/yewstack/yew/tree/v0.14.0/examples/custom_components)
|
||||
* [**Multi-threading \(Agents\)(多线程 Agents)\(stdweb\)**](https://github.com/yewstack/yew/tree/v0.14.0/examples/std_web/multi_thread)
|
||||
* [**Multi-threading \(Agents\)(多线程 Agents)\(web\_sys\)**](https://github.com/yewstack/yew/tree/v0.14.0/examples/web_sys/multi_thread)
|
||||
* [**Timer Service(计时器)**](https://github.com/yewstack/yew/tree/v0.14.0/examples/timer)
|
||||
* [**Nested Components(嵌套 Component 组件)**](https://github.com/yewstack/yew/tree/v0.14.0/examples/nested_list)
|
||||
|
||||
@ -0,0 +1,138 @@
|
||||
---
|
||||
description: 为成功做好准备
|
||||
---
|
||||
|
||||
# 项目设置
|
||||
|
||||
## Rust
|
||||
|
||||
首先 ,你需要安装 Rust 。如何安装 Rust 和 `cargo` 构建工具,请参考[官方说明](https://www.rust-lang.org/tools/install)。
|
||||
|
||||
## **Wasm 构建工具**
|
||||
|
||||
需要安装额外的工具以方便 WebAssembly 与 JavaScript 间的相互操作。此外,根据你选择的工具,他们可以生成所有必需的 JavaScript 包装代码来让你的应用程序中的 `.wasm` 文件运行在浏览器中,从而帮助减轻部署和打包的麻烦。
|
||||
|
||||
### [**`wasm-pack`**](https://rustwasm.github.io/docs/wasm-pack/)
|
||||
|
||||
一个由 Rust / Wasm 工作组开发的用于打包 WebAssembly 的 CLI 工具。与 Webpack 的 [`wasm-pack-plugin`](https://github.com/wasm-tool/wasm-pack-plugin) 插件搭配使用最佳。
|
||||
|
||||
[开始使用 wasm-pack](project-setup/using-wasm-pack.md)
|
||||
|
||||
### [**`wasm-bindgen`**](https://rustwasm.github.io/docs/wasm-bindgen/)
|
||||
|
||||
同时是一个库和一个 CLI 工具,也是由 Rust / Wasm 工作组开发。它是一个促进 JS 和 WebAssembly 之间互操作性的底层工具(在 `wasm-pack` 内部被用到)。我们不建议直接使用 `wasm-bindgen` 因为它需要手写一些 JavaScript 代码来引导你的 WebAssembly 二进制程序。但是,直接使用它也是可能的并且可以在 [**`wasm-bindgen` 指南**](https://rustwasm.github.io/docs/wasm-bindgen/) 上找到更多信息。
|
||||
|
||||
[开始使用 wasm-bindgen](project-setup/using-wasm-bindgen.md)
|
||||
|
||||
### [**`cargo-web`**](https://github.com/koute/cargo-web)
|
||||
|
||||
在 `wasm-pack` 和 `wasm-bindgen` 被介绍前的首选 web 工作流工具。它仍然是**最快捷**的启动和运行方式,值得安装以运行尚未迁移到支持 `wasm-pack` 的示例程序。
|
||||
|
||||
[开始使用 cargo-web](project-setup/using-cargo-web.md)
|
||||
|
||||
### 对比
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="text-align:left"></th>
|
||||
<th style="text-align:left"><code>wasm-pack</code>
|
||||
</th>
|
||||
<th style="text-align:left"><code>wasm-bindgen</code>
|
||||
</th>
|
||||
<th style="text-align:left"><code>cargo-web</code>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="text-align:left">项目状态</td>
|
||||
<td style="text-align:left">由 <a href="https://rustwasm.github.io/">Rust / Wasm 工作组</a>积极维护</td>
|
||||
<td
|
||||
style="text-align:left">由 <a href="https://rustwasm.github.io/">Rust / Wasm 工作组</a>积极维护</td>
|
||||
<td
|
||||
style="text-align:left">超过六个月没有 Github 活动</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">开发体验</td>
|
||||
<td style="text-align:left">接近完美!需要 <code>webpack</code> 以获得最佳体验。</td>
|
||||
<td
|
||||
style="text-align:left">比较基础。你需要编写一些脚本来简化你的开发体验。</td>
|
||||
<td
|
||||
style="text-align:left">管用!自带“电池”,不需要外部依赖。</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">本地服务器</td>
|
||||
<td style="text-align:left">通过 <code>webpack</code> 插件支持</td>
|
||||
<td
|
||||
style="text-align:left">不支持</td>
|
||||
<td style="text-align:left">支持</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">根据本地更改自动重新构建</td>
|
||||
<td
|
||||
style="text-align:left">通过 <code>webpack</code> 插件支持</td>
|
||||
<td
|
||||
style="text-align:left">不支持</td>
|
||||
<td style="text-align:left">支持</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">无头浏览器测试</td>
|
||||
<td style="text-align:left"><a href="https://rustwasm.github.io/docs/wasm-pack/commands/test.html">支持</a>
|
||||
</td>
|
||||
<td style="text-align:left"><a href="https://rustwasm.github.io/docs/wasm-bindgen/wasm-bindgen-test/index.html">支持</a>
|
||||
</td>
|
||||
<td style="text-align:left"><a href="https://github.com/koute/cargo-web#features">支持</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">支持生成的目标代码</td>
|
||||
<td
|
||||
style="text-align:left">
|
||||
<ul>
|
||||
<li><code>wasm32-unknown-unknown</code>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td style="text-align:left">
|
||||
<ul>
|
||||
<li><code>wasm32-unknown-unknown</code>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td style="text-align:left">
|
||||
<ul>
|
||||
<li><code>wasm32-unknown-unknown</code>
|
||||
</li>
|
||||
<li><code>wasm32-unknown-emscripten</code>
|
||||
</li>
|
||||
<li><code>asmjs-unknown-emscripten</code>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left"><code>web-sys</code>
|
||||
</td>
|
||||
<td style="text-align:left">兼容</td>
|
||||
<td style="text-align:left">兼容</td>
|
||||
<td style="text-align:left">不兼容</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left"><code>stdweb</code>
|
||||
</td>
|
||||
<td style="text-align:left">兼容</td>
|
||||
<td style="text-align:left">兼容</td>
|
||||
<td style="text-align:left">兼容</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">示例用法</td>
|
||||
<td style="text-align:left"><a href="https://github.com/yewstack/yew-wasm-pack-minimal">新手模板</a>
|
||||
</td>
|
||||
<td style="text-align:left">Yew 示例程序的<a href="https://github.com/yewstack/yew/blob/master/examples/build_all.sh">构建脚本</a>
|
||||
</td>
|
||||
<td style="text-align:left">Yew 示例程序的<a href="https://github.com/yewstack/yew/blob/master/examples/build_all.sh">构建脚本</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@ -0,0 +1,32 @@
|
||||
# 使用 cargo-web
|
||||
|
||||
Cargo web 是一个用来构建 web 客户端应用的 Cargo 子命令,它让构建和部署 web 应用变得非常的简单。它同样也是唯一一个支持生成 Emscripten 目标代码的工具链。点击[这里](https://github.com/koute/cargo-web)了解更多。
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
cargo install cargo-web
|
||||
```
|
||||
|
||||
## 构建
|
||||
|
||||
```bash
|
||||
cargo web build
|
||||
```
|
||||
|
||||
## 运行
|
||||
|
||||
```bash
|
||||
cargo web start
|
||||
```
|
||||
|
||||
## 支持生成的目标代码
|
||||
|
||||
* `wasm32-unknown-unknown`
|
||||
* `wasm32-unknown-emscripten`
|
||||
* `asmjs-unknown-emscripten`
|
||||
|
||||
:::note
|
||||
对于 `*-emscripten` 的目标代码, 你需要安装 Emscripten SDK。
|
||||
:::
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
# 使用 wasm-bindgen
|
||||
|
||||
:::note
|
||||
`Contribute to our docs:` [Explain how to use wasm-bindgen to build an app](https://github.com/yewstack/docs/issues/34)
|
||||
:::
|
||||
|
||||
@ -0,0 +1,42 @@
|
||||
# 使用 wasm-pack
|
||||
|
||||
这个工具由 Rust / Wasm 工作组开发维护,并且是现在最为活跃的 WebAssembly 应用开发工具。 它支持将代码打包成 `npm` 模块,并且随附了 [Webpack 插件](https://github.com/wasm-tool/wasm-pack-plugin),可以轻松的与已有的 JavaScript 应用结合。可以点击[这里](https://rustwasm.github.io/docs/wasm-pack/introduction.html)了解更多。
|
||||
|
||||
:::note
|
||||
注:如果使用 `wasm-pack`作为开发工具,`Cargo.toml` 中的 `crate-type` 需要为 `cdylib`
|
||||
:::
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
cargo install wasm-pack
|
||||
```
|
||||
|
||||
## 构建
|
||||
|
||||
这条命令将在工程根目录下的 `./pkg` 目录中生成打包后的应用,其中包含应用的 WebAssembly 文件以及用来启动应用的 JavaScript 包装器。
|
||||
|
||||
```bash
|
||||
wasm-pack build
|
||||
```
|
||||
|
||||
## 打包
|
||||
|
||||
关于 Rollup 的更多信息,请查看这篇[指南](https://rollupjs.org/guide/en/#quick-start)
|
||||
|
||||
```bash
|
||||
rollup ./main.js --format iife --file ./pkg/bundle.js
|
||||
```
|
||||
|
||||
## 部署
|
||||
|
||||
选取你喜爱的服务器。这里我们使用一个简单的 Python 服务器来将项目部署到:[http://\[::1\]:8000](http://[::1]:8000)。
|
||||
|
||||
```bash
|
||||
python -m SimpleHTTPServer 8080
|
||||
```
|
||||
|
||||
## 支持生成的目标代码
|
||||
|
||||
* `wasm32-unknown-unknown`
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
# 新手模板
|
||||
|
||||
## `wasm-pack`
|
||||
|
||||
* [Minimal Template](https://github.com/yewstack/yew-wasm-pack-minimal) - 使用 `wasm-pack` 和 `rollup` 来构建你的应用, 并使用你自己的服务器来部署它,No bells or whistles here.
|
||||
* [Webpack Template](https://github.com/yewstack/yew-wasm-pack-template) - 使用 `wasm-pack` 和 wasm-pack 的插件 [`wasm-pack-plugin`](https://github.com/wasm-tool/wasm-pack-plugin) 来简化开发。
|
||||
|
||||
使用这些例子和使用 `cargo-web` 的最重要的区别是 它们 使用了 `lib` 类型 而非 `bin` 类型的工程,同时你的应用的入口应该使用 `#[wasm_bindgen]` 标记出来。
|
||||
|
||||
你的 `Cargo.toml` 同样应该指明你的工程的 crate-type 是 "cdylib" 。
|
||||
|
||||
{% code title="Cargo.toml" %}
|
||||
```text
|
||||
[package]
|
||||
name = "yew-app"
|
||||
version = "0.1.0"
|
||||
authors = ["Yew App Developer <name@example.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
yew = { version = "0.13.0", features = ["web_sys" OR "std_web"] }
|
||||
wasm-bindgen = "0.2"
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
## Parcel
|
||||
|
||||
* [Parcel Template](https://github.com/spielrs/yew-parcel-template) - 由一位社区成员建立并使用了 [Parcel](https://parceljs.org/) 。
|
||||
|
||||
46
website/translated_docs/zh-CN/version-0.17.3/intro.md
Normal file
46
website/translated_docs/zh-CN/version-0.17.3/intro.md
Normal file
@ -0,0 +1,46 @@
|
||||
---
|
||||
title: Introduction
|
||||
---
|
||||
|
||||
## Yew 是什么?
|
||||
|
||||
**Yew** 是一个设计先进的 [Rust](https://www.rust-lang.org/) 框架,目的是使用 [WebAssembly](https://webassembly.org/) 来创建多线程的前端 web 应用。
|
||||
|
||||
- **基于组件的框架**,可以轻松的创建交互式 UI。拥有 [React](https://reactjs.org/) 或 [Elm](https://elm-lang.org/) 等框架经验的开发人员在使用 Yew 时会感到得心应手。
|
||||
- **高性能** ,前端开发者可以轻易的将工作分流至后端来减少 DOM API 的调用,从而达到异常出色的性能。
|
||||
- **支持与 Javascript 交互** ,允许开发者使用 NPM 包,并与现有的 Javascript 应用程序结合。
|
||||
|
||||
### 加入我们 😊
|
||||
|
||||
- 你可以在这里 [GitHub issues page](https://github.com/yewstack/yew/issues) 报告 Bugs 或者是提出新的想法。
|
||||
- 我们欢迎 pull requests 。 如果你想要帮助我们,先参考下 [good first issues](https://github.com/yewstack/yew/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) 吧!
|
||||
- 我们的 [Discord chat](https://discord.gg/VQck8X4) 非常的热闹,也是一个问问题和解决问题的好地方!
|
||||
|
||||
### 准备好开始了吗?
|
||||
|
||||
点击下面的链接,来学习并编写你的第一个 Yew 前端 App , 并通过丰富的社区示例项目来学习。
|
||||
|
||||
[项目设置](getting-started/project-setup.md)
|
||||
|
||||
### 还没有完全信服?
|
||||
|
||||
Yew 项目基于划时代的新技术,非常适合那些希望开发未来基础项目的开发者。接下来是一些我们相信 Yew 这样的框架将为成为未来 Web 开发的主流。
|
||||
|
||||
#### 等等,为什么选用 WebAssembly?
|
||||
|
||||
WebAssembly *(Wasm)* 是一种可移植的底层语言,并且可以由 Rust 编译而来。它在浏览器中可以以原生速度运行,还同时支持和 JavaScript 交互。这些在所有的主流浏览器中都已经提供。希望了解更多关于 WebAssembly 是如何为前端应用提速的,可以查看官方[用例](https://webassembly.org/docs/use-cases/).
|
||||
|
||||
值得注意的是,Wasm(目前还)并不是提高 Web 应用性能的万金油(原文:A Silver Bullet)就目前来说,在 WebAssembly 中使用 DOM API 仍然比从 JavaScript 中调用要慢。但只是暂时性问题的,[WebAssembly Interface Types](https://github.com/WebAssembly/interface-types/blob/master/proposals/interface-types/Explainer.md) 计划将解决这个问题。如果你想要了解更多关于这方面的信息,可以查看 Mozilla 的这篇[佳作](https://hacks.mozilla.org/2019/08/webassembly-interface-types/) 。
|
||||
|
||||
#### 好的,那为什么选用 Rust 呢?
|
||||
|
||||
Rust 是一门运行速度超快,并且以他丰富的类型系统和可信赖的所有权模型而闻名的语言。尽管它的学习曲线非常的陡峭,但是带来的回报完全成正比!Rust 已经连续四年在 Stack Overflow 开发者调查报告中被评选为最受喜爱的编程语言:[2016](https://insights.stackoverflow.com/survey/2016#technology-most-loved-dreaded-and-wanted),[2017](https://insights.stackoverflow.com/survey/2017#most-loved-dreaded-and-wanted),[2018](https://insights.stackoverflow.com/survey/2018#technology-_-most-loved-dreaded-and-wanted-languages) 和 [2019](https://insights.stackoverflow.com/survey/2019#technology-_-most-loved-dreaded-and-wanted-languages)。
|
||||
|
||||
Rust 同样可以用它丰富的类型系统和可信赖的所有权模型来帮助开发者编写出更加安全的代码。和那些在 JavaScript 中难以定位的竞争条件 Bug 们说再见吧! 事实上,通过 Rust ,大部分的 Bugs 都将在项目上线之前的编写阶段被编译器发现。同时不用担心,当你的应用出现错误的时候,你仍然可以在浏览器的调试控制台中获得你 Rust 代码的完整的错误栈追踪。
|
||||
|
||||
#### 同类的项目?
|
||||
|
||||
我们非常愿意和其他的类似项目交流想法,并且相信通过这种方式,我们可以互相扶持进步来发挥出这个新技术的潜力。如果你对 Yew 没有兴趣,你可能会喜欢这些项目。
|
||||
|
||||
- [Percy](https://github.com/chinedufn/percy) - *"A modular toolkit for building isomorphic web apps with Rust + WebAssembly"*
|
||||
- [Seed](https://github.com/seed-rs/seed) - *"A Rust framework for creating web apps"*
|
||||
6
website/translated_docs/zh-CN/version-0.17.3/more/css.md
Normal file
6
website/translated_docs/zh-CN/version-0.17.3/more/css.md
Normal file
@ -0,0 +1,6 @@
|
||||
# CSS
|
||||
|
||||
<TODO>
|
||||
|
||||
对适当的 CSS 支持的提案可以在这里找到:[https://github.com/yewstack/yew/issues/533](https://github.com/yewstack/yew/issues/533)
|
||||
|
||||
@ -0,0 +1,51 @@
|
||||
# Debugging
|
||||
|
||||
## Panics
|
||||
|
||||
Please use the [`console_error_panic`](https://github.com/rustwasm/console_error_panic_hook) crate for nicer stacktraces with Rust symbols. Note, that it is not compatible with apps built with `cargo-web`.
|
||||
|
||||
## Console Logging
|
||||
|
||||
In general, Wasm web apps are able to interact with Browser APIs, and the `console.log` api is no exception. There are a few options available:
|
||||
|
||||
### [`wasm-logger`](https://crates.io/crates/wasm-logger)
|
||||
|
||||
This crate integrates with the familiar Rust `log` crate:
|
||||
|
||||
```rust
|
||||
// setup
|
||||
fn main() {
|
||||
wasm_logger::init(wasm_logger::Config::default());
|
||||
}
|
||||
|
||||
// usage
|
||||
log::info!("Update: {:?}", msg);
|
||||
```
|
||||
|
||||
### **\`\`**[**`ConsoleService`**](https://docs.rs/yew/0.13.2/yew/services/console/struct.ConsoleService.html)**\`\`**
|
||||
|
||||
This service is included within yew and is available when the `"services"` feature is enabled:
|
||||
|
||||
```rust
|
||||
// usage
|
||||
ConsoleService::new()::info(format!("Update: {:?}", msg));
|
||||
```
|
||||
|
||||
## Source Maps
|
||||
|
||||
There is currently no first-class support for source maps for Rust / Wasm web apps. This, of course, is subject to change. If this is no longer true or if progress is made, please suggest a change!
|
||||
|
||||
### Latest Info
|
||||
|
||||
\[Dec 2019\] [Chrome DevTools update](https://developers.google.com/web/updates/2019/12/webassembly#the_future)
|
||||
|
||||
> There is still quite a bit of work to do though. For example, on the tooling side, Emscripten \(Binaryen\) and wasm-pack \(wasm-bindgen\) don’t support updating DWARF information on transformations they perform yet.
|
||||
|
||||
\[2020\] [Rust Wasm debugging guide](https://rustwasm.github.io/book/reference/debugging.html#using-a-debugger)
|
||||
|
||||
> Unfortunately, the debugging story for WebAssembly is still immature. On most Unix systems, [DWARF](http://dwarfstd.org/) is used to encode the information that a debugger needs to provide source-level inspection of a running program. There is an alternative format that encodes similar information on Windows. Currently, there is no equivalent for WebAssembly.
|
||||
|
||||
\[2019\] [Rust Wasm roadmap](https://rustwasm.github.io/rfcs/007-2019-roadmap.html#debugging)
|
||||
|
||||
> Debugging is tricky because much of the story is out of this working group's hands, and depends on both the WebAssembly standardization bodies and the folks implementing browser developer tools instead.
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
---
|
||||
description: 可以帮助 Yew 开发的库
|
||||
---
|
||||
|
||||
# 外部库
|
||||
|
||||
### Yewtil
|
||||
|
||||
Yewtil 是一个帮助你编写 Yew 程序的通用工具集合。它包括:
|
||||
|
||||
* NeqAssign - 如前所述,这是给 props 赋值以保证最小化重新渲染的最佳方式。
|
||||
* PureComponents - 不更新任何状态的组件。它们在内部使用 NeqAssign,表现得像记忆化函数并像普通组件一样在 `html!` 宏内部被调用。
|
||||
* Lrc - 链表引用计数智能指针,功能类似于 `Rc`,但是允许新颖的数据更新模式。
|
||||
* Mrc/Irc - 可变/不可变引用计数智能指针,功能类似于 `Rc`,但由于为 `Mrc` 实现了 `DerefMut` 和 `BorrowMut`,因此在 Yew 中对用户更友好。这允许 `Mrc` 与 `NeqAssign` 一起使用。`Irc` 充当数据的不可变视图,这使其成为保存仅用于显示的数据的理想选择。
|
||||
* History - 历史记录追踪包装器,它使用 `VecDeque` 来保存其展示过的历史值。
|
||||
* Futures - 支持运行将消息发送到组件更新循环的 futures。
|
||||
* Fetch - 用于处理使用 `web-sys` 和前面提到的 Futures 功能发请求的抽象。
|
||||
|
||||
## 寻求
|
||||
|
||||
生态需要但目前还没有的库。
|
||||
|
||||
Bootstrap/MaterialUi/任意 css 框架的组件封装。
|
||||
|
||||
40
website/translated_docs/zh-CN/version-0.17.3/more/roadmap.md
Normal file
40
website/translated_docs/zh-CN/version-0.17.3/more/roadmap.md
Normal file
@ -0,0 +1,40 @@
|
||||
---
|
||||
description: Yew 框架规划功能的路线图
|
||||
---
|
||||
|
||||
# 路线图
|
||||
|
||||
## `v1.0.0`
|
||||
|
||||
### 规划中的功能
|
||||
|
||||
* 标记 key 的列表项:[https://github.com/yewstack/yew/issues/479](https://github.com/yewstack/yew/issues/479)
|
||||
* 路由:[https://github.com/yewstack/yew\_router](https://github.com/yewstack/yew_router)
|
||||
|
||||
### 生产环境准备
|
||||
|
||||
* 浏览器兼容性
|
||||
* 提高 Yew 框架的测试覆盖率
|
||||
* 增加性能基准测试:[https://github.com/yewstack/yew/issues/5](https://github.com/yewstack/yew/issues/5)
|
||||
|
||||
### 指南
|
||||
|
||||
* 最佳实践:[https://yew.rs/docs/optimizations](https://yew.rs/docs/optimizations)
|
||||
* 端到端教程
|
||||
* Futures / 并发
|
||||
* CSS / 样式
|
||||
* 测试
|
||||
* 状态管理
|
||||
|
||||
## 未来
|
||||
|
||||
### 潜在功能
|
||||
|
||||
* 服务端渲染:[https://github.com/yewstack/yew/issues/41](https://github.com/yewstack/yew/issues/41)
|
||||
* 组件库:[https://github.com/yewstrap/yewstrap](https://github.com/yewstrap/yewstrap)
|
||||
* 代码分割:[https://github.com/yewstack/yew/issues/599](https://github.com/yewstack/yew/issues/599)
|
||||
* 允许不同的虚拟 DOM 后端:[https://github.com/yewstack/yew/issues/482](https://github.com/yewstack/yew/issues/482)
|
||||
* 反思 Services:[https://github.com/yewstack/yew/issues/364](https://github.com/yewstack/yew/issues/364)
|
||||
* 成熟的工具包:[https://github.com/yewstack/yewtil](https://github.com/yewstack/yewtil)
|
||||
* HTML 模板备选方案:[https://github.com/yewstack/yew/issues/438](https://github.com/yewstack/yew/issues/438)
|
||||
|
||||
12
website/translated_docs/zh-CN/version-0.17.3/more/testing.md
Normal file
12
website/translated_docs/zh-CN/version-0.17.3/more/testing.md
Normal file
@ -0,0 +1,12 @@
|
||||
---
|
||||
description: 测试你的应用程序
|
||||
---
|
||||
|
||||
# 测试
|
||||
|
||||
<TODO>
|
||||
|
||||
## Rust WebDriving
|
||||
|
||||
使用 Rust 以编程方式驱动 UI 集成测试,[fantoccini](https://crates.io/crates/fantoccini) 是一个推荐的选择。它允许你通过使用 CSS 选择器来查找特定的元素,然后对它们执行特定的操作,例如输入文本,点击按钮,或等待特定时间以使客户端代码执行(例如等待一个网络请求完成并导致 UI 改变),来测试你的网站。
|
||||
|
||||
44
website/translated_docs/zh-TW/version-0.17.3/SUMMARY.md
Normal file
44
website/translated_docs/zh-TW/version-0.17.3/SUMMARY.md
Normal file
@ -0,0 +1,44 @@
|
||||
# Table of contents
|
||||
|
||||
* [簡介](README.md)
|
||||
|
||||
## 從零開始 <a id="getting-started"></a>
|
||||
|
||||
* [專案設定](getting-started/project-setup.md)
|
||||
* [使用 wasm-pack](getting-started/project-setup/using-wasm-pack.md)
|
||||
* [使用 wasm-bindgen](getting-started/project-setup/using-wasm-bindgen.md)
|
||||
* [使用 cargo-web](getting-started/project-setup/using-cargo-web.md)
|
||||
* [初始模板](getting-started/starter-templates.md)
|
||||
* [第一個簡單的 App](getting-started/build-a-sample-app.md)
|
||||
* [選擇 web-sys 或 stdweb](getting-started/choose-web-library.md)
|
||||
* [透過範例學習](getting-started/examples.md)
|
||||
|
||||
## 核心觀念 <a id="concepts"></a>
|
||||
|
||||
* [使用 html!](concepts/html.md)
|
||||
* [Lists](concepts/html/lists.md)
|
||||
* [Elements](concepts/html/elements.md)
|
||||
* [Literals & Expressions](concepts/html/literals-and-expressions.md)
|
||||
* [Components](concepts/html/components.md)
|
||||
* [元件](concepts/components.md)
|
||||
* [Properties](concepts/components/properties.md)
|
||||
* [Callbacks](concepts/components/callbacks.md)
|
||||
* [Refs](concepts/components/refs.md)
|
||||
* [Agents](concepts/agents.md)
|
||||
* [Services](concepts/services.md)
|
||||
* [Format](concepts/services/format.md)
|
||||
* [路由器](concepts/router.md)
|
||||
|
||||
## 進階主題 <a id="advanced-topics"></a>
|
||||
|
||||
* [優化與最佳實例](advanced-topics/optimizations.md)
|
||||
* [內部底層的 library](advanced-topics/how-it-works.md)
|
||||
|
||||
## 更多 <a id="more"></a>
|
||||
|
||||
* [CSS](more/css.md)
|
||||
* [Roadmap](more/roadmap.md)
|
||||
* [測試](more/testing.md)
|
||||
* [除錯](more/debugging.md)
|
||||
* [額外的函式庫](more/external-libs.md)
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
---
|
||||
description: 關於框架的底層細節
|
||||
---
|
||||
|
||||
# 內部底層的 library
|
||||
|
||||
元件生命周期的狀態機與 vdom diff 演算法
|
||||
|
||||
@ -0,0 +1,132 @@
|
||||
---
|
||||
description: 加速你的專案
|
||||
---
|
||||
|
||||
# 優化與最佳實例
|
||||
|
||||
## neq\_assign
|
||||
|
||||
當元件從父元件接收到屬性時, `change` 的方法就會被呼叫。除了讓你更新元件的狀態,也讓你回傳,決定元件是否要在屬性改變時,重新渲染自己的布林值 `ShouldRender` 。
|
||||
|
||||
重新渲染是很浪費效能的,儘可能避免這麼做。一般來說,只有在屬性真的改變時,才重新渲染。下面的程式碼是體現這個原則的例子,當屬性改變時,才回傳 `true`:
|
||||
|
||||
```rust
|
||||
use yew::ShouldRender;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
struct ExampleProps;
|
||||
|
||||
struct Example {
|
||||
props: ExampleProps,
|
||||
};
|
||||
|
||||
impl Example {
|
||||
fn change(&mut self, props: ExampleProps) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
但我們可以走的更遠!這六行的模板,使用一個 trait 和一個 實作了 `PartialEq` 的 blanket implementation ,可以被縮短至一行。請參考[這裡](https://docs.rs/yewtil/*/yewtil/trait.NeqAssign.html), `yewtil` 的 crate 裡的 `NeqAssign` trait。
|
||||
|
||||
## RC
|
||||
|
||||
為了避免重新渲染時,複製大量的資料來建立屬性,我們可以使用智慧指針來讓程式只複製指針。如果你使用 `Rc<_>` 來封裝你的屬性,而不是未封裝的值,你可以使用 `Rc::make_mut`,去複製與存取你想要改變的資料的可變參考,這做到了延遲複製,直到你需要更動子元件的資料。透過避免複製直到有值改變,子元件可以在 `Component::change` 拒絕與他狀態中的屬性相同值的屬性,而且這樣不會有任何效能成本。另外,這個方式,資料必須在與子元件比較與被拒絕之前,被複製進父元件的屬性中。
|
||||
|
||||
這個優化最那些無法 `Copy` 的資料型別最有用。如果你可以輕易複製你的資料,那把資料放進智慧指針裡面似乎就沒有這麼值得。對於那些包含很多像是 `Vec` 、 `HashMap` 與 `String` 的結構,這個優化對他們會更值得。
|
||||
|
||||
如果子元件幾乎不會更新值,那這個優化效果會很好,甚至如果父元件也很少更新,那效果會更好。上面的情況,使在純元件中使用 `Rc<_>s` 是一個封裝屬性值很好的選擇。
|
||||
|
||||
## View 方法
|
||||
|
||||
出於程式碼的可讀性,通常會寫方法包裝複雜的 `html!`,這樣你可以避免巢狀的 HTML 造成過多的向右縮排。
|
||||
|
||||
## 純元件/函數式元件
|
||||
|
||||
純元件 是一種不會改變自己狀態的元件,他們只單純顯示內容或是向普通可變的元件傳送訊息。他們和 view 方法不同的地方在於們可以在 `html!` 巨集中使用,語法會像(`<SomePureComponent />`),而不是表達式語法(`{some_view_function()}`),而且根據他們的實作方式,他們可以被 memoized,這樣可以套用前面所述的 `neq_assign` 的邏輯避免重新渲染。
|
||||
|
||||
Yew 本身不支援純元件或是函數式元件,但是你可以透過 external crates 使用。
|
||||
|
||||
函數式元件還不存在,但是理論上純元件可以透過巨集與宣告方法產生。
|
||||
|
||||
## Keyed DOM nodes when they arrive
|
||||
|
||||
## 使用 Cargo Workspaces 加速編譯
|
||||
|
||||
Yew 最大的缺點就是花太多時間在編譯上了。編譯時間似乎和 `html!` 巨集中的程式碼質量相同。 對於小專案來說,這應該不是什麼大問題,但是對於有很多頁面的大型網頁應用程式來說,就必須要將程式碼封裝成很多 crates 以減少編譯所花的時間。
|
||||
|
||||
你應該將路由與頁面區塊封裝成一個 main crate,然後將共用的程式碼與元件封裝成另一個 crate,將每個頁面會用到的不同的元件,各自封裝到不同的 crate 中,或是只產生 `Html` 的大方法中。最好的狀況,你只需要重新編譯你 main crate 與修改的頁面的 crate 的程式碼;而最壞的情況,你編輯了共用的 crate,你就必須重新編譯所有依賴這個共用 crate 的程式碼。
|
||||
|
||||
如果你的 main crate 太過龐大,或是你希望快速迭代深層巢狀的頁面(一個頁面渲染另一個頁面的頂層),你可以使用範例的 crate ,在一個簡單的主頁面上編輯你未完成的元件。
|
||||
|
||||
## 編譯大小的優化 <a id="build-size-optimization"></a>
|
||||
|
||||
* 優化 Rust 的程式碼
|
||||
* `wee_alloc` (使用輕量的分配器)
|
||||
* `cargo.toml` (定義釋出的設定檔)
|
||||
* 使用 `wasm-opt` 優化 wasm 程式碼
|
||||
|
||||
更多關於程式碼大小的資訊,請參考: [rustwasm book](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)
|
||||
|
||||
### wee\_alloc
|
||||
|
||||
[wee\_alloc](https://github.com/rustwasm/wee_alloc) 是一個比一般用在 Rust 二進制檔中的分配器更輕量的分配器。用他取代預設的分配器,可以讓 WASM 的檔案大小更小,但是會造成速度和記憶體的開銷變大。
|
||||
|
||||
但比起檔案大小,速度和記憶體的開銷比較次要。更小的檔案大小意味著你的頁面可以載入的更快,因此我們通常建議你使用這個分配器作為預設的分配器,除分你的專案有很多吃重的記憶體分配工作。
|
||||
|
||||
```rust
|
||||
// 使用 `wee_alloc` 作為全局的分配器
|
||||
#[global_allocator]
|
||||
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
|
||||
```
|
||||
|
||||
### Cargo.toml <a id="cargo-toml"></a>
|
||||
|
||||
你可以設定你的發行版本更小的檔案大小,透過設定 `Cargo.toml` 的 `[profile.release]` 。
|
||||
|
||||
[Rust profiles documentation](https://doc.rust-lang.org/cargo/reference/profiles.html)
|
||||
|
||||
```rust
|
||||
[profile.release]
|
||||
# less code to include into binary
|
||||
panic = 'abort'
|
||||
# optimization over all codebase ( better optimization, slower build )
|
||||
codegen-units = 1
|
||||
# optimization for size ( more aggresive )
|
||||
opt-level = 'z'
|
||||
# optimization for size
|
||||
# opt-level = 's'
|
||||
# link time optimization using using whole-program analysis
|
||||
lto = true
|
||||
```
|
||||
|
||||
### wasm-opt <a id="wasm-opt"></a>
|
||||
|
||||
更多優化 `wasm` 程式碼大小的方法。
|
||||
|
||||
wasm-opt 資訊: [binaryen project](https://github.com/WebAssembly/binaryen)
|
||||
|
||||
Rust Wasm 中有一個關於減少 WASM 二進位檔大小的章節:[Shrinking .wasm size](https://rustwasm.github.io/book/game-of-life/code-size.html)
|
||||
|
||||
* 使用`wasm-pack` 預設在發行版本編譯時優化 `wasm` 程式碼
|
||||
* 直接在 wasm 檔案上使用 `wasm-opt` 。
|
||||
|
||||
```rust
|
||||
wasm-opt wasm_bg.wasm -Os -o wasm_bg_opt.wasm
|
||||
```
|
||||
|
||||
#### 編譯 yew/examples/ 中 最小的例子 <a id="build-size-of-minimal-example-in-yew-examples"></a>
|
||||
|
||||
注意: `wasm-pack` 包含對 Rust 與 wasm 程式碼的優化。而`wasm-bindgen` 只是一個單純的例子,沒有對 `Rust` 做任何優化。
|
||||
|
||||
| used tool | size |
|
||||
| :--- | :--- |
|
||||
| wasm-bindgen | 158KB |
|
||||
| wasm-binggen + wasm-opt -Os | 116KB |
|
||||
| wasm-pack | 99KB |
|
||||
|
||||
@ -0,0 +1,42 @@
|
||||
---
|
||||
description: Yew 的 Actor 系統
|
||||
---
|
||||
|
||||
# Agents
|
||||
|
||||
Agents 類似於 Angular 的 [Services](https://angular.io/guide/architecture-services) (但沒有依賴注入)而且提供 Tew 一個 [Actor Model](https://en.wikipedia.org/wiki/Actor_model). Agents 可以用來作為兩個元件間的路由訊息,而且與他們在元件間的層級關係獨立出來,所以他也可以用來作為一個全域的狀態,甚至可以用來減輕用來渲染 UI 畫面的主執行緒的大量運算任務。 未來,我們還規劃要讓 agents 幫忙 Yew 專案可以跨頁籤溝通。
|
||||
|
||||
為了讓 agents 可以並行, Yew 使用了 [web-workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers)。
|
||||
|
||||
## 生命周期
|
||||
|
||||

|
||||
|
||||
## Agents 的型別
|
||||
|
||||
#### 範圍
|
||||
|
||||
* Job - 在 UI 執行緒上,為每一個 bridge,新增一個 agent。這對於將「共享但獨立的行為」移出元件很有用。(待驗證)當工作結束,agent 會消失。
|
||||
* Context - Bridges 會建立並連接上 UI 執行緒上的 agent。這可以用來協調元件與其他 agent 之間的狀態。當沒有任何 bridge 連接上這個 agent,這個 agnet 就會消失。
|
||||
* Private - 與 Job 相同,但是是在自己的 web worker 上執行的。
|
||||
* Public - 與 Context 相同,但是是在自己的 web worker 上執行的。
|
||||
* Global (編寫中)
|
||||
|
||||
## 在 Agents 與元件之間溝通
|
||||
|
||||
### Bridges
|
||||
|
||||
bridge 允許 agent 與元件進行雙向的溝通。bridge 也允許 agents 之間互相溝通。
|
||||
|
||||
### Dispatchers
|
||||
|
||||
dispatcher 允許元件與 agnet 進行單向的溝通。dispatcher 也允許元件向 agnet 發送訊息。
|
||||
|
||||
## 開銷
|
||||
|
||||
Agents 透過使用 [bincode](https://github.com/servo/bincode) 序列化他們的訊息,來溝通。所以比起呼叫方法,他的效能花費比較高。除非計算的成本,或是跨元件計算的成本,比傳遞訊息的成本要高,否則 agnet 的方法儘量只有包含單純的邏輯運算。
|
||||
|
||||
## 延伸閱讀
|
||||
|
||||
* [pub\_sub](https://github.com/yewstack/yew/tree/master/examples/pub_sub) 範例顯示了如何在 agnets 之間溝通。
|
||||
|
||||
@ -0,0 +1,176 @@
|
||||
---
|
||||
description: 元件,以及生命周期鉤子
|
||||
---
|
||||
|
||||
# 元件
|
||||
|
||||
## 什麼是元件?
|
||||
|
||||
元件是 Yew 的基石。他們管理自己的狀態,可以渲染自己成為 DOM。元件可以透過實作,描述元件生命周期的 `Component` trait 來建立。
|
||||
|
||||
## 生命周期
|
||||
|
||||
:::note
|
||||
`歡迎來貢獻我們的文件:` [Add a diagram of the component lifecycle](https://github.com/yewstack/docs/issues/22)
|
||||
:::
|
||||
|
||||
## 生命周期的方法
|
||||
|
||||
### Create
|
||||
|
||||
當一個元件被建立,他會接收從父元件,也就是 `ComponentLink` ,傳下來的屬性。 這些屬性用來初始化元件的狀態,此外,「link」可以用來註冊回調函式或傳訊息給元件。
|
||||
|
||||
通常,你的元件 struct 會儲存 props 與 link,就像下面的例子:
|
||||
|
||||
```rust
|
||||
pub struct MyComponent {
|
||||
props: Props,
|
||||
link: ComponentLink<Self>,
|
||||
}
|
||||
|
||||
impl Component for MyComponent {
|
||||
type Properties = Props;
|
||||
// ...
|
||||
|
||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
MyComponent { props, link }
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### View
|
||||
|
||||
元件會在 `view()` 方法中宣告佈局。Yew 提供 `html!` 巨集來宣告 HTML 合 SVG 的結點,包含他們的監聽事件與子結點。這個巨集扮演像是 React 的 JSX 的角色,但是是使用 Rust 的表達式,而不是 JavaScript 的。
|
||||
|
||||
```rust
|
||||
impl Component for MyComponent {
|
||||
// ...
|
||||
|
||||
fn view(&self) -> Html {
|
||||
let onclick = self.link.callback(|_| Msg::Click);
|
||||
html! {
|
||||
<button onclick=onclick>{ self.props.button_text }</button>
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
更多使用細節,請參考 [`html!` 教學](html.md)。
|
||||
|
||||
### Rendered
|
||||
|
||||
`rendered()` 生命周期的方法會,在 `view()` 處理完並且 Yew 渲染完你的元件之後,與瀏覽器刷新頁面之前,被呼叫。一個元件可能希望實作這個方法,去執行只能在元件被渲染完元素才能做的事情。 你可以透過 `first_render` 變數來確認這個元件是不是第一次被渲染。
|
||||
|
||||
```rust
|
||||
use stdweb::web::html_element::InputElement;
|
||||
use stdweb::web::IHtmlElement;
|
||||
use yew::prelude::*;
|
||||
|
||||
pub struct MyComponent {
|
||||
node_ref: NodeRef,
|
||||
}
|
||||
|
||||
impl Component for MyComponent {
|
||||
// ...
|
||||
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<input ref=self.node_ref.clone() type="text" />
|
||||
}
|
||||
}
|
||||
|
||||
fn rendered(&mut self, first_render: bool) {
|
||||
if first_render {
|
||||
if let Some(input) = self.node_ref.cast::<InputElement>() {
|
||||
input.focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::note
|
||||
注意,這個生命周期方法,不是一定要被實作,預設的行為是不做任何事情。
|
||||
:::
|
||||
|
||||
### Update
|
||||
|
||||
元件是可動態更新且可以註冊接收非同步的訊息。 `update()` 生命周期方法會被每個訊息呼叫。他基於訊息是什麼,來允許元件更新自己,且會決定是否需要重新渲染。 訊息可以被 HTML 元素的監聽器觸發,或被子元件、Agents、Services 或 Futures 傳送。
|
||||
|
||||
`update()` 應用範例:
|
||||
|
||||
```rust
|
||||
pub enum Msg {
|
||||
SetInputEnabled(bool)
|
||||
}
|
||||
|
||||
impl Component for MyComponent {
|
||||
type Message = Msg;
|
||||
|
||||
// ...
|
||||
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
match msg {
|
||||
Msg::SetInputEnabled(enabled) => {
|
||||
if self.input_enabled != enabled {
|
||||
self.input_enabled = enabled;
|
||||
true // 重新渲染
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Change
|
||||
|
||||
元件可能會被他的父元件重新渲染。當他被父元件重新渲染時,他會收到新的屬性,然後決定要不要再渲染一次。 這設計是讓父元件透過便於跟子元件溝通。
|
||||
|
||||
一個簡單的實作方式像:
|
||||
|
||||
```rust
|
||||
impl Component for MyComponent {
|
||||
// ...
|
||||
|
||||
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Destroy
|
||||
|
||||
當元件從 DOM 上被解除掛載,Yew 會呼叫 `destroy()` 生命周期方法以提供任何需要清理的操作。這個方法是不一定要被實作的,預設不會做設任何事。
|
||||
|
||||
## 相關的型別
|
||||
|
||||
`Component` trait 有兩個相關的型別:`Message` 與 `Properties`。
|
||||
|
||||
```rust
|
||||
impl Component for MyComponent {
|
||||
type Message = Msg;
|
||||
type Properties = Props;
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
`Message` 負責各式各樣的訊息,他可能被元件處理去觸發各種影響。舉例來說,你可能有一個 `Click` 的訊息,他會觸發 API 請求,或是切換 UI 元件的樣貌。下面是一個常見的實作,在你的元件模組中,創建一個叫作 `Msg` 的 enum,然後把他當作元件裡的 Message 型別。通常 message 會縮寫成 msg。
|
||||
|
||||
```rust
|
||||
enum Msg {
|
||||
Click,
|
||||
}
|
||||
```
|
||||
|
||||
`Properties` 代表要從父員件傳遞到子元件的資訊。這個型別必須實作 `Properties` trait (通常會 deriving 他)並且可以決定某個屬性是必要的屬性,或是可選的屬性。這個型別會在創建元件的時候,或是更新元件的時候被使用到。常見的實作會在你的元件模組中,建立一個叫作 `Props` 的 struct,然後把他當作元件的`Properties` 型別。通常 properties 或縮寫成 props。因為屬性是從父原件被傳下來的,所以應用程式中的根元件的 `Properties` 原則上都是 `()`。如果你希望你的根元件有特定的屬性,可以使用 `App::mount_with_props` 的方法。
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
---
|
||||
description: ComponentLink 與 Callbacks.
|
||||
---
|
||||
|
||||
# Callbacks
|
||||
|
||||
元件的「link」是一個讓元件註冊 callbacks 並自我更新的機制。
|
||||
|
||||
## ComponentLink API
|
||||
|
||||
### callback
|
||||
|
||||
註冊一個 callback 後,當這個 callback 被執行時,會發送一個訊息給元件的更新機制。在生命周期的勾子下,他會呼叫 `send_self` 並將被閉包回傳的訊息帶給他。
|
||||
|
||||
提供一個 `Fn(IN) -> Vec<COMP::Message>` 並回傳一個 `Callback<IN>` 。
|
||||
|
||||
### send\_message
|
||||
|
||||
當現在的迴圈結束後,向元件發送訊息,並且開啟另一個迴圈。
|
||||
|
||||
### send\_message\_batch
|
||||
|
||||
註冊一個 callback,當這個 callback 被執行時,這個 callback 會一次送很多訊息。如果有任何一個訊息導致元件被重新渲染,元件會在所有批次送來的訊息都被處理完後,再重新渲染。
|
||||
|
||||
提供一個 `Fn(IN) -> COMP::Message` 並回傳一個 `Callback<IN>` 。
|
||||
|
||||
## Callbacks
|
||||
|
||||
_(他可能需要一個獨立的短頁來介紹)_
|
||||
|
||||
Callbacks 被用來當作 services 、 agents 與父元件跟 Yew 溝通的方式。他們只是一個被 `Rc` 包裹著的 `Fn`,好讓他們可以被複製。
|
||||
|
||||
他們有一個 `emit` 方法,這個方法拿他們的 `<IN>` 型別當作參數,並且轉換他作為目的地所期望的訊息。如果一個從父元件來的 callback被提供作為子元件的屬性,子元件可以在他的 update 生命周期中,呼叫 callback 中的 emit 以傳遞訊息回給父元件。 在 `html!` 巨集中的閉包與方法如果被當作屬性傳遞,會被自動轉為 Callbacks。
|
||||
|
||||
@ -0,0 +1,71 @@
|
||||
---
|
||||
description: 父元件與子元件的溝通橋樑
|
||||
---
|
||||
|
||||
# Properties
|
||||
|
||||
屬性讓子元件與父元件可以互相溝通。
|
||||
|
||||
## Derive macro
|
||||
|
||||
不要嘗試自己實作 `Properties`,而是用`#[derive(Properties)]`derive 他。
|
||||
|
||||
### 必填的欄位
|
||||
|
||||
預設所有在 `Properties` struct 裡的欄位都是必填的。當必填的欄位沒有值,而元件在 `html!` 巨集中又被建立,編譯器就會報錯。如果希望欄位是可選的,可以使用 `#[prop_or_default]` 來讓該欄位有預設值。如果希望欄位預設特定值,可以使用 `#[prop_or_else(value)]` ,裡面的 value 就會是這個欄位的預設值。舉例來說,希望預設值是 `true`可以在欄位宣告上面這樣寫 `#[prop_or_else(true)]`. 通常可選的屬性,會用 `Option` ,且預設值為`None`。
|
||||
|
||||
### PartialEq
|
||||
|
||||
如果可以,最好在你的屬性上面 derive `PartialEq` 。他可以避免畫面多餘的渲染,更細節的內容請參考,**優化與最佳實例**的區塊。
|
||||
|
||||
## 屬性的記憶體與速度的開銷
|
||||
|
||||
在 `Component::view`,裡,你可以拿到元件狀態的參考,且用他來建立 `Html` 。但是屬性是有所有權的。這代表著為了建立屬性,並且將他們傳遞給子元件,我們必須取得被 `view` 方法拿走的所有權。 當將參考傳給元件時,可以透過隱式的複製來做到得到所有權。
|
||||
|
||||
這意味著,每個元件,都有從父元件傳遞下來的獨有的狀態複本,且每當你重新渲染一次元件,被重新渲染的元件的所有的子元件的屬性就會被重新複製一次。
|
||||
|
||||
代表如果你要在屬性中傳遞_大量_的資料(大於 10 KB 的字串之類的),你可能需要考慮將你的子元件變成一個回傳 `Html` 的方法,讓父元件呼叫,以避免資料被複製。
|
||||
|
||||
如果你不需要改變傳下去的資料,你可以用 `Rc` 將資料包裝起來,這樣就會只複製參考的指針,而不是資料本身。
|
||||
|
||||
## 範例
|
||||
|
||||
```rust
|
||||
use std::rc::Rc;
|
||||
use yew::Properties;
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum LinkColor {
|
||||
Blue,
|
||||
Red,
|
||||
Green,
|
||||
Black,
|
||||
Purple,
|
||||
}
|
||||
|
||||
impl Default for LinkColor {
|
||||
fn default() -> Self {
|
||||
// 除非有指定,否則預設是藍色
|
||||
LinkColor::Blue
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Properties, Clone, PartialEq)]
|
||||
pub struct LinkProps {
|
||||
/// 連結必須要有一個目標
|
||||
href: String,
|
||||
/// 如果連結文字很大,複製字串的參考可以減少記憶體的開銷
|
||||
/// 但除非效能已經成為嚴重的問題,否則通常不建議這麼做
|
||||
text: Rc<String>,
|
||||
/// 連結的顏色
|
||||
#[prop_or_default]
|
||||
color: LinkColor,
|
||||
/// 如果為 None,那 view 方法將不會指定 size
|
||||
#[prop_or_default]
|
||||
size: Option<u32>,
|
||||
/// 當沒有指定 active,預設為 true
|
||||
#[prop_or(true)]
|
||||
active: bool,
|
||||
}
|
||||
```
|
||||
|
||||
@ -0,0 +1,26 @@
|
||||
---
|
||||
description: 外帶 DOM 的存取
|
||||
---
|
||||
|
||||
# Refs
|
||||
|
||||
## Refs
|
||||
|
||||
`ref` 關鍵字可以被使用在任何 HTML 的元素或是元件,用來得到那個物件附加的 DOM `Element`。這個可以在 view 生命周期方法之外,改變 DOM。
|
||||
|
||||
對於要存取 canvas 元素,或滾動到頁面不同的區塊,很有幫助。
|
||||
|
||||
語法可以這樣使用:
|
||||
|
||||
```rust
|
||||
// 建立
|
||||
self.node_ref = NodeRef::default();
|
||||
|
||||
// 在 view 裡
|
||||
html! {
|
||||
<div ref=self.node_ref.clone()></div>
|
||||
}
|
||||
|
||||
// 更新
|
||||
let has_attributes = self.node_ref.cast::<Element>().unwrap().has_attributes();
|
||||
```
|
||||
@ -0,0 +1,13 @@
|
||||
---
|
||||
description: 用來產生 HTML 與 SVG 的巨集
|
||||
---
|
||||
|
||||
# 使用 html!
|
||||
|
||||
`html!` 巨集可以讓你用 HTML 與 SVG 寫元件。如果你寫過 React 的 JSX(一種 JavaScript 的擴展,可以讓你在 JavaScript 中寫 HTML),應該會覺得這兩者十分相似。
|
||||
|
||||
**重要提示**
|
||||
|
||||
1. 在 `html!` 裡,只能有一個根結點(但你可以用 [Fragment 或是 Iterators](https://yew.rs/docs/concepts/html/lists) 來繞過這個限制。)
|
||||
2. 空的 `html! {}` 是合法的,且他不會渲染任何東西在畫面上
|
||||
3. 字串必須被雙引號與大括號包裹住:`html! { "Hello, World" }`
|
||||
@ -0,0 +1,107 @@
|
||||
---
|
||||
description: 建立複雜元件層級與佈局
|
||||
---
|
||||
|
||||
# Components
|
||||
|
||||
## 基本
|
||||
|
||||
任何實作 `Component` 的型別,都可以在 `html!` 的巨集中使用:
|
||||
|
||||
```rust
|
||||
html!{
|
||||
<>
|
||||
// 沒有屬性
|
||||
<MyComponent />
|
||||
|
||||
// 有屬性
|
||||
<MyComponent prop1="lorem" prop2="ipsum" />
|
||||
|
||||
// 一次提供很多屬性
|
||||
<MyComponent with props />
|
||||
</>
|
||||
}
|
||||
```
|
||||
|
||||
## 巢狀
|
||||
|
||||
只要元件的 `Properties` 中有 `children`,就可以傳遞子結點給元件。
|
||||
|
||||
{% code title="parent.rs" %}
|
||||
```rust
|
||||
html! {
|
||||
<Container>
|
||||
<h4>{ "Hi" }</h4>
|
||||
<div>{ "Hello" }</div>
|
||||
</Container>
|
||||
}
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
{% code title="container.rs" %}
|
||||
```rust
|
||||
pub struct Container(Props);
|
||||
|
||||
#[derive(Properties)]
|
||||
pub struct Props {
|
||||
pub children: Children,
|
||||
}
|
||||
|
||||
impl Component for Container {
|
||||
type Properties = Props;
|
||||
|
||||
// ...
|
||||
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<div id="container">
|
||||
{ self.0.children.render() }
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
## 指定子結點的型別
|
||||
|
||||
如果指定了子結點的型別,就可以使用或改變巢狀元件的屬性。下面的範例就是, `List` 元件包裹 `ListItem` 元件。另一個真實的範例是 `yew-router` 的原始碼。還有一個更進階的範例,請參考 Yew GitHub repo 中的 `nested-list` 範例。
|
||||
|
||||
{% code title="parent.rs" %}
|
||||
```rust
|
||||
html! {
|
||||
<List>
|
||||
<ListItem value="a" />
|
||||
<ListItem value="b" />
|
||||
<ListItem value="c" />
|
||||
</List>
|
||||
}
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
{% code title="list.rs" %}
|
||||
```rust
|
||||
pub struct List(Props);
|
||||
|
||||
#[derive(Properties)]
|
||||
pub struct Props {
|
||||
pub children: ChildrenWithProps<ListItem>,
|
||||
}
|
||||
|
||||
impl Component for List {
|
||||
type Properties = Props;
|
||||
|
||||
// ...
|
||||
|
||||
fn view(&self) -> Html {
|
||||
html!{{
|
||||
for self.0.children.iter().map(|mut item| {
|
||||
item.props.value = format!("item-{}", item.props.value);
|
||||
item
|
||||
})
|
||||
}}
|
||||
}
|
||||
}
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
@ -0,0 +1,246 @@
|
||||
---
|
||||
description: HTML 與 SVG 元件都支援
|
||||
---
|
||||
|
||||
# Elements
|
||||
|
||||
## 標籤結構
|
||||
|
||||
元件標籤都必須要是自封閉的標籤 `<... />` 或是跟開啟標籤對應的關閉標籤。
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--Open - Close-->
|
||||
```rust
|
||||
html! {
|
||||
<div id="my_div"></div>
|
||||
}
|
||||
```
|
||||
|
||||
<!--INVALID-->
|
||||
```rust
|
||||
html! {
|
||||
<div id="my_div"> // <- 缺少關閉標籤
|
||||
}
|
||||
```
|
||||
|
||||
<!--Self-Closing-->
|
||||
```rust
|
||||
html! {
|
||||
<input id="my_input" />
|
||||
}
|
||||
```
|
||||
|
||||
<!--INVALID-->
|
||||
```rust
|
||||
html! {
|
||||
<input id="my_input"> // <- 缺少自封閉標籤語法
|
||||
}
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
:::note
|
||||
為了方便起見,通常需要關閉標籤的元件,也都可以用自封閉標籤表示。例如,寫 `html! { <div class="placeholder" /> }` 是合法的。
|
||||
:::
|
||||
|
||||
## 子結點
|
||||
|
||||
輕鬆寫出複雜巢狀的 HTML 與 SVG 架構:
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--HTML-->
|
||||
```rust
|
||||
html! {
|
||||
<div>
|
||||
<div data-key="abc"></div>
|
||||
<div class="parent">
|
||||
<span class="child" value="anything"></span>
|
||||
<label for="first-name">{ "First Name" }</label>
|
||||
<input type="text" id="first-name" value="placeholder" />
|
||||
<input type="checkbox" checked=true />
|
||||
<textarea value="write a story" />
|
||||
<select name="status">
|
||||
<option selected=true disabled=false value="">{ "Selected" }</option>
|
||||
<option selected=false disabled=true value="">{ "Unselected" }</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
```
|
||||
|
||||
<!--SVG-->
|
||||
```rust
|
||||
html! {
|
||||
<svg width="149" height="147" viewBox="0 0 149 147" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M60.5776 13.8268L51.8673 42.6431L77.7475 37.331L60.5776 13.8268Z" fill="#DEB819"/>
|
||||
<path d="M108.361 94.9937L138.708 90.686L115.342 69.8642" stroke="black" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<g filter="url(#filter0_d)">
|
||||
<circle cx="75.3326" cy="73.4918" r="55" fill="#FDD630"/>
|
||||
<circle cx="75.3326" cy="73.4918" r="52.5" stroke="black" stroke-width="5"/>
|
||||
</g>
|
||||
<circle cx="71" cy="99" r="5" fill="white" fill-opacity="0.75" stroke="black" stroke-width="3"/>
|
||||
<defs>
|
||||
<filter id="filter0_d" x="16.3326" y="18.4918" width="118" height="118" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feGaussianBlur stdDeviation="2"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
|
||||
</filter>
|
||||
</defs>
|
||||
</svg>
|
||||
}
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## Classes
|
||||
|
||||
你很多方便的選項可以寫元件裡的 class:
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--Literal-->
|
||||
```rust
|
||||
html! {
|
||||
<div class="container"></div>
|
||||
}
|
||||
```
|
||||
|
||||
<!--Multiple-->
|
||||
```rust
|
||||
html! {
|
||||
<div class="container center-align"></div>
|
||||
}
|
||||
```
|
||||
|
||||
<!--Interpolated-->
|
||||
```rust
|
||||
html! {
|
||||
<div class=format!("{}-container", size)></div>
|
||||
}
|
||||
```
|
||||
|
||||
<!--Expression-->
|
||||
```rust
|
||||
html! {
|
||||
<div class=self.classes()></div>
|
||||
}
|
||||
```
|
||||
|
||||
<!--Tuple-->
|
||||
```rust
|
||||
html! {
|
||||
<div class=("class-1", "class-2")></div>
|
||||
}
|
||||
```
|
||||
|
||||
<!--Vector-->
|
||||
```rust
|
||||
html! {
|
||||
<div class=vec!["class-1", "class-2"]></div>
|
||||
}
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## 監聽
|
||||
|
||||
監聽器的屬性必須要傳入一個 `Callback` ,他封裝了閉包。callback 的內容取決於,當觸發監聽事件時,你希望應用程式有什麼反應:
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--Component Handler-->
|
||||
```rust
|
||||
struct MyComponent {
|
||||
link: ComponentLink<Self>,
|
||||
}
|
||||
|
||||
enum Msg {
|
||||
Click,
|
||||
}
|
||||
|
||||
impl Component for MyComponent {
|
||||
type Message = Msg;
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
MyComponent { link }
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
match msg {
|
||||
Msg::Click => {
|
||||
// 處理點擊事件
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
// 從一個元件連結中,建立一個 callback 並在元件中處理他
|
||||
let click_callback = self.link.callback(|_: ClickEvent| Msg::Click);
|
||||
html! {
|
||||
<button onclick=click_callback>
|
||||
{ "Click me!" }
|
||||
</button>
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<!--Agent Handler-->
|
||||
```rust
|
||||
struct MyComponent {
|
||||
worker: Dispatcher<MyWorker>,
|
||||
}
|
||||
|
||||
impl Component for MyComponent {
|
||||
type Message = ();
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {
|
||||
MyComponent {
|
||||
worker: MyWorker::dispatcher()
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, _: Self::Message) -> ShouldRender {
|
||||
false
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
// 從一個 worker 中建立一個 callback,並在其他的 context 中處理他
|
||||
let click_callback = self.worker.callback(|_: ClickEvent| WorkerMsg::Process);
|
||||
html! {
|
||||
<button onclick=click_callback>
|
||||
{ "Click me!" }
|
||||
</button>
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<!--Other Cases-->
|
||||
```rust
|
||||
struct MyComponent;
|
||||
|
||||
impl Component for MyComponent {
|
||||
type Message = ();
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {
|
||||
MyComponent
|
||||
}
|
||||
|
||||
fn update(&mut self, _: Self::Message) -> ShouldRender {
|
||||
false
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
// 建立一個臨時的 callback
|
||||
let click_callback = Callback::from(|| {
|
||||
ConsoleService::new().log("clicked!");
|
||||
});
|
||||
|
||||
html! {
|
||||
<button onclick=click_callback>
|
||||
{ "Click me!" }
|
||||
</button>
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
@ -0,0 +1,52 @@
|
||||
# Lists
|
||||
|
||||
## Fragments
|
||||
|
||||
`html!` 巨集裡必須只有一個根結點。為了可以繞過這個限制,將兩個以上的結點,用空的標籤包裹起來,是合法的:
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--Valid-->
|
||||
```rust
|
||||
html! {
|
||||
<>
|
||||
<div></div>
|
||||
<p></p>
|
||||
</>
|
||||
}
|
||||
```
|
||||
|
||||
<!--Invalid-->
|
||||
```rust
|
||||
/* error: only one root html element allowed */
|
||||
|
||||
html! {
|
||||
<div></div>
|
||||
<p></p>
|
||||
}
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
## Iterators
|
||||
|
||||
Yew 支援兩種不同的方式,從 iterator 建構 html:
|
||||
|
||||
<!--DOCUSAURUS_CODE_TABS-->
|
||||
<!--Syntax Type 1-->
|
||||
```rust
|
||||
html! {
|
||||
<ul class="item-list">
|
||||
{ self.props.items.iter().map(renderItem).collect::<Html>() }
|
||||
</ul>
|
||||
}
|
||||
```
|
||||
|
||||
<!--Syntax Type 2-->
|
||||
```rust
|
||||
html! {
|
||||
<ul class="item-list">
|
||||
{ for self.props.items.iter().map(renderItem) }
|
||||
</ul>
|
||||
}
|
||||
```
|
||||
<!--END_DOCUSAURUS_CODE_TABS-->
|
||||
|
||||
@ -0,0 +1,58 @@
|
||||
# Literals & Expressions
|
||||
|
||||
## Literals
|
||||
|
||||
如果表達式中的型別有實作 `Display` ,他們會被轉換成字串,並在 DOM 中作為 [Text](https://developer.mozilla.org/en-US/docs/Web/API/Text) (文字)結點。
|
||||
|
||||
所有的文字都必須用 `{}` 括起來,因為文字是被當作表達式處理。這是 HTML 語法與 Yew 的語法中,最大的不同。
|
||||
|
||||
```rust
|
||||
let text = "lorem ipsum";
|
||||
html!{
|
||||
<>
|
||||
<div>{text}</div>
|
||||
<div>{"dolor sit"}</div>
|
||||
<span>{42}</span>
|
||||
</>
|
||||
}
|
||||
```
|
||||
|
||||
## Expressions
|
||||
|
||||
只要可以回傳 `Html`,你都可以在你的 HTML 中用 `{}` 插入表達式。
|
||||
|
||||
```rust
|
||||
html! {
|
||||
<div>
|
||||
{
|
||||
if show_link {
|
||||
html! {
|
||||
<a href="https://example.com">{"Link"}</a>
|
||||
}
|
||||
} else {
|
||||
html! {}
|
||||
}
|
||||
}
|
||||
</div>
|
||||
}
|
||||
```
|
||||
|
||||
通常把這些表達式與包裝成方法或閉包會比較好,可以提升可讀性:
|
||||
|
||||
```rust
|
||||
let show_link = true;
|
||||
let maybe_display_link = move || -> Html {
|
||||
if show_link {
|
||||
html! {
|
||||
<a href="https://example.com">{"Link"}</a>
|
||||
}
|
||||
} else {
|
||||
html! {}
|
||||
}
|
||||
};
|
||||
|
||||
html! {
|
||||
<div>{maybe_display_link()}</div>
|
||||
}
|
||||
```
|
||||
|
||||
@ -0,0 +1,82 @@
|
||||
---
|
||||
description: Yew 的官方路由器
|
||||
---
|
||||
|
||||
# 路由器
|
||||
|
||||
[https://crates.io/crates/yew-router](https://crates.io/crates/yew-router)
|
||||
|
||||
單頁應用程式(SPA)中的路由器,會依據 URL 來顯示不同的畫面。當連結被點擊後,路由器沒有預設要請求遠端的資源, 而是將 URL 設定導向應用程式中的有效路由。路由器會偵測 URL 被更改,然後決定要渲染什麼畫面。
|
||||
|
||||
## 核心元素
|
||||
|
||||
### Route
|
||||
|
||||
包含一個字串,這個字串是網域名後的那串文字,並且可以選擇要不要將狀態存入 history api。
|
||||
|
||||
### RouteService
|
||||
|
||||
與瀏覽器溝通,存取路由。
|
||||
|
||||
### RouteAgent
|
||||
|
||||
擁有 RouteService 並且協調與更新,從應用程式邏輯造成的,或是從瀏覽器事件中造成的,路由的改變。
|
||||
|
||||
### Switch
|
||||
|
||||
`Switch` trait 用於讓 Route 在實作的 `trait` 之間來回轉換。
|
||||
|
||||
### Router
|
||||
|
||||
Router 元件會與 `RouteAgent` 溝通,並且自動解析從 agent 到 switch 的 Routes,Routes 會在 render 的 屬性中被揭露,這個屬性會決定 switch 的結果如何被轉換成 `Html`。
|
||||
|
||||
## 如何使用路由器
|
||||
|
||||
首先,你要建立一個代表你的應用程式所有狀態的型別。特別注意,這個型別可以是 enum、struct 都可以,而且你可以透過在裡面實作 `Switch` 來巢狀其他項目
|
||||
|
||||
然後你必須為你的型別 derive `Switch` 。對 enums 來說,每一個變數都必須宣告 `#[to = "/some/route"]`,或是如果你用 struct,那就要 struct 的外部宣告。
|
||||
|
||||
```rust
|
||||
#[derive(Switch)]
|
||||
enum AppRoute {
|
||||
#[to="/login"]
|
||||
Login,
|
||||
#[to="/register"]
|
||||
Register,
|
||||
#[to="/delete_account"]
|
||||
Delete,
|
||||
#[to="/posts/{id}"]
|
||||
ViewPost(i32),
|
||||
#[to="/posts/view"]
|
||||
ViewPosts,
|
||||
#[to="/"]
|
||||
Home
|
||||
}
|
||||
```
|
||||
|
||||
特別注意,這個巨集會試著依序配對每個變數,所以如果有任何路由可能配對到兩著不同的 `to` 宣告,那會配對到第一個,而第二個就永遠不會被配對到。舉例來說,如果你定義以下的 `Switch` ,那路由將永遠只會配對到 `AppRoute::Home`。
|
||||
|
||||
```rust
|
||||
#[derive(Switch)]
|
||||
enum AppRoute {
|
||||
#[to="/"]
|
||||
Home,
|
||||
#[to="/login"]
|
||||
Login,
|
||||
#[to="/register"]
|
||||
Register,
|
||||
#[to="/delete_account"]
|
||||
Delete,
|
||||
#[to="/posts/{id}"]
|
||||
ViewPost(i32),
|
||||
#[to="/posts/view"]
|
||||
ViewPosts,
|
||||
}
|
||||
```
|
||||
|
||||
你還可以拿到 url 中的參數,透過在`#[to = ""]` 中宣告 `{}`。`{}` 代表下一個分隔符號("/"、"?"、"&"、"\#" )之前, url 中的參數。`{*}` 表示取得直到後續字符匹配為止之間的變數,如果不存在任何字串,則它將匹配任何內容。 `{<number>}` 表示取得特定數量的的分隔符號之前的變數。(例如: `{2}` 會取得兩個分隔符號之前的變數。)
|
||||
|
||||
對於有命名欄位的 struct 與 enum,你必須給出變數的名字,像是: `{user_name}` 或是 `{*:age}`。
|
||||
|
||||
Switch trait 可以協助取得比起字串要更有結構的變數。你可以實作 `Switch`,這樣你就可以得到特定結構的變數,而他會是一個 `unsize`。但如果這個 URL 無法被轉換,就會被視為沒有匹配。
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
---
|
||||
description: Yew 與瀏覽器的 API 的接合劑
|
||||
---
|
||||
|
||||
# Services
|
||||
|
||||
這個區塊有的文章:
|
||||
|
||||
- [Format](services/format.md)
|
||||
@ -0,0 +1,6 @@
|
||||
# Format
|
||||
|
||||
:::note
|
||||
`歡迎來貢獻文件:` [Explain the format module in depth](https://github.com/yewstack/docs/issues/24)
|
||||
:::
|
||||
|
||||
@ -0,0 +1,122 @@
|
||||
# 第一個簡單的 App
|
||||
|
||||
首先,先建立一個新的 binary 專案:
|
||||
|
||||
```bash
|
||||
cargo new --bin yew-app && cd yew-app
|
||||
```
|
||||
|
||||
在依賴庫裡加入 `yew` 與 `wasm-bindgen`(最新的版號,請參考[這裡](https://docs.rs/yew))
|
||||
|
||||
{% code title="Cargo.toml" %}
|
||||
```text
|
||||
[package]
|
||||
name = "yew-app"
|
||||
version = "0.1.0"
|
||||
authors = ["Yew App Developer <name@example.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
yew = "0.16"
|
||||
wasm-bindgen = "0.2"
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
將下面的模板複製進你的 `src/lib.rs` 檔案:
|
||||
|
||||
{% code title="src/lib.rs" %}
|
||||
```rust
|
||||
use wasm_bindgen::prelude::*;
|
||||
use yew::prelude::*;
|
||||
|
||||
struct Model {
|
||||
link: ComponentLink<Self>,
|
||||
value: i64,
|
||||
}
|
||||
|
||||
enum Msg {
|
||||
AddOne,
|
||||
}
|
||||
|
||||
impl Component for Model {
|
||||
type Message = Msg;
|
||||
type Properties = ();
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
Self {
|
||||
link,
|
||||
value: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
match msg {
|
||||
Msg::AddOne => self.value += 1
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
|
||||
// 如果有新的不同屬性,應該只能回傳 true
|
||||
// 若是這個元件沒有任何屬性,那就可以只回傳 false
|
||||
false
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<button onclick=self.link.callback(|_| Msg::AddOne)>{ "+1" }</button>
|
||||
<p>{ self.value }</p>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen(start)]
|
||||
pub fn run_app() {
|
||||
App::<Model>::new().mount_to_body();
|
||||
}
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
模板會建置名叫 `Model` 的根元件 `Component`,Model 會顯示一個按鈕,當你按下按鈕時, `Model` 會更新自己的狀態。需要特別注意的是,在 `main()` 裡的 `App::<Model>::new().mount_to_body()`,他會啟動你的 app 並且掛載 `Model` 裡的 HTML 到 `<body>` 標籤中。如果你想要在啟動應用程式時,帶入動態的屬性,你可以改用 `App::<Model>::new().mount_to_body_with_props(..)`。
|
||||
|
||||
最後,在你的專案,新增 `static` 資料夾,並新增 `index.html` 檔案到 static 裡。
|
||||
|
||||
```bash
|
||||
mkdir static
|
||||
```
|
||||
|
||||
{% code title="index.html" %}
|
||||
```bash
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Yew Sample App</title>
|
||||
<script type="module">
|
||||
import init from "./wasm.js"
|
||||
init()
|
||||
</script>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
## 執行你的 App!
|
||||
|
||||
使用 [`wasm-pack`](https://rustwasm.github.io/docs/wasm-pack/) 來執行專案是比較好的選擇。如果你還沒有做任何準備,先用`cargo install wasm-pack`安裝 `wasm-pack` ,然後用下面的指令,建置與開啟開發用伺服器:
|
||||
|
||||
```bash
|
||||
wasm-pack build --target web --out-name wasm --out-dir ./static
|
||||
```
|
||||
|
||||
`wasm-pack` 會在 `./static` 裡產生一個 bundle,裡面包含專案編成的 WebAssembly,以及 JavaScript 的包裹器,這些東西都會在你的專案執行時被載入。
|
||||
|
||||
最後,用你最喜歡的網頁伺服器,去啟動在`./static` 底下的檔案。範例:
|
||||
|
||||
```bash
|
||||
cargo +nightly install miniserve
|
||||
miniserve ./static --index index.html
|
||||
```
|
||||
|
||||
@ -0,0 +1,110 @@
|
||||
# 選擇 web-sys 或 stdweb
|
||||
|
||||
## 簡介
|
||||
|
||||
Yew apps 可以用 `web-sys` 或 `stdweb` 編譯。這兩個 creates 都提供了 Rust 與 WebAPIs 的連結。當把 `yew` 加進你的依賴時,請擇其一使用:
|
||||
|
||||
{% code title="Cargo.toml" %}
|
||||
```rust
|
||||
# 選擇 `web-sys`
|
||||
yew = { version = "0.13", features = ["web_sys"] }
|
||||
|
||||
# 選擇 `stdweb`
|
||||
yew = { version = "0.13", features = ["std_web"] }
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
我們建議使用 `web-sys`,因為他是由 [Rust / Wasm Working Group](https://rustwasm.github.io/) 維護。
|
||||
|
||||
## 使用範例
|
||||
|
||||
```rust
|
||||
// web-sys
|
||||
let window: web_sys::Window = web_sys::window().expect("window not available");
|
||||
window.alert_with_message("hello from wasm!").expect("alert failed");
|
||||
|
||||
// stdweb
|
||||
let window: stdweb::web::Window = stdweb::web::window();
|
||||
window.alert("hello from wasm!");
|
||||
|
||||
// stdweb with js! macro
|
||||
use stdweb::js;
|
||||
use stdweb::unstable::TryFrom;
|
||||
use stdweb::web::Window;
|
||||
|
||||
let window_val: stdweb::Value = js!{ return window; }; // <- JS syntax inside!
|
||||
let window = Window::try_from(window_val).expect("conversion to window failed");
|
||||
window.alert("hello from wasm!");
|
||||
```
|
||||
|
||||
兩個 crates 提供的 APIs 雖然不一樣,但是他們的目標與功能大致相同。
|
||||
|
||||
## 比較
|
||||
|
||||
以下列出幾點,幫助你從不同的角度去考慮要使用 `web-sys` 還是 `stdweb`。請注意,雖然你可以兩個 crates 都使用,但是為了減少編譯成 `.wasm` 的檔案大小,最好還是只選一個使用。
|
||||
|
||||
| | `web-sys` | `stdweb` |
|
||||
| :--- | :--- | :--- |
|
||||
|
||||
|
||||
| 專案狀態 | 由 [Rust / Wasm Working Group](https://rustwasm.github.io/) 持續維護中 | GitHub repo 已經有四個月沒有動靜了 |
|
||||
| :--- | :--- | :--- |
|
||||
|
||||
|
||||
| Web API 覆蓋率 | Rust APIs 是由 Web IDL 自動產生,所以應該已經有 100% 的覆蓋率 | 依社群所需加入 Browser APIs |
|
||||
| :--- | :--- | :--- |
|
||||
|
||||
|
||||
| Rust API 設計 | 使用保守的方式,大多的 API 呼叫後會返回 `Result` | 通常比起使用 `Result` 更傾向於直接造成 panic。例如,在 worker 中呼叫 `stdweb::web::window()` 的話就會 panic。 |
|
||||
| :--- | :--- | :--- |
|
||||
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="text-align:left">支援的建置工具</th>
|
||||
<th style="text-align:left">
|
||||
<ul>
|
||||
<li><code>wasm-bindgen</code>
|
||||
</li>
|
||||
<li><code>wasm-pack</code>
|
||||
</li>
|
||||
</ul>
|
||||
</th>
|
||||
<th style="text-align:left">
|
||||
<ul>
|
||||
<li><code>cargo-web</code>
|
||||
</li>
|
||||
<li><code>wasm-bindgen</code>
|
||||
</li>
|
||||
<li><code>wasm-pack</code>
|
||||
</li>
|
||||
</ul>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table><table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="text-align:left">支援的目標平台</th>
|
||||
<th style="text-align:left">
|
||||
<ul>
|
||||
<li><code>wasm32-unknown-unknown</code>
|
||||
</li>
|
||||
</ul>
|
||||
</th>
|
||||
<th style="text-align:left">
|
||||
<ul>
|
||||
<li><code>wasm32-unknown-unknown</code>
|
||||
</li>
|
||||
<li><code>wasm32-unknown-emscripten</code>
|
||||
</li>
|
||||
<li><code>asmjs-unknown-emscripten</code>
|
||||
</li>
|
||||
</ul>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
@ -0,0 +1,12 @@
|
||||
# 透過範例學習
|
||||
|
||||
我們有各種範例(都持續在維護中),建議你可以仔細閱讀他們,以了解如何使用各種不同的框架功能。當遇到問題或需要幫忙時,我們也很歡迎大家 pull-requests 或開 issues ♥️
|
||||
|
||||
* [**Todo App \(stdweb\)**](https://github.com/yewstack/yew/tree/v0.14.0/examples/std_web/todomvc)
|
||||
* [**Todo App \(web\_sys\)**](https://github.com/yewstack/yew/tree/v0.14.0/examples/web_sys/todomvc)
|
||||
* [**Custom Components**](https://github.com/yewstack/yew/tree/v0.14.0/examples/custom_components)
|
||||
* [**Multi-threading \(Agents\) \(stdweb\)**](https://github.com/yewstack/yew/tree/v0.14.0/examples/std_web/multi_thread)
|
||||
* [**Multi-threading \(Agents\) \(web\_sys\)**](https://github.com/yewstack/yew/tree/v0.14.0/examples/web_sys/multi_thread)
|
||||
* [**Timer Service**](https://github.com/yewstack/yew/tree/v0.14.0/examples/timer)
|
||||
* [**Nested Components**](https://github.com/yewstack/yew/tree/v0.14.0/examples/nested_list)
|
||||
|
||||
@ -0,0 +1,137 @@
|
||||
---
|
||||
description: Set yourself up for success
|
||||
---
|
||||
|
||||
# 專案設定
|
||||
|
||||
## Rust
|
||||
|
||||
首先,你的電腦裡必須要安裝 Rust。請參考[官網的教學](https://www.rust-lang.org/tools/install)安裝 Rust 與 `cargo` 這個套件管理工具。
|
||||
|
||||
## **Wasm 編譯工具**
|
||||
|
||||
我們需要額外的工具來增加 WebAssembly 與 JavaScript 的互操作性。此外,根據你選擇的工具,他們可以產生當你的應用程式運行在瀏覽器時, `.wasm` 檔案所需要的 JavaScript 程式碼,減少佈署與打包的麻煩。
|
||||
|
||||
### [**`wasm-pack`**](https://rustwasm.github.io/docs/wasm-pack/)
|
||||
|
||||
一套 CLI 工具,由 Rust/Wasm Working Group 為了編譯並打包 WebAssembly 所開發的。最好與 Webpack 的 [`wasm-pack-plugin`](https://github.com/wasm-tool/wasm-pack-plugin) 搭配使用。
|
||||
|
||||
[開始使用 wasm-pack](project-setup/using-wasm-pack.md)
|
||||
|
||||
### [**`wasm-bindgen`**](https://rustwasm.github.io/docs/wasm-bindgen/)
|
||||
|
||||
同時是套件,也是 CLI 工具,並由 Rust / Wasm Working Group 開發。他是一套較底層的工具(通常是 `wasm-pack` 內部使用),用以增加 JavaScript 與 WebAssembly 的互操作性。我們不建議直接使用 `wasm-bindgen`,因為你需要多寫一些 JavaScript 的程式碼來引入你的 WebAssembly 二進位檔案。雖然如此,你仍然可以使用 wasm-bindgen,更多資訊請參考 [**`wasm-bindgen` guide**](https://rustwasm.github.io/docs/wasm-bindgen/)**。**
|
||||
|
||||
[開始使用 wasm-bindgen](project-setup/using-wasm-bindgen.md)
|
||||
|
||||
### [**`cargo-web`**](https://github.com/koute/cargo-web)
|
||||
|
||||
在 `wasm-pack` 與 `wasm-bindgen` 出來之前,這是我們的首選工具。在安裝與執行方面,他的速度仍是最快的,我們推薦你安裝他去執行我們的那些還沒有使用 `wasm-pack` 的範例。
|
||||
|
||||
[開始使用 cargo-web](project-setup/using-cargo-web.md)
|
||||
|
||||
### 比較
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="text-align:left"></th>
|
||||
<th style="text-align:left"><code>wasm-pack</code>
|
||||
</th>
|
||||
<th style="text-align:left"><code>wasm-bindgen</code>
|
||||
</th>
|
||||
<th style="text-align:left"><code>cargo-web</code>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="text-align:left">專案狀態</td>
|
||||
<td style="text-align:left">持續由 <a href="https://rustwasm.github.io/">Rust / Wasm Working Group</a> 維護中</td>
|
||||
<td
|
||||
style="text-align:left">持續由 <a href="https://rustwasm.github.io/">Rust / Wasm Working Group</a> 維護中</td>
|
||||
<td
|
||||
style="text-align:left">GitHub Repo 已經六個月以上沒有動靜了</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">開發體驗</td>
|
||||
<td style="text-align:left">還可以,需要搭配 Webpack</td>
|
||||
<td
|
||||
style="text-align:left">太過底層,你需要寫一腳本來優化開發體驗</td>
|
||||
<td
|
||||
style="text-align:left">可以動!另外無需外部套件支援</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">本地端的伺服器 (Local Server)</td>
|
||||
<td
|
||||
style="text-align:left">搭配 <code>webpack</code> 插件</td>
|
||||
<td style="text-align:left">不支援</td>
|
||||
<td style="text-align:left">支援</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">當檔案被更動,自動重編譯</td>
|
||||
<td
|
||||
style="text-align:left">搭配 <code>webpack</code> 插件</td>
|
||||
<td style="text-align:left">不支援</td>
|
||||
<td style="text-align:left">支援</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">無頭瀏覽器測試</td>
|
||||
<td style="text-align:left"><a href="https://rustwasm.github.io/docs/wasm-pack/commands/test.html">Supported</a>
|
||||
</td>
|
||||
<td style="text-align:left"><a href="https://rustwasm.github.io/docs/wasm-bindgen/wasm-bindgen-test/index.html">Supported</a>
|
||||
</td>
|
||||
<td style="text-align:left"><a href="https://github.com/koute/cargo-web#features">Supported</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">支援的目標程式碼</td>
|
||||
<td
|
||||
style="text-align:left">
|
||||
<ul>
|
||||
<li><code>wasm32-unknown-unknown</code>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td style="text-align:left">
|
||||
<ul>
|
||||
<li><code>wasm32-unknown-unknown</code>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td style="text-align:left">
|
||||
<ul>
|
||||
<li><code>wasm32-unknown-unknown</code>
|
||||
</li>
|
||||
<li><code>wasm32-unknown-emscripten</code>
|
||||
</li>
|
||||
<li><code>asmjs-unknown-emscripten</code>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left"><code>web-sys</code>
|
||||
</td>
|
||||
<td style="text-align:left">相容</td>
|
||||
<td style="text-align:left">相容</td>
|
||||
<td style="text-align:left">不相容</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left"><code>stdweb</code>
|
||||
</td>
|
||||
<td style="text-align:left">相容</td>
|
||||
<td style="text-align:left">相容</td>
|
||||
<td style="text-align:left">相容</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">範例用法</td>
|
||||
<td style="text-align:left"><a href="https://github.com/yewstack/yew-wasm-pack-minimal">新手模板</a>
|
||||
</td>
|
||||
<td style="text-align:left">Yew 範例的<a href="https://github.com/yewstack/yew/blob/master/examples/build_all.sh">編譯腳本</a>
|
||||
</td>
|
||||
<td style="text-align:left">Yew 範例的<a href="https://github.com/yewstack/yew/blob/master/examples/build_all.sh">編譯腳本</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@ -0,0 +1,32 @@
|
||||
# 使用 cargo-web
|
||||
|
||||
Cargo web 是一個 cargo 的指令之一,用來建置客戶端的網頁應用程式。使用它可以非常輕鬆的建置與開發網頁應用程式。他也是唯一一個支援 Emscripten targets 的工具。詳情請見[這裡](https://github.com/koute/cargo-web)。
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
cargo install cargo-web
|
||||
```
|
||||
|
||||
## Build
|
||||
|
||||
```bash
|
||||
cargo web build
|
||||
```
|
||||
|
||||
## Run
|
||||
|
||||
```bash
|
||||
cargo web start
|
||||
```
|
||||
|
||||
## 支援目標平台
|
||||
|
||||
* `wasm32-unknown-unknown`
|
||||
* `wasm32-unknown-emscripten`
|
||||
* `asmjs-unknown-emscripten`
|
||||
|
||||
:::note
|
||||
更多關於 `*-emscripten` targets 的資訊,請自行安裝 Emscripten SDK。
|
||||
:::
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
# 使用 wasm-bindgen
|
||||
|
||||
:::note
|
||||
`歡迎來貢獻文件:`[`解說如何用 wasm-bindgen 建立一個應用程式`](https://github.com/yewstack/docs/issues/34)\`\`
|
||||
:::
|
||||
|
||||
@ -0,0 +1,42 @@
|
||||
# 使用 wasm-pack
|
||||
|
||||
這個工具由 Rust / Wasm Working Group 開發,是建置 WebAssembly 應用程式中,社群最活躍的開發工具。他可以幫忙打包程式碼進 `npm` 的模組中,同時也有一個相應的 [Webpack plugin](https://github.com/wasm-tool/wasm-pack-plugin) 可以配合使用,並輕鬆跟已經存在的 JavaScript 應用程式整合。詳情請參考[這裡](https://rustwasm.github.io/docs/wasm-pack/introduction.html)。
|
||||
|
||||
:::note
|
||||
注意,使用 `wasm-pack` 時,`Cargo.toml` 的 crate-type 必須是 `cdylib`。
|
||||
:::
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
cargo install wasm-pack
|
||||
```
|
||||
|
||||
## Build
|
||||
|
||||
這個指令會編譯你的程式碼,並將編譯好的 WebAssembly 與用於啟動專案的 JavaScript wrapper,在 .`/pkg` 的資料夾中製作成一個 bundle。
|
||||
|
||||
```bash
|
||||
wasm-pack build
|
||||
```
|
||||
|
||||
## Bundle
|
||||
|
||||
有關更多 Rollup 的資訊,請參見這個[指南](https://rollupjs.org/guide/en/#quick-start)。
|
||||
|
||||
```bash
|
||||
rollup ./main.js --format iife --file ./pkg/bundle.js
|
||||
```
|
||||
|
||||
## Serve
|
||||
|
||||
你可以使用任何你喜歡的伺服器服務。這裡我們只示範用用簡易的 python 伺服器服務,在 [http://\[::1\]:8000](http://[::1]:8000) 啟動我們的專案。
|
||||
|
||||
```bash
|
||||
python -m http.server 8000
|
||||
```
|
||||
|
||||
## 支援目標平台
|
||||
|
||||
* `wasm32-unknown-unknown`
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
# 初始模板
|
||||
|
||||
## `wasm-pack`
|
||||
|
||||
* [Minimal Template](https://github.com/yewstack/yew-wasm-pack-minimal) - 使用 `wasm-pack` 與 `rollup` 來建置應用程式。你必須用你自己的伺服器服務來啟動它。
|
||||
* [Webpack Template](https://github.com/yewstack/yew-wasm-pack-template) - 使用 `wasm-pack` 與 [`wasm-pack-plugin`](https://github.com/wasm-tool/wasm-pack-plugin),用 Wepack 套件來簡化開發流程。
|
||||
|
||||
使用上述的模板與單純使用 `cargo-web` 最重要的區別在於,模板使用的是 `lib` 而不是 `bin` crate,而且程式的進入點會註解 `#[wasm_bindgen]`
|
||||
|
||||
你的 `Cargo.toml` 必須要設定一個 `cdylib` 的 crate-type。
|
||||
|
||||
{% code title="Cargo.toml" %}
|
||||
```text
|
||||
[package]
|
||||
name = "yew-app"
|
||||
version = "0.1.0"
|
||||
authors = ["Yew App Developer <name@example.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
# for web_sys
|
||||
yew = 0.15
|
||||
# or for stdweb
|
||||
# yew = { version = "0.15", package = "yew-stdweb" }
|
||||
wasm-bindgen = "0.2"
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
## 其他的模板
|
||||
|
||||
* [Parcel Template](https://github.com/spielrs/yew-parcel-template) - 由一個社群成員用 [Parcel](https://parceljs.org/) 製作
|
||||
|
||||
46
website/translated_docs/zh-TW/version-0.17.3/intro.md
Normal file
46
website/translated_docs/zh-TW/version-0.17.3/intro.md
Normal file
@ -0,0 +1,46 @@
|
||||
---
|
||||
title: 簡介
|
||||
---
|
||||
|
||||
## 什麼是 Yew?
|
||||
|
||||
**Yew** 是現代化的 [Rust](https://www.rust-lang.org/) 框架,使用 [WebAssembly](https://webassembly.org/) 來開發多執行緒的網頁前端應用程式
|
||||
|
||||
* **基於元件的框架**,可以輕鬆開發互動的使用者介面 \(UI\)。有使用過 [React](https://reactjs.org/) 與 [Elm](https://elm-lang.org/) 的開發者在使用 Yew 的時候更容易上手。
|
||||
* **高效能**,減少 DOM API 的呼叫次數,並幫助開發者輕鬆的將行程分流到背景的 web workers 中執行
|
||||
* **與 JavaScript 互通**,允許開發者使用 NPM 的套件,並可以與現有的 JavaScript 應用程式整合
|
||||
|
||||
### 加入我們 😊
|
||||
|
||||
* 你可以在 [GitHub issues page](https://github.com/yewstack/yew/issues) 回報 bugs 及針對功能進行討論
|
||||
* 我們歡迎大家多發 PR \(pull request\)。 如果你有興趣與我們一起開發,別忘了先閱讀 [good first issues](https://github.com/yewstack/yew/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) !
|
||||
* 我們 [Gitter](https://gitter.im/yewframework/Lobby) 聊天室非常活躍,歡迎提問
|
||||
|
||||
### 準備好「潛」入了嗎?
|
||||
|
||||
點選下列的連結學習如何建立一個 Yew 應用程式並且從社群的範例專案中學習
|
||||
|
||||
[專案設定](getting-started/project-setup.md)
|
||||
|
||||
### 還在猶豫嗎?
|
||||
|
||||
這個專案是建立在最新穎的科技之上,對於想要打造未來基礎專案的開發者而言是絕佳的選擇。以下是我們認為 Yew 會成為網路開發未來式的幾個理由。
|
||||
|
||||
#### 等等,為何選擇 WebAssembly ?
|
||||
|
||||
WebAssembly \(Wasm\) 是一個可攜式的低階語言也是 Rust 的編譯目標之一。它在瀏覽器中具有原生的執行速度且可以跟 JavaScript 相互協作還得到所有主要瀏覽器的支援。如果你想知道如何在應用程式中充分利用 WebAssembly ,不妨檢閱這個[使用情境](https://webassembly.org/docs/use-cases/)列表。
|
||||
|
||||
注意, Wasm (尚且)不是改善網路應用程式效能的萬靈丹。最少目前為止,在使用 DOM API 上 Wasm 仍然比不上直接以 JavaScript 呼叫。但這僅是暫時的問題, [WebAssembly Interface Types](https://github.com/WebAssembly/interface-types/blob/master/proposals/interface-types/Explainer.md) 提案正是以它作為解決的目標。如果你想瞭解更多有這個議題的資訊,別忘了檢閱這篇 Mozilla 的[超棒文章](https://hacks.mozilla.org/2019/08/webassembly-interface-types/)。
|
||||
|
||||
#### 好的,但為什麼是 Rust 呢?
|
||||
|
||||
Rust 的速度極快,同時豐富的型別系統和所有權模型也讓它非常可靠。雖然它的學習曲線陡峭,但這些付出會非常值得。Rust 也分別在 [2016](https://insights.stackoverflow.com/survey/2016#technology-most-loved-dreaded-and-wanted) 、 [2017](https://insights.stackoverflow.com/survey/2017#most-loved-dreaded-and-wanted) 、 [2018](https://insights.stackoverflow.com/survey/2018#technology-_-most-loved-dreaded-and-wanted-languages) 、 [2019](https://insights.stackoverflow.com/survey/2019#technology-_-most-loved-dreaded-and-wanted-languages) 連續四年在 Stack Overflow 的開發者調查中獲選為最喜愛的程式設計語言。
|
||||
|
||||
Rust 豐富的型別系統及所有權模型協助開發者撰寫更加安全的程式碼。忘了 JavaScript 中難以追蹤的競賽條件吧!在多數情況下 Rust 的編譯器甚至可以在你的應用程式執行前就把 bug 抓出來。而且就算你的應用程式真的在執行時發生了錯誤,你仍然可以在瀏覽器控制台中取得 Rust 程式碼的完整堆疊追蹤。
|
||||
|
||||
#### 有其他選擇嗎?
|
||||
|
||||
我們喜愛跟其他專案分享點子而且相信在互相幫助之下可以激發這個最新科技的全部潛能。如果你不是 Yew 的一份子,那你或許會想要關注這些專案。
|
||||
|
||||
* [Percy](https://github.com/chinedufn/percy) —_「 Rust + WebAssembly 的模組化工具組,用於建立同購的網路應用程式」_
|
||||
* [Seed](https://github.com/seed-rs/seed) —_「建立網路應用程式的 Rust 框架」_
|
||||
6
website/translated_docs/zh-TW/version-0.17.3/more/css.md
Normal file
6
website/translated_docs/zh-TW/version-0.17.3/more/css.md
Normal file
@ -0,0 +1,6 @@
|
||||
# CSS
|
||||
|
||||
<TODO>
|
||||
|
||||
有關 CSS 的支援與建議可以在這裡找到: [https://github.com/yewstack/yew/issues/533](https://github.com/yewstack/yew/issues/533)
|
||||
|
||||
@ -0,0 +1,51 @@
|
||||
# 除錯
|
||||
|
||||
## Panics
|
||||
|
||||
請使用 [`console_error_panic`](https://github.com/rustwasm/console_error_panic_hook) crate ,他會用 Rust symbols 來做 stacktraces。注意,他跟 `cargo-web` 不相容。
|
||||
|
||||
## Console Logging
|
||||
|
||||
通常,Wasm 的網頁應用程式可以跟瀏覽器的 API 互操作,所以 `console.log` 這個 api 也不例外,你可以使用以下幾種方法:
|
||||
|
||||
### [`wasm-logger`](https://crates.io/crates/wasm-logger)
|
||||
|
||||
這個 crate 整合了令人熟悉的 Rust `log` crate:
|
||||
|
||||
```rust
|
||||
// 設定
|
||||
fn main() {
|
||||
wasm_logger::init(wasm_logger::Config::default());
|
||||
}
|
||||
|
||||
// 使用
|
||||
log::info!("Update: {:?}", msg);
|
||||
```
|
||||
|
||||
### **\`\`**[**`ConsoleService`**](https://docs.rs/yew/0.13.2/yew/services/console/struct.ConsoleService.html)**\`\`**
|
||||
|
||||
Yew 包含了這個 service,而且如果 `"services"` 這個 feaure 有被打開的話,你可以直接使用他:
|
||||
|
||||
```rust
|
||||
// 使用
|
||||
ConsoleService::new()::info(format!("Update: {:?}", msg));
|
||||
```
|
||||
|
||||
## Source Maps
|
||||
|
||||
目前 Rust/Wasm 網頁應用程式,不對 source maps 第一線支援。當然,這件事在未來可能會改變,如果這裡寫的資訊不正確,或是事情有所變化,請建議我們修改這篇文件!
|
||||
|
||||
### 最新資訊
|
||||
|
||||
\[2019 12月\] [Chrome DevTools update](https://developers.google.com/web/updates/2019/12/webassembly#the_future)
|
||||
|
||||
> 但還是有大量的工作要做。舉例還說,在工具方面,Emscripten \(Binaryen\) 與 wasm-pack \(wasm-bindgen\),還不支援更新轉換他們的行為的 DWARF 資訊。
|
||||
|
||||
\[2020\] [Rust Wasm 除錯指南](https://rustwasm.github.io/book/reference/debugging.html#using-a-debugger)
|
||||
|
||||
> 不幸地,WebAssembly 的除錯還不夠完善。在大部分的 Unix 系統中,[DWARF](http://dwarfstd.org/) 被用來編碼除錯器需要提供的程式碼等級的資訊。還有一種在 Windows 上的編碼資訊。但現在還沒有跟 WebAssembly 等價。
|
||||
|
||||
\[2019\] [Rust Wasm roadmap](https://rustwasm.github.io/rfcs/007-2019-roadmap.html#debugging)
|
||||
|
||||
> 除錯是一件棘手的事情,因為大部分的事情都不是掌握在這個工作群組中,而是依賴 WebAssembly 的標準,與瀏覽器的開發者工具如何實作。
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
---
|
||||
description: 函式庫可以幫助 yew 的開發者
|
||||
---
|
||||
|
||||
# 額外的函式庫
|
||||
|
||||
### Yewtil
|
||||
|
||||
Yewtil 是一個常見的工具懶人包,可以幫助你編寫 Yew 的程式碼,裡面包含了:
|
||||
|
||||
* NeqAssign - 如前面的章節所述,這是一個減少因為屬性改變而重新渲染的最佳方法。
|
||||
* PureComponents - 不會更新自己狀態的元件。在他的生命周期底下使用 NeqAssign,可以讓他就像是 memoized 的函式。他可以寫在 `html!` 巨集中看起來就像是一般的元件。
|
||||
* Lrc - linked list 參考計數的智慧指針函式,跟 `Rc` 差不多,但是他可以讓新的資料更新他的模型。
|
||||
* Mrc/Irc - 可變與不可變的參考計數智慧指針,跟 Rc 差不多。但是因為 `Mrc` 實作了 `DerefMut` 與 `BorrowMut`,所以讓他在 Yew 中更便於使用。 這讓 `Mrc` 可以與 `NeqAssign` 一起使用。 `Irc` 在資料裡就像是不可變得 view,他可以管理只用來顯示用的資料。
|
||||
* History - 一個歷史追蹤器,他用 `VecDeque` 管理先前的值。
|
||||
* Futures - 支援運行 futures,他會送訊息給元件的更新迴圈。
|
||||
* Fetch - 處理使用 web\_sys 與前面所提的 futures 的功能所發出的請求,的抽象層。
|
||||
|
||||
## 尋找
|
||||
|
||||
我們需要函式庫的社群生態,目前還沒有。
|
||||
|
||||
Boostrap/MaterialUI/任何 css 框架的元件封裝。
|
||||
|
||||
45
website/translated_docs/zh-TW/version-0.17.3/more/roadmap.md
Normal file
45
website/translated_docs/zh-TW/version-0.17.3/more/roadmap.md
Normal file
@ -0,0 +1,45 @@
|
||||
---
|
||||
description: Yew 的版本紀錄
|
||||
---
|
||||
|
||||
# Roadmap
|
||||
|
||||
### 優先順序
|
||||
|
||||
即將推出的新功能和重點開發方向的優先順序將由社群決定。在 2020 的春季,我們會發出一個開發者調查,收集專案方向的回饋。你可以在 [Yew Wiki](https://github.com/yewstack/yew/wiki/Dev-Survey-%5BSpring-2020%5D) 中找到結果。
|
||||
|
||||
:::note
|
||||
你可以在 Yew GitHub 追蹤我們主要的開發方向 [Project board](https://github.com/yewstack/yew/projects)
|
||||
:::
|
||||
|
||||
### 重點 <a id="focuses"></a>
|
||||
|
||||
1. 需求最多的功能
|
||||
2. 產品準備
|
||||
3. 文件
|
||||
4. 痛點
|
||||
|
||||
#### 需求最多的功能 <a id="top-requested-features"></a>
|
||||
|
||||
1. [函數式元件](https://github.com/yewstack/yew/projects/3)
|
||||
2. [元件函式庫](https://github.com/yewstack/yew/projects/4)
|
||||
3. 更好的狀態管理器
|
||||
4. [Server side rendering](https://github.com/yewstack/yew/projects/5)
|
||||
|
||||
#### 產品準備
|
||||
|
||||
* 提升 Yew 的測試覆蓋率
|
||||
* 減少二進位檔的大小
|
||||
* [Benchmark performance](https://github.com/yewstack/yew/issues/5)
|
||||
|
||||
#### 文件
|
||||
|
||||
* 建立教學文件
|
||||
* 簡化專案設定
|
||||
|
||||
#### 痛點
|
||||
|
||||
* [元件模板](https://github.com/yewstack/yew/issues/830)
|
||||
* Fetch API
|
||||
* Agents
|
||||
|
||||
12
website/translated_docs/zh-TW/version-0.17.3/more/testing.md
Normal file
12
website/translated_docs/zh-TW/version-0.17.3/more/testing.md
Normal file
@ -0,0 +1,12 @@
|
||||
---
|
||||
description: 測試你的專案
|
||||
---
|
||||
|
||||
# 測試
|
||||
|
||||
<TODO>
|
||||
|
||||
## wasm\_bindgen\_test <a id="wasm_bindgen_test"></a>
|
||||
|
||||
Rust WASM 工作群組有維護一個 crate 叫作 [`wasm_bindgen_test`](https://rustwasm.github.io/docs/wasm-bindgen/wasm-bindgen-test/index.html) ,他讓你可以在瀏覽器裡跑類似於用內建的巨集`#[test]`測試流程。 更多資訊可以參考 [Rust WASM working group's documentation](https://rustwasm.github.io/docs/wasm-bindgen/wasm-bindgen-test/index.html) 。
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
---
|
||||
title: How it works
|
||||
description: Low level details about the framework
|
||||
id: version-0.17.3-how-it-works
|
||||
original_id: how-it-works
|
||||
---
|
||||
|
||||
# Low-level library internals
|
||||
|
||||
Component-lifecycle state machine, vdom diff algorithm.
|
||||
|
||||
@ -0,0 +1,189 @@
|
||||
---
|
||||
title: Optimizations & Best Practices
|
||||
sidebar_label: Optimizations
|
||||
description: Make your app faster
|
||||
id: version-0.17.3-optimizations
|
||||
original_id: optimizations
|
||||
---
|
||||
|
||||
## neq\_assign
|
||||
|
||||
When a component receives props from its parent component, the `change` method is called. This, in addition to allowing you to update the component's state, also allows you to return a `ShouldRender` boolean value that indicates if the component should re-render itself in response to the prop changes.
|
||||
|
||||
Re-rendering is expensive, and if you can avoid it, you should. As a general rule, you only want to re-render when the props actually changed. The following block of code represents this rule, returning `true` if the props differed from the previous props:
|
||||
|
||||
```rust
|
||||
use yew::ShouldRender;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
struct ExampleProps;
|
||||
|
||||
struct Example {
|
||||
props: ExampleProps,
|
||||
};
|
||||
|
||||
impl Example {
|
||||
fn change(&mut self, props: ExampleProps) -> ShouldRender {
|
||||
if self.props != props {
|
||||
self.props = props;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
But we can go further! This is six lines of boilerplate can be reduced down to one by using a trait and a blanket implementation for anything that implements `PartialEq`. Check out the `yewtil` crate's `NeqAssign` trait [here](https://docs.rs/yewtil/*/yewtil/trait.NeqAssign.html).
|
||||
|
||||
## Using smart pointers effectively
|
||||
|
||||
**Note: if you're unsure about some of the terms used in this section, the Rust Book has a useful
|
||||
[chapter about smart pointers](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html).**
|
||||
|
||||
In an effort to avoid cloning large amounts of data to create props when re-rendering, we can use
|
||||
smart pointers to only clone a reference to the data instead of the data itself. If you pass
|
||||
references to the relevant data in your props and child components instead of the actual data you
|
||||
can avoid cloning any data until you need to modify it in the child component, where you can
|
||||
use `Rc::make_mut` to clone and obtain a mutable reference to the data you want to alter.
|
||||
|
||||
This brings further benefits in `Component::change` when working out whether prop changes require
|
||||
the component to re-render. This is because instead of comparing the value of the data the
|
||||
underlying pointer addresses (i.e. the position in a machine's memory where the data is stored) can
|
||||
instead be compared; if two pointers point to the same data then the value of the data they point to
|
||||
must be the same. Note that the inverse might not be true! Even if two pointer addresses differ the
|
||||
underlying data might still be the same - in this case you should compare the underlying data.
|
||||
|
||||
To do this comparison you'll need to use `Rc::ptr_eq` instead of just using `PartialEq` (which is
|
||||
automatically used when comparing data using the equality operator `==`). The Rust documentation
|
||||
has [more details about `Rc::ptr_eq`](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.ptr_eq).
|
||||
|
||||
This optimization is most useful for data types that don't implement `Copy`. If you can copy your
|
||||
data cheaply, then it isn't worth putting it behind a smart pointer. For structures that
|
||||
can be data-heavy like `Vec`s, `HashMap`s, and `String`s using smart pointers is likely to bring
|
||||
performance improvements.
|
||||
|
||||
This optimization works best if the values are never updated by the children, and even better, if
|
||||
they are rarely updated by parents. This makes `Rc<_>s` a good choice for wrapping property values
|
||||
in for pure components.
|
||||
|
||||
## View functions
|
||||
|
||||
For code readability reasons, it often makes sense to migrate sections of `html!` to their own
|
||||
functions. Not only does this make your code more readable because it reduces the amount of
|
||||
indentation present, it also encourages good design patterns – particularly around building
|
||||
composable applications because these functions can be called in multiple places which reduces the
|
||||
amount of code that has to be written.
|
||||
|
||||
## Pure Components
|
||||
|
||||
Pure components are components that don't mutate their state, only displaying content and
|
||||
propagating messages up to normal, mutable components. They differ from view functions in that they
|
||||
can be used from within the `html!` macro using the component syntax \(`<SomePureComponent />`\)
|
||||
instead of expression syntax \(`{some_view_function()}`\), and that depending on their
|
||||
implementation, they can be memoized (this means that once a function is called its value is "saved"
|
||||
so that if it's called with the same arguments more than once it doesn't have to recompute its value
|
||||
and can just return the saved value from the first function call) - preventing re-renders for
|
||||
identical props using the aforementioned `neq_assign` logic.
|
||||
|
||||
Yew doesn't natively support pure or function components, but they are available via external crates.
|
||||
|
||||
## Functional components (a.k.a hooks)
|
||||
|
||||
Functional components are still in development! There's a
|
||||
[project board](https://github.com/yewstack/yew/projects/3) detailing their status.
|
||||
|
||||
## Keyed DOM nodes when they arrive
|
||||
|
||||
## Reducing compile time using workspaces
|
||||
|
||||
Arguably, the largest drawback to using Yew is the long time it takes to compile Yew apps. The time
|
||||
taken to compile a project seems to be related to the quantity of code passed to the `html!` macro.
|
||||
This tends to not be much of an issue for smaller projects, but for larger applications it makes
|
||||
sense to split code across multiple crates to minimize the amount of work the compiler has to do for
|
||||
each change made to the application.
|
||||
|
||||
One possible approach is to make your main crate handle routing/page selection, and then make a
|
||||
different crate for each page, where each page could be a different component, or just a big
|
||||
function that produces `Html`. Code which is shared between the crates containing different parts of
|
||||
the application could be stored in a separate crate which is depended on throughout the project.
|
||||
In the best case scenario, you go from rebuilding all of your code on each compile to rebuilding
|
||||
only the main crate, and one of your page crates. In the worst case, where you edit something in the
|
||||
"common" crate, you will be right back to where you started: compiling all code that depends on that
|
||||
commonly shared crate, which is probably everything else.
|
||||
|
||||
If your main crate is too heavyweight, or you want to rapidly iterate on a deeply nested page \(eg.
|
||||
a page that renders on top of another page\), you can use an example crate to create a simplified
|
||||
implementation of the main page and render the component you are working on on top of that.
|
||||
|
||||
## Reducing binary sizes
|
||||
|
||||
* optimize Rust code
|
||||
* `wee_alloc` \( using tiny allocator \)
|
||||
* `cargo.toml` \( defining release profile \)
|
||||
* optimize wasm code using `wasm-opt`
|
||||
|
||||
**Note: more information about reducing binary sizes can be found in the
|
||||
[Rust Wasm Book](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size).**
|
||||
|
||||
### wee\_alloc
|
||||
|
||||
[wee\_alloc](https://github.com/rustwasm/wee_alloc) is a tiny allocator that is much smaller than the allocator that is normally used in Rust binaries. Replacing the default allocator with this one will result in smaller WASM file sizes, at the expense of speed and memory overhead.
|
||||
|
||||
The slower speed and memory overhead are minor in comparison to the size gains made by not including the default allocator. This smaller file size means that your page will load faster, and so it is generally recommended that you use this allocator over the default, unless your app is doing some allocation-heavy work.
|
||||
|
||||
```rust
|
||||
// Use `wee_alloc` as the global allocator.
|
||||
#[global_allocator]
|
||||
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
|
||||
```
|
||||
|
||||
### Cargo.toml
|
||||
|
||||
It is possible to configure release builds to be smaller using the available settings in the
|
||||
`[profile.release]` section of your `Cargo.toml`.
|
||||
|
||||
|
||||
```text
|
||||
[profile.release]
|
||||
# less code to include into binary
|
||||
panic = 'abort'
|
||||
# optimization over all codebase ( better optimization, slower build )
|
||||
codegen-units = 1
|
||||
# optimization for size ( more aggressive )
|
||||
opt-level = 'z'
|
||||
# optimization for size
|
||||
# opt-level = 's'
|
||||
# link time optimization using using whole-program analysis
|
||||
lto = true
|
||||
```
|
||||
|
||||
### wasm-opt
|
||||
|
||||
Further more it is possible to optimize size of `wasm` code.
|
||||
|
||||
The Rust Wasm Book has a section about reducing the size of WASM binaries:
|
||||
[Shrinking .wasm size](https://rustwasm.github.io/book/game-of-life/code-size.html)
|
||||
|
||||
* using `wasm-pack` which by default optimizes `wasm` code in release builds
|
||||
* using `wasm-opt` directly on `wasm` files.
|
||||
|
||||
```text
|
||||
wasm-opt wasm_bg.wasm -Os -o wasm_bg_opt.wasm
|
||||
```
|
||||
|
||||
#### Build size of 'minimal' example in yew/examples/
|
||||
|
||||
Note: `wasm-pack` combines optimization for Rust and Wasm code. `wasm-bindgen` is used in this example without any Rust size optimization.
|
||||
|
||||
| used tool | size |
|
||||
| :--- | :--- |
|
||||
| wasm-bindgen | 158KB |
|
||||
| wasm-bindgen + wasm-opt -Os | 116KB |
|
||||
| wasm-pack | 99 KB |
|
||||
|
||||
## Further reading:
|
||||
* [The Rust Book's chapter on smart pointers](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html)
|
||||
* [Information from the Rust Wasm Book about reducing binary sizes](https://rustwasm.github.io/book/reference/code-size.html#optimizing-builds-for-code-size)
|
||||
* [Documentation about Rust profiles](https://doc.rust-lang.org/cargo/reference/profiles.html)
|
||||
* [binaryen project](https://github.com/WebAssembly/binaryen)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user