ホームページ > 記事 > ウェブフロントエンド > Vuejs テクノロジースタックに関する知識のまとめ
前の会社のプロジェクトでは主に jQuery と Angular1 を使用していて、その後 React を学びました。この会社に来て突然 Vue を始めるとは予想していませんでしたが、Vue はまだ簡単に始めることができます。 。以下は vue テクノロジー スタックの概要であり、すべて公式 Web サイトからのものです。主に vue テクノロジー スタックの知識を私がまとめたものです。したがって、この記事は非常に内容が濃いので、以前の記事 Vuejs を読むことをお勧めします。 CLI からパッケージ化、オンライン実装までの技術スタックを完全に分析
独立ビルドとランタイムビルドの 2 つのビルド方法があります。両者の違いは、前者にはテンプレート コンパイラが含まれているのに対し、後者にはテンプレート コンパイラが含まれていないことです。
テンプレート コンパイラーの役割は、テンプレート文字列を純粋な JavaScript レンダリング関数にコンパイルすることです。コンポーネントでテンプレート オプションを使用する場合は、コンパイラが必要です。
特に注意すべき点は、created と mount の違いです。Created は、vm インスタンスが作成されているがマウントされていないことを意味するため、一部の DOM 操作が実行される必要があります。マウントされた状態で配置されます。非同期リクエストが作成されたかマウントされたかに違いはありません。違いがわかる場合はコメントしてください。
テンプレート内の式には、あまりにも多くのロジックが含まれるべきではありません。複雑なロジックの場合は、計算された属性を使用する必要があります。
計算された属性とメソッドの違いは、計算された属性がその依存関係に基づいてキャッシュされることです。
計算プロパティと計算プロパティ。通常は、命令型監視コールバックの代わりに計算プロパティを使用することをお勧めします。ほとんどの場合、計算されたプロパティの方が適切ですが、カスタム ウォッチャーが必要になる場合もあります。これは、データの変更に応じて非同期または高コストの操作を実行する場合に便利です。
配列の変更メソッド (これらのメソッドによって呼び出される元の配列を変更する変更メソッド) は、次の 7 つがあります:
push() pop() shift() unshift() splice() sort() reverse()
非変更メソッドを使用する場合、新しい配列または古い配列に置き換えることも、Vue.set メソッドを使用することもできます。
古いオブジェクトを新しいオブジェクトに置き換えることも、Vue.setメソッドを使用することもできます
Vue.set(vm.someObject, 'foo', 'bar') this.someObject = Object.assign({}, this.someObject, { a:1, b:2 })
Vue.jsはv-on用のイベント修飾子とキー修飾子を提供します
v-model ディレクティブを使用して、フォーム コントロール要素に双方向のデータ バインディングを作成できます。一般的な修飾子には、.lazy、.number、.trim などがあります。
カスタム イベントでフォーム入力コンポーネントを使用することもできます。
Vue コンポーネントの API は、プロップ、イベント、スロットの 3 つの部分から構成されます。
プロップにより、外部環境がコンポーネントにデータを渡すことができます
イベントにより、コンポーネントがコンポーネントの副作用をトリガーすることができます外部環境
スロットを使用すると、外部環境で追加のコンテンツをコンポーネントに結合できます。
1) コンポーネントのデータ属性は関数である必要があります
2) 親子コンポーネント
Vue.js では、親子コンポーネント間の関係は、プロパティが下、イベントが上として要約できます。親コンポーネントは props を通じて子コンポーネントにデータを渡し、子コンポーネントはイベントを通じて親コンポーネントにメッセージを送信します。
prop は一方向のバインディングです。親コンポーネントのプロパティが変更されると、それは子コンポーネントに送信されますが、その逆は行われません。これは、子コンポーネントが親コンポーネントの状態を不注意に変更することを防ぐためです。これにより、アプリケーションのデータ フローが理解しにくくなります。
さらに、親コンポーネントが更新されるたびに、子コンポーネントのすべての props が最新の値に更新されます。これは、子コンポーネント内の props を変更すべきではないことを意味します。これを行うと、Vue はコンソールに警告を表示します。
なぜ prop のデータを変更する衝動に駆られるのでしょうか?通常、理由は 2 つあります。
1.prop が初期値として渡され、サブコンポーネントがそれをローカル データとして使用する必要がある。
2.prop が初期値として渡され、サブコンポーネントがそれを他のデータに処理する。データ出力。
これら 2 つの理由に対する正しい応答は次のとおりです:
1. ローカル変数を定義し、prop の値で初期化します:
props: ['initialCounter'], data: function () { return { counter: this.initialCounter } }
2. 計算されたプロパティを定義し、prop の値を処理して返します。
props: ['size'], computed: { normalizedSize: function () { return this.size.trim().toLowerCase() } }
JavaScript ではオブジェクトと配列は参照型であり、同じメモリ空間を指すことに注意してください。prop がオブジェクトまたは配列の場合、子コンポーネント内で変更すると親コンポーネントの状態に影響します。
3) 非親子コンポーネント
場合によっては、2 つのコンポーネントも通信する必要があります (非親子関係)。単純なシナリオでは、空の Vue インスタンスを中央イベント バスとして使用できます。複雑なケースでは、特殊な状態管理パターンの使用を検討する必要があります。
4).sync modifier
場合によっては、プロップに対して「双方向バインディング」を実行する必要があるかもしれません。
.sync は 2.0 で削除され、Vue2.3.0+ で再び追加されましたが、今回はコンパイル時の糖衣構文としてのみ存在し、親コンポーネントのプロパティを自動的に更新する v-on に拡張されます。リスナー。次のコード
<comp :foo.sync="bar"></comp>
は次のように展開されます:
<comp :foo="bar" @update:foo="val => bar = val"></comp>
サブコンポーネントが foo の値を更新する必要がある場合、更新イベントを明示的にトリガーする必要があります:
this.$emit('update:foo', newValue)
5) コンテンツ配布にスロットを使用します
スコープ スロット: 受信子コンポーネントから渡された prop オブジェクト。スコープ スロットのより代表的な使用例はリスト コンポーネントです。これにより、コンポーネントはリスト内の各項目のレンダリング方法をカスタマイズできます
6) 動的コンポーネント、is 属性およびキープアライブ ディレクティブ
7) サブコンポーネント インデックス
尽管有props和events,但是有时仍然需要JavaScript中直接访问子组件。为此可以使用ref为子组件指定一个索引ID。
虽然 Vue.js 通常鼓励开发人员沿着“数据驱动”的方式思考,避免直接接触 DOM,但是有时我们确实要这么做。为了在数据变化之后等待 Vue 完成更新 DOM ,可以在数据变化之后立即使用 Vue.nextTick(callback) 。这样回调函数在 DOM 更新完成后就会调用。
Vue在插入、更新或者移除DOM时,提供多种不同方式的应用过渡效果。包括以下工具:
在CSS过渡和动画中自动应用class
可以配合使用第三方CSS动画库,如Animate.css
在过渡钩子函数中使用JavaScript直接操作DOM
可以配合使用第三方JavaScript动画库,如Velocity.js
1)单元素/组件的过渡
Vue提供了transition的封装组件,在下列情形中,可以给任何元素和组件添加过渡
条件渲染(使用v-if)
条件展示(使用v-show)
动态组件
组件根节点
2)多个元素的过渡
对于原生标签可以使用 v-if/v-else
3)多个组件的过渡
多个组件的过渡我们可以使用动态组件。
4)列表过渡
和Angular的指令类似,主要操作DOM,下面是一个滚动加载的指令,holder暂时没想到什么更好的处理方法:
let scrollCallback = function (callback) { let windowH = window.innerHeight let getDocumentHeight = function () { var body = document.body var html = document.documentElement return Math.max( body.offsetHeight, body.scrollHeight, html.clientHeight, html.offsetHeight, html.scrollHeight ) } let scrollH = document.documentElement.scrollTop || document.body.scrollTop if (windowH + scrollH >= getDocumentHeight() - (this.holder || 20)) { callback() } } let callBackWarpped export default { bind (el, binding, vnode) { let holder if (vnode.data && vnode.data.attrs && vnode.data.attrs['scroll-placeholder']) { holder = parseInt(vnode.data.attrs['scroll-placeholder']) } else { holder = 20 } callBackWarpped = scrollCallback.bind({el, holder}, binding.value) window.addEventListener('scroll', callBackWarpped, false) }, unbind: function () { window.removeEventListener('scroll', callBackWarpped, false) } }
混合是一种灵活的分布式复用Vue组件的方式。混合对象可以包含任意组件选项。以组件使用混合对象时,所有混合对象的选项将被混入该组件本身的选项。
1)创建插件
Vue.js的插件应当有一个公开方法install。这个方法的第一个参数是Vue构造器 , 第二个参数是一个可选的选项对象。
2)使用插件
通过全局方法Vue.use()使用插件:
// 调用 `MyPlugin.install(Vue)` Vue.use(MyPlugin)
也可以传入一个选项对象:
Vue.use(MyPlugin, { someOption: true })
1)router-link声明式导航
<router-link to="/foo">Go to Foo</router-link>
router-link对应的路由匹配成功,将自动设置class属性值.router-link-active。
2)编程式导航
// 字符串 router.push('home') // 对象 router.push({ path: 'home' }) // 命名的路由 router.push({ name: 'user', params: { userId: 123 }}) // 带查询参数,变成 /register?plan=private router.push({ path: 'register', query: { plan: 'private' }})
vue-router默认hash模式,也可以设置为路由的history模式。
vue-router提供的导航钩子主要用来拦截导航,让它完成跳转或取消。有多种方式可以在路由导航发生时执行钩子:全局的, 单个路由独享的, 或者组件级的。
一个路由匹配到的所有路由记录会暴露为$route对象(还有在导航钩子中的route对象)的$route.matched数组。因此,我们需要遍历$route.matched来检查路由记录中的meta字段。
router-view是基本的动态组件,所以我们可以用transition组件给它添加一些过渡效果。
有时候,进入某个路由后,需要从服务器获取数据。例如,在渲染用户信息时,你需要从服务器获取用户的数据。我们可以通过两种方式来实现:
导航完成之后获取:先完成导航,然后在接下来的组件生命周期钩子中获取数据。在数据获取期间显示『加载中』之类的指示。
导航完成之前获取:导航完成前,在路由的enter钩子中获取数据,在数据获取成功后执行导航。
注意: 这个功能只在HTML5 history模式下可用。
当打包构建应用时,Javascript包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。
结合Vue的异步组件和Webpack的code splitting功能,轻松实现路由组件的懒加载。
const Foo = resolve => require(['./Foo.vue'], resolve) const router = new VueRouter({ routes: [ { path: '/foo', component: Foo } ] })
可以设置tag、append、active-class、exact等属性
有时候我们要让 "激活时的CSS类名" 应用在外层元素,而不是a标签本身,那么可以用router-link渲染外层元素,包裹着内层的原生a标签:
<router-link tag="li" to="/foo"> <a>/foo</a> </router-link>
在这种情况下,a将作为真实的链接(它会获得正确的 href 的),而"激活时的CSS类名"则设置到外层的li。
routes、mode、base、linkActiveClass、scrollBehavior
1)注入的属性
通过在Vue根实例的router配置传入router实例,下面两个属性成员会被注入到每个子组件。
$router:router实例
$route:当前激活的路由信息对象。这个属性是只读的,里面的属性是immutable(不可变)的,不过你可以watch(监测变化)它。
2)允许的额外配置:beforeRouteEnter、beforeRouteLeave
1)单一状态树
Vuex使用单一状态树--是的,用一个对象就包含了全部的应用层级状态。至此它便作为一个『唯一数据源(SSOT)』而存在。这也意味着,每个应用将仅仅包含一个store实例。单一状态树让我们能够直接地定位任一特定的状态片段,在调试的过程中也能轻易地取得整个当前应用状态的快照。
2)在Vue组件中获得Vuex状态
最好在根实例中注册store选项,该store实例会注入到根组件下的所有子组件中,且子组件能通过this.$store访问到。而不是在每个需要使用state的组件中需要频繁地导入。
3)mapState辅助函数
当一个组件需要获取多个状态时候,可以使用mapState辅助函数帮助我们生成计算属性,这样可以简化代码书写。mapState函数会返回一个对象,然后可以使用对象展开运算符将它与局部计算属性混合使用。
4)不要滥用vuex
使用Vuex并不意味着你需要将所有的状态放入Vuex。虽然将所有的状态放到Vuex会使状态变化更显式和易调试,但也会使代码变得冗长和不直观。如果有些状态严格属于单个组件,最好还是作为组件的局部状态。你应该根据你的应用开发需要进行权衡和确定。
getters用来从store中的state中派生出一些状态,例如对列表进行过滤并计数:
computed: { doneTodosCount () { return this.$store.state.todos.filter(todo => todo.done).length } }
getters可以认为是store的计算属性。和state类似,有mapGetters辅助函数。
更改Vuex的store中的状态的唯一方法是提交mutation。Vuex中的mutations非常类似于事件:每个mutation都有一个字符串的事件类型(type)和一个回调函数(handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受state作为第一个参数
1)提交载荷(Payload)
你可以向store.commit传入额外的参数,即mutation的载荷(payload):
// ... mutations: { increment (state, n) { state.count += n } } store.commit('increment', 10)
2)Mutations需遵守Vue的响应规则
3)使用常量替代Mutation事件类型
4)mutation必须是同步函数
5)在组件中提交Mutations
你可以在组件中使用this.$store.commit('xxx')提交mutation,或者使用mapMutations辅助函数将组件中的methods映射为store.commit调用(需要在根节点注入store)。
actions类似于mutation,不同在于:
actions提交的是mutation,而不是直接变更状态。
actions可以包含任意异步操作。
1)在组件中分发Action
你在组件中使用this.$store.dispatch('xxx')分发action,或者使用mapActions辅助函数将组件的methods映射为store.dispatch调用(需要先在根节点注入store)
2)组合Actions
Action通常是异步的,那么如何知道action什么时候结束呢?更重要的是,我们如何才能组合多个action,以处理更加复杂的异步流程?
首先,你需要明白store.dispatch可以处理被触发的action的回调函数返回的Promise,并且store.dispatch仍旧返回Promise。
使用async/await会更加简单:
// 假设 getData() 和 getOtherData() 返回的是 Promise actions: { async actionA ({ commit }) { commit('gotData', await getData()) }, async actionB ({ dispatch, commit }) { await dispatch('actionA') // 等待 actionA 完成 commit('gotOtherData', await getOtherData()) } }
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store对象就有可能变得相当臃肿。
为了解决以上问题,Vuex允许我们将store分割成模块(module)。每个模块拥有自己的state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:
const moduleA = { state: { ... }, mutations: { ... }, actions: { ... }, getters: { ... } } const moduleB = { state: { ... }, mutations: { ... }, actions: { ... } } const store = new Vuex.Store({ modules: { a: moduleA, b: moduleB } }) store.state.a // -> moduleA 的状态 store.state.b // -> moduleB 的状态
Vuex的store接受plugins选项,这个选项暴露出每次mutation的钩子。Vuex插件就是一个函数,它接收store作为唯一参数。
开启严格模式,仅需在创建store的时候传入strict:true
在严格模式下,无论何时发生了状态变更且不是由mutation函数引起的,将会抛出错误。这能保证所有的状态变更都能被调试工具跟踪到。
不要在发布环境下启用严格模式!严格模式会深度监测状态树来检测不合规的状态变更--请确保在发布环境下关闭严格模式,以避免性能损失。
以上がVuejs テクノロジースタックに関する知識のまとめの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。