Vuex_html/css_WEB-ITnose を使用してメモを取るアプリケーションを構築する
原文: Learn Vuex by Building a Notes App, with deletions.
この記事は、読者が Vuex ドキュメントの内容に精通していることを前提としています。まだ知らない方はぜひ!
このチュートリアルでは、メモを取るアプリケーションを構築することによって Vuex の使用方法を学びます。 Vuex の基本、いつ使用するか、Vuex を使用する際のコードの編成方法を簡単に紹介します。その後、これらの概念をこのメモ作成アプリケーションに段階的に適用していきます。
これはこれから構築するメモ作成アプリケーションのスクリーンショットです:
ソース コードは Github Repo からダウンロードできます。デモのアドレスはここにあります。
Vuex の概要
Vuex は、主に中規模および大規模のシングルページ アプリケーションで使用される Flux のようなデータ管理アーキテクチャです。これは主に、コードをより適切に整理し、アプリケーション内の状態を保守可能で理解可能な状態に保つのに役立ちます。
Vue.js アプリケーションの状態が何を意味するのかよく理解できない場合は、前に作成した Vue コンポーネントのデータ フィールドを想像してください。 Vuex は、状態をコンポーネントの内部状態とアプリケーションレベルの状態に分割します。
-
コンポーネントの内部状態: 1つのコンポーネント(データフィールド)内でのみ使用される状態
-
アプリケーションレベルの状態: 複数のコンポーネントによって共有される状態
例: 2 つの子コンポーネントを持つ親コンポーネントがあるとします。この親コンポーネントは props を使用してデータを子コンポーネントに渡すことができます。このデータ チャネルは理解しやすいです。
それでは、2 つのサブコンポーネントが相互にデータを共有する必要がある場合はどうすればよいでしょうか? あるいは、サブコンポーネントがデータを親コンポーネントに渡す必要がある場合はどうすればよいでしょうか? これら 2 つの問題は、アプリケーションが小さい場合には簡単に解決できます。カスタム コンポーネントを使用するだけです。イベント。
しかし、アプリが拡大するにつれて、
-
これらのイベントを追跡することがますます困難になります。このイベントをトリガーしたコンポーネントはどれですか?誰がそれを聞いているのでしょうか?
-
ビジネス ロジックはさまざまなコンポーネントに分散されており、さまざまな予期しない問題を引き起こします。
-
イベントの明示的な配布とリスニングにより、親コンポーネントと子コンポーネントは強く結合されます。
Vuex はこれらの問題を解決したいと考えています。Vuex の背後には 4 つの中心的な概念があります:
-
状態ツリー: すべてのアプリケーション レベルの状態を含むオブジェクト
- ゲッター: 内部のストア内の状態を取得する関数コンポーネント
- ミューテーション: 状態を変更するイベント コールバック関数
- アクション: コンポーネント内でミューテーション イベントを分散するために使用される関数
この図の重要なポイント:
- データフローは一方向です
- コンポーネントはアクションを呼び出すことができます
- アクションはミューテーションを配布するために使用されます
- ミューテーションのみが状態を変更できます
- store これはリアクティブです。つまり、状態の変更はコンポーネント内に反映されます
プロジェクトの構造は次のようになります:
- コンポーネント/すべてのコンポーネントが含まれます
- vuex/ Vuex 関連ファイル (ストア、アクション) が含まれています
- build.js は webpack が出力するファイルです
- Index.html はレンダリングされるページです
- main.js はアプリケーションのエントリ ポイントです、ルート インスタンスを含む
- style.css
- webpack.config.js
mkdir vuex-notes-app && cd vuex-note-appnpm init -y
npm install\ webpack webpack-dev-server\ vue-loader vue-html-loader css-loader vue-style-loader vue-hot-reload-api\ babel-loader babel-core babel-plugin-transform-runtime babel-preset-es2015\ babel-runtime@5\ --save-devnpm install vue vuex --save
// webpack.config.jsmodule.exports = { entry: './main.js', output: { path: __dirname, filename: 'build.js' }, module: { loaders: [ { test: /\.vue$/, loader: 'vue' }, { test: /\.js$/, loader: 'babel', exclude: /node_modules/ } ] }, babel: { presets: ['es2015'], plugins: ['transform-runtime'] }}
次に、npm スクリプトの設定をパックしますage.json:
"scripts": { "dev": "webpack-dev-server --inline --hot", "build": "webpack -p"}
後でテスト中や運用中に npm run dev と npm run build を直接実行するだけです。
Vuex ストアを作成する
vuex/ フォルダーに store.js を作成します:
import Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex)const state = { notes: [], activeNote: {}}const mutations = { ... }export default new Vuex.Store({ state, mutations})
次に、下の図を使用してアプリケーションを複数のコンポーネントに分解し、コンポーネント内で必要なデータを store.js の状態にマッピングします。
アプリのルート コンポーネントは、一番外側の赤いボックスです
store.js 里面的状态对象会包含所有应用级别的状态,也就是各个组件需要共享的状态。
笔记列表( notes: [] )包含了 NodesList 组件要渲染的 notes 对象。当前笔记(activeNote: {})则包含当前选中的笔记对象,多个组件都需要这个对象:
-
Toolbar 组件的收藏和删除按钮都对应这个对象
-
NotesList 组件通过 CSS 高亮显示这个对象
-
Editor 组件展示及编辑这个笔记对象的内容。
聊完了状态(state),我们来看看 mutations, 我们要实现的 mutation 方法包括:
-
添加笔记到数组里 (state.notes)
-
把选中的笔记设置为「当前笔记」(state.activeNote)
-
删掉当前笔记
-
编辑当前笔记
-
收藏/取消收藏当前笔记
首先,要添加一条新笔记,我们需要做的是:
-
新建一个对象
-
初始化属性
-
push 到 state.notes 里去
-
把新建的这条笔记设为当前笔记(activeNote)
ADD_NOTE (state) { const new Note = { text: 'New note', favorite: fals } state.notes.push(newNote) state.activeNote= newNote}
然后,编辑笔记需要用笔记内容 text 作参数:
EDIT_NOTE (state, text) { state.activeNote.text = text}
剩下的这些 mutations 很简单就不一一赘述了。整个 vuex/store.js 是这个样子的:
import Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex)const state = { note: [], activeNote: {}}const mutations = { ADD_NOTE (state) { const newNote = { text: 'New Note', favorite: false } state.notes.push(newNote) state.activeNote = newNote }, EDIT_NOTE (state, text) { state.activeNote.text = text }, DELETE_NOTE (state) { state.notes.$remove(state.activeNote) state.activeNote = state.notes[0] }, TOGGLE_FAVORITE (state) { state.activeNote.favorite = !state.activeNote.favorite }, SET_ACTIVE_NOTE (state, note) { state.activeNote = note }}export default new Vuex.Store({ state, mutations})
接下来聊 actions, actions 是组件内用来分发 mutations 的函数。它们接收 store 作为第一个参数。比方说,当用户点击 Toolbar 组件的添加按钮时,我们想要调用一个能分发 ADD_NOTE mutation 的 action。现在我们在 vuex/文件夹下创建一个 actions.js 并在里面写上 addNote 函数:
// actions.jsexport const addNote = ({ dispatch }) => { dispatch('ADD_NOTE')}
剩下的这些 actions 都跟这个差不多:
export const addNote = ({ dispatch }) => { dispatch('ADD_NOTE')}export const editNote = ({ dispatch }, e) => { dispatch('EDIT_NOTE', e.target.value)}export const deleteNote = ({ dispatch }) => { dispatch('DELETE_NOTE')}export const updateActiveNote = ({ dispatch }, note) => { dispatch('SET_ACTIVE_NOTE', note)}export const toggleFavorite = ({ dispatch }) => { dispatch('TOGGLE_FAVORITE')}
这样,在 vuex 文件夹里面要写的代码就都写完了。这里面包括了 store.js 里的 state 和 mutations,以及 actions.js 里面用来分发 mutations 的 actions。
构建 Vue 组件
最后这个小结,我们来实现四个组件 (App, Toolbar, NoteList 和 Editor) 并学习怎么在这些组件里面获取 Vuex store 里的数据以及调用 actions。
创建根实例 - main.js
main.js是应用的入口文件,里面有根实例,我们要把 Vuex store 加到到这个根实例里面,进而注入到它所有的子组件里面:
import Vue from 'vue'import store from './vuex/store'import App from './components/App.vue'new Vue({ store, // 注入到所有子组件 el: 'body', components: { App }})
App - 根组件
根组件 App 会 import 其余三个组件:Toolbar, NotesList 和 Editor:
<template> <div id="app"> <toolbar></toolbar> <notes-list></notes-list> <editor></editor> </div></template><script>import Toolbar from './Toolbar.vue'import NotesList from './NotesList.vue'import Editor from './Editor.vue'export default { components: { Toolbar, NotesList, Editor }}</script>
把 App 组件放到 index.html 里面,用 BootStrap 提供基本样式,在 style.css 里写组件相关的样式:
<!-- index.html --><!DOCTYPE html><html lang="en"> <head> <meta charset="utf-8"> <title>Notes | coligo.io</title> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> <link rel="stylesheet" href="styles.css"> </head> <body> <app></app> <script src="build.js"></script> </body></html>
Toolbar
Toolbar 组件提供给用户三个按钮:创建新笔记,收藏当前选中的笔记和删除当前选中的笔记。
这对于 Vuex 来说是个绝佳的用例,因为 Toolbar 组件需要知道「当前选中的笔记」是哪一条,这样我们才能删除、收藏/取消收藏它。前面说了「当前选中的笔记」是各个组件都需要的,不应该单独存在于任何一个组件里面,这时候我们就能发现共享数据的必要性了。
每当用户点击笔记列表中的某一条时,NodeList 组件会调用 updateActiveNote() action 来分发 SET_ACTIVE_NOTE mutation, 这个 mutation 会把当前选中的笔记设为 activeNote 。
也就是说,Toolbar 组件需要从 state 获取 activeNote 属性:
vuex: { getters: { activeNote: state => state.activeNote }}
我们也需要把这三个按钮所对应的 actions 引进来,因此 Toolbar.vue 就是这样的:
<template> <div id="toolbar"> <i @click="addNote" class="glyphicon glyphicon-plus"></i> <i @click="toggleFavorite" class="glyphicon glyphicon-star" :class="{starred: activeNote.favorite}"></i> <i @click="deleteNote" class="glyphicon glyphicon-remove"></i> </div></template><script>import { addNote, deleteNote, toggleFavorite } from '../vuex/actions'export default { vuex: { getters: { activeNote: state => state.activeNote }, actions: { addNote, deleteNote, toggleFavorite } }}</script>
注意到当 activeNote.favorite === true 的时候,收藏按钮还有一个 starred 的类名,这个类的作用是对收藏按钮提供高亮显示。
NotesList
NotesList 组件主要有三个功能:
-
把笔记列表渲染出来
-
允许用户选择"所有笔记"或者只显示"收藏的笔记"
-
当用户点击某一条时,调用 updateActiveNote action 来更新 store 里的 activeNote
显然,在 NoteLists 里需要 store 里的 notes array 和 activeNote :
vuex: { getters: { notes: state => state.notes, activeNote: state => state.activeNote }}
当用户点击某一条笔记时,把它设为当前笔记:
import { updateActiveNote } from '../vuex/actions'export default { vuex: { getters: { // as shown above }, actions: { updateActiveNote } }}
接下来,根据用户点击的是"所有笔记"还是"收藏笔记"来展示过滤后的列表:
import { updateActiveNote } from '../vuex/actions'export default { data () { return { show: 'all' } }, vuex: { // as shown above }, computed: { filteredNotes () { if (this.show === 'all'){ return this.notes } else if (this.show === 'favorites') { return this.notes.filter(note => note.favorite) } } }}
在这里组件内的 show 属性是作为组件内部状态出现的,很明显,它只在 NoteList 组件内出现。
以下是完整的 NotesList.vue:
<template> <div id="notes-list"> <div id="list-header"> <h2>Notes | coligo</h2> <div class="btn-group btn-group-justified" role="group"> <!-- All Notes button --> <div class="btn-group" role="group"> <button type="button" class="btn btn-default" @click="show = 'all'" :class="{active: show === 'all'}"> All Notes </button> </div> <!-- Favorites Button --> <div class="btn-group" role="group"> <button type="button" class="btn btn-default" @click="show = 'favorites'" :class="{active: show === 'favorites'}"> Favorites </button> </div> </div> </div> <!-- render notes in a list --> <div class="container"> <div class="list-group"> <a v-for="note in filteredNotes" class="list-group-item" href="#" :class="{active: activeNote === note}" @click="updateActiveNote(note)"> <h4 class="list-group-item-heading"> {{note.text.trim().substring(0, 30)}} </h4> </a> </div> </div> </div></template><script>import { updateActiveNote } from '../vuex/actions'export default { data () { return { show: 'all' } }, vuex: { getters: { notes: state => state.notes, activeNote: state => state.activeNote }, actions: { updateActiveNote } }, computed: { filteredNotes () { if (this.show === 'all'){ return this.notes } else if (this.show === 'favorites') { return this.notes.filter(note => note.favorite) } } }}</script>
这个组件的几个要点:
-
用前30个字符当作该笔记的标题
-
当用户点击一条笔记,该笔记变成当前选中笔记
-
在"all"和"favorite"之间选择实际上就是设置 show 属性
-
通过 :class="" 设置样式
Editor
Editor 组件是最简单的,它只做两件事:
-
从 store 获取当前笔记 activeNote ,把它的内容展示在 textarea
-
在用户更新笔记的时候,调用 editNote() action
以下是完整的 Editor.vue:
<template> <div id="note-editor"> <textarea :value="activeNoteText" @input="editNote" class="form-control"> </textarea> </div></template><script>import { editNote } from '../vuex/actions'export default { vuex: { getters: { activeNoteText: state => state.activeNote.text }, actions: { editNote } }}</script>
这里的 textarea 不用 v-model 的原因在 vuex 文档里面有 详细的说明 。
至此,这个应用的代码就写完了,不明白的地方可以看 源代码 , 然后动手操练一遍。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











公式アカウントのWebページはキャッシュを更新します。これはシンプルでシンプルで、ポットを飲むのに十分な複雑です。あなたは公式のアカウントの記事を更新するために一生懸命働きましたが、ユーザーはまだ古いバージョンを開くことができますか?この記事では、この背後にあるtwist余曲折と、この問題を優雅に解決する方法を見てみましょう。それを読んだ後、さまざまなキャッシュの問題に簡単に対処でき、ユーザーが常に新鮮なコンテンツを体験できるようになります。最初に基本について話しましょう。それを率直に言うと、アクセス速度を向上させるために、ブラウザまたはサーバーはいくつかの静的リソース(写真、CSS、JSなど)やページコンテンツを保存します。次回アクセスするときは、もう一度ダウンロードすることなく、キャッシュから直接検索できます。自然に高速です。しかし、このことは両刃の剣でもあります。新しいバージョンはオンラインです、

この記事では、CSSを使用したWebページへの効率的なPNG境界追加を示しています。 CSSはJavaScriptやライブラリと比較して優れたパフォーマンスを提供し、微妙または顕著な効果のために境界幅、スタイル、色を調整する方法を詳述していると主張しています

この記事では、ブラウザのユーザー入力を直接検証するために、必要、パターン、MIN、MAX、および長さの制限などのHTML5フォーム検証属性を使用して説明します。

記事では、HTML5クロスブラウザーの互換性を確保するためのベストプラクティスについて説明し、機能検出、プログレッシブエンハンスメント、およびテスト方法に焦点を当てています。

この記事では、HTML&lt; Datalist&GT;について説明します。オートコンプリートの提案を提供し、ユーザーエクスペリエンスの改善、エラーの削減によりフォームを強化する要素。

この記事では、HTML&lt; Progress&gt;について説明します。要素、その目的、スタイリング、および&lt; meter&gt;との違い要素。主な焦点は、&lt; Progress&gt;を使用することです。タスクの完了と&lt; Meter&gt; statiの場合

この記事では、html&lt; meter&gt;について説明します。要素は、範囲内でスカラーまたは分数値を表示するために使用され、Web開発におけるその一般的なアプリケーション。それは差別化&lt; Meter&gt; &lt; Progress&gt;およびex

この記事では、html5&lt; time&gt;について説明します。セマンティックデート/時刻表現の要素。 人間の読み取り可能なテキストとともに、マシンの読みやすさ(ISO 8601形式)のDateTime属性の重要性を強調し、Accessibilitを増やします
