Ich mag es normalerweise, einige Dinge aufzunehmen und zusammenzufassen, einschließlich einiger Komponenten. Wenn ich viele von ihnen sammle, finde ich, dass die verstreute Akkumulation nicht mehr für das Management geeignet ist.
Also begann ich zu denken, gibt es eine gute Möglichkeit, diese verstreuten Dinge relativ standardisiert zu verwalten? Wenn Komponenten in Form von Komponentenbibliotheken verwaltet werden, eignet es sich dann besser für Ihre eigene Akkumulation und erleichtert zukünftige Arbeiten?
Also begann ich mich auf einige hervorragende UI-Komponentenbibliotheken auf dem Markt zu beziehen, wie element-ui , vux , vant usw., las den Quellcode, um die Konstruktion seiner Architektur zu verstehen, und sortierte dann eine Menge meiner eigenen Bibliothek für mobile UI-Komponenten vui .
In meiner Freizeit bin ich in großen technischen Gemeinschaften aktiv. Ich habe oft einige Freunde, die eine Weile gearbeitet haben oder immer noch darauf vorbereiten, ein Praktikum zu finden, um dem Autor einige Fragen zu stellen: Wie kann man sich niederlassen und Ihr eigenes Rahmen, Ihr Rad und Ihr eigenes Bibliothek erstellen? Wie erstelle ich eine Komponentenbibliothek? Wird das Erstellen einer Komponentenbibliothek selbst zum Höhepunkt Ihres Lebenslaufs werden? Können Sie einige Artikel über die Entwicklung der Komponentenbibliothek schreiben? ...
Dieser Blog -Beitrag wurde in der Stimmung geboren, Zweifel zu beantworten und Fragen zu teilen.
Wenn Sie beim Lesen von Artikeln Fragen haben, schließen Sie sich der Diskussionsgruppe an, um zu diskutieren (zusätzlich zu einer Gruppe großer Jungs, die jeden Tag sprechen, gibt es auch eine Gruppe von Mädchen ~).
Front-End HodgePodge: 731175396
Github: https://github.com/xuqiang521
Gehen wir ohne weiteres direkt zum tatsächlichen Kampfkapitel ~ gehen ~
Hier werde ich nur über die Installation des Knotens unter Mac und Fenster sprechen
Wenn Sie das homebrew des Mac Package Managers nicht installiert haben, besteht der erste Schritt darin, ihn zuerst zu installieren
/usr/bin/ruby -e " $( curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install ) " Installieren Sie node mit homebrew
brew install node Wenn Sie zur offiziellen Website der window gehen möchten, um die entsprechende Version herunterzuladen, klicken Sie auf den nächsten Schritt, um die Installation abzuschließen.
Überprüfen Sie nach Abschluss der Installation node und npm
node -v
# v9.6.1
npm -v
# 5.6.0 Seitdem wurde die node auf Ihrem Computer erstellt. Als nächstes müssen wir die Komponentenbibliothek installieren, um das Abhängigkeitsgerüst zu erstellen.
# 全局安装
npm i -g vue-cli
# 查看vue-cli用法
vue -h
# 查看版本
vue -V
# 2.9.3 Initialisieren Sie ein Projekt namens personal-components-library mit der init -Richtlinie des vue-cli
# 项目基于 webpack
vue init webpack personal-components-libraryBeim Bauaufbau werden Sie aufgefordert, einige Beschreibungen und Abhängigkeiten des Projekts auszufüllen. Bitte beachten Sie den Inhalt, den ich unten ausgewählt habe, um ihn auszufüllen.
# 项目名称
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 Nachdem Sie es ausgewählt haben, können Sie warten. vue-cli hilft Ihnen beim Aufbau des Projekts und zur Durchführung von Abhängigkeitsinstallationen.
Die Initialisierungsprojektstruktur lautet wie folgt:
├── 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 测试文档和案例Wenn Sie npm verwenden, um Abhängigkeiten zu langsam herunterzuladen oder einige Ressourcen ummauert, wird empfohlen, cnpm zum Herunterladen von Abhängigkeiten zu verwenden
# 全局安装 cnpm
npm install -g cnpm --registry=https://registry.npm.taobao.org
# 使用 cnpm 进行依赖安装
cnpm i Sie können Ihr vue -Projekt nach Abschluss der Abhängigkeitsinstallation starten ~
npm run dev Besuchen Sie dann http://localhost:8080 und Sie können erfolgreich auf das über vue-cli erstellte vue Projekt zugreifen. Zu diesem Zeitpunkt wurde die Entwicklungsumgebung, von der Ihre Komponentenbibliothek abhängt, installiert.
Zunächst müssen wir den Zweck dieses Abschnitts klären. Wir müssen das Verzeichnis ändern, um Komponentenbibliotheken besser zu entwickeln.
Wir haben das vue -Projekt bereits im vorherigen Abschnitt gebaut, das initialisierte Projektverzeichnis kann jedoch nicht die anschließende Entwicklung und Wartung einer Komponentenbibliothek erfüllen. Daher müssen wir in diesem Kapitel das Verzeichnis des initialisierten vue -Projekts umwandeln und es in das von der Komponentenbibliothek benötigte Verzeichnis umwandeln. Lassen Sie uns als nächstes Maßnahmen ergreifen.
demo und文档von Komponentenbibliotheken zu speichernmixins usw. der Komponentenregistrierung verwendet (dafür müssen wir das initialisierte src -Verzeichnis transformieren)OK, beginnen Sie, das Verzeichnis der von Ihnen initialisierten Projekte zu verändern.
Aus dem vorherigen Beispiel wissen wir, dass die Haupteintragsdatei der Seite, wenn wir den lokalen Dienst starten, index.html lautet. Jetzt ist unser erster Schritt, den Haupteingang der Seite html und js in das examples zu verschieben. Das spezifische examples ist wie folgt
├── assets css,图片等资源都在这
├── pages 路由中所有的页面
├── src
│ ├── components demo中可以复用的模块放在这里面
│ ├── index.js 入口js
│ ├── index.tpl 页面入口
│ ├── App.vue vue主入口文件
│ ├── router.config.js 路由jsDer geänderte Code jeder Datei lautet wie folgt
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 -Verzeichnis wird hauptsächlich zum Speichern der Haupteintragsdateien, Werkzeugmethoden, mixins und anderen Dateien für die registrierte Komponente verwendet. Aus dem obigen examples können wir wissen, dass einige Dateien im ursprünglichen src gelöscht werden müssen. Das modifizierte Verzeichnis ist wie folgt
├── mixins mixins方法存放在这
├── utils 一些常用辅助方法存放在这
├── index.js 组件注册主入口 Denken Sie darüber nach, wenn Sie dies sehen, sollten Sie auch wissen, was wir jetzt tun müssen. Das ist richtig, nur um die Eintragsdatei des lokalen Dienstes zu ändern. Wenn es einfach möglich ist, auszuführen, ändern Sie den JS-Eintrag im entry und die Seiteneintragsreferenz von html-webpack-plugin . Der Code ist wie folgt (es werden nur Schlüsselcodes platziert)
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, modifiziert. NPM npm run dev , UND Ihr Projekt kann unter der neuen Eintragsdatei ausgeführt werden
In diesem Abschnitt müssen wir den Dienst implementieren, den wir lokal gestartet haben und die Komponenten unterhalb packages verwenden können. Entwickeln wir die einfachste hello -Komponente, um sie zu erklären
hello -Komponente unter packages Um eine gute bindende Natur zu haben, beschränken wir uns hier: Bevor wir mit dem Schreiben einer Komponente beginnen, muss ein angegebenes Verzeichnis und ein angegebenes Dateiname einheitlich verwaltet werden. Die Dateien unter hello -Komponente im Verzeichnis packages sind wie folgt
├── hello
│ ├── hello.vue hello.vue Inhalt ist wie folgt
< 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 wird oben auch erwähnt. Es wird hauptsächlich verwendet, um die Registrierung aller Komponenten in unserer Komponentenbibliothek zu verwalten
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 -Eintrag JS -Datei Als nächstes muss ich auf die hello -Komponente verweisen, die wir in den geänderten examples im vorherigen Abschnitt geschrieben haben
import vui from 'src/index.js'
// 完整引用
Vue . use ( vui )
// 独立引用
const { Hello } = vui
Vue . component ( Hello . name , Hello ) examples/pages/hello.vue In examples/pages müssen wir eine Demo -Datei mit demselben Namen wie der Komponentenname erstellen und die Komponente verwenden
< v-hello message =" my component library " > </ v-hello >Wenn Ihr laufendes Ergebnis dem obigen Bild übereinstimmt, herzlichen Glückwunsch. Sie haben erfolgreich einen weiteren Schritt zur Entwicklung von Komponentenbibliotheken gemacht ~
Nachdem ich dies gesehen habe, brauche ich alle Leser, um Dateien zentral nach ihren eigenen Vorlieben zu verwalten (natürlich können Sie auch die Demo, die ich oben gegeben habe). Nur auf diese Weise kann die nachfolgende Entwicklungsarbeit unserer Komponentenbibliothek reibungslos sein.
Im nächsten Abschnitt optimieren wir die folgenden verpackten build und bringen Sie mit der Veröffentlichung Ihrer entwickelten Komponenten auf npm -Website, damit Ihre Komponentenbibliothek bequemer verwendet werden kann!
Wie üblich müssen wir vor Beginn des Kapitels Text wissen, was in diesem Kapitel getan werden muss und warum.
Seit dem ersten Projekt des Gerüsts verfügt nur eine zentral verpackte Datei für build -Dateien webpack.prod.conf.js
Damit unsere Komponentenbibliothek in Zukunft besser verwendet werden kann, müssen wir alle Module, die der Komponentenbibliothek entsprechen, in eine vui.js -Datei (was Ihnen der Name gefällt) extrahieren, damit wir unsere Komponentenbibliothek auf die folgende Weise verweisen können.
import Vue from 'vue'
import vui from 'x-vui'
Vue . use ( vui ) Wir müssen auch die relevanten Dateien in examples verpacken und verwalten, da wir später die offizielle Website der Dokument -offiziellen Komponentenbibliothek entwickeln müssen, und die entsprechenden Eingänge der offiziellen Dokument -Website sind in examples
Aus dem Initialisierungsprojekt können wir sehen, dass webpack -Datei in der build -Datei wie folgt lautet
├── webpack.base.conf.js 基础配置文件
├── webpack.dev.conf.js 本地服务配置文件
├── webpack.prod.conf.js 打包配置文件
├── webpack.test.conf.js 测试配置文件(这里先不做过多描述) Das initialisierte output ist dist . Dieses Verzeichnis ist das Ausgabeverzeichnis, nachdem das gesamte Projekt verpackt ist, nicht das von unserer Komponentenbibliothek erforderliche Verzeichnis. Was wollen wir in dem Verzeichnis, das wir brauchen, nicht das ist, was wir wollen?
lib/vui.js (Komponentenbibliothek JS -Hauptdatei)lib/vui-css/index.css (die Hauptdatei der Komponentenbibliothek-CSS, wir werden in diesem Kapitel nicht zu viel über die CSS-Verpackung beschreiben, und die folgenden Kapitel werden separat erläutert)examples examples/dist Packaged aus der Beispiel -Datei (der Haupteintritt der offiziellen Website des späteren Dokuments) Da webpack Ziel festgelegt wurde
├── 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
Bevor wir beginnen, die Datei webpack.base.conf.js zu transformieren, müssen wir verstehen, was in zwei verpackten Dateien erfolgen muss.
webpack.build.js : Ausgibt die JS -Hauptdatei lib/vui.js Komponentenbibliothek und verwendet webpack.base.conf.js und webpack.dev.conf.js verwandte Konfigurationenwebpack.build.min.js : Ausgibt examples/dist -Dokument -verwandte Dateien und verwendet webpack.base.conf.js und webpack.dev.conf.js verwandte Konfigurationen Da beide webpack -Verpackungsdateien webpack.base.conf.js und webpack.dev.conf.js verwandte Konfigurationen verwenden, integrieren Sie einige der gleichen Dateien nicht in die Dateien webpack.base.conf.js ? Das Ziel ist klar, lass uns als nächstes folgen
'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
Hier müssen Sie nur die in webpack.base.conf.js integrierte Konfiguration löschen, um die Doppelarbeit von Code zu vermeiden
'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 )
}
} )
} ) Nachdem die beiden Dateien von webpack.base.conf.js und webpack.dev.conf.js angepasst werden, npm run dev erneut aus.
Das obige Bild scheint anzuzeigen, dass Ihre lokale Servicedatei wie erwartet erfolgreich geändert wurde ~
1. Webpack.build.js
Der Hauptzweck dieser Datei besteht darin, alle komponentenbezogenen Dateien in der Komponentenbibliothek zusammenzupacken und lib/vui.js auszugeben
'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
Der Hauptzweck dieser Datei besteht darin, eine einzelne Paketadresse zu öffnen und die relevanten Dateien in examples für das Beispiel für examples/dist (dh den offiziellen Eingang der Website des nachfolgenden Dokuments) auszugeben.
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 Wenn wir alle diese Dateien zusammenbringen, besteht der letzte Schritt darin, den Paketbefehl an scripts von package.json zu schreiben.
"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 "
}, Führen Sie den Befehl aus, npm run build:vui , go
Zu diesem Zeitpunkt wurden der lokale Service und zwei verpackte Dateien verwandelt. Versuchen wir, npm ~ zu verwenden
Beachten Sie, dass, wenn Sie kein eigenes npm -Konto haben, bitte ein Konto selbst auf der offiziellen npm -Website registrieren. Klicken Sie hier, um die offizielle Website einzugeben, um sich zu registrieren. Die Registrierungsschritte sind relativ einfach. Ich werde es hier nicht mehr beschreiben. Wenn Sie Fragen haben, können Sie mich in der WeChat -Gruppe stellen.
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) Bestätigen Sie dann, package.json wird wie folgt generiert
{
"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"
} Als nächstes müssen wir uns lokal mit unserem registrierten npm -Konto verbinden
npm adduser
# Username: 填写你自己的npm账号
# Password: npm账号密码
# Email: (this IS public) 你npm账号的认证邮箱
# Logged in as xuqiang521 on https://registry.npmjs.org/. 连接成功Führen Sie npm publish aus, um mit der Veröffentlichung zu beginnen
npm publish
# + [email protected] Zu diesem npm können Sie das Paket suchen und sehen, das Sie gerade veröffentlicht haben ~
Gegenwärtig haben wir die einfachste hello -Komponente in der Komponentenbibliothek geschrieben, dies hat jedoch keine Auswirkungen auf unsere Veröffentlichung auf npm -Website, und die Veröffentlichungsschritte sind so einfach wie das obige Beispiel.
Ändern Sie einige Beschreibungen in der Datei package.json
// npm 包js入口文件改为 lib/vui.js
"main" : "lib/vui.js" ,
// npm 发布出去的包包含的文件
"files" : [
"lib" ,
"src" ,
"packages"
] ,
// 将包的属性改为公共可发布的
"private" : false , Beachten Sie, dass beim Testen des npm -Pakets die version in package.json höher als die vorherige ist.
Beginnen Sie mit der Veröffentlichung
# 打包,输出lib/vui.js
npm run build:vui
# 发布
npm publish
# + [email protected] Wählen Sie ein lokales Vue -Projekt aus und geben Sie das Projekt ein
npm i component-library-test
# or
cnpm i component-library-testRegistrieren Sie Komponenten in der Projekteingangsdatei
import Vue from 'vue'
import vui from 'component-library-test'
Vue . use ( vui )Verwendung auf der Seite
< v-hello message =" component library " > </ v-hello > Zu diesem Zeitpunkt haben wir die lokalen Servicedateien erfolgreich transformiert, das Paket der Hauptdatei der Komponentenbibliothek und das Paket des Haupteingangs der offiziellen Dokumentwebsite implementiert und schließlich erfahren, wie npm für die Projektveröffentlichung verwendet wird.
Im nächsten Kapitel werde ich die Verpackung css -Datei in der Komponentenbibliothek erläutern.
Im vorherigen Abschnitt haben wir die JS -Datei bereits verpackt. Für Komponentenbibliotheken müssen wir jedoch nicht nur die JS -Datei verwalten, sondern auch die CSS -Datei verwalten, um die anschließende Verwendung der Komponentenbibliothek sicherzustellen.
In diesem Abschnitt werde ich darüber sprechen, wie gulp angemessen verwendet wird, um die Verpackung und Verwaltung von CSS -Dateien in Projekten zu trennen, die auf webpack -Konstruktion basieren.
Bevor wir beginnen, müssen wir zwei Ziele klären:
Um das Management zu erleichtern, müssen wir jedes Mal, wenn wir eine neue Komponente erstellen, eine entsprechende CSS -Datei erstellen, um den Stil der Komponente zu verwalten und ein einzelnes Management zu erreichen.
Hier speichern wir alle CSS-Dateien im Verzeichnis packages/vui-css . Die spezifische Struktur ist wie folgt
├── src
│ ├── common 存放组件公用的css文件
│ ├── mixins 存放一些mixin的css文件
│ ├── index.css css主入口文件
│ ├── hello.css 对应hello组件的单一css文件
├── gulpfile.js css打包配置文件
├── package.json 相关的版本依赖Bevor wir anfangen, Komponenten -CSS zu schreiben, müssen wir einige Punkte klären:
Ich persönlich denke, dass der beste Weg auf dem Markt darin besteht, die Komponenten in einem einzigen CSS zu verwalten und das CSS mit bem zu schreiben. Wenn Sie bem wissen möchten, klicken Sie auf den Link unten
Lassen Sie uns als nächstes die einfache hello -Komponente erklären. Stellen Sie vor Beginn den Inhalt von hello.vue ein
< 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 > Erstellen Sie hello.css in packages/vui-css/src -Verzeichnis
@b v-hello {
color : # fff ;
transform : scale ( 1 );
@e message {
background : # 0067ED ;
}
} Importieren Sie dann die hello.css -Datei im index.css
@import './hello.css' ; Einführung von Komponentenbibliotheksstilen in examples/src/index.js
import 'packages/vui-css/src/index.css' Aber aus dem Inhalt hello.css können wir sehen, dass dies eine typische bem -Schreibmethode ist und nicht normal analysiert werden kann. Wir müssen das entsprechende postcss -Plugin einführen, um die bem -Syntax zu analysieren. Hier werden wir das饿了么团队entwickelte postcss-salad Plugin verwenden, um die bem Syntax zu analysieren. Zweitens muss diese CSS-Datei sass-like Stil auch ein Plugin namens precss verwenden. Installieren Sie zuerst die Abhängigkeiten.
npm i postcss-salad precss -D Nach Abschluss der Abhängigkeitsinstallation müssen wir im Projektroot -Verzeichnis salad.config.json erstellen, um bem -Regeln zu konfigurieren. Die spezifischen Regeln sind wie folgt
{
"browsers" : [ " ie > 8 " , " last 2 versions " ],
"features" : {
"bem" : {
"shortcuts" : {
"component" : " b " ,
"modifier" : " m " ,
"descendent" : " e "
},
"separators" : {
"descendent" : " __ " ,
"modifier" : " -- "
}
}
}
} Als nächstes müssen wir postcss-salad und precss Plugins in der initialisierten .postcssrc Datei wie folgt verwenden
module . exports = {
"plugins" : {
"postcss-import" : { } ,
"postcss-salad" : require ( './salad.config.json' ) ,
"postcss-url" : { } ,
"precss" : { } ,
"autoprefixer" : { } ,
}
}OK, wenn Sie das Projekt zu diesem Zeitpunkt erneut ausführen, werden Sie feststellen, dass das CSS wirksam wird, wie in der Abbildung gezeigt
Um die CSS -Dateien in der Komponentenbibliothek besser zu verwalten und sicherzustellen, dass Benutzer auch die CSS -Dateien einführen können, die der Komponente entsprechen, wenn nur ein oder mehrere Komponenten in der Komponentenbibliothek eingeführt werden. Daher müssen wir die CSS -Datei separat verpacken. Hier müssen wir gulp verwenden, um den entsprechenden Verpackungsvorgang durchzuführen. Bevor Sie die Verpackungsdetails erhalten, stellen Sie bitte sicher, dass Sie gulp weltweit installiert haben. Wenn nicht, installieren Sie es bitte
npm i gulp -g
# 查看版本
gulp -v
# CLI version 3.9.1 Schauen wir uns als 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" : { }
} Wir können sehen, dass dies tatsächlich der Abhängigkeit ähnelt, die für CSS-Dateien in der Komponentenbibliothek erforderlich ist, außer dass dies das postcss Plug-In basierend auf gulp ist. Vergessen Sie nicht, npm i für gulpfile.js Abhängigkeitsinstallation auszuführen.
Als nächstes konfigurieren wir gulpfile.js wie folgt
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' ] ) Jetzt können Sie den Befehl gulp build ausführen, um die CSS -Datei zu verpacken. Um Verpackungsbefehle zu erleichtern und besser auszuführen, müssen wir jetzt wie folgt einen CSS Build -Befehl zum package.json hinzufügen
"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 "
} Führen Sie npm run build:vui-css , gehen Sie voran und verpacken schließlich die JS- und CSS-Dateien der Komponentenbibliothek, wie in der folgenden Abbildung gezeigt
OK, zu diesem Zeitpunkt können Sie bereits Komponenten und ihre Stile separat einführen. Um npm den Benutzern zu ermöglichen, das CSS Ihrer Komponente direkt zu verwenden
# 进到vui-css目录
cd packages/vui-css
# 发布
npm publishZu diesem Zeitpunkt haben wir die Verwaltung und separate Verpackung der CSS -Datei abgeschlossen und die einzelne Ausgabe der CSS -Datei abgeschlossen. Auf diese Weise können wir eine bessere Möglichkeit haben, die CSS -Datei der Komponentenbibliothek zu entwickeln und zu verwalten und gleichzeitig die Verwendung der Komponentenbibliothek zu erleichtern!
Bisher haben wir ein neues Verzeichnis erstellt, das für die Komponentenbibliothek erforderlich ist, und wir haben auch die Verpackung von JS -Dateien und CSS -Dateien verändert. Wir haben ausreichende Vorbereitungen für die Entwicklung der Komponentenbibliothek getroffen, müssen jedoch noch einige sehr wichtige Vorarbeiten durchführen, um die Entwicklung und Wartung nachfolgender Komponenten der Komponentenbibliothek zu erleichtern.
Für Front-End-Tests ist es ein wichtiger Zweig der Front-End-Engineering. Wie kann ein so wichtiger Teil in unserer Komponentenbibliothek übersehen werden? Für Unit -Tests gibt es hauptsächlich zwei Arten
In diesem Kapitel Karma ich Sie zu Unit -Testkomponenten in unserer Komponentenbibliothek unter Verwendung der beiden Rahmenbedingungen basieren, die auf Mocha basieren.
Ich glaube, die meisten Menschen, die Unit -Tests ausgesetzt waren, sind mit den beiden Frameworks Karma + Mocha vertraut, aber hier denke ich, dass es notwendig ist, einen separaten Abschnitt zu öffnen, um eine kurze Einführung in die beiden Frameworks zu geben.
Um die Komponenten in unserer Komponentenbibliothek in den Mainstream -Webbrowsern zum Testen zu ermöglichen, haben wir uns für Karma entschieden. Das Wichtigste ist, dass Karma ein von vue-cli empfohlener Einheiten-Test-Framework ist. Wenn Sie mehr über Karma erfahren möchten, lesen Sie bitte die offizielle Website von Karma
simple , flexible und fun TestgerüstPromisecoveragebefore() , after() beforeEach() und afterEach() , damit wir unterschiedliche Vorgänge in verschiedenen Phasen festlegen können, um unsere Tests besser abzuschließen. Hier werde ich drei grundlegende Verwendungen von mocha sowie die vier Hakenfunktionen von describe (Lebenszyklus) einführen (Lebenszyklus)
Beschreiben (Modulenname, Funktion): describe ist nestbar und beschreiben, ob der Testfall korrekt ist.
describe ( '测试模块的描述' , ( ) => {
// ....
} ) ; ** IT (Info, Funktion): ** it entspricht einem Unit -Testfall
it ( '单元测试用例的描述' , ( ) => {
// ....
} )Verwendung der Assertion -Bibliothek
expect ( 1 + 1 ) . to . be . equal ( 2 ) Lebenszyklus der describe
describe ( 'Test Hooks' , function ( ) {
before ( function ( ) {
// 在本区块的所有测试用例之前执行
} ) ;
after ( function ( ) {
// 在本区块的所有测试用例之后执行
} ) ;
beforeEach ( function ( ) {
// 在本区块的每个测试用例之前执行
} ) ;
afterEach ( function ( ) {
// 在本区块的每个测试用例之后执行
} ) ;
// test cases
} ) ; Schüler, die mehr über mocha -Operationen erfahren möchten, können auf den folgenden Link klicken, um ihn anzuzeigen
Im obigen Abschnitt stelle ich kurz die Test -Frameworks Karma und Mocha ein, die offiziell von Vue empfohlen werden. Ich hoffe auch, dass Sie, wenn Sie dies sehen, ein einfaches Verständnis von Unit -Tests und gemeinsamen Testframeworks haben können.
Schauen wir uns vor Beginn des tatsächlichen Unit -Tests die Konfiguration von Karma an. Hier betrachten wir die Konfiguration in der Datei karma.conf.js , die vom vue-cli Gerüst initialisiert wurde (ich habe die spezifische Verwendung kommentiert)
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' }
]
}
} )
} Lassen Sie uns als nächstes einen einfachen Test in unserer eigenen hello -Komponente durchführen (nur einen Testfall schreiben), erstellen Sie eine neue hello.spec.js -Datei in test/unit/specs und schreiben Sie den folgenden Code
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
} )
} ) Nach dem Schreiben des Testbeispiels besteht der nächste Schritt darin, den Test durchzuführen. Führen Sie npm run test aus, gehen Sie zu Ihnen ~, geben Sie das Ergebnis aus
hello.vue
✓ render default classList in hello Aus der obigen Testinstanz der hello -Komponente müssen wir die Komponente in eine VUE -Instanz instanziieren, und manchmal müssen wir sie auf dem DOM montieren
const Constructor = Vue . extend ( Hello )
const vm = new Constructor ( {
propsData : {
message : 'component'
}
} ) . $mount ( ) Wenn jede Komponente später mehrere Unit -Testinstanzen aufweist, wird dieses Schreiben dazu führen, dass unser endgültiger Test aufgebläht wird. Hier können wir uns auf das von element eingekapselte Unit -Test -Tool beziehen. Wir müssen einige häufig verwendete Methoden in der Einheitstests einkapseln. Im Folgenden werde ich einige im Tool bereitgestellte Methoden auflisten.
/**
* 回收 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 ) { } Im Folgenden werden wir die definierte Testwerkzeugmethode verwenden, um die Testinstanz hello -Komponente zu transformieren und die Datei hello.spec.js zu transformieren
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 erneut ausführen und das Ergebnis ausgeben
hello.vue
✓ render default classList in hello Oben haben wir die Verwendung von Unit -Tests bei statischen Urteilen eingeführt. Als nächstes werden wir einige asynchrone Anwendungsfälle und einige interaktive Ereignisse testen. Vor dem Testen müssen wir den Code unserer hello -Komponente wie folgt geringfügig ändern
< 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 > Als nächstes möchten wir testen, ob hello -Komponente Informationen durch Versprechen erfolgreich emit kann. Zum Beispiel lautet der Testfall wie folgt
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 )
} ) Starten Sie den Test erneut, führen Sie npm run test aus, geben Sie das Ergebnis aus
hello.vue
✓ render default classList in hello
✓ create a hello for click with promiseZu diesem Zeitpunkt haben wir die Konfiguration von Unit -Tests und einigen häufig verwendeten Verwendungen gelernt. Wenn Sie mehr über Unit -Tests erfahren müssen, folgen Sie dem Link, den ich zuvor zur Verfügung gestellt habe, um zu einer tieferen Studie zu gehen
Freunde, folgen Sie mir, um die vorherigen 5 Kapitel zu üben und haben das grundlegende Regal für unsere Komponentenentwicklung aufgebaut. Als nächstes werde ich Sie alle mitnehmen, um die offizielle Website des Dokuments mit hohen wichtigen Komponenten in der Komponentenbibliothek zu beenden.
Jeder sollte wissen, dass gute Open -Source -Projekte offizielle Dokumentationswebsites haben müssen. Um unsere UI -Bibliothek zu einer der besten zu machen, sollten wir auch unsere eigene offizielle Dokumentationswebsite verwenden.
Eine gute offizielle Dokumentwebsite erfordert zwei Dinge.
Da die Komponentenbibliothek, die Sie zu entwickeln haben, für mobile Geräte geeignet ist, wie können wir unsere offizielle Dokumentwebsite sowohl für API -Dokumentationsbeschreibungen als auch für mobile Beispiel -Demos erstellen. Dies erfordert, dass wir zwei Seiten von Seiten zur Anpassung entwickeln. Die folgenden Dinge müssen wir tun:
Bevor der tatsächliche Kampf beginnt, werfen wir einen Blick auf die in diesem Kapitel erforderliche Verzeichnisstruktur.
├── 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 动态注册路由In diesem Kapitel werden Sie hauptsächlich die Konvertierung von Markdown -Dateien und die Routing -Anpassung verschiedener Geräte erkennen.
Nach der Klärung der Ideen entwickeln wir weiterhin unsere offizielle Dokumentwebsite!
Aus dem oben angegebenen Verzeichnis, das ich oben angegeben habe, können wir feststellen, dass der Ordner docs in der Markdown -Datei gespeichert ist, und jede Markdown -Datei entspricht dem API -Dokument einer Komponente. Das gewünschte Ergebnis ist, jede Markdown -Datei in den Dokumenten in VUE -Komponenten umzuwandeln und die konvertierten VUE -Komponenten in die Route zu registrieren, damit sie über die Route auf jede Markdown -Datei zugreifen kann.
Um Markdown-Dateien in VUE-Komponenten zu analysieren, gibt es auf dem Markt viele Drei-Parteien webpack Plug-Ins. Wenn Sie ein tiefes Verständnis von webpack haben, können Sie natürlich auch versuchen, selbst eine auszuwählen. Hier verwende ich direkt Vue-Markdown-Loader, das vom饿了么团队entwickelt wurde.
Der erste Schritt besteht darin, sich auf die Installation zu verlassen
npm i vue-markdown-loader -D vue-markdown-loader zweite Schritt webpack.base.conf.js
{
test : / .md$ / ,
loader : 'vue-markdown-loader' ,
options : {
// 阻止提取脚本和样式标签
preventExtract : true
}
} Der dritte Schritt ist Versuch. Fügen Sie zuerst die Datei hello.md in docs hinzu und schreiben Sie dann die Anweisungen für die Verwendung von hello -Komponenten
## 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 | 点击操作 | — | Schritt 4: hello.md in die Route registrieren
route . push ( {
path : '/component/hello' ,
component : require ( '../docs/hello.md' )
} ) Besuchen Sie schließlich die Seite. Zu diesem Zeitpunkt können Sie feststellen, dass der Inhalt von hello.md in eine VUE -Komponente konvertiert wurde und durch Routing -Ladevorgang zugegriffen werden kann, aber die Seite ist hässlich ~ genau wie diese
Natürlich muss ich diese Situation nicht erklären, Sie wissen es vielleicht auch. Ja, die Parsen -Markdown -Datei ist so hässlich, nur weil wir das Thema für unsere Markdown -Datei weder hervorgehoben haben noch den Grundstil der Dokumentseite festgelegt haben. Als nächstes müssen wir unserer Markdown -Datei ein schönes hervorgehobenes Thema und einen sauberen Grundstil hinzufügen.
Für Themen verwenden wir hier das Atom-One-Dark-Thema in highlight.js .
Der erste Schritt ist die Installation von highlight.js
npm i highlight -D Der zweite Schritt besteht darin, das Thema in examples/src/App.vue vorzustellen. Um den Grundstil des Dokuments festzulegen, müssen wir auch das Layout von App.vue ändern
< 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 > Der dritte Schritt besteht darin, den Grundstil des Dokuments festzulegen. Erstellen Sie neue docs.css in assets und schreiben Sie den anfänglichen Stil. Da das Codevolumen zu groß ist, werde ich es hier nicht veröffentlichen. Sie können den Code in docs.css in die lokale docs.css -Datei selbst kopieren und ihn dann in examples/src/index.js
import '../assets/docs.css' Verwandeln Sie schließlich die Markdown -Parsing -Regeln. vue-markdown-loader bietet eine preprocess für uns, um frei zu arbeiten. Als nächstes definieren wir die Struktur der Parsen -Markdown -Datei und schreiben sie in die Datei 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 ;
}
}
}Dann besuchen Sie Localhost: 8080/#/Komponente/Hallo
OK, unsere MD -Datei wurde erfolgreich in VUE -Komponenten analysiert und hat ein schönes hervorgehobenes Thema und einen einfachen grundlegenden Stil ~
Wie ich bereits sagte, ist die von diesem Artikel entwickelte Komponentenbibliothek an Mobilgeräte angepasst. Daher müssen wir Dokumente auf dem PC und Demos auf dem Handy anzeigen.
In diesem Abschnitt werde ich Sie dazu bringen, die Routen an verschiedene Ziele anzupassen. Natürlich ist dieses Ding nicht schwierig. Es verwendet hauptsächlich Webpack, um mehrseitige Funktionen zu erstellen. Wie geht es also speziell? Ok, fangen wir jetzt an
Der erste Schritt besteht darin, die JS -Eintragsdatei zu registrieren und in die Datei webpack.base.conf.js zu schreiben
entry: {
// ...
'vui' : './examples/src/index.js' , // PC端入口js
'vui-mobile' : './examples/src/mobile.js' // 移动端入口js
} Der zweite Schritt besteht darin, den Seiteneingang zu registrieren und in der Datei webpack.base.conf.js zu schreiben.
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
} )
] Die Registrierung der Eintragsdatei ist abgeschlossen und wir müssen als nächstes die Geräteumgebung bestimmen. Hier werde ich navigator.userAgent mit regelmäßigen Ausdrücken verwenden, um festzustellen, ob die Umgebung, in der unsere Komponentenbibliothek ausgeführt wird, zur PC -Seite oder zur mobilen Seite gehört?
Der erste Schritt besteht darin, den folgenden Code in examples/src/is-mobile.js Datei zu schreiben
/* 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 Der zweite Schritt besteht darin, die folgenden Urteilsregeln in die examples/src/index.js auf der PC -Seite zu schreiben
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 ( )
} ) Der dritte Schritt besteht darin, Urteilsregeln zu schreiben, die dem vorherigen Schritt in den examples/src/mobile.js ähnlich sind
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 ( )
} ) Verbessern Sie schließlich examples/src/mobile.js -Datei und die mobile Seite Portal MobileApp.vue -Datei
Schreiben Sie den folgenden Code in 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/>'
} ) Schreiben Sie in MobileApp.vue
< template >
< div class =" mobile-container " >
< router-view > </ router-view >
</ div >
</ template >Als nächstes können Sie den Effekt im Browser versuchen, um festzustellen, ob verschiedene Geräteumgebungen den entsprechenden Inhalt ~ anzeigen können
Zu diesem Zeitpunkt wurden alle Pläne, die wir in diesem Kapitel formuliert haben, abgeschlossen. "Perfekte" Konvertierung von MD -Dateien und Anpassung des Routings in verschiedenen Geräteumgebungen. Die Entwicklung der offiziellen Website des Dokuments (Teil 1) endet hier. Im nächsten Kapitel werden wir weiterhin die verbleibenden Entwicklungsarbeiten der offiziellen Website des Dokuments abschließen!
Im vorherigen Kapitel haben wir abgeschlossen:
In diesem Kapitel werden wir die Details der offiziellen Website des Dokuments verbessern und eine vollständige offizielle Website für Dokumenten entwickeln.
Aus dem im vorherigen Kapitel angegebenen Verzeichnis können wir wissen, dass das DOCS -Verzeichnis zum Speichern von MD -Dateien verwendet wird, die der PC angezeigt werden muss, und das Pages -Verzeichnis zum Speichern mobiler Demo -Dateien. Wie können Komponenten ihre entsprechenden Dateien in verschiedenen Geräteumgebungen anzeigen (PC -Seite zeigt die MD -Dateien an, die Komponenten entsprechen, und die mobile Seite zeigt die VUE -Dateien an, die Komponenten entsprechen)? Wie können wir in diesem Fall das Routing unserer Komponentenbibliothek vernünftigerweise verwalten? Als nächstes setzen wir die folgende Entwicklung anhand dieser Probleme fort. is-mobile.js wird hier definitiv verwendet, um die Geräteumgebung zu bestimmen. Bitte folgen Sie mir, um die spezifische Arbeit zu erledigen.
nav.config.json erste Schritt examples/src
{
// 为了之后组件文档多语言化
"zh-CN" : [
{
"name" : "Vui 组件" ,
"showInMobile" : true ,
"groups" : [
{
// 管理相同类型下的所有组件
"groupName" : "基础组件" ,
"list" : [
{
// 访问组件的相对路径
"path" : "/hello" ,
// 组件描述
"title" : "Hello"
}
]
}
]
}
]
} Der zweite Schritt besteht darin, die Datei router.config.js zu verbessern und sie in eine Helferfunktion für die Routing -Registrierung zu ändern.
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 Der dritte Schritt besteht darin, die Route im Hauptportal -JS -Datei examples/src/index.js der Hauptportal -JS examples/src/mobile.js der Hauptportal -JS -Dateibeispiele/src/mobile.js der mobilen Mannschaft zu registrieren.
import registerRoute from './router.config'
import navConfig from './nav.config'
const routesConfig = registerRoute ( navConfig )
const router = new VueRouter ( {
routes : routesConfig
} )Besuchen Sie dann unsere offizielle Website des aktuellen Dokuments der Komponentenbibliothek
Aus den endgültigen Darstellungen des vorherigen Kapitels können wir sehen, dass das PC -Terminal in drei Teile unterteilt ist, nämlich:
Lassen Sie uns als nächstes die PC -API anzeigen
Der Header ist relativ einfach. Wir müssen nur eine neue Datei page-header.vue unter examples/src/components erstellen und den folgenden Inhalt schreiben
< 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 >Für bestimmte Stile besuchen Sie bitte die Seitenübernahme.
Auf der linken Seite zeigen wir die Komponentenrouten und -titel. Tatsächlich soll examples/src/nav.config.json .
Wir erstellen eine neue side-nav.vue -Datei unter examples/src/components . Die normale Struktur der Datei lautet wie folgt
< 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 > Aber jetzt müssen wir examples/src/nav.config.json basierend auf der aktuellen Struktur analysieren. Der verbesserte Code ist wie folgt
< 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 >Klicken Sie hier, um den vollständigen Code-Seiten-Nave.vue zu erhalten
Wir verwenden 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 >Besuchen Sie dann die Seite erneut, das Ergebnis ist wie im Bild gezeigt
Die Prinzipien der mobilen Demo und des PC sind ähnlich. Beide müssen die Datei nav.config.json für die Anzeige analysieren
Derzeit hat unser mobiles Terminal mit Ausnahme der MobileApp.vue keine Abhängigkeit von Wurzelkomponenten. examples/src/components demo-list.vue
< template >
< div class =" side-nav " >
< h1 class =" vui-title " > </ h1 >
< h2 class =" vui-desc " > VUI 移动组件库</ h2 >
</ div >
</ template > Dann müssen wir es in der Route verweisen und es in die Datei mobile.js schreiben
import DemoList from './components/demo-list.vue'
routesConfig . push ( {
path : '/' ,
component : DemoList
} ) Fangen Sie an, demo-list.vue Datei zu verbessern
< 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
美团点评长期招人,如果有兴趣的话,欢迎一起搞基,简历投递方式交流群中有说明~
小伙伴们你们还在等什么呢?赶紧先给文章点波赞,然后关注我一波,然后加群和大佬们一起交流啊~~~