私たちの vue プロジェクト (特にバックエンド システム) では、複数のビジネスラインが同じプロジェクトを共同開発する必要があるシナリオが常にあります。各ビジネス チームがいくつかのプライベート表示コンポーネントをフレームワークに提供する場合、これらのコンポーネントを組み合わせることができません。フレームワークは、プライベート モジュールが頻繁に変更されるため、ビルドとリリースを繰り返して行うことができないため、一緒にパッケージ化されています。このシナリオでは、リモートの非同期コードをロードして、これらのコンポーネントのフレームワークへのロードを完了するコンポーネントが必要です。
vue-cli は、Vue が公式に推奨するプロジェクト構築スキャフォールディングであり、ホットリロード、ビルド、デバッグ、単体テスト、コード検出、その他の機能など、開発プロセスで一般的に使用される機能を提供します。今回の非同期リモートコンポーネントはvue-cliをベースに開発します。
要件分析
リモートコードをロードする方法
ロードされたコードをフレームワークに登録する方法。
親コンポーネントがリモートで導入されたコンポーネントと通信する方法。
フレームワークに導入されたライブラリをリモート コードで再利用する方法。
v-for のようにリモート コードが複数回呼び出されることで発生する不要なリクエストを回避します。
リモート コードをロードする
リモート コードは、Axios などの HTTP クライアントを通じてこのリンクをリクエストしてソース コードを取得できるように、アクセス可能な URL に保存する必要があります。
import Axios from 'axios'; export default { name: 'SyncComponent', props: { // 父组件提供请求地址 url: { type: String, default: '' } }, data() { return { resData: '' }; }, async mounted() { if (!this.url) return; const res = await Axios.get(this.url); // 我们在组件挂载完成时,请求远端代码并存储结果。 this.resData = res.data; } };
上記は基本的なコードです。便宜上、以下の例では重複するコード部分を省略します。
コードをフレームワークに登録します
この部分は少し面倒で、複数の問題が関係しています:
ブラウザは .vue テンプレートまたは ES.next 構文をサポートしていないため、モジュールを使用する前にコンパイルする必要があります。
この部分に対処するのは比較的簡単です。これらのテンプレートをパッケージ化するために Webpack 構成ファイルを独自に定義します。
// 在 build 目录下新建 webpack.sync-components.prod.conf.js 文件 const webpack = require('webpack'); const path = require('path'); const utils = require('./utils'); const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') function resolve(dir) { return path.join(__dirname, '..', dir) } module.exports = { // 此处引入要打包的组件 entry: { componentA: resolve('/src/views/component-a.vue') }, // 输出到静态目录下 output: { path: resolve('/static/'), filename: '[name].js', }, resolve: { extensions: ['.js', '.vue', '.json'], alias: { 'vue$': 'vue/dist/vue.esm.js', '@': resolve('src'), } }, module: { rules: [ { test: /\.vue$/, loader: 'vue-loader', options: { esModule: false, // ****** vue-loader v13 更新 默认值为 true v12及之前版本为 false, 此项配置影响 vue 自身异步组件写法以及 webpack 打包结果 loaders: utils.cssLoaders({ sourceMap: true, extract: false // css 不做提取 }), transformToRequire: { video: 'src', source: 'src', img: 'src', image: 'xlink:href' } } }, { test: /\.js$/, loader: 'babel-loader', include: [resolve('src'), resolve('test')] }, { test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, loader: 'url-loader', options: { limit: 10000, name: utils.assetsPath('img/[name].[hash:7].[ext]') } }, { test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, loader: 'url-loader', options: { limit: 10000, name: utils.assetsPath('media/[name].[hash:7].[ext]') } }, { test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, loader: 'url-loader', options: { limit: 10000, name: utils.assetsPath('fonts/[name].[hash:7].[ext]') } } ] }, plugins: [ new webpack.DefinePlugin({ 'process.env.NODE_ENV': '"production"' }), // 压缩JS new webpack.optimize.UglifyJsPlugin({ compress: false, sourceMap: true }), // 压缩CSS 注意不做提取 new OptimizeCSSPlugin({ cssProcessorOptions: { safe: true } }) ] };
この時点で、モジュールはフレームワークで認識できるファイルにコンパイルされました。
1.文字列をjsオブジェクトに変換する方法。
new Function。 async mounted() { if (!this.url) return; const res = await Axios.get(this.url); let Fn = Function; this.mode = new Fn(`return ${res.data}`)(); }
1. 変換されたjsオブジェクトはvueで認識できません。
この問題の原因としては 2 つの可能性があります:
// vue-loader v13 esModule 更新 默认值为 true, v12及之前版本为 false, 此项配置影响 vue 自身异步组件写法以及 webpack 打包结果 { test: /\.vue$/, loader: 'vue-loader', options: { esModule: false ... 以下省略千军万码 } } // UglifyJs 需要取消变量名替换配置,此配置并不会极大影响压缩率 new webpack.optimize.UglifyJsPlugin({ compress: false, sourceMap: true })
この時点で、リモート コンポーネントがフレームワークに導入されています。
親コンポーネントはリモートでインポートされたコンポーネントとどのように通信するのでしょうか? ここには、ビュー コンポーネントからリモートの非同期読み込みコンポーネント、そして実際のビジネス コンポーネントまでの 3 つの層の通信があります。ビュー コンポーネントは、実際のビジネス コンポーネントと直接通信するために必要です。 vuex と eventsBus の両方のソリューションは非常に面倒です。ここでは、$attrs と $listeners (vue v2.4+) を使用して、「フォールスルー」(vue コンポーネントのクロスレベル通信) を実現します。
// 修改 sync-component.vue 组件 // 新增 v-bind="$attrs" v-on="$listeners" <component :is="mode" v-bind="$attrs" v-on="$listeners"> </component> // inheritAttrs: true export default { name: 'SyncComponent', props: { // 父组件提供请求地址 url: { type: String, default: '' } }, inheritAttrs: true ... 以下省略千军万码 }
フレームワークに導入されたライブラリをリモート コードがどのように再利用するか
リモート コンポーネントやフレームワークに大きなライブラリやプラグインが繰り返し導入されることは望ましくありません。コンテンツのこの部分はまだ残っています。実践段階 主なアイデアは、コンポーネント Vue.prototype.$xxx のパブリック再利用を実現するために、パブリック ライブラリを Vue プロトタイプ チェーンにマウントすることです。
// 全局添加 axios 对象 import axios from 'axios'; Vue.prototype.$http = axios;
で導入されたリモートコンポーネントはフレームワーク内のパブリックパッケージにアクセスできますが、このときリモートコンポーネントをパッケージ化する際にパブリックパッケージのコードが含まれないようにwebpackを設定する必要があります。
// webpack.sync-components.prod.conf.js 添加 externals: { vue: 'vue', 'element-ui': 'element-ui', axios: 'axios' }
v-for のようにリモート コードが複数回呼び出されることで発生する不要なリクエストを回避します。
このパートでは、グローバル変数を辞書として直接使用し、サブ項目としてリクエスト アドレス: データを持つ配列を保存します。
async mounted() { if (!this.url) return; // Cache 缓存 根据 url 参数 if (!window.SyncComponentCache) { window.SyncComponentCache = {}; } let res; if (!window.SyncComponentCache[this.url]) { window.SyncComponentCache[this.url] = Axios.get(this.url); res = await window.SyncComponentCache[this.url]; } else { res = await window.SyncComponentCache[this.url]; } let Fn = Function; this.mode = new Fn(`return ${res.data}`)(); console.log(this.mode); }
この時点で、非同期リモート コンポーネントをロードしてフレームワークと通信できるようになります。
この記事のソース コードを入手するには、github にアクセスしてください。コンポーネントは NPM に公開されており、直接インストールできます。
関連する推奨事項:
以上がvueリモートコードをロードするコンポーネント共有の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。