Files
dioxus/docs/nightly/guide/pt-br/interactivity/hooks.html
T
2023-06-01 11:09:51 -05:00

389 lines
27 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js light">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Hooks &amp; Estado de Componentes - Documentação do Dioxus</title>
<!-- Custom HTML head -->
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta name="description" content="Introdução ao Dioxus, um framework portátil, de alto desempenho e ergonômico para criar interfaces de usuário multiplataforma em Rust.">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff" />
<link rel="icon" href="../favicon.svg">
<link rel="shortcut icon" href="../favicon.png">
<link rel="stylesheet" href="../css/variables.css">
<link rel="stylesheet" href="../css/general.css">
<link rel="stylesheet" href="../css/chrome.css">
<link rel="stylesheet" href="../css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="../highlight.css">
<link rel="stylesheet" href="../tomorrow-night.css">
<link rel="stylesheet" href="../ayu-highlight.css">
<!-- Custom theme stylesheets -->
<!-- MathJax -->
<script async type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
</head>
<body>
<!-- Provide site root to javascript -->
<script type="text/javascript">
var path_to_root = "../";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script type="text/javascript">
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script type="text/javascript">
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('no-js')
html.classList.remove('light')
html.classList.add(theme);
html.classList.add('js');
</script>
<!-- Hide / unhide sidebar before it is displayed -->
<script type="text/javascript">
var html = document.querySelector('html');
var sidebar = 'hidden';
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
}
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
<ol class="chapter"><li class="chapter-item expanded affix "><a href="../index.html">Introdução</a></li><li class="chapter-item expanded "><a href="../getting_started/index.html"><strong aria-hidden="true">1.</strong> Introdução Rápida as Plataformas</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../getting_started/desktop.html"><strong aria-hidden="true">1.1.</strong> Desktop</a></li><li class="chapter-item expanded "><a href="../getting_started/web.html"><strong aria-hidden="true">1.2.</strong> Web</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../getting_started/hot_reload.html"><strong aria-hidden="true">1.2.1.</strong> Hot Reload</a></li></ol></li><li class="chapter-item expanded "><a href="../getting_started/ssr.html"><strong aria-hidden="true">1.3.</strong> Renderização por Servidor</a></li><li class="chapter-item expanded "><a href="../getting_started/tui.html"><strong aria-hidden="true">1.4.</strong> Interface do Terminal</a></li><li class="chapter-item expanded "><a href="../getting_started/mobile.html"><strong aria-hidden="true">1.5.</strong> Móvel</a></li></ol></li><li class="chapter-item expanded "><a href="../describing_ui/index.html"><strong aria-hidden="true">2.</strong> Descrevendo a Interface do Usuário</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../describing_ui/special_attributes.html"><strong aria-hidden="true">2.1.</strong> Atributos Especiais</a></li><li class="chapter-item expanded "><a href="../describing_ui/components.html"><strong aria-hidden="true">2.2.</strong> Componentes</a></li><li class="chapter-item expanded "><a href="../describing_ui/component_props.html"><strong aria-hidden="true">2.3.</strong> Props</a></li><li class="chapter-item expanded "><a href="../describing_ui/component_children.html"><strong aria-hidden="true">2.4.</strong> Componente Filho</a></li></ol></li><li class="chapter-item expanded "><a href="../interactivity/index.html"><strong aria-hidden="true">3.</strong> Interatividade</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../interactivity/event_handlers.html"><strong aria-hidden="true">3.1.</strong> Manipuladores de Eventos</a></li><li class="chapter-item expanded "><a href="../interactivity/hooks.html" class="active"><strong aria-hidden="true">3.2.</strong> Hooks &amp; Estado de Componentes</a></li><li class="chapter-item expanded "><a href="../interactivity/user_input.html"><strong aria-hidden="true">3.3.</strong> Entradas do Usuário</a></li><li class="chapter-item expanded "><a href="../interactivity/sharing_state.html"><strong aria-hidden="true">3.4.</strong> Estado Compartilhado</a></li><li class="chapter-item expanded "><a href="../interactivity/custom_hooks.html"><strong aria-hidden="true">3.5.</strong> Hooks Personalizados</a></li><li class="chapter-item expanded "><a href="../interactivity/dynamic_rendering.html"><strong aria-hidden="true">3.6.</strong> Renderização Dinâmica</a></li><li class="chapter-item expanded "><a href="../interactivity/roteador.html"><strong aria-hidden="true">3.7.</strong> Roteamento</a></li></ol></li><li class="chapter-item expanded "><a href="../async/index.html"><strong aria-hidden="true">4.</strong> Assincronia</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../async/use_future.html"><strong aria-hidden="true">4.1.</strong> UseFuture</a></li><li class="chapter-item expanded "><a href="../async/use_coroutine.html"><strong aria-hidden="true">4.2.</strong> UseCoroutine</a></li><li class="chapter-item expanded "><a href="../async/spawn.html"><strong aria-hidden="true">4.3.</strong> Gerando Futures</a></li></ol></li><li class="chapter-item expanded "><a href="../best_practices/index.html"><strong aria-hidden="true">5.</strong> Práticas Recomendadas</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../best_practices/error_handling.html"><strong aria-hidden="true">5.1.</strong> Tratamento de erros</a></li><li class="chapter-item expanded "><a href="../best_practices/antipatterns.html"><strong aria-hidden="true">5.2.</strong> Antipadrões</a></li></ol></li><li class="chapter-item expanded "><a href="../publishing/index.html"><strong aria-hidden="true">6.</strong> Publicação</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../publishing/desktop.html"><strong aria-hidden="true">6.1.</strong> Desktop</a></li><li class="chapter-item expanded "><a href="../publishing/web.html"><strong aria-hidden="true">6.2.</strong> Web</a></li><li class="spacer"></li></ol></li><li class="chapter-item expanded "><a href="../custom_renderer/index.html"><strong aria-hidden="true">7.</strong> Renderizador Personalizado</a></li><li class="spacer"></li><li class="chapter-item expanded affix "><a href="../roadmap.html">Roteiro</a></li><li class="chapter-item expanded affix "><a href="../contributing.html">Contribuindo</a></li></ol>
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky bordered">
<div class="left-buttons">
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</button>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
<button id="language-toggle" class="icon-button" type="button" title="Select language" aria-label="Select language" aria-haspopup="true" aria-expanded="false" aria-controls="language-list">
<i class="fa fa-globe"></i>
</button>
<ul id="language-list" class="language-popup" aria-label="Languages" role="menu">
<li role="none"><a href="../../en/interactivity/hooks.html"><button role="menuitem" class="language" id="light">English</button></a></li>
<li role="none"><a href="../../pt-br/interactivity/hooks.html"><button role="menuitem" class="language" id="light">Português Brasileiro</button></a></li>
</ul>
</div>
<h1 class="menu-title">Documentação do Dioxus</h1>
<div class="right-buttons">
<a href="../print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
<a href="https://github.com/DioxusLabs/dioxus/edit/master/docs/guide" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
<a href="https://github.com/DioxusLabs/dioxus/edit/master/docs/guide/src/interactivity/hooks.md" title="Suggest an edit" aria-label="Suggest an edit">
<i id="git-edit-button" class="fa fa-edit"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script type="text/javascript">
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="hooks-e-estado-do-componente"><a class="header" href="#hooks-e-estado-do-componente">Hooks e Estado do Componente</a></h1>
<p>Até agora nossos componentes, sendo funções Rust, não tinham estado – eles estavam sempre renderizando a mesma coisa. No entanto, em um componente de interface do usuário, geralmente é útil ter uma funcionalidade com estado para criar interações do usuário. Por exemplo, você pode querer rastrear se o usuário abriu uma lista suspensa e renderizar coisas diferentes de acordo.</p>
<p>Para lógica com estado, você pode usar <em>hooks</em>. <em>Hooks</em> são funções Rust que fazem referência a <code>ScopeState</code> (em um componente, você pode passar <code>&amp;cx</code>), e fornecem funcionalidade e estado.</p>
<h2 id="hook-use_state"><a class="header" href="#hook-use_state">Hook <code>use_state</code></a></h2>
<p><a href="https://docs.rs/dioxus/latest/dioxus/hooks/fn.use_state.html"><code>use_state</code></a> é um dos <em>hooks</em> mais simples.</p>
<ul>
<li>Você fornece um fechamento que determina o valor inicial</li>
<li><code>use_state</code> fornece o valor atual e uma maneira de atualizá-lo, definindo-o para outra coisa</li>
<li>Quando o valor é atualizado, <code>use_state</code> faz o componente renderizar novamente e fornece o novo valor</li>
</ul>
<p>Por exemplo, você pode ter visto o exemplo do contador, no qual o estado (um número) é rastreado usando o <em>hook</em> <code>use_state</code>:</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn App(cx: Scope) -&gt; Element {
// count will be initialized to 0 the first time the component is rendered
let mut count = use_state(cx, || 0);
cx.render(rsx!(
h1 { &quot;High-Five counter: {count}&quot; }
button {
onclick: move |_| {
// changing the count will cause the component to re-render
count += 1
},
&quot;Up high!&quot;
}
button {
onclick: move |_| {
// changing the count will cause the component to re-render
count -= 1
},
&quot;Down low!&quot;
}
))
}
<span class="boring">}
</span></code></pre></pre>
<p><img src="./images/counter.png" alt="Screenshot: counter app" /></p>
<p>Toda vez que o estado do componente muda, ele é renderizado novamente e a função do componente é chamada, para que você possa descrever como deseja que a nova interface do usuário se pareça. Você não precisa se preocupar em &quot;mudar&quot; nada - apenas descreva o que você quer em termos de estado, e Dioxus cuidará do resto!</p>
<blockquote>
<p><code>use_state</code> retorna seu valor envolto em uma <em>smart pointer</em> do tipo <a href="https://docs.rs/dioxus/latest/dioxus/hooks/struct.UseState.html"><code>UseState</code></a>. É por isso que você pode ler o valor e atualizá-lo, mesmo dentro de um manipulador.</p>
</blockquote>
<p>Você pode usar vários <em>hooks</em> no mesmo componente se quiser:</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn App(cx: Scope) -&gt; Element {
let mut count_a = use_state(cx, || 0);
let mut count_b = use_state(cx, || 0);
cx.render(rsx!(
h1 { &quot;Counter_a: {count_a}&quot; }
button { onclick: move |_| count_a += 1, &quot;a++&quot; }
button { onclick: move |_| count_a -= 1, &quot;a--&quot; }
h1 { &quot;Counter_b: {count_b}&quot; }
button { onclick: move |_| count_b += 1, &quot;b++&quot; }
button { onclick: move |_| count_b -= 1, &quot;b--&quot; }
))
}
<span class="boring">}
</span></code></pre></pre>
<p><img src="./images/counter_two_state.png" alt="Screenshot: app with two counters" /></p>
<h2 id="regras-dos-hooks"><a class="header" href="#regras-dos-hooks">Regras dos Hooks</a></h2>
<p>O exemplo acima pode parecer um pouco mágico, já que as funções Rust normalmente não estão associadas ao estado. O Dioxus permite que os <em>hooks</em> mantenham o estado entre as renderizações através de uma referência a <code>ScopeState</code>, e é por isso que você deve passar <code>&amp;cx</code> para eles.</p>
<p>Mas como Dioxus pode diferenciar entre vários <em>hooks</em> no mesmo componente? Como você viu no segundo exemplo, ambas as funções <code>use_state</code> foram chamadas com os mesmos parâmetros, então como elas podem retornar coisas diferentes quando os contadores são diferentes?</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span> let mut count_a = use_state(cx, || 0);
let mut count_b = use_state(cx, || 0);
<span class="boring">}
</span></code></pre></pre>
<p>Isso só é possível porque os dois <em>hooks</em> são sempre chamados na mesma ordem, então Dioxus sabe qual é qual. Portanto, a ordem em que você chama os <em>hooks</em> é importante, e é por isso que você deve seguir certas regras ao usar os <em>hooks</em>:</p>
<ol>
<li><em>Hooks</em> só podem ser usados em componentes ou outros <em>hooks</em> (falaremos disso mais tarde)</li>
<li>Em cada chamada para a função componente
<ol>
<li>Os mesmos <em>hooks</em> devem ser chamados</li>
<li>Na mesma ordem</li>
</ol>
</li>
<li>Os nomes dos <em>hooks</em> devem começar com <code>use_</code> para que você não os confunda acidentalmente com funções normais</li>
</ol>
<p>Essas regras significam que há certas coisas que você não pode fazer com <em>hooks</em>:</p>
<h3 id="sem-hooks-em-condicionais"><a class="header" href="#sem-hooks-em-condicionais">Sem Hooks em Condicionais</a></h3>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// ❌ don't call hooks in conditionals!
// We must ensure that the same hooks will be called every time
// But `if` statements only run if the conditional is true!
// So we might violate rule 2.
if you_are_happy &amp;&amp; you_know_it {
let something = use_state(cx, || &quot;hands&quot;);
println!(&quot;clap your {something}&quot;)
}
// ✅ instead, *always* call use_state
// You can put other stuff in the conditional though
let something = use_state(cx, || &quot;hands&quot;);
if you_are_happy &amp;&amp; you_know_it {
println!(&quot;clap your {something}&quot;)
}
<span class="boring">}
</span></code></pre></pre>
<h3 id="sem-hooks-em-closures"><a class="header" href="#sem-hooks-em-closures">Sem Hooks em Closures</a></h3>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// ❌ don't call hooks inside closures!
// We can't guarantee that the closure, if used, will be called in the same order every time
let _a = || {
let b = use_state(cx, || 0);
b.get()
};
// ✅ instead, move hook `b` outside
let b = use_state(cx, || 0);
let _a = || b.get();
<span class="boring">}
</span></code></pre></pre>
<h3 id="sem-hooks-em-loops"><a class="header" href="#sem-hooks-em-loops">Sem Hooks em Loops</a></h3>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// `names` is a Vec&lt;&amp;str&gt;
// ❌ Do not use hooks in loops!
// In this case, if the length of the Vec changes, we break rule 2
for _name in &amp;names {
let is_selected = use_state(cx, || false);
println!(&quot;selected: {is_selected}&quot;);
}
// ✅ Instead, use a hashmap with use_ref
let selection_map = use_ref(cx, HashMap::&lt;&amp;str, bool&gt;::new);
for name in &amp;names {
let is_selected = selection_map.read()[name];
println!(&quot;selected: {is_selected}&quot;);
}
<span class="boring">}
</span></code></pre></pre>
<h2 id="gancho-use_ref"><a class="header" href="#gancho-use_ref">Gancho <code>use_ref</code></a></h2>
<p><code>use_state</code> é ótimo para rastrear valores simples. No entanto, você pode notar na <a href="https://docs.rs/dioxus/latest/dioxus/hooks/struct.UseState.html"><code>UseState</code> API</a> que a única maneira de modificar seu valor é substituí-lo por algo else (por exemplo, chamando <code>set</code>, ou através de um dos operadores <code>+=</code>, <code>-=</code>). Isso funciona bem quando é barato construir um valor (como qualquer primitivo). Mas e se você quiser manter dados mais complexos no estado dos componentes?</p>
<p>Por exemplo, suponha que queremos manter um <code>Vec</code> de valores. Se o armazenamos com <code>use_state</code>, a única maneira de adicionar um novo valor à lista seria criar um novo <code>Vec</code> com o valor adicional e colocá-lo no estado. Isto é custoso! Queremos modificar o <code>Vec</code> existente.</p>
<p>Felizmente, existe outro <em>hook</em> para isso, <code>use_ref</code>! É semelhante ao <code>use_state</code>, mas permite obter uma referência mutável aos dados contidos.</p>
<p>Aqui está um exemplo simples que mantém uma lista de eventos em um <code>use_ref</code>. Podemos adquirir acesso de escrita ao estado com <code>.write()</code>, e então apenas <code>.push</code> um novo valor para o estado:</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn App(cx: Scope) -&gt; Element {
let list = use_ref(cx, Vec::new);
cx.render(rsx!(
p { &quot;Current list: {list.read():?}&quot; }
button {
onclick: move |event| {
list.with_mut(|list| list.push(event));
},
&quot;Click me!&quot;
}
))
}
<span class="boring">}
</span></code></pre></pre>
<blockquote>
<p>Os valores de retorno de <code>use_state</code> e <code>use_ref</code>, (<code>UseState</code> e <code>UseRef</code>, respectivamente) são de alguma forma semelhantes a [<code>Cell</code>](https://doc.rust-lang.org/std/ cell/) e <a href="https://doc.rust-lang.org/std/cell/struct.RefCell.html"><code>RefCell</code></a> – eles fornecem mutabilidade interior. No entanto, esses <em>wrappers</em> do Dioxus também garantem que o componente seja renderizado novamente sempre que você alterar o estado.</p>
</blockquote>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../interactivity/event_handlers.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next" href="../interactivity/user_input.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../interactivity/event_handlers.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next" href="../interactivity/user_input.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script type="text/javascript">
window.playground_line_numbers = true;
</script>
<script type="text/javascript">
window.playground_copyable = true;
</script>
<script src="../ace.js" type="text/javascript" charset="utf-8"></script>
<script src="../editor.js" type="text/javascript" charset="utf-8"></script>
<script src="../mode-rust.js" type="text/javascript" charset="utf-8"></script>
<script src="../theme-dawn.js" type="text/javascript" charset="utf-8"></script>
<script src="../theme-tomorrow_night.js" type="text/javascript" charset="utf-8"></script>
<script src="../elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
<script src="../mark.min.js" type="text/javascript" charset="utf-8"></script>
<script src="../searcher.js" type="text/javascript" charset="utf-8"></script>
<script src="../clipboard.min.js" type="text/javascript" charset="utf-8"></script>
<script src="../highlight.js" type="text/javascript" charset="utf-8"></script>
<script src="../book.js" type="text/javascript" charset="utf-8"></script>
<!-- Custom JS scripts -->
</body>
</html>