私は通常、いくつかのコンポーネントを含むいくつかのものを記録して要約するのが好きです。それらの多くを蓄積すると、散在する蓄積はもはや管理に適していないことがわかります。
それで、私は考え始めました、比較的標準化された方法でこれらのより散在するものを管理する良い方法はありますか?コンポーネントがコンポーネントライブラリの形で管理されている場合、それはあなた自身の蓄積により適しており、将来の仕事を促進しますか?
そこで、私は、 element-ui 、 vux 、 vantなど、市場にあるいくつかの優れたUIコンポーネントライブラリを参照し始め、ソースコードを読んでアーキテクチャの構築を理解し、自分のモバイルUIコンポーネントライブラリvuiのセットを整理しました。
私の暇なとき、私は主要な技術コミュニティで活動しています。私はしばしばしばらく働いてきた友人がいるか、著者にいくつかの質問をするためのインターンシップを見つける準備をしている友人がいます。コンポーネントライブラリを作成する方法は?コンポーネントライブラリを自分で作ることは、履歴書のハイライトになりますか?コンポーネントライブラリ開発に関する記事を書くことはできますか? ...
このブログ投稿は、疑問に答え、質問を共有する気分で生まれました。
記事を読むときにご質問がある場合は、ディスカッショングループに参加して話し合います(毎日話している大きな男性のグループに加えて、女の子のグループもあります〜)
フロントエンドホッジポッジ:731175396
Github:https://github.com/xuqiang521
これ以上苦労せずに、実際の戦闘章に直接行きましょう〜
ここでは、Macとウィンドウの下にノードのインストールについてのみお話します
Macパッケージマネージャーhomebrewをインストールしていない場合、最初のステップは最初にインストールすることです
/usr/bin/ruby -e " $( curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install ) " homebrewを使用してnodeをインストールします
brew install nodewindow公式Webサイトにアクセスして対応するバージョンをダウンロードする場合は、次の手順をクリックしてインストールを完了します。
インストールが完了したら、 nodeとnpmバージョンを確認してください
node -v
# v9.6.1
npm -v
# 5.6.0それ以来、コンピューターのnode環境が構築されています。次に、コンポーネントライブラリをインストールして、依存関係の足場を構築する必要があります。
# 全局安装
npm i -g vue-cli
# 查看vue-cli用法
vue -h
# 查看版本
vue -V
# 2.9.3 vue-cliのinit指示を使用して、 personal-components-libraryという名前のプロジェクトを初期化します
# 项目基于 webpack
vue init webpack personal-components-library構築するとき、足場はプロジェクトのいくつかの説明と依存関係を記入するように求められます。以下に選択したコンテンツを参照して、入力してください。
# 项目名称
Project name ? personal-components-library
# 项目描述
Project description ? A Personal Vue.js components Library project
# 项目作者
Author ? qiangdada
# 项目构建 vue 版本(选择默认项)
Vue build ? standalone
# 是否下载 vue-router (后期会用到,这里选 Yes)
Install vue-router ? Yes
# 是否下载 eslint (为了制定合理的开发规范,这个必填)
Use ESLint to lint your code ? Yes
# 安装默认的标准 eslint 规则
Pick an ESLint preset ? Standard
# 构建测试案例
Set up unit tests ? Yes
# 安装 test 依赖 (选择 karma + mocha)
Pick a test runner ? karma
# 构建 e2e 测试案例 (No)
Setup e2e tests with Nightwatch ? No
# 项目初始化完是否安装依赖 (npm)
Should we run ` npm install ` for you after the project has been created ? (recom
mended) npm選択したら、待つことができます。 vue-cliプロジェクトを構築し、依存関係のインストールを実行するのに役立ちます。
初期化プロジェクト構造は次のとおりです。
├── build webpack打包以及本地服务的文件都在里面
├── config 不同环境的配置都在这里
├── index.html 入口html
├── node_modules npm安装的依赖包都在这里面
├── package.json 项目配置信息
├── README.md 项目介绍
├── src 我们的源代码
│ ├── App.vue vue主入口文件
│ ├── assets 资源存放(如图片)
│ ├── components 可以复用的模块放在这里面
│ ├── main.js 入口js
│ ├── router 路由管理
└── webpack.config.js webpack配置文件
├── static 被copy的静态资源存放地址
├── test 测试文档和案例npmを使用して依存関係を遅くダウンロードしたり、リソースの一部が壁に囲まれている場合は、 cnpmを使用して依存関係をダウンロードすることをお勧めします
# 全局安装 cnpm
npm install -g cnpm --registry=https://registry.npm.taobao.org
# 使用 cnpm 进行依赖安装
cnpm i依存関係のインストールが完了した後、 vueプロジェクトを開始できます〜
npm run devその後、 http://localhost:8080にアクセスすると、 vue-cliを通じて構築されたvueプロジェクトへのアクセスに成功できます。この時点で、コンポーネントライブラリが依存する開発環境がインストールされています。
まず、このセクションの目的を明確にする必要があります。コンポーネントライブラリをより適切に開発するには、ディレクトリを変更する必要があります。
前のセクションではすでにvueプロジェクトを構築していますが、初期化されたプロジェクトディレクトリは、コンポーネントライブラリのその後の開発とメンテナンスを満たすことができません。したがって、この章で行う必要があることは、初期化されたvueプロジェクトのディレクトリを変換し、コンポーネントライブラリが必要とするディレクトリに変えることです。次に行動を起こしましょう。
demoとコンポーネントライブラリの文档に関連するすべてのファイルを保存するために使用されますmixinsなどを管理するために使用されます(このためには、初期化されたsrcディレクトリを変換する必要があります)わかりました、初期化したプロジェクトのディレクトリを変換し始めます。
前の例から、ローカルサービスを開始すると、ページのメインエントリファイルがindex.htmlであることがわかります。ここで、最初のステップは、ページhtmlとjsのメインエントランスをexamplesディレクトリに移動することです。特定のexamplesディレクトリは次のとおりです
├── assets css,图片等资源都在这
├── pages 路由中所有的页面
├── src
│ ├── components demo中可以复用的模块放在这里面
│ ├── index.js 入口js
│ ├── index.tpl 页面入口
│ ├── App.vue vue主入口文件
│ ├── router.config.js 路由js各ファイルの変更されたコードは次のとおりです
index.js
import Vue from 'vue'
import App from './App'
import router from './router.config'
Vue . config . productionTip = false
/* eslint-disable no-new */
new Vue ( {
el : '#app-container' ,
router ,
components : { App } ,
template : '<App/>'
} ) index.tpl
<!DOCTYPE html >
< html lang =" en " >
< head >
< meta charset =" UTF-8 " >
< meta name =" viewport " content =" width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0 " >
< title > My Component Library </ title >
</ head >
< body >
< div id =" app-container " >
< app > </ app >
</ div >
</ body >
</ html > App.vue
< template >
< div id =" app " >
< router-view />
</ div >
</ template >
< script >
export default {
name : 'App'
}
</ script > router.config.js
import Vue from 'vue'
import Router from 'vue-router'
import hello from '../pages/hello' // 请自行去pages下面创建一个hello.vue,以方便之后的测试
Vue . use ( Router )
export default new Router ( {
routes : [
{
path : '/' ,
component : hello
}
]
} ) srcディレクトリは、主に登録コンポーネントのメインエントリファイル、ツールメソッド、 mixins 、その他のファイルを保存するために使用されます。上記のexamplesから、元のsrcの一部のファイルを削除する必要があることを知ることができます。変更されたディレクトリは次のとおりです
├── mixins mixins方法存放在这
├── utils 一些常用辅助方法存放在这
├── index.js 组件注册主入口考えてみてください、あなたがこれを見るとき、あなたは私たちが今何をする必要があるかを知っている必要があります。そうです、それはただローカルサービスのエントリファイルを変更するためです。実行できる場合は、 entryのJSエントリとhtml-webpack-pluginのページエントリリファレンスを変更します。コードは次のとおりです(キーコードのみが配置されます)
entry: {
'vendor' : [ 'vue' , 'vue-router' ] ,
'vui' : './examples/src/index.js'
} ,
// ...
plugins : [
// ...
// 将入口改成examples/src/index.tpl
new HtmlWebpackPlugin ( {
chunks : [ 'vendor' , 'vui' ] ,
template : 'examples/src/index.tpl' ,
filename : 'index.html' ,
inject : true
} )
] OK、変更されました。 npm run dev 1回再実行すると、プロジェクトは新しいエントリファイルの下で実行できます
このセクションでは、実装する必要があるのは、ローカルで開始したサービスで、 packagesの下のコンポーネントを使用できます。説明するために最も簡単なhelloコンポーネントを開発しましょう
packagesの下にhelloコンポーネントを作成します適切なバインド性を持つために、ここでは、コンポーネントの書き込みを開始する前に、指定されたディレクトリとファイル名を均一に管理する必要があります。 packagesディレクトリのhelloコンポーネントの下のファイルは次のとおりです
├── hello
│ ├── hello.vue hello.vueコンテンツは次のとおりです
< template >
< div class =" v-hello " >
hello {{ message }}
</ div >
</ template >
< script >
export default {
name : 'v-hello' ,
props : {
message : String
}
}
</ script > src/index.jsにコンポーネントを登録しますsec/index.jsファイルも上記です。主にコンポーネントライブラリのすべてのコンポーネントの登録を管理するために使用されます
import Hello from '../packages/hello'
const install = function ( Vue ) {
if ( install . installed ) return
Vue . component ( Hello . name , Hello )
}
if ( typeof window !== 'undefined' && window . Vue ) {
install ( window . Vue )
}
export default {
install ,
Hello
} examples/src/index.jsエントリJSファイルの参照次に、前のセクションの修正されたexamplesに書いたhelloコンポーネントを参照する必要があります
import vui from 'src/index.js'
// 完整引用
Vue . use ( vui )
// 独立引用
const { Hello } = vui
Vue . component ( Hello . name , Hello ) examples/pages/hello.vueで直接使用しますexamples/pagesコンポーネント名と同じ名前のデモファイルを作成し、コンポーネントを使用する必要があります。
< v-hello message =" my component library " > </ v-hello >実行中の結果が上の写真と同じ場合、おめでとうございます。コンポーネントライブラリの開発に向けて別の一歩を踏み出しました〜
これを見た後、私はすべての読者が自分の好みに応じてファイルを中央に管理する必要があります(もちろん、上記のデモを参照することもできます)。この方法でのみ、コンポーネントライブラリのその後の開発作業をスムーズにすることができます。
次のセクションでは、以下のパッケージファイルをbuild以下のパッケージファイルを最適化し、開発したコンポーネントをnpm公式Webサイトに公開して、コンポーネントライブラリをより便利に使用できるようにします。
いつものように、章のテキストが始まる前に、この章で何をする必要があるか、そしてその理由を知る必要があります。
足場の最初のプロジェクトには、 buildファイル用の中央パッケージファイルが1つしかないためwebpack.prod.conf.js
コンポーネントライブラリを将来使用するためには、コンポーネントライブラリに対応するすべてのモジュールをvui.jsファイル(名前が気に入っている)に抽出する必要があります。
import Vue from 'vue'
import vui from 'x-vui'
Vue . use ( vui )また、 examplesの関連ファイルをパッケージ化および管理する必要があります。これは、後でコンポーネントライブラリのドキュメント公式Webサイトを開発する必要があり、ドキュメントの公式Webサイトの関連する入り口はexamplesにあるためです。
初期化プロジェクトから、 buildファイルのwebpackファイルが次のとおりであることがわかります
├── webpack.base.conf.js 基础配置文件
├── webpack.dev.conf.js 本地服务配置文件
├── webpack.prod.conf.js 打包配置文件
├── webpack.test.conf.js 测试配置文件(这里先不做过多描述)初期化されたoutput出力ディレクトリはdistです。このディレクトリは、プロジェクト全体がパッケージ化された後の出力ディレクトリであり、コンポーネントライブラリで必要なディレクトリではありません。それは私たちが望むものではないので、私たちは必要なディレクトリで何をしたいですか?
lib/vui.js (コンポーネントライブラリJSメインファイル)lib/vui-css/index.cssのメインエントリ(コンポーネントライブラリCSSのメインファイル、この章のCSSパッケージについてはあまり説明しません。examplesのexamples/dist examplesファイル(後のドキュメントの公式ウェブサイトのメインエントランス)目標が設定されているため、次のことをする必要がある次のことは、次のように関連するwebpackパッケージファイルを最初に整理することです。
├── webpack.base.conf.js 基础配置文件(配置方面和webpack.dev.conf.js的配置进行部分整合)
├── webpack.dev.conf.js 本地服务配置文件(将纯配置文件进行对应的删减)
├── webpack.build.js 组件库入口文件打包配置文件(将webpack.prod.conf.js重命名)
├── webpack.build.min.js examples展示文件打包配置文件(新增文件)1。webpack.base.conf.js
webpack.base.conf.jsファイルの変換を開始する前に、2つのパッケージファイルで何をする必要があるかを理解する必要があります。
webpack.build.js : lib/vui.jsコンポーネントライブラリJSメインファイルを出力し、 webpack.base.conf.jsおよびwebpack.dev.conf.js関連する構成を使用しますwebpack.build.min.js : examples/distドキュメント関連ファイルを出力し、 webpack.base.conf.js and webpack.dev.conf.js関連構成を使用します両方のwebpackパッケージファイルはwebpack.base.conf.jsとwebpack.dev.conf.js関連の構成を使用しているため、同じファイルの一部をwebpack.base.conf.jsファイルに統合してみませんか?目標は明確です、次に私に従ってみましょう
'use strict'
const path = require ( 'path' )
const utils = require ( './utils' )
const config = require ( '../config' )
const vueLoaderConfig = require ( './vue-loader.conf' )
const webpack = require ( 'webpack' )
const CopyWebpackPlugin = require ( 'copy-webpack-plugin' )
const HtmlWebpackPlugin = require ( 'html-webpack-plugin' )
function resolve ( dir ) {
return path . join ( __dirname , '..' , dir )
}
const HOST = process . env . HOST
const PORT = process . env . PORT && Number ( process . env . PORT )
const createLintingRule = ( ) => ( {
test : / .(js|vue)$ / ,
loader : 'eslint-loader' ,
enforce : 'pre' ,
include : [ resolve ( 'src' ) , resolve ( 'test' ) ] ,
options : {
formatter : require ( 'eslint-friendly-formatter' ) ,
emitWarning : ! config . dev . showEslintErrorsInOverlay
}
} )
module . exports = {
context : path . resolve ( __dirname , '../' ) ,
// 文件入口
entry : {
'vendor' : [ 'vue' , 'vue-router' ] ,
'vui' : './examples/src/index.js'
} ,
// 输出目录
output : {
path : path . join ( __dirname , '../examples/dist' ) ,
publicPath : '/' ,
filename : '[name].js'
} ,
resolve : {
extensions : [ '.js' , '.vue' , '.json' ] ,
// 此处新增了一些 alias 别名
alias : {
'vue$' : 'vue/dist/vue.esm.js' ,
'@' : resolve ( 'src' ) ,
'src' : resolve ( 'src' ) ,
'packages' : resolve ( 'packages' ) ,
'lib' : resolve ( 'lib' ) ,
'components' : resolve ( 'examples/src/components' )
}
} ,
// 延用原先的大部分配置
module : {
rules : [
// 原先的配置...
// 整合webpack.dev.conf.js中css相关配置
... utils . styleLoaders ( { sourceMap : config . dev . cssSourceMap , usePostCSS : true } )
]
} ,
// 延用原先的配置
node : {
// ...
} ,
devtool : config . dev . devtool ,
// 整合webpack.dev.conf.js中的devServer选项
devServer : {
clientLogLevel : 'warning' ,
historyApiFallback : {
rewrites : [
{ from : / .* / , to : path . posix . join ( config . dev . assetsPublicPath , 'index.html' ) } ,
] ,
} ,
hot : true ,
contentBase : false , // since we use CopyWebpackPlugin.
compress : true ,
host : HOST || config . dev . host ,
port : PORT || config . dev . port ,
open : config . dev . autoOpenBrowser ,
overlay : config . dev . errorOverlay
? { warnings : false , errors : true }
: false ,
publicPath : config . dev . assetsPublicPath ,
proxy : config . dev . proxyTable ,
quiet : true , // necessary for FriendlyErrorsPlugin
watchOptions : {
poll : config . dev . poll ,
}
} ,
// 整合webpack.dev.conf.js中的plugins选项
plugins : [
new webpack . DefinePlugin ( {
'process.env' : require ( '../config/dev.env' )
} ) ,
new webpack . HotModuleReplacementPlugin ( ) ,
new webpack . NamedModulesPlugin ( ) ,
new webpack . NoEmitOnErrorsPlugin ( ) ,
// 页面主入口
new HtmlWebpackPlugin ( {
chunks : [ 'manifest' , 'vendor' , 'vui' ] ,
template : 'examples/src/index.tpl' ,
filename : 'index.html' ,
inject : true
} )
]
}2。webpack.dev.conf.js
ここでは、コードの複製を避けるために、 webpack.base.conf.jsに統合された構成を削除するだけです
'use strict'
const utils = require ( './utils' )
const config = require ( '../config' )
const baseWebpackConfig = require ( './webpack.base.conf' )
const FriendlyErrorsPlugin = require ( 'friendly-errors-webpack-plugin' )
const portfinder = require ( 'portfinder' )
module . exports = new Promise ( ( resolve , reject ) => {
portfinder . basePort = process . env . PORT || config . dev . port
portfinder . getPort ( ( err , port ) => {
if ( err ) {
reject ( err )
} else {
process . env . PORT = port
baseWebpackConfig . devServer . port = port
baseWebpackConfig . plugins . push ( new FriendlyErrorsPlugin ( {
compilationSuccessInfo : {
messages : [ `Your application is running here: http:// ${ baseWebpackConfig . devServer . host } : ${ port } ` ] ,
} ,
onErrors : config . dev . notifyOnErrors
? utils . createNotifierCallback ( )
: undefined
} ) )
resolve ( baseWebpackConfig )
}
} )
} ) webpack.base.conf.jsとwebpack.dev.conf.jsの2つのファイルが調整されたら、 npm run devを再度実行します。
上記の写真は、あなたのローカルサービスファイルが予想どおりに正常に変更されたことを示しているように見えます〜
1。webpack.build.js
このファイルの主な目的は、コンポーネントライブラリ内のすべてのコンポーネント関連ファイルを一緒にパッケージ化し、 lib/vui.jsメインファイルを出力することです。
'use strict'
const webpack = require ( 'webpack' )
const config = require ( './webpack.base.conf' )
// 修改入口文件
config . entry = {
'vui' : './src/index.js'
}
// 修改输出目录
config . output = {
filename : './lib/[name].js' ,
library : 'vui' ,
libraryTarget : 'umd'
}
// 配置externals选项
config . externals = {
vue : {
root : 'Vue' ,
commonjs : 'vue' ,
commonjs2 : 'vue' ,
amd : 'vue'
}
}
// 配置plugins选项
config . plugins = [
new webpack . DefinePlugin ( {
'process.env' : require ( '../config/prod.env' )
} )
]
// 删除devtool配置
delete config . devtool
module . exports = config2。webpack.build.min.js
このファイルの主な目的は、単一のパッケージアドレスを開き、 examplesに関連するファイルをexamples/distディレクトリに出力することです(つまり、後続のドキュメントの公式ウェブサイトの入り口)
const path = require ( 'path' )
const webpack = require ( 'webpack' )
const merge = require ( 'webpack-merge' )
const baseWebpackConfig = require ( './webpack.base.conf' )
const config = require ( '../config' )
const ExtractTextPlugin = require ( 'extract-text-webpack-plugin' )
const webpackConfig = merge ( baseWebpackConfig , {
output : {
chunkFilename : '[id].[hash].js' ,
filename : '[name].min.[hash].js'
} ,
plugins : [
new webpack . optimize . UglifyJsPlugin ( {
compress : {
warnings : false
} ,
output : {
comments : false
} ,
sourceMap : false
} ) ,
// extract css into its own file
new ExtractTextPlugin ( {
filename : '[name].[contenthash].css' ,
allChunks : true ,
} ) ,
// keep module.id stable when vendor modules does not change
new webpack . HashedModuleIdsPlugin ( ) ,
// enable scope hoisting
new webpack . optimize . ModuleConcatenationPlugin ( ) ,
// split vendor js into its own file
new webpack . optimize . CommonsChunkPlugin ( {
name : 'vendor' ,
minChunks ( module ) {
// any required modules inside node_modules are extracted to vendor
return (
module . resource &&
/ .js$ / . test ( module . resource ) &&
module . resource . indexOf (
path . join ( __dirname , '../node_modules' )
) === 0
)
}
} ) ,
new webpack . optimize . CommonsChunkPlugin ( {
name : 'manifest' ,
minChunks : Infinity
} ) ,
new webpack . optimize . CommonsChunkPlugin ( {
name : 'app' ,
async : 'vendor-async' ,
children : true ,
minChunks : 3
} ) ,
]
} )
module . exports = webpackConfigこれらすべてのファイルをまとめると、最後のステップは、 package.jsonのscriptsにパッケージコマンドを書き込むことです。
"scripts" : {
"build:vui" : " webpack --progress --hide-modules --config build/webpack.build.js && rimraf examples/dist && cross-env NODE_ENV=production webpack --progress --hide-modules --config build/webpack.build.min.js "
},コマンドを実行する、 npm run build:vui 、go
この時点で、ローカルサービスと2つのパッケージファイルが変換されました。 npmを使用してみましょう
独自のnpmアカウントがない場合は、 npm公式Webサイトで独自のアカウントを登録してください。ここをクリックして公式ウェブサイトを入力して登録してください。登録手順は比較的簡単です。ここではこれ以上説明しません。ご質問がある場合は、WeChatグループで私に尋ねることができます。
mkdir qiangdada520-npm-test
cd qiangdada520-npm-test
# npm 包主入口js文件
touch index.js
# npm 包首页介绍(具体啥内容你自行写入即可)
touch README.md
npm init
# package name: (qiangdada520-npm-test)
# version: (1.0.0)
# description: npm test
# entry point: (index.js) index.js
# test command:
# git repository:
# keywords: npm test
# author: qiangdada
# license: (ISC)次に、 package.jsonが次のように生成されます
{
"name" : "qiangdada-npm-test" ,
"version" : "1.0.0" ,
"description" : "npm test" ,
"main" : "index.js" , // npm 包主入口js文件
"scripts" : {
"test" : "echo "Error: no test specified" && exit 1"
} ,
"keywords" : [
"npm" ,
"test"
] ,
"author" : "qiangdada" ,
"license" : "MIT"
}次に、登録されたnpmアカウントにローカルに接続する必要があります
npm adduser
# Username: 填写你自己的npm账号
# Password: npm账号密码
# Email: (this IS public) 你npm账号的认证邮箱
# Logged in as xuqiang521 on https://registry.npmjs.org/. 连接成功npm publishを実行して公開を開始します
npm publish
# + [email protected]この時点でnpmリリースしたばかりのパッケージを検索して確認できます〜
現在、コンポーネントライブラリで最もシンプルなhelloコンポーネントを作成しましたが、これはnpm公式Webサイトへの公開にはまったく影響しません。公開ステップは上記の例と同じくらい簡単です。
package.jsonファイルでいくつかの説明を変更します
// npm 包js入口文件改为 lib/vui.js
"main" : "lib/vui.js" ,
// npm 发布出去的包包含的文件
"files" : [
"lib" ,
"src" ,
"packages"
] ,
// 将包的属性改为公共可发布的
"private" : false , npmパッケージのテストがリリースされたとき、 package.jsonのversionバージョンは前のバージョンよりも高いことに注意してください。
公開を開始します
# 打包,输出lib/vui.js
npm run build:vui
# 发布
npm publish
# + [email protected] ローカルVUEプロジェクトを選択し、プロジェクトに参加します
npm i component-library-test
# or
cnpm i component-library-testプロジェクトの入場ファイルにコンポーネントを登録します
import Vue from 'vue'
import vui from 'component-library-test'
Vue . use ( vui )ページで使用します
< v-hello message =" component library " > </ v-hello >この時点で、ローカルサービスファイルを正常に変換し、コンポーネントライブラリメインファイルのパッケージと公式ドキュメントWebサイトのメインエントランスのパッケージを実装し、最後にプロジェクトリリースにnpm使用する方法を学びました。
次の章では、コンポーネントライブラリのcssファイルのパッケージを説明します。
前のセクションでは、すでにJSファイルをパッケージ化しています。ただし、コンポーネントライブラリの場合、コンポーネントライブラリのその後の使用を確保するために、JSファイルを管理するだけでなく、CSSファイルを管理することも必要です。
このセクションでは、 webpack構造に基づいてプロジェクトでCSSファイルのパッケージングと管理を分離するためにgulp合理的に使用する方法について説明します。
開始する前に、2つの目標を明確にする必要があります。
管理を促進するために、新しいコンポーネントを作成するたびに、コンポーネントのスタイルを管理し、単一の管理を実現するために、対応するCSSファイルを作成する必要があります。
ここでは、すべてのCSSファイルをpackages/vui-cssディレクトリに保存します。特定の構造は次のとおりです
├── src
│ ├── common 存放组件公用的css文件
│ ├── mixins 存放一些mixin的css文件
│ ├── index.css css主入口文件
│ ├── hello.css 对应hello组件的单一css文件
├── gulpfile.js css打包配置文件
├── package.json 相关的版本依赖コンポーネントCSSの作成を開始する前に、いくつかのポイントを明確にする必要があります。
個人的には、市場での最良の方法は、単一のCSSでコンポーネントを管理し、 bemを使用してCSSを書くことだと思います。 bemを知りたい場合は、以下のリンクをクリックしてください
次に、シンプルなhelloコンポーネントを説明しましょう。開始する前に、 hello.vueのコンテンツを入れます
< template >
< div class =" v-hello " >
< p class =" v-hello__message " > hello {{ message }} </ p >
</ div >
</ template >
< script >
export default {
name : 'v-hello' ,
props : {
message : String
}
}
</ script > packages/vui-css/srcディレクトリにhello.cssを作成します
@b v-hello {
color : # fff ;
transform : scale ( 1 );
@e message {
background : # 0067ED ;
}
}次に、メインエントランスindex.cssにhello.cssファイルをインポートします。css
@import './hello.css' ; examples/src/index.jsでコンポーネントライブラリスタイルを導入します
import 'packages/vui-css/src/index.css'しかし、 hello.cssコンテンツから、これは典型的なbemライティング方法であり、正常に解析できないことがわかります。 bem構文を解析するには、対応するpostcssプラグインを導入する必要があります。ここでは饿了么团队開発したpostcss-saladプラグインを使用して、 bem構文を解析します。第二に、このsass-likeスタイルのCSSファイルも、 precssというプラグインを使用する必要があります。最初に依存関係をインストールします。
npm i postcss-salad precss -D依存関係のインストールが完了したら、 bemルールを構成するためにProject Root Directoryにsalad.config.jsonを作成する必要があります。特定のルールは次のとおりです
{
"browsers" : [ " ie > 8 " , " last 2 versions " ],
"features" : {
"bem" : {
"shortcuts" : {
"component" : " b " ,
"modifier" : " m " ,
"descendent" : " e "
},
"separators" : {
"descendent" : " __ " ,
"modifier" : " -- "
}
}
}
}次に、次のように、初期化された.postcssrcファイルでpostcss-saladおよびprecssプラグインを使用する必要があります
module . exports = {
"plugins" : {
"postcss-import" : { } ,
"postcss-salad" : require ( './salad.config.json' ) ,
"postcss-url" : { } ,
"precss" : { } ,
"autoprefixer" : { } ,
}
}わかりました、この時点で再びプロジェクトを実行すると、図に示すようにCSSが有効になっていることがわかります。
コンポーネントライブラリ内のCSSファイルをより適切に管理し、コンポーネントライブラリ内の1つまたは複数のコンポーネントのみが導入された場合、ユーザーがコンポーネントに対応するCSSファイルを導入できるようにするため。したがって、CSSファイルを個別にパッケージ化する必要があります。ここでは、 gulpを使用して、対応するパッケージ操作を実行する必要があります。パッケージの詳細を取得する前に、 gulpグローバルにインストールしていることを確認してください。そうでない場合は、インストールしてください
npm i gulp -g
# 查看版本
gulp -v
# CLI version 3.9.1次に、 packages/vui-css/package.jsonファイルで依存関係を使用する必要があるものを見てみましょう
{
"name" : "vui-css" ,
"version" : "1.0.0" ,
"description" : "vui css." ,
"main" : "lib/index.css" ,
"style" : "lib/index.css" ,
// 和组件发布一样,也需要指定目录
"files" : [
"lib" ,
"src"
] ,
"scripts" : {
"build" : "gulp build"
} ,
"license" : "MIT" ,
"devDependencies" : {
"gulp" : "^3.9.1" ,
"gulp-cssmin" : "^0.2.0" ,
"gulp-postcss" : "^7.0.1" ,
"postcss-salad" : "^2.0.1"
} ,
"dependencies" : { }
}これは実際には、コンポーネントライブラリのCSSファイルに必要な依存関係に似ていることがわかりますが、これはgulpに基づくpostcssプラグインであることを除きます。 gulpfile.js構成を開始する前に、依存関係のインストールのためにnpm iを実行することを忘れないでください。
次に、次のようにgulpfile.jsの構成を開始します
const gulp = require ( 'gulp' )
const postcss = require ( 'gulp-postcss' )
const cssmin = require ( 'gulp-cssmin' )
const salad = require ( 'postcss-salad' ) ( require ( '../../salad.config.json' ) )
gulp . task ( 'compile' , function ( ) {
return gulp . src ( './src/*.css' )
// 使用postcss-salad
. pipe ( postcss ( [ salad ] ) )
// 进行css压缩
. pipe ( cssmin ( ) )
// 输出到 './lib' 目录下
. pipe ( gulp . dest ( './lib' ) )
} )
gulp . task ( 'build' , [ 'compile' ] )これで、 gulp buildコマンドの実行を開始して、CSSファイルをパッケージ化できます。もちろん、パッケージングコマンドを容易にし、より良い実行するために、次のように、プロジェクトのルートディレクトリにpackage.jsonにCSSビルドコマンドを追加する必要があります。
"scripts" : {
"build:vui-css" : " gulp build --gulpfile packages/vui-css/gulpfile.js && rimraf lib/vui-css && cp-cli packages/vui-css/lib lib/vui-css && rimraf packages/vui-css/lib "
} npm run build:vui-css実行し、先に進み、次の図に示すようにコンポーネントライブラリのJSおよびCSSファイルをパッケージ化しました
OK、この時点では、既にコンポーネントとそのスタイルを個別に導入できます。最後に、ユーザーがコンポーネントのCSSを直接使用できるようにするために、 npm公式Webサイトに公開することを忘れないでください〜手順は次のとおりです。
# 进到vui-css目录
cd packages/vui-css
# 发布
npm publishこの時点で、CSSファイルの管理と個別のパッケージを完了し、CSSファイルの単一出力を完了しました。このようにして、コンポーネントライブラリCSSファイルを開発および管理しながら、コンポーネントライブラリの使用を容易にするためのより良い方法を確保できます。
これまでのところ、コンポーネントライブラリに必要な新しいディレクトリを構築しており、JSファイルとCSSファイルのパッケージも変換しました。コンポーネントライブラリの開発に十分な準備をしましたが、コンポーネントライブラリの後続コンポーネントの開発とメンテナンスを促進するために、非常に重要な事前作業を行う必要があります。
フロントエンドテストの場合、それはフロントエンドエンジニアリングの重要な分野です。したがって、コンポーネントライブラリでこのような重要な部分をどのように見逃すことができますか?単体テストには、主に2つのタイプがあります
この章では、 Mocha初期化に基づいて2つのフレームワークを使用して、コンポーネントライブラリのユニットテストコンポーネントに導きKarma 。
ユニットテストにさらされたほとんどの人は、 Karma + Mocha 2つのフレームワークに精通していると思いますが、ここでは、2つのフレームワークを簡単に紹介するために別のセクションを開く必要があると思います。
コンポーネントライブラリのコンポーネントをテスト用の主要な主流のWebブラウザで実行できるようにするために、 Karmaを選択しました。最も重要なことは、 Karmaがvue-cliが推奨するユニットテストフレームワークであることです。カルマについてもっと知りたい場合は、カルマの公式ウェブサイトをチェックしてください
simple flexibleでfunテストフレームワークですPromiseなどの非同期画像テストのユースケースをサポートしていますcoverageテストレポートをサポートしていますbefore() 、 after() 、 beforeEach() 、およびafterEach()提供するため、テストをよりよく完了するために異なる操作を設定できます。ここでは、 mochaの3つの基本的な使用法と、 describe (ライフサイクル)の4つのフック関数を紹介します。
説明(moduleName、function): describeネスト可能であり、テストケースが正しいかどうかを説明します。
describe ( '测试模块的描述' , ( ) => {
// ....
} ) ; ** it(情報、関数):**ユニットテストケースに対応するit
it ( '单元测试用例的描述' , ( ) => {
// ....
} )アサーションライブラリの使用
expect ( 1 + 1 ) . to . be . equal ( 2 ) describeのライフサイクル
describe ( 'Test Hooks' , function ( ) {
before ( function ( ) {
// 在本区块的所有测试用例之前执行
} ) ;
after ( function ( ) {
// 在本区块的所有测试用例之后执行
} ) ;
beforeEach ( function ( ) {
// 在本区块的每个测试用例之前执行
} ) ;
afterEach ( function ( ) {
// 在本区块的每个测试用例之后执行
} ) ;
// test cases
} ) ; mocha Operationsについてもっと知りたい学生は、以下のリンクをクリックして表示できます
上記のセクションでは、Vueが正式に推奨するテストフレームワークのKarmaとMocha簡単に紹介します。また、これを見ると、単体テストと一般的なテストフレームワークを簡単に理解できることを願っています。
実際のユニットテストが始まる前に、 Karmaの構成を見てみましょう。ここではvue-cli足場によって初期化されたkarma.conf.jsファイルの構成を直接見ていきます(特定の使用についてコメントしました)
var webpackConfig = require ( '../../build/webpack.test.conf' )
module . exports = function karmaConfig ( config ) {
config . set ( {
// 浏览器
browsers : [ 'PhantomJS' ] ,
// 测试框架
frameworks : [ 'mocha' , 'sinon-chai' , 'phantomjs-shim' ] ,
// 测试报告
reporters : [ 'spec' , 'coverage' ] ,
// 测试入口文件
files : [ './index.js' ] ,
// 预处理器 karma-webpack
preprocessors : {
'./index.js' : [ 'webpack' , 'sourcemap' ]
} ,
// webpack配置
webpack : webpackConfig ,
// webpack中间件
webpackMiddleware : {
noInfo : true
} ,
// 测试覆盖率报告
coverageReporter : {
dir : './coverage' ,
reporters : [
{ type : 'lcov' , subdir : '.' } ,
{ type : 'text-summary' }
]
}
} )
}次に、独自のhelloコンポーネントで簡単なテストを実施し(1つのテストケースのみ)、 test/unit/specsで新しいhello.spec.jsファイルを作成し、次のコードを記述しましょう
import Vue from 'vue' // 导入Vue用于生成Vue实例
import Hello from 'packages/hello' // 导入组件
// 测试脚本里面应该包括一个或多个describe块,称为测试套件(test suite)
describe ( 'Hello.vue' , ( ) => {
// 每个describe块应该包括一个或多个it块,称为测试用例(test case)
it ( 'render default classList in hello' , ( ) => {
const Constructor = Vue . extend ( Hello ) // 获得Hello组件实例
const vm = new Constructor ( ) . $mount ( ) // 将组件挂在到DOM上
// 断言:DOM中包含class为v-hello的元素
expect ( vm . $el . classList . contains ( 'v-hello' ) ) . to . be . true
const message = vm . $el . querySelector ( '.v-hello__message' )
// 断言:DOM中包含class为v-hello__message的元素
expect ( message . classList . contains ( 'v-hello__message' ) ) . to . be . true
} )
} )テストの例を書いた後、次のステップはテストを実施することです。 npm run testを実行して、あなたに移動して、結果を出力します
hello.vue
✓ render default classList in hellohelloコンポーネントの上記のテストインスタンスから、コンポーネントをVUEインスタンスにインスタンスにインスタンスする必要があります。
const Constructor = Vue . extend ( Hello )
const vm = new Constructor ( {
propsData : {
message : 'component'
}
} ) . $mount ( )各コンポーネントに複数の単体テストインスタンスがある場合、この執筆により最終テストが肥大化されます。ここでは、 elementによってカプセル化されたユニットテストツールutil.jsを参照できます。単体テストで一般的に使用されるいくつかの方法をカプセル化する必要があります。以下に、ツールに提供されているいくつかの方法をリストします。
/**
* 回收 vm,一般在每个测试脚本测试完成后执行回收vm。
* @param {Object} vm
*/
exports . destroyVM = function ( vm ) { }
/**
* 创建一个 Vue 的实例对象
* @param {Object|String} Compo - 组件配置,可直接传 template
* @param {Boolean=false} mounted - 是否添加到 DOM 上
* @return {Object} vm
*/
exports . createVue = function ( Compo , mounted = false ) { }
/**
* 创建一个测试组件实例
* @param {Object} Compo - 组件对象
* @param {Object} propsData - props 数据
* @param {Boolean=false} mounted - 是否添加到 DOM 上
* @return {Object} vm
*/
exports . createTest = function ( Compo , propsData = { } , mounted = false ) { }
/**
* 触发一个事件
* 注: 一般在触发事件后使用 vm.$nextTick 方法确定事件触发完成。
* mouseenter, mouseleave, mouseover, keyup, change, click 等
* @param {Element} elm - 元素
* @param {String} name - 事件名称
* @param {*} opts - 配置项
*/
exports . triggerEvent = function ( elm , name , ... opts ) { }
/**
* 触发 “mouseup” 和 “mousedown” 事件,既触发点击事件。
* @param {Element} elm - 元素
* @param {*} opts - 配置选项
*/
exports . triggerClick = function ( elm , ... opts ) { }以下に定義されたテストツール方法を使用して、 helloコンポーネントのテストインスタンスを変換し、 hello.spec.jsファイルを変換します
import { destroyVM , createTest } from '../util'
import Hello from 'packages/hello'
describe ( 'hello.vue' , ( ) => {
let vm
// 测试用例执行之后销毁实例
afterEach ( ( ) => {
destroyVM ( vm )
} )
it ( 'render default classList in hello' , ( ) => {
vm = createTest ( Hello )
expect ( vm . $el . classList . contains ( 'v-hello' ) ) . to . be . true
const message = vm . $el . querySelector ( '.v-hello__message' )
expect ( message . classList . contains ( 'v-hello__message' ) ) . to . be . true
} )
} ) npm run testを再実行し、結果を出力します
hello.vue
✓ render default classList in hello上記では、静的判断に関する単体テストの使用を導入しました。次に、いくつかの非同期ユースケースといくつかのインタラクティブなイベントをテストします。テストする前に、次のように、 helloコンポーネントのコードをわずかに変更する必要があります
< template >
< div class =" v-hello " @click =" handleClick " >
< p class =" v-hello__message " > hello {{ message }} </ p >
</ div >
</ template >
< script >
export default {
name : 'v-hello' ,
props : {
message : String
} ,
methods : {
handleClick ( ) {
return new Promise ( ( resolve ) => {
resolve ( )
} ) . then ( ( ) => {
this . $emit ( 'click' , 'this is click emit' )
} )
}
}
}
</ script >次に、 helloコンポーネントが約束を通じて情報を正常にemitできるかどうかをテストしたいと思います。たとえば、テストケースは次のとおりです
it ( 'create a hello for click with promise' , ( done ) => {
let result
vm = createVue ( {
template : `<v-hello @click="handleClick"></v-hello>` ,
methods : {
handleClick ( msg ) {
result = msg
}
}
} , true )
vm . $el . click ( )
// 断言消息是异步emit出去的
expect ( result ) . to . not . exist
setTimeout ( _ => {
expect ( result ) . to . exist
expect ( result ) . to . equal ( 'this is click emit' )
done ( )
} , 20 )
} )もう一度テストを開始し、 npm run testを実行し、結果を出力します
hello.vue
✓ render default classList in hello
✓ create a hello for click with promiseこの時点で、単体テストの構成と一般的に使用されるいくつかの使用を学びました。ユニットテストについて詳しく知る必要がある場合は、以前に提供したリンクをたどって、より深い研究に進んでください
友人、私にフォローして、前の5つの章を練習し、コンポーネント開発のための基本的な棚を構築しました。次に、コンポーネントライブラリに高い重要なコンポーネントを使用して、ドキュメントの公式Webサイトを完成させてください。
優れたオープンソースプロジェクトには公式のドキュメントWebサイトが必要であることを誰もが知っておく必要があります。そのため、UIライブラリを最高の1つにするために、独自の公式ドキュメントWebサイトも使用する必要があります。
優れた公式ドキュメントWebサイトには2つのことが必要です。
私が開発するコンポーネントライブラリはモバイルデバイスに適しているため、公式のドキュメントWebサイトにAPIドキュメントの説明とモバイルの例のデモの両方を持つようにするにはどうすればよいですか。これには、適応のために2セットのページを開発する必要があります。次のことをする必要があります。
実際の戦闘が始まる前に、この章で必要なディレクトリ構造を見てみましょう。
├── assets css,图片等资源都在这
├── dist 打包好的文件都在这
├── docs PC端需要展示的markdown文件都在这
├── pages 移动端所有的demo都在这
├── src
│ ├── components demo中可以复用的模块放在这里面
│ ├── index.tpl 页面入口
│ ├── is-mobile.js 判断设备
│ ├── index.js PC端主入口js
│ ├── App.vue PC端入口文件
│ ├── mobile.js 移动端端主入口js
│ ├── MobileApp.vue 移动端入口文件
│ ├── nav.config.json 路由控制文件
│ ├── router.config.js 动态注册路由この章では、主に、マークダウンファイルの変換とさまざまなデバイスのルーティングの適応を実現することをお勧めします。
アイデアを明確にした後、公式のドキュメントWebサイトを開発し続けましょう!
上記のディレクトリから、DocsフォルダーがMarkdownファイルに保存されており、各MarkdownファイルがコンポーネントのAPIドキュメントに対応していることがわかります。私たちが望む結果は、ドキュメント内のすべてのマークダウンファイルを変換してVUEコンポーネントに変換し、変換されたVUEコンポーネントをルートに登録して、ルートを介して各マークダウンファイルにアクセスできるようにします。
マークダウンファイルをVUEコンポーネントに解析するには、市場に多くの3つのパーティwebpackプラグインがあります。もちろん、 webpackを深く理解している場合は、自分で選択することもできます。ここでは饿了么团队が開発したVue-Markdown-Roaderを直接使用しています。
最初のステップは、インストールに依存することです
npm i vue-markdown-loader -D 2番目のステップは、 webpack.base.conf.jsファイルでvue-markdown-loader使用することです
{
test : / .md$ / ,
loader : 'vue-markdown-loader' ,
options : {
// 阻止提取脚本和样式标签
preventExtract : true
}
} 3番目のステップは試行です。最初にdocsにhello.mdファイルを追加してから、 helloコンポーネントを使用する手順を書きます
## Hello
** Hello 组件,Hello 组件,Hello 组件,Hello 组件**
### 基本用法
```html
< template >
< div class = " hello-page " >
<v-hello message="my component library" @click="handleClick"></v-hello>
<p>{{ msg }}</p>
</ div >
</ template >
< script >
export default {
name : ' hello ' ,
data () {
return {
msg : ' '
}
},
methods : {
handleClick ( msg ) {
this . msg = msg
}
}
}
</ script >
```
### Attributes
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ---------- | -------- | ---------- | ------------- | -------- |
| message | 文本信息 | string | — | — |
### Events
| 事件名称 | 说明 | 回调参数 |
| ---------- | -------- | ---------- |
| click | 点击操作 | — |ステップ4: hello.mdをルートに登録します
route . push ( {
path : '/component/hello' ,
component : require ( '../docs/hello.md' )
} )最後に、ページにアクセスしてください。現時点では、 hello.mdのコンテンツがVueコンポーネントに変換され、ルーティングの読み込みを通じてアクセスできることがわかりますが、ページはugい〜このようなものです
もちろん、私はこの状況を説明する必要はありません、あなたもそれを知っているかもしれません。はい、解析されたMarkdownファイルは非常に醜いです。なぜなら、マークダウンファイルのテーマを強調していないからといって、ドキュメントページの基本スタイルを設定していないからです。したがって、次に、マークダウンファイルにハイライトされたテーマとクリーンな基本スタイルを追加する必要があります。
トピックについては、 highlight.jsでAtom-One-Darkテーマを使用します。
最初のステップは、 highlight.jsをインストールすることです
npm i highlight -D 2番目のステップは、 examples/src/App.vueでテーマを紹介することです。ドキュメントの基本スタイルを設定するには、app.vueのレイアウトを変更する必要があります。
< template >
< div class =" app " >
< div class =" main-content " >
< div class =" page-container clearfix " >
< div class =" page-content " >
< router-view > </ router-view >
</ div >
</ div >
</ div >
</ div >
</ template >
< script >
import 'highlight.js/styles/atom-one-dark.css'
export default {
name : 'App'
}
</ script > 3番目のステップは、ドキュメントの基本スタイルを設定することです。 assetsに新しいdocs.cssを作成し、初期スタイルを作成します。コードボリュームが大きすぎるため、ここには投稿しません。 docs.cssのコードをローカルdocs.cssファイルに自分でコピーしてから、 examples/src/index.js
import '../assets/docs.css'最後に、マークダウンの解析ルールを変換します。 vue-markdown-loader自由に動作するためのpreprocessインターフェイスを提供します。次に、解析されたマークダウンファイルの構造を定義し、 webpack.base.conf.jsファイルに書き込みます。
// 定义辅助函数wrap,将<code>标签都加上名为'hljs'的class
function wrap ( render ) {
return function ( ) {
return render . apply ( this , arguments )
. replace ( '<code v-pre class="' , '<code class="hljs ' )
. replace ( '<code>' , '<code class="hljs">' )
}
}
// ...
{
test : / .md$ / ,
loader : 'vue-markdown-loader' ,
options : {
preventExtract : true ,
preprocess : function ( MarkdownIt , source ) {
// 为table标签加上名为'table'的class
MarkdownIt . renderer . rules . table_open = function ( ) {
return '<table class="table">'
} ;
MarkdownIt . renderer . rules . fence = wrap ( MarkdownIt . renderer . rules . fence ) ;
return source ;
}
}
}次に、localhostを再訪します:8080/#/component/hello
OK、私たちのMDファイルはVueコンポーネントに正常に解析され、美しいハイライトされたテーマとシンプルな基本スタイルを持っています〜
前にも言ったように、この記事で開発されたコンポーネントライブラリはモバイルに適合しているため、PCにドキュメントとモバイルにデモを表示する必要があります。
このセクションでは、ルートを異なる端に適応させます。もちろん、このことは難しくありません。主にWebpackを使用してマルチページ機能を構築します。では、具体的にどのように行うのでしょうか?さて、今から始めましょう
最初のステップは、JSエントリファイルを登録してwebpack.base.conf.jsファイルに書き込むことです
entry: {
// ...
'vui' : './examples/src/index.js' , // PC端入口js
'vui-mobile' : './examples/src/mobile.js' // 移动端入口js
} 2番目のステップは、ページの入り口を登録し、 webpack.base.conf.jsファイルに書き込むことです。
plugins: [
// ...
// PC端页面入口
new HtmlWebpackPlugin ( {
chunks : [ 'manifest' , 'vendor' , 'vui' ] ,
template : 'examples/src/index.tpl' ,
filename : 'index.html' ,
inject : true
} ) ,
// 移动端页面入口
new HtmlWebpackPlugin ( {
chunks : [ 'manifest' , 'vendor' , 'vui-mobile' ] ,
template : 'examples/src/index.tpl' ,
filename : 'mobile.html' ,
inject : true
} )
] エントリファイルの登録が完了しました。次に行う必要があることは、デバイス環境を決定することです。ここでは、 navigator.userAgentを使用して正規表現を使用して、コンポーネントライブラリが実行される環境がPC側に属しているかモバイル側に属しているかを判断しますか?
最初のステップはexamples/src/is-mobile.jsファイルに次のコードを記述することです
/* eslint-disable */
const isMobile = ( function ( ) {
var platform = navigator . userAgent . toLowerCase ( )
return ( / (android|bbd+|meego).+mobile|kdtunion|weibo|m2oapp|micromessenger|avantgo|bada/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)/|plucker|pocket|psp|series(4|6)0|symbian|treo|up.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino / i ) . test ( platform ) ||
( / 1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw-(n|u)|c55/|capi|ccwa|cdm-|cell|chtm|cldc|cmd-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc-s|devi|dica|dmob|do(c|p)o|ds(12|-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(-|_)|g1 u|g560|gene|gf-5|g-mo|go(.w|od)|gr(ad|un)|haie|hcit|hd-(m|p|t)|hei-|hi(pt|ta)|hp( i|ip)|hs-c|ht(c(-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i-(20|go|ma)|i230|iac( |-|/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |/)|klon|kpt |kwc-|kyo(c|k)|le(no|xi)|lg( g|/(k|l|u)|50|54|-[a-w])|libw|lynx|m1-w|m3ga|m50/|ma(te|ui|xo)|mc(01|21|ca)|m-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|-([1-8]|c))|phil|pire|pl(ay|uc)|pn-2|po(ck|rt|se)|prox|psio|pt-g|qa-a|qc(07|12|21|32|60|-[2-7]|i-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55/|sa(ge|ma|mm|ms|ny|va)|sc(01|h-|oo|p-)|sdk/|se(c(-|0|1)|47|mc|nd|ri)|sgh-|shar|sie(-|m)|sk-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h-|v-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl-|tdg-|tel(i|m)|tim-|t-mo|to(pl|sh)|ts(70|m-|m3|m5)|tx-9|up(.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas-|your|zeto|zte- / i ) . test ( platform . substr ( 0 , 4 ) ) ;
} ) ( )
// 返回设备所处环境是否为移动端,值为boolean类型
export default isMobile 2番目のステップは、PC側のJSエントリファイルのexamples/src/index.jsに次の判断ルールを記述することです
import isMobile from './is-mobile'
// 是否为生产环境
const isProduction = process . env . NODE_ENV === 'production'
router . beforeEach ( ( route , redirect , next ) => {
if ( route . path !== '/' ) {
window . scrollTo ( 0 , 0 )
}
// 获取不同环境下,移动端Demo对应的地址
const pathname = isProduction ? '/vui/mobile' : '/mobile.html'
// 如果设备环境为移动端,则直接加载移动端Demo的地址
if ( isMobile ) {
window . location . replace ( pathname )
return
}
document . title = route . meta . title || document . title
next ( )
} ) 3番目のステップは、モバイルJSエントリファイルの例の前のステップと同様の判断ルールを記述することですexamples/src/mobile.js
import isMobile from './is-mobile'
const isProduction = process . env . NODE_ENV === 'production'
router . beforeEach ( ( route , redirect , next ) => {
if ( route . path !== '/' ) {
window . scrollTo ( 0 , 0 )
}
// 获取不同环境下,PC端对应的地址
const pathname = isProduction ? '/vui/mobile' : '/mobile.html'
// 如果设备环境不是移动端,则直接加载PC端的地址
if ( ! isMobile ) {
window . location . replace ( pathname )
return
}
document . title = route . meta . title || document . title
next ( )
} )最後に、 examples/src/mobile.jsファイルとモバイルページPortal MobileApp.vueファイルを改善します
examples/src/mobile.jsで次のコードを記述します
import Vue from 'vue'
import VueRouter from 'vue-router'
import MobileApp from './MobileApp'
import Vui from 'src/index'
import isMobile from './is-mobile.js'
import Hello from '../pages/hello.vue'
import 'packages/vui-css/src/index.css'
Vue . use ( Vui )
Vue . use ( VueRouter )
const isProduction = process . env . NODE_ENV === 'production'
const router = new VueRouter ( {
base : isProduction ? '/vui/' : __dirname ,
routes : [ {
path : '/component/hello' ,
component : Hello
} ]
} )
router . beforeEach ( ( route , redirect , next ) => {
if ( route . path !== '/' ) {
window . scrollTo ( 0 , 0 )
}
const pathname = isProduction ? '/vui/' : '/'
if ( ! isMobile ) {
window . location . replace ( pathname )
return
}
document . title = route . meta . title || document . title
next ( )
} )
new Vue ( {
el : '#app-container' ,
router ,
components : { MobileApp } ,
template : '<MobileApp/>'
} ) MobileApp.vueで書いてください
< template >
< div class =" mobile-container " >
< router-view > </ router-view >
</ div >
</ template >次に、ブラウザの効果を試して、異なるデバイス環境が対応するコンテンツを表示できるかどうかを確認できます〜
この時点で、この章で策定したすべての計画が完了しました。 MDファイルの「完璧な」変換、およびさまざまなデバイス環境でのルーティングの適応。ドキュメントの公式ウェブサイト(パート1)の開発は、ここで終わりを告げています。次の章では、ドキュメントの公式ウェブサイトの残りの開発作業を引き続き完了します!
前の章では、完了しました。
この章では、ドキュメント公式ウェブサイトの詳細を改善し、完全なドキュメント公式Webサイトを開発します。
前の章にあるディレクトリから、ドキュメントディレクトリを使用して、PCを表示する必要があるMDファイルを保存するために使用され、ページディレクトリはモバイルデモファイルを保存するために使用されることがわかります。では、コンポーネントはどのようにして異なるデバイス環境に対応するファイルを表示できますか(PC側はコンポーネントに対応するMDファイルを表示し、モバイルサイドはコンポーネントに対応するVUEファイルを表示します)。この場合、コンポーネントライブラリのルーティングをどのように合理的に管理できますか?次に、これらの問題に基づいて以下の開発を続けます。 is-mobile.jsデバイス環境を決定するために間違いなくここで使用されます。特定の仕事をするために私をフォローしてください。
最初のステップは、新しいファイルnav.config.jsonファイルをexamples/srcの下に作成し、次のコンテンツを作成することです
{
// 为了之后组件文档多语言化
"zh-CN" : [
{
"name" : "Vui 组件" ,
"showInMobile" : true ,
"groups" : [
{
// 管理相同类型下的所有组件
"groupName" : "基础组件" ,
"list" : [
{
// 访问组件的相对路径
"path" : "/hello" ,
// 组件描述
"title" : "Hello"
}
]
}
]
}
]
} 2番目のステップは、 router.config.jsファイルを改善し、登録をルーティングするためにヘルパー関数に変更することです。
const registerRoute = ( navConfig , isMobile ) => {
let route = [ ]
// 目前只有中文版的文档
let navs = navConfig [ 'zh-CN' ]
// 遍历路由文件,逐一进行路由注册
navs . forEach ( nav => {
if ( isMobile && ! nav . showInMobile ) {
return
}
if ( nav . groups ) {
nav . groups . forEach ( group => {
group . list . forEach ( nav => {
addRoute ( nav )
} )
} )
} else if ( nav . children ) {
nav . children . forEach ( nav => {
addRoute ( nav )
} )
} else {
addRoute ( nav )
}
} )
// 进行路由注册
function addRoute ( page ) {
// 不同的设备环境引入对应的路由文件
const component = isMobile
? require ( `../pages ${ page . path } .vue` )
: require ( `../docs ${ page . path } .md` )
route . push ( {
path : '/component' + page . path ,
component : component . default || component
} )
}
return route
}
export default registerRoute 3番目のステップは、メインポータルのメインポータルJSファイルのexamples/src/index.jsにルートexamples/src/mobile.jsに登録することです。
import registerRoute from './router.config'
import navConfig from './nav.config'
const routesConfig = registerRoute ( navConfig )
const router = new VueRouter ( {
routes : routesConfig
} )次に、現在のコンポーネントライブラリドキュメントの公式Webサイトにアクセスしてください
前の章の最終レンダリングから、PC端末が3つの部分に分割されていることがわかります。
次に、PC APIの表示を開始しましょう
ヘッダーは比較的簡単です。 examples/src/componentsの下に新しいpage-header.vueファイルを作成し、次のコンテンツを記述する必要があります
< template >
< div class =" page-header " >
< div class =" page-header__top " >
< h1 class =" page-header__logo " >
< a href =" # " > Vui.js </ a >
</ h1 >
< ul class =" page-header__navs " >
< li class =" page-header__item " >
< a href =" / " class =" page-header__link " >组件</ a >
</ li >
< li class =" page-header__item " >
< a href =" https://github.com/Brickies/vui " class =" page-header__github " target =" _blank " > </ a >
</ li >
< li class =" page-header__item " >
< span class =" page-header__link " > </ span >
</ li >
</ ul >
</ div >
</ div >
</ template >特定のスタイルについては、Page-Header.vueにアクセスして直接表示してください。
左側には、コンポーネントルートとタイトルを表示します。実際、 examples/src/nav.config.jsonを解析して表示することです。
examples/src/componentsの下に新しいside-nav.vueファイルを作成します。ファイルの通常の構造は次のとおりです
< li class =" nav-item " >
< a href =" javascript:void(0) " > Vui 组件</ a >
< div class =" nav-group " >
< div class =" nav-group__title " >基础组件</ div >
< ul class =" pure-menu-list " >
< li class =" nav-item " >
< router-link
active-class =" active "
:to =" /component/hello "
v-text =" navItem.title " > Hello
</ router-link >
</ li >
</ ul >
</ div >
</ li >ただし、現在の構造に基づいて、 examples/src/nav.config.jsonを解析する必要があります。改良されたコードは次のとおりです
< li class =" nav-item " v-for =" item in data " >
< a href =" javascript:void(0) " @click =" handleTitleClick(item) " > {{ item.name }} </ a >
< template v-if =" item.groups " >
< div class =" nav-group " v-for =" group in item.groups " >
< div class =" nav-group__title " > {{ group.groupName }} </ div >
< ul class =" pure-menu-list " >
< template v-for =" navItem in group.list " >
< li class =" nav-item " v-if =" !navItem.disabled " >
< router-link
active-class =" active "
:to =" base + navItem.path "
v-text =" navItem.title " />
</ li >
</ template >
</ ul >
</ div >
</ template >
</ li >完全なコードSide-Nav.vueについては、ここをクリックしてください
page-header.vueとside-nav.vueを使用してApp.vueで書きました
< template >
< div class =" app " >
< page-header > </ page-header >
< div class =" main-content " >
< div class =" page-container clearfix " >
< side-nav :data =" navConfig['zh-CN'] " base =" /component " > </ side-nav >
< div class =" page-content " >
< router-view > </ router-view >
</ div >
</ div >
</ div >
</ div >
</ template >
< script >
import 'highlight.js/styles/atom-one-dark.css'
import navConfig from './nav.config.json'
import PageHeader from './components/page-header'
import SideNav from './components/side-nav'
export default {
name : 'App' ,
components : { PageHeader , SideNav } ,
data ( ) {
return {
navConfig : navConfig
}
}
}
</ script >次に、もう一度ページにアクセスしてください、結果は写真に示されています
モバイルデモとPCの原則は似ています。両方とも、 nav.config.jsonファイルを表示する必要があります
現在、メインエントランスページMobileApp.vueを除き、モバイル端末にはルートコンポーネントの依存関係がありません。次に、最初にルートコンポーネントの開発を完了し、 examples/src/componentsの下に新しいdemo-list.vueファイルを作成し、コンテンツを作成します
< template >
< div class =" side-nav " >
< h1 class =" vui-title " > </ h1 >
< h2 class =" vui-desc " > VUI 移动组件库</ h2 >
</ div >
</ template >次に、ルートでそれを参照し、 mobile.jsファイルに書き込む必要があります
import DemoList from './components/demo-list.vue'
routesConfig . push ( {
path : '/' ,
component : DemoList
} )次に、 demo-list.vueファイルの改善を開始します
< template >
< div class =" side-nav " >
< h1 class =" vui-title " > </ h1 >
< h2 class =" vui-desc " > VUI 移动组件库</ h2 >
< div class =" mobile-navs " >
< div v-for =" (item, index) in data " :key =" index " >
< div class =" mobile-nav-item " v-if =" item.showInMobile " >
< mobile-nav v-for =" (group, s) in item.groups " :group =" group " :base =" base " :key =" s " > </ mobile-nav >
</ div >
</ div >
</ div >
</ div >
</ template >
< script >
import navConfig from '../nav.config.json' ;
import MobileNav from './mobile-nav' ;
export default {
data ( ) {
return {
data : navConfig [ 'zh-CN' ] ,
base : '/component'
} ;
} ,
components : {
MobileNav
}
} ;
</ script >
< style lang =" postcss " >
.side-nav {
width: 100%;
box-sizing: border-box;
padding: 90px 15px 20px;
position: relative;
z-index: 1;
.vui-title,
.vui-desc {
text-align: center;
font-weight: normal;
user-select: none;
}
.vui-title {
padding-top: 40px;
height: 0;
overflow: hidden;
background: url(https://raw.githubusercontent.com/xuqiang521/vui/master/src/assets/logo.png) center center no-repeat;
background-size: 40px 40px;
margin-bottom: 10px;
}
.vui-desc {
font-size: 14px;
color: #666;
margin-bottom: 50px;
}
}
</ style >这里我们引用了mobile-nav.vue文件,这也是我们接下来要完成的移动端Demo 列表展示组件
在examples/src/components下新建mobile-nav.vue文件,解析nav.config.json文件,从而进行Demo 列表展示。
< template >
< div class =" mobile-nav-group " >
< div
class =" mobile-nav-group__title mobile-nav-group__basetitle "
:class =" {
'mobile-nav-group__title--open': isOpen
} "
@click =" isOpen = !isOpen " >
{{group.groupName}}
</ div >
< div class =" mobile-nav-group__list-wrapper " :class =" { 'mobile-nav-group__list-wrapper--open': isOpen } " >
< ul class =" mobile-nav-group__list " :class =" { 'mobile-nav-group__list--open': isOpen } " >
< template v-for =" navItem in group.list " >
< li
class =" mobile-nav-group__title "
v-if =" !navItem.disabled " >
< router-link
active-class =" active "
:to =" base + navItem.path " >
< p >
{{ navItem.title }}
</ p >
</ router-link >
</ li >
</ template >
</ ul >
</ div >
</ div >
</ template >
< script >
export default {
props : {
group : {
type : Object ,
default : ( ) => {
return [ ] ;
}
} ,
base : String
} ,
data ( ) {
return {
isOpen : false
} ;
}
} ;
</ script >然后写入列表样式
< style lang =" postcss " >
@component-namespace mobile {
@b nav-group {
border-radius: 2px;
margin-bottom: 15px;
background-color: #fff;
box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1);
@e basetitle {
padding-left: 20px;
}
@e title {
font-size: 16px;
color: #333;
line-height: 56px;
position: relative;
user-select: none;
@m open {
color: #38f;
}
a {
color: #333;
display: block;
user-select: none;
padding-left: 20px;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
&:active {
background: #ECECEC;
}
> p {
border-top: 1px solid #e5e5e5;
}
}
}
@e list-wrapper {
height: 0;
overflow: hidden;
@m open {
height: auto;
}
}
@e list {
transform: translateY(-50%);
transition: transform .2s ease-out;
@m open {
transform: translateY(0);
}
}
li {
list-style: none;
}
ul {
padding: 0;
margin: 0;
overflow: hidden;
}
}
}
</ style >接下来,重新访问http://localhost:8080/mobile.html ,不出意外你便能访问到我们预想的结果
到这一步为止,我们“粗陋”的组件库架子便已经全部搭建完毕。
博文到这里也差不多要结束了,文章中所有的代码都已经托管到了github上,后续我还会写一篇文章,带着搭建逐步完善我们组件库中的一些细节,让我们的组件库能够更加的完美。
github地址:https://github.com/xuqiang521/personal-component-library
文章末尾再打一波广告~~~
前端交流群:731175396
美团点评长期招人,如果有兴趣的话,欢迎一起搞基,简历投递方式交流群中有说明~
小伙伴们你们还在等什么呢?赶紧先给文章点波赞,然后关注我一波,然后加群和大佬们一起交流啊~~~