今回は、エディターが簡単な例を通して vue プラグインの書き方と注意点を説明しますので、必要な読者はフォローして学ぶことができます。
学習する前に、なぜ Vue プラグインを作成したいのかを自問してください。
プロジェクト、特に大規模なプロジェクトでは、アニメーションやポップアップ ボックスの読み込みなど、再利用する必要がある部分がたくさんあります。一つ一つ参照するのは少々面倒ですし、vueファイル内で参照するコンポーネントが多すぎるとコードが肥大化してしまうため、vueプラグインをカプセル化する必要があります。
要件について説明した後、具体的な実装を見てみましょう。現在、2種類のプラグインの書き方を試してみたので、順に紹介していきます。
これは私のプロジェクトディレクトリです。大まかな構造をできるだけシンプルに、わかりやすく説明します。
1 つは読み込みプラグインで、もう 1 つはトースト プラグインです。違いは、読み込みプラグインがコンポーネントとして導入されるのに対し、トースト プラグインはマウント ポイントに直接追加されて呼び出されることです。メソッドのステータスを変更します。
現在使用しているのは Jiangzi です:
トーストプラグイン
接尾辞 vue が付いたファイルがプラグインのスケルトンです。js ファイルはこのスケルトンを置きます。を Vue グローバルに書き込み、動作ロジックを書き留めます。
toast.vue の内容を見てみましょう:
<template> <transition name="fade"> <p v-show="show"> {{message}} </p> </transition> </template> <script> export default { data() { return { show: false, message: "" }; } }; </script> <style lang="scss" scoped> .toast { position: fixed; top: 40%; left: 50%; margin-left: -15vw; padding: 2vw; width: 30vw; font-size: 4vw; color: #fff; text-align: center; background-color: rgba(0, 0, 0, 0.8); border-radius: 5vw; z-index: 999; } .fade-enter-active, .fade-leave-active { transition: 0.3s ease-out; } .fade-enter { opacity: 0; transform: scale(1.2); } .fade-leave-to { opacity: 0; transform: scale(0.8); } </style>
主な内容は 2 つだけです。表示するかどうかを決定する show
と、何を表示するかを決定する message
です。表示する内容。 show
和显示什么内容的message
。
粗看这里,有没有发现什么问题?
这个文件中并没有props
属性,也就是无论是show也好,message也好,就没有办法通过父子组件通信的方式进行修改,那他们是怎么正确处理的呢。别急,来看他的配置文件。
index.js:
import ToastComponent from './toast.vue' const Toast = {}; // 注册Toast Toast.install = function (Vue) { // 生成一个Vue的子类 // 同时这个子类也就是组件 const ToastConstructor = Vue.extend(ToastComponent) // 生成一个该子类的实例 const instance = new ToastConstructor(); // 将这个实例挂载在我创建的p上 // 并将此p加入全局挂载点内部 instance.$mount(document.createElement('p')) document.body.appendChild(instance.$el) // 通过Vue的原型注册一个方法 // 让所有实例共享这个方法 Vue.prototype.$toast = (msg, duration = 2000) => { instance.message = msg; instance.show = true; setTimeout(() => { instance.show = false; }, duration); } } export default Toast
这里的逻辑大致可以分成这么几步:
创建一个空对象,这个对象就是日后要使用到的插件的名字。此外,这个对象中要有一个install的函数。使用vue的extend方法创建一个插件的构造函数(可以看做创建了一个vue的子类),实例化该子类,之后的所有操作都可以通过这个子类完成。之后再Vue的原型上添加一个共用的方法。
这里需要着重提的是Vue.extend()
。举个例子,我们日常使用vue编写组件是这个样子的:
Vue.component('MyComponent',{ template:'<p>这是组件</p>' })
这是全局组件的注册方法,但其实这是一个语法糖,真正的运行过程是这样的:
let component = Vue.extend({ template:'<p>这是组件</p>' }) Vue.component('MyComponent',component)
Vue.extend会返回一个对象,按照大多数资料上提及的,也可以说是返回一个Vue的子类,既然是子类,就没有办法直接通过他使用Vue原型上的方法,所以需要new一个实例出来使用。
在代码里console.log(instance)
得出的是这样的结果:
可以看到$el:p.toast
也就是toast组件模板的根节点。
疑惑的是,我不知道为什么要创建一个空的p节点,并把这个实例挂载在上面。我尝试注释这段代码,但是运行会报错。
查找这个错误的原因,貌似是因为
document.body.appendChild(instance.$el)
这里面的instance.$el
的问题,那好,我们console下这个看看。WTF!!!!结果居然是undefined
props
属性がありません。つまり、show であろうと message であろうと、親子コンポーネント通信を通じてそれを変更する方法はありません。では、どうすればそれを正しく処理できるのでしょうか。心配しないで、設定ファイルを見てみましょう。 index.js:
console.log(instance)
ここでのロジックは、大まかに次のステップに分けることができます:
将来使用するプラグインの名前である空のオブジェクトを作成します。さらに、このオブジェクトにはインストール関数が必要です。 vue の extend メソッドを使用して、プラグイン コンストラクター (vue のサブクラスの作成と見なされます) を作成し、サブクラスをインスタンス化し、後続のすべての操作をこのサブクラスを通じて完了できます。次に、共有メソッドを Vue プロトタイプに追加します。
ここで言及する必要があるのは、Vue.extend()
です。たとえば、コンポーネントを作成するための Vue の日常的な使用方法は次のようになります。
instance.$mount(document.createElement('p'))
これはグローバル コンポーネントの登録メソッドですが、実際には、実際の実行プロセスは次のとおりです。
instance.$mount(instance.$el)
Vue.extendほとんどの情報で述べたように、オブジェクトは Vue のサブクラスを返すとも言えます。これはサブクラスであるため、それを介して Vue プロトタイプのメソッドを直接使用する方法がないため、新しいインスタンスが必要です。それを使うために。
コード console.log(instance) の結果は次のようになります:
トースト コンポーネント テンプレートのルート ノードである $el:p.toast
が確認できます。
混乱しているのは、なぜ空の p ノードを作成し、その上にこのインスタンスをマウントする必要があるのかがわからないことです。このコードをコメントしようとしましたが、実行するとエラーが発生します。
このエラーの理由を見つけてください。それは
import Vue from 'vue' import App from './App' // import router from './router' import Toast from './components/taost' Vue.use(Toast) Vue.config.productionTip = false /* eslint-disable no-new */ new Vue({ // router, render: h => h(App) }).$mount('#app')
ここに instance.$el
の問題があるからです。わかりました。これを慰めて見てみましょう。なんと! ! ! !結果は 未定義
であることが判明しました。
// app.vue <template> <p id="app"> <loading duration='2s' :isshow='show'></loading> <!-- <button @click="show = !show">显示/隐藏loading</button> --> <button @click="toast">显示taost弹出框</button> </p> </template> <script> export default { name: "app", data() { return { show: false }; }, methods: { toast() { this.$toast("你好"); } } }; </script> <style> #app { font-family: "Avenir", Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
<template> <p class='wrapper' v-if="isshow"> <p class='loading'> <img src="./loading.gif"> </p> </p> </template> <script> export default { props: { duration: { type: String, default: "1s" //默认1s }, isshow: { type: Boolean, default: false } }, data: function() { return {}; } }; </script> <style lang="scss" scoped> </style>
import LoadingComponent from './loading.vue' let Loading = {}; Loading.install = (Vue) => { Vue.component('loading', LoadingComponent) } export default Loading;
// main.js import Vue from 'vue' import App from './App' // import router from './router' import Toast from './components/taost' import Loading from './components/loading' Vue.use(Toast) Vue.use(Loading) Vue.config.productionTip = false /* eslint-disable no-new */ new Vue({ // router, render: h => h(App) }).$mount('#app') // app.vue <template> <p id="app"> <loading duration='2s' :isshow='show'></loading> <!-- <button @click="show = !show">显示/隐藏loading</button> --> <button @click="toast">显示taost弹出框</button> </p> </template> <script> export default { name: "app", data() { return { show: false }; }, methods: { toast() { this.$toast("你好"); } } }; </script> <style> #app { font-family: "Avenir", Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
vue.use(toast)
import LoadingComponent from './loading.vue' let Loading = {}; Loading.install = (Vue) => { Vue.component('loading', LoadingComponent) } export default Loading;
这个和taoat的插件相比,简单了很多,依然是一个空对象,里面有一个install方法,然后在全局注册了一个组件。
比较
那介绍了这两种不同的插件编写方法,貌似没有什么不一样啊,真的是这样么?
来看一下完整的main.js和app.vue这两个文件:
// main.js import Vue from 'vue' import App from './App' // import router from './router' import Toast from './components/taost' import Loading from './components/loading' Vue.use(Toast) Vue.use(Loading) Vue.config.productionTip = false /* eslint-disable no-new */ new Vue({ // router, render: h => h(App) }).$mount('#app') // app.vue <template> <p id="app"> <loading duration='2s' :isshow='show'></loading> <!-- <button @click="show = !show">显示/隐藏loading</button> --> <button @click="toast">显示taost弹出框</button> </p> </template> <script> export default { name: "app", data() { return { show: false }; }, methods: { toast() { this.$toast("你好"); } } }; </script> <style> #app { font-family: "Avenir", Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
可以看出来,loading是显示的写在app.vue模板里的,而toast并没有作为一个组件写入,仅仅是通过一个方法控制显示。
来看一下html结构和vue工具给出的结构:
看出来了么,toast插件没有在挂载点里面,而是独立存在的,也就是说当执行
vue.use(toast)
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
以上がvueプラグインの書き方の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。