Saya biasanya suka merekam dan merangkum beberapa hal, termasuk beberapa komponen. Ketika saya mengumpulkan banyak dari mereka, saya menemukan bahwa akumulasi yang tersebar tidak lagi cocok untuk manajemen.
Jadi saya mulai berpikir, apakah ada cara yang baik untuk mengelola hal -hal yang lebih tersebar ini dengan cara yang relatif terstandarisasi? Jika komponen dikelola dalam bentuk pustaka komponen, apakah akan lebih cocok untuk akumulasi Anda sendiri dan memfasilitasi pekerjaan di masa depan?
Jadi saya mulai merujuk ke beberapa pustaka komponen UI yang sangat baik di pasaran, seperti element-ui , vux , vant , dll., Baca kode sumber untuk memahami konstruksi arsitekturnya, dan kemudian memilah satu set pustaka komponen UI seluler saya sendiri vui .
Di waktu luang saya, saya aktif di komunitas teknis utama. Saya sering memiliki beberapa teman yang telah bekerja untuk sementara waktu atau masih bersiap untuk menemukan magang untuk mengajukan beberapa pertanyaan kepada penulis: bagaimana menyelesaikan diri sendiri dan membuat kerangka kerja, roda, dan perpustakaan Anda sendiri? Bagaimana cara membuat pustaka komponen? Akankah membuat perpustakaan komponen sendiri menjadi sorotan dari resume Anda? Bisakah Anda menulis beberapa artikel tentang pengembangan pustaka komponen? ...
Posting blog ini lahir dalam mood menjawab keraguan dan berbagi pertanyaan.
Jika Anda memiliki pertanyaan saat membaca artikel, silakan bergabung dengan grup diskusi untuk membahas (selain sekelompok orang besar yang berbicara setiap hari, ada juga sekelompok gadis ~)
Front-end Hodgepodge: 731175396
Github: https://github.com/xuqiang521
Tanpa basa -basi lagi, mari kita langsung ke bab pertempuran yang sebenarnya ~
Di sini saya hanya akan berbicara tentang pemasangan node di bawah Mac dan jendela
Jika Anda belum menginstal homebrew Paket Mac Manager, langkah pertama adalah menginstalnya terlebih dahulu
/usr/bin/ruby -e " $( curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install ) " Instal node Menggunakan homebrew
brew install node Jika Anda ingin pergi ke situs web resmi window untuk mengunduh versi yang sesuai, lalu klik langkah berikutnya untuk menyelesaikan instalasi.
Setelah instalasi selesai, periksa versi node dan npm
node -v
# v9.6.1
npm -v
# 5.6.0 Sejak itu, lingkungan node di komputer Anda telah dibangun. Selanjutnya, kita perlu menginstal pustaka komponen untuk membangun perancah ketergantungan.
# 全局安装
npm i -g vue-cli
# 查看vue-cli用法
vue -h
# 查看版本
vue -V
# 2.9.3 Inisialisasi proyek bernama personal-components-library menggunakan arahan init vue-cli
# 项目基于 webpack
vue init webpack personal-components-librarySaat membangun, perancah akan meminta Anda untuk mengisi beberapa deskripsi dan ketergantungan proyek. Silakan merujuk ke konten yang saya pilih di bawah ini untuk mengisinya.
# 项目名称
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 Setelah Anda memilihnya, Anda bisa menunggu. vue-cli akan membantu Anda membangun proyek dan melakukan instalasi ketergantungan.
Struktur proyek inisialisasi adalah sebagai berikut:
├── 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 测试文档和案例Jika Anda menggunakan npm untuk mengunduh dependensi terlalu lambat atau beberapa sumber daya berdinding, disarankan untuk menggunakan cnpm untuk mengunduh dependensi
# 全局安装 cnpm
npm install -g cnpm --registry=https://registry.npm.taobao.org
# 使用 cnpm 进行依赖安装
cnpm i Anda dapat memulai proyek vue Anda setelah instalasi ketergantungan selesai ~
npm run dev Kemudian kunjungi http://localhost:8080 dan Anda dapat berhasil mengakses proyek vue yang dibangun melalui vue-cli . Pada titik ini, lingkungan pengembangan yang bergantung pada perpustakaan komponen Anda telah diinstal.
Pertama -tama, kita perlu mengklarifikasi tujuan bagian ini. Kita perlu memodifikasi direktori untuk mengembangkan perpustakaan komponen dengan lebih baik.
Kami telah membangun proyek vue di bagian sebelumnya, tetapi direktori proyek yang diinisialisasi tidak dapat memenuhi pengembangan dan pemeliharaan perpustakaan komponen selanjutnya. Oleh karena itu, yang perlu kita lakukan dalam bab ini adalah mengubah direktori proyek vue yang diinisialisasi dan mengubahnya menjadi direktori yang dibutuhkan oleh pustaka komponen. Mari kita beraksi berikutnya.
demo tampilan dan文档pustaka komponenmixins , dll. dari pendaftaran komponen (untuk ini kita perlu mengubah direktori src yang diinisialisasi)Oke, mulailah mengubah direktori proyek yang Anda inisialisasi.
Dari contoh sebelumnya, kita tahu bahwa ketika kita memulai layanan lokal, file entri utama halaman adalah index.html . Sekarang langkah pertama kami adalah memindahkan pintu masuk utama halaman html dan js ke Direktori examples . Direktori examples spesifik adalah sebagai berikut
├── assets css,图片等资源都在这
├── pages 路由中所有的页面
├── src
│ ├── components demo中可以复用的模块放在这里面
│ ├── index.js 入口js
│ ├── index.tpl 页面入口
│ ├── App.vue vue主入口文件
│ ├── router.config.js 路由jsKode yang dimodifikasi dari setiap file adalah sebagai berikut
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
}
]
} ) Direktori src terutama digunakan untuk menyimpan file entri utama, metode alat, mixins dan file lainnya untuk komponen terdaftar. Kita dapat mengetahui dari direktori examples di atas bahwa beberapa file dalam src asli perlu dihapus. Direktori yang dimodifikasi adalah sebagai berikut
├── mixins mixins方法存放在这
├── utils 一些常用辅助方法存放在这
├── index.js 组件注册主入口 Pikirkan tentang itu, ketika Anda melihat ini, Anda juga harus tahu apa yang perlu kami lakukan sekarang. Itu benar, itu hanya untuk memodifikasi file entri layanan lokal. Jika hanya mungkin untuk dijalankan, maka modifikasi entri JS di entry dan referensi entri halaman dari html-webpack-plugin . Kode adalah sebagai berikut (hanya kode kunci yang ditempatkan)
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, dimodifikasi. Eksekusi ulang npm run dev sekali, dan proyek Anda dapat berjalan di bawah file entri baru
Di bagian ini, yang perlu kami terapkan adalah layanan yang kami mulai secara lokal, yang dapat menggunakan komponen di bawah packages . Mari kita kembangkan komponen hello paling sederhana untuk menjelaskannya
hello di bawah packages Untuk memiliki sifat ikatan yang baik, di sini kami membatasi: sebelum mulai menulis komponen, direktori dan nama file tertentu harus dikelola secara seragam. File di bawah komponen hello di direktori packages adalah sebagai berikut
├── hello
│ ├── hello.vue hello.vue konten adalah sebagai berikut
< template >
< div class =" v-hello " >
hello {{ message }}
</ div >
</ template >
< script >
export default {
name : 'v-hello' ,
props : {
message : String
}
}
</ script > src/index.js File sec/index.js juga disebutkan di atas. Ini terutama digunakan untuk mengelola pendaftaran semua komponen di pustaka komponen kami
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 Entri JS File Selanjutnya, saya perlu merujuk komponen hello yang kami tulis di examples yang dimodifikasi di bagian sebelumnya
import vui from 'src/index.js'
// 完整引用
Vue . use ( vui )
// 独立引用
const { Hello } = vui
Vue . component ( Hello . name , Hello ) examples/pages/hello.vue Dalam examples/pages kita perlu membuat file demo dengan nama yang sama dengan nama komponen dan menggunakan komponen
< v-hello message =" my component library " > </ v-hello >Jika hasil lari Anda sama dengan gambar di atas, maka selamat. Anda telah berhasil mengambil langkah lain menuju pengembangan pustaka komponen ~
Setelah melihat ini, saya membutuhkan semua pembaca untuk mengelola file secara terpusat sesuai dengan preferensi mereka sendiri (tentu saja, Anda juga dapat merujuk pada demo yang saya berikan di atas). Hanya dengan cara ini pekerjaan pengembangan selanjutnya dari perpustakaan komponen kami yang halus.
Di bagian selanjutnya, kami akan mengoptimalkan file yang dikemas di bawah build dan membawa Anda untuk menerbitkan komponen yang dikembangkan Anda ke situs web resmi npm , sehingga perpustakaan komponen Anda dapat digunakan dengan lebih nyaman!
Seperti biasa, sebelum teks bab dimulai, kita perlu tahu apa yang perlu dilakukan dalam bab ini dan mengapa.
Karena proyek awal perancah hanya memiliki satu file yang dikemas secara terpusat untuk file build webpack.prod.conf.js
Agar perpustakaan komponen kami lebih baik digunakan di masa depan, kami perlu mengekstrak semua modul yang sesuai dengan pustaka komponen ke dalam file vui.js (apa yang Anda sukai) sehingga kami dapat merujuk ke pustaka komponen kami dengan cara berikut.
import Vue from 'vue'
import vui from 'x-vui'
Vue . use ( vui ) Kami juga perlu mengemas dan mengelola file yang relevan dalam examples , karena kami harus mengembangkan situs web resmi dokumen perpustakaan komponen nanti, dan pintu masuk yang relevan dari situs web resmi dokumen ada dalam examples
Kita dapat melihat dari proyek inisialisasi bahwa file webpack dalam file build adalah sebagai berikut
├── webpack.base.conf.js 基础配置文件
├── webpack.dev.conf.js 本地服务配置文件
├── webpack.prod.conf.js 打包配置文件
├── webpack.test.conf.js 测试配置文件(这里先不做过多描述) Direktori output output yang diinisialisasi adalah dist . Direktori ini adalah direktori output setelah seluruh proyek dikemas, bukan direktori yang dibutuhkan oleh pustaka komponen kami. Karena bukan itu yang kita inginkan, apa yang ingin kita lakukan di direktori yang kita butuhkan?
lib/vui.js (component library js file utama)lib/vui-css/index.css (file utama CSS pustaka komponen, kami tidak akan menjelaskan terlalu banyak tentang kemasan CSS dalam bab ini, dan bab-bab berikut akan dijelaskan secara terpisah)examples file examples/dist dikemas dari file contoh (pintu masuk utama situs web resmi dokumen selanjutnya) Karena tujuan telah ditetapkan, hal berikutnya yang perlu kita lakukan adalah mengatur file pengemasan webpack yang relevan terlebih dahulu, sebagai berikut
├── 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
Sebelum mulai mengubah file webpack.base.conf.js , kita perlu memahami apa yang perlu dilakukan dalam dua file kemasan.
webpack.build.js : output file utama lib/vui.js pustaka js, dan akan menggunakan webpack.base.conf.js dan webpack.dev.conf.js konfigurasi terkaitwebpack.build.min.js : output File terkait dokumen examples/dist , dan menggunakan webpack.base.conf.js dan webpack.dev.conf.js konfigurasi terkait Karena kedua file pengemasan webpack menggunakan webpack.base.conf.js dan webpack.dev.conf.js konfigurasi terkait, mengapa tidak mengintegrasikan beberapa file yang sama ke dalam file webpack.base.conf.js ? Tujuannya jelas, mari kita ikuti saya berikutnya
'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
Di sini Anda hanya perlu menghapus konfigurasi yang terintegrasi ke dalam webpack.base.conf.js untuk menghindari duplikasi kode
'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 )
}
} )
} ) Setelah dua file webpack.base.conf.js dan webpack.dev.conf.js disesuaikan, jalankan npm run dev lagi.
Gambar di atas tampaknya menunjukkan bahwa file layanan lokal Anda telah berhasil dimodifikasi seperti yang diharapkan ~
1. Webpack.build.js
Tujuan utama dari file ini adalah untuk mengemas semua file terkait komponen di pustaka komponen bersama-sama dan output file utama 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
Tujuan utama dari file ini adalah untuk membuka alamat paket tunggal dan mengeluarkan file yang relevan dalam examples ke examples/dist (yaitu, pintu masuk situs web resmi dari dokumen berikutnya)
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 Ketika kita mengumpulkan semua file ini, langkah terakhir adalah menulis perintah paket ke scripts package.json .
"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 "
}, Jalankan perintah, npm run build:vui , go
Pada titik ini, layanan lokal dan dua file yang dikemas telah diubah. Mari kita coba gunakan npm ~
Perhatikan bahwa jika Anda tidak memiliki akun npm sendiri, silakan daftarkan akun Anda sendiri di situs web resmi npm . Klik di sini untuk memasukkan situs web resmi untuk mendaftar. Langkah -langkah pendaftaran relatif sederhana. Saya tidak akan menggambarkannya lebih banyak di sini. Jika Anda memiliki pertanyaan, Anda dapat bertanya kepada saya di grup 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) Kemudian konfirmasi, package.json akan dihasilkan sebagai berikut
{
"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"
} Selanjutnya, kami perlu terhubung ke akun npm terdaftar kami secara lokal
npm adduser
# Username: 填写你自己的npm账号
# Password: npm账号密码
# Email: (this IS public) 你npm账号的认证邮箱
# Logged in as xuqiang521 on https://registry.npmjs.org/. 连接成功Mengeksekusi npm publish untuk mulai menerbitkan
npm publish
# + [email protected] Saat ini npm Anda dapat mencari dan melihat paket yang baru saja Anda rilis ~
Saat ini, kami telah menulis komponen hello paling sederhana di perpustakaan komponen, tetapi ini tidak mempengaruhi penerbitan kami ke situs web resmi npm sama sekali, dan langkah -langkah penerbitan sesederhana contoh di atas.
Ubah beberapa deskripsi dalam file package.json
// npm 包js入口文件改为 lib/vui.js
"main" : "lib/vui.js" ,
// npm 发布出去的包包含的文件
"files" : [
"lib" ,
"src" ,
"packages"
] ,
// 将包的属性改为公共可发布的
"private" : false , Perhatikan bahwa ketika menguji paket npm dirilis, ingatlah bahwa versi version dalam package.json lebih tinggi dari yang sebelumnya.
Mulai penerbitan
# 打包,输出lib/vui.js
npm run build:vui
# 发布
npm publish
# + [email protected] Pilih proyek VUE lokal dan masukkan proyek
npm i component-library-test
# or
cnpm i component-library-testDaftar Komponen di File Masuk Proyek
import Vue from 'vue'
import vui from 'component-library-test'
Vue . use ( vui )Gunakan di halaman
< v-hello message =" component library " > </ v-hello > Pada titik ini, kami telah berhasil mengubah file layanan lokal, mengimplementasikan paket file utama pustaka komponen dan paket situs web dokumen resmi pintu masuk utama, dan akhirnya belajar cara menggunakan npm untuk rilis proyek.
Di bab berikutnya, saya akan menjelaskan kemasan file css di pustaka komponen.
Di bagian sebelumnya, kami telah mengemas file JS. Namun, untuk pustaka komponen, yang perlu kita lakukan adalah tidak hanya mengelola file JS, tetapi juga mengelola file CSS, untuk memastikan penggunaan pustaka komponen selanjutnya.
Di bagian ini, saya akan berbicara tentang cara menggunakan gulp secara wajar untuk memisahkan kemasan dan manajemen file CSS dalam proyek berdasarkan konstruksi webpack .
Sebelum kita mulai, kita perlu mengklarifikasi dua tujuan:
Untuk memfasilitasi manajemen, setiap kali kami membuat komponen baru, kami perlu membuat file CSS yang sesuai untuk mengelola gaya komponen dan mencapai manajemen tunggal.
Di sini, kami akan menyimpan semua file CSS di direktori packages/vui-css . Struktur spesifiknya adalah sebagai berikut
├── src
│ ├── common 存放组件公用的css文件
│ ├── mixins 存放一些mixin的css文件
│ ├── index.css css主入口文件
│ ├── hello.css 对应hello组件的单一css文件
├── gulpfile.js css打包配置文件
├── package.json 相关的版本依赖Sebelum mulai menulis CSS komponen, kita perlu mengklarifikasi beberapa poin:
Saya pribadi berpikir bahwa cara terbaik di pasaran adalah mengelola komponen dalam satu CSS dan menulis CSS menggunakan bem . Jika Anda ingin tahu bem , klik tautan di bawah ini
Selanjutnya, mari kita jelaskan komponen hello sederhana. Sebelum memulai, letakkan konten 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 > Buat hello.css di direktori packages/vui-css/src
@b v-hello {
color : # fff ;
transform : scale ( 1 );
@e message {
background : # 0067ED ;
}
} Kemudian impor file hello.css di index.css masuk utama
@import './hello.css' ; Memperkenalkan gaya pustaka komponen dalam examples/src/index.js
import 'packages/vui-css/src/index.css' Tetapi dari konten hello.css , kita dapat melihat bahwa ini adalah metode penulisan bem yang khas dan tidak dapat diuraikan secara normal. Kita perlu memperkenalkan plugin postcss yang sesuai untuk mengurai sintaks bem . Di sini kita akan menggunakan plugin postcss-salad yang dikembangkan饿了么团队untuk mengurai sintaks bem . Kedua, file CSS gaya sass-like ini juga perlu menggunakan plugin yang disebut precss . Instal dependensi terlebih dahulu.
npm i postcss-salad precss -D Setelah instalasi ketergantungan selesai, kita perlu membuat salad.config.json di direktori root proyek untuk mengonfigurasi aturan bem . Aturan spesifiknya adalah sebagai berikut
{
"browsers" : [ " ie > 8 " , " last 2 versions " ],
"features" : {
"bem" : {
"shortcuts" : {
"component" : " b " ,
"modifier" : " m " ,
"descendent" : " e "
},
"separators" : {
"descendent" : " __ " ,
"modifier" : " -- "
}
}
}
} Selanjutnya kita perlu menggunakan postcss-salad dan precss Plugin dalam file .postcssrc yang diinisialisasi, sebagai berikut
module . exports = {
"plugins" : {
"postcss-import" : { } ,
"postcss-salad" : require ( './salad.config.json' ) ,
"postcss-url" : { } ,
"precss" : { } ,
"autoprefixer" : { } ,
}
}Oke, saat Anda menjalankan proyek lagi saat ini, Anda akan melihat bahwa CSS berlaku, seperti yang ditunjukkan pada gambar
Untuk mengelola file CSS dengan lebih baik di pustaka komponen, dan untuk memastikan bahwa pengguna juga dapat memperkenalkan file CSS yang sesuai dengan komponen ketika hanya satu atau beberapa komponen di pustaka komponen yang diperkenalkan. Oleh karena itu, kita perlu mengemas file CSS secara terpisah. Di sini kita perlu menggunakan gulp untuk melakukan operasi kemasan yang sesuai. Sebelum Anda mulai mendapatkan detail kemasan, pastikan Anda telah menginstal gulp secara global. Jika tidak, silakan instal
npm i gulp -g
# 查看版本
gulp -v
# CLI version 3.9.1 Selanjutnya, mari kita lihat dependensi apa yang perlu digunakan dalam file 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" : { }
} Kita dapat melihat bahwa ini sebenarnya mirip dengan ketergantungan yang diperlukan untuk file CSS di pustaka komponen, kecuali bahwa ini adalah plug-in postcss berdasarkan gulp . Sebelum mulai mengkonfigurasi gulpfile.js , jangan lupa untuk menjalankan npm i untuk instalasi ketergantungan.
Selanjutnya kita mulai mengkonfigurasi gulpfile.js , sebagai berikut
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' ] ) Sekarang Anda dapat mulai mengeksekusi perintah gulp build untuk mengemas file CSS. Tentu saja, untuk memfasilitasi dan lebih baik menjalankan perintah pengemasan, kita sekarang perlu menambahkan perintah CSS Build ke package.json di direktori root proyek, sebagai berikut
"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 "
} Jalankan npm run build:vui-css , silakan dan akhirnya mengemas file JS dan CSS dari pustaka komponen seperti yang ditunjukkan pada gambar berikut
Oke, pada titik ini, Anda sudah dapat memperkenalkan komponen dan gaya mereka secara terpisah. Akhirnya, untuk memungkinkan pengguna menggunakan CSS komponen Anda secara langsung, jangan lupa untuk mempublikasikannya ke situs web resmi npm ~ langkah -langkahnya adalah sebagai berikut
# 进到vui-css目录
cd packages/vui-css
# 发布
npm publishPada titik ini, kami telah menyelesaikan manajemen dan kemasan yang terpisah dari file CSS, dan menyelesaikan output tunggal dari file CSS. Dengan cara ini, kita dapat memiliki cara yang lebih baik untuk mengembangkan dan mengelola file CSS pustaka komponen sambil juga dapat memfasilitasi penggunaan pustaka komponen!
Sejauh ini, kami telah membangun direktori baru yang diperlukan untuk pustaka komponen, dan kami juga telah mengubah kemasan file JS dan file CSS. Kami telah membuat persiapan yang cukup untuk pengembangan perpustakaan komponen, tetapi kami masih perlu melakukan beberapa pekerjaan pra-kerja yang sangat penting untuk memfasilitasi pengembangan dan pemeliharaan komponen selanjutnya dari pustaka komponen.
Untuk pengujian front-end, ini adalah cabang penting dari rekayasa front-end. Oleh karena itu, bagaimana bagian penting yang dapat dilewatkan di perpustakaan komponen kami? Untuk tes unit, terutama ada dua jenis
Dalam bab ini, saya Karma membawa Anda ke komponen uji unit di pustaka komponen kami menggunakan dua kerangka kerja berdasarkan inisialisasi Mocha .
Saya percaya kebanyakan orang yang telah terpapar tes unit akrab dengan dua kerangka kerja, Karma + Mocha , tetapi di sini saya pikir perlu untuk membuka bagian terpisah untuk memberikan pengantar singkat untuk dua kerangka kerja.
Untuk mengaktifkan komponen di pustaka komponen kami untuk dijalankan di browser web utama utama untuk pengujian, kami memilih Karma . Yang paling penting adalah bahwa Karma adalah kerangka kerja pengujian unit yang direkomendasikan oleh vue-cli . Jika Anda ingin tahu lebih banyak tentang Karma , silakan periksa situs web resmi Karma
simple , flexible , dan funPromisecoverage kodebefore() , after() , beforeEach() , dan afterEach() , sehingga kami dapat mengatur operasi yang berbeda pada tahap yang berbeda untuk menyelesaikan tes kami dengan lebih baik. Di sini saya akan memperkenalkan tiga penggunaan dasar mocha , serta empat fungsi kait dari describe (siklus hidup)
Jelaskan (Modulename, Function): describe bersarang, jelaskan apakah test case benar.
describe ( '测试模块的描述' , ( ) => {
// ....
} ) ; ** IT (info, fungsi): ** satu it dengan casing uji unit
it ( '单元测试用例的描述' , ( ) => {
// ....
} )Penggunaan Perpustakaan Pernyataan
expect ( 1 + 1 ) . to . be . equal ( 2 ) Siklus hidup describe
describe ( 'Test Hooks' , function ( ) {
before ( function ( ) {
// 在本区块的所有测试用例之前执行
} ) ;
after ( function ( ) {
// 在本区块的所有测试用例之后执行
} ) ;
beforeEach ( function ( ) {
// 在本区块的每个测试用例之前执行
} ) ;
afterEach ( function ( ) {
// 在本区块的每个测试用例之后执行
} ) ;
// test cases
} ) ; Siswa yang ingin tahu lebih banyak tentang operasi mocha dapat mengklik tautan di bawah ini untuk melihatnya
Pada bagian di atas, saya secara singkat memperkenalkan kerangka kerja Tes Karma dan Mocha , yang secara resmi direkomendasikan oleh Vue. Saya juga berharap bahwa ketika Anda melihat ini, Anda dapat memiliki pemahaman sederhana tentang pengujian unit dan kerangka kerja pengujian umum.
Sebelum tes unit yang sebenarnya dimulai, mari kita lihat konfigurasi karma . Di sini kita langsung melihat konfigurasi dalam file karma.conf.js yang diinisialisasi oleh vue-cli scaffold (saya telah mengomentari penggunaan spesifik)
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' }
]
}
} )
} Selanjutnya, mari kita melakukan tes sederhana pada komponen hello kami sendiri (hanya menulis satu test case), membuat file hello.spec.js baru dalam test/unit/specs , dan tulis kode berikut
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
} )
} ) Setelah menulis contoh tes, langkah selanjutnya adalah melakukan tes. Jalankan npm run test , Pergi ke Anda ~, Keluarkan Hasilnya
hello.vue
✓ render default classList in hello Dari instance uji di atas komponen hello , kita perlu instantiate komponen ke instance vue, dan kadang -kadang kita perlu memasangnya di dom
const Constructor = Vue . extend ( Hello )
const vm = new Constructor ( {
propsData : {
message : 'component'
}
} ) . $mount ( ) Jika setiap komponen memiliki beberapa instance uji unit nanti, tulisan ini akan menyebabkan tes akhir kami membengkak. Di sini kita dapat merujuk ke alat uji unit util.js yang dienkapsulasi oleh element . Kita perlu merangkum beberapa metode yang umum digunakan dalam pengujian unit. Di bawah ini saya akan mencantumkan beberapa metode yang disediakan dalam alat ini.
/**
* 回收 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 ) { } Di bawah ini kami akan menggunakan metode alat uji yang ditentukan untuk mengubah instance uji komponen hello dan mengubah file 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
} )
} ) Eksekusi ulang npm run test dan output hasilnya
hello.vue
✓ render default classList in hello Di atas kami memperkenalkan penggunaan pengujian unit pada penilaian statis. Selanjutnya, kami akan menguji beberapa kasus penggunaan asinkron dan beberapa peristiwa interaktif. Sebelum pengujian, kita perlu sedikit mengubah kode komponen hello kami, sebagai berikut
< 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 > Selanjutnya, kami ingin menguji apakah komponen hello dapat berhasil emit informasi melalui janji. Misalnya, test case adalah sebagai berikut
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 )
} ) Mulailah tes lagi, jalankan npm run test , output hasilnya
hello.vue
✓ render default classList in hello
✓ create a hello for click with promisePada titik ini, kami telah mempelajari konfigurasi tes unit dan beberapa penggunaan yang umum digunakan. Jika Anda perlu tahu lebih banyak tentang pengujian unit, silakan ikuti tautan yang saya berikan sebelumnya untuk pergi ke studi yang lebih dalam
Teman -teman, ikuti saya untuk berlatih 5 bab sebelumnya dan telah membangun rak dasar untuk pengembangan komponen kami. Selanjutnya, saya akan membawa Anda semua untuk menyelesaikan situs web resmi dokumen dengan komponen penting yang tinggi di perpustakaan komponen.
Setiap orang harus tahu bahwa proyek open source yang baik harus memiliki situs web dokumentasi resmi, jadi untuk menjadikan perpustakaan UI kami salah satu yang terbaik, kami juga harus menggunakan situs web dokumentasi resmi kami sendiri.
Situs web dokumen resmi yang bagus membutuhkan dua hal.
Karena pustaka komponen yang saya kembangkan untuk Anda kembangkan cocok untuk perangkat seluler, bagaimana kami dapat membuat situs web dokumen resmi kami memiliki deskripsi dokumentasi API dan demo contoh seluler. Ini mengharuskan kita untuk mengembangkan dua set halaman untuk adaptasi. Hal -hal berikut yang perlu kita lakukan:
Sebelum pertempuran yang sebenarnya dimulai, mari kita lihat struktur direktori yang diperlukan dalam bab ini.
├── 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 动态注册路由Bab ini terutama membawa Anda untuk mewujudkan konversi file penurunan harga dan routing adaptasi perangkat yang berbeda.
Setelah mengklarifikasi ide -ide itu, mari kita terus mengembangkan situs web dokumen resmi kami!
Dari direktori yang saya berikan di atas, kita dapat melihat bahwa folder Docs disimpan dalam file Markdown, dan setiap file Markdown sesuai dengan dokumen API komponen. Hasil yang kami inginkan adalah mengonversi setiap file penurunan harga di dokumen untuk mengubahnya menjadi komponen VUE, dan mendaftarkan komponen VUE yang dikonversi ke dalam rute sehingga dapat mengakses setiap file penurunan harga melalui rute.
Untuk parsing file markdown ke dalam komponen VUE, ada banyak plug-in webpack tiga partai di pasaran. Tentu saja, jika Anda memiliki pemahaman yang mendalam tentang webpack , Anda juga dapat mencoba memilihnya sendiri. Di sini saya langsung menggunakan Vue-Markdown-Loader yang dikembangkan oleh饿了么团队
Langkah pertama adalah mengandalkan instalasi
npm i vue-markdown-loader -D Langkah kedua adalah menggunakan vue-markdown-loader di file webpack.base.conf.js
{
test : / .md$ / ,
loader : 'vue-markdown-loader' ,
options : {
// 阻止提取脚本和样式标签
preventExtract : true
}
} Langkah ketiga adalah coba. Pertama tambahkan file hello.md di docs , dan kemudian tulis instruksi untuk menggunakan komponen 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 | 点击操作 | — | Langkah 4: Daftarkan hello.md ke rute
route . push ( {
path : '/component/hello' ,
component : require ( '../docs/hello.md' )
} ) Akhirnya, kunjungi halaman. Pada saat ini, Anda dapat menemukan bahwa konten hello.md telah dikonversi menjadi komponen vue dan dapat diakses melalui pemuatan perutean, tetapi halamannya jelek ~ seperti ini
Tentu saja, saya tidak perlu menjelaskan situasi ini, Anda mungkin juga mengetahuinya. Ya, file markdown parsed sangat jelek, hanya karena kami tidak menyoroti tema untuk file penurunan harga kami atau mengatur gaya dasar halaman dokumen. Jadi, selanjutnya kita perlu menambahkan tema yang disorot yang bagus dan gaya dasar yang bersih untuk file penurunan harga kita.
Untuk topik, di sini kita akan menggunakan tema Atom-One-Dark di highlight.js .
Langkah pertama adalah menginstal highlight.js
npm i highlight -D Langkah kedua adalah memperkenalkan tema dalam examples/src/App.vue , dan untuk mengatur gaya dasar dokumen, kita juga perlu memodifikasi tata letak 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 > Langkah ketiga adalah mengatur gaya dasar dokumen. Buat docs.css baru dalam assets dan tulis gaya awal. Karena volume kode terlalu besar, saya tidak akan mempostingnya di sini. Anda dapat menyalin kode di docs.css ke file docs.css lokal sendiri, dan kemudian mengimpornya dalam examples/src/index.js
import '../assets/docs.css' Akhirnya, ubah aturan penguraian penurunan harga. vue-markdown-loader menyediakan antarmuka preprocess bagi kami untuk beroperasi dengan bebas. Selanjutnya, kami mendefinisikan struktur file markdown parsed dan menulisnya di file 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 ;
}
}
}Kemudian, kunjungi kembali localhost: 8080/#/komponen/halo
Oke, file MD kami telah berhasil diuraikan menjadi komponen vue, dan memiliki tema yang disorot dan gaya dasar sederhana ~
Seperti yang saya katakan sebelumnya, pustaka komponen yang dikembangkan oleh artikel ini disesuaikan dengan seluler, jadi kami perlu menampilkan dokumen di PC dan demo di ponsel.
Di bagian ini, saya akan membawa Anda untuk mengadaptasi rute ke berbagai tujuan. Tentu saja, hal ini tidak sulit. Ini terutama menggunakan webpack untuk membangun fitur multi-halaman. Jadi bagaimana melakukannya secara khusus? Oke, mari kita mulai sekarang
Langkah pertama adalah mendaftarkan file entri JS dan menulisnya ke file webpack.base.conf.js
entry: {
// ...
'vui' : './examples/src/index.js' , // PC端入口js
'vui-mobile' : './examples/src/mobile.js' // 移动端入口js
} Langkah kedua adalah mendaftarkan pintu masuk halaman dan menulisnya di file 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
} )
] Pendaftaran file entri selesai, dan yang perlu kita lakukan selanjutnya adalah menentukan lingkungan perangkat. Di sini, saya akan menggunakan navigator.userAgent dengan ekspresi reguler untuk menentukan apakah lingkungan di mana perpustakaan komponen kami berjalan milik sisi PC atau sisi seluler?
Langkah pertama adalah menulis kode berikut dalam file 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 Langkah kedua adalah menulis aturan penilaian berikut dalam examples/src/index.js di sisi pc
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 ( )
} ) Langkah ketiga adalah menulis aturan penilaian yang mirip dengan langkah sebelumnya dalam 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 ( )
} ) Akhirnya, tingkatkan file examples/src/mobile.js dan file portal portal MobileApp.vue
Tulis kode berikut dalam 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/>'
} ) Tulis di MobileApp.vue
< template >
< div class =" mobile-container " >
< router-view > </ router-view >
</ div >
</ template >Selanjutnya, Anda dapat mencoba efek di browser untuk melihat apakah lingkungan perangkat yang berbeda dapat menampilkan konten yang sesuai ~
Pada titik ini, semua rencana yang telah kami rumuskan dalam bab ini telah selesai. Konversi "sempurna" dari file MD, dan adaptasi perutean di lingkungan perangkat yang berbeda. Pengembangan situs web resmi dokumen (Bagian 1) akan segera berakhir di sini. Di bab berikutnya, kami akan terus menyelesaikan karya pengembangan yang tersisa dari situs web resmi dokumen!
Di bab sebelumnya, kami telah menyelesaikan:
Dalam bab ini, kami akan meningkatkan rincian situs web resmi dokumen dan mengembangkan situs web resmi dokumen lengkap.
Dari direktori yang diberikan di bab sebelumnya, kita dapat mengetahui bahwa direktori Docs digunakan untuk menyimpan file MD yang perlu ditampilkan PC, dan direktori halaman digunakan untuk menyimpan file demo seluler. Jadi bagaimana komponen dapat menampilkan file yang sesuai di lingkungan perangkat yang berbeda (PC Sisi menampilkan file MD yang sesuai dengan komponen, dan sisi seluler menampilkan file VUE yang sesuai dengan komponen)? Bagaimana kita bisa mengelola perutean perpustakaan komponen kita secara wajar dalam kasus ini? Selanjutnya, kami melanjutkan pengembangan di bawah ini berdasarkan masalah ini. is-mobile.js pasti akan digunakan di sini untuk menentukan lingkungan perangkat. Silakan ikuti saya untuk melakukan pekerjaan tertentu.
Langkah pertama adalah membuat file baru nav.config.json di bawah examples/src dan menulis konten berikut
{
// 为了之后组件文档多语言化
"zh-CN" : [
{
"name" : "Vui 组件" ,
"showInMobile" : true ,
"groups" : [
{
// 管理相同类型下的所有组件
"groupName" : "基础组件" ,
"list" : [
{
// 访问组件的相对路径
"path" : "/hello" ,
// 组件描述
"title" : "Hello"
}
]
}
]
}
]
} Langkah kedua adalah meningkatkan file router.config.js dan mengubahnya menjadi fungsi pembantu untuk pendaftaran perutean.
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 Langkah ketiga adalah mendaftarkan rute di examples/src/index.js dari examples/src/mobile.js dari contoh file portal js/src/seluler.
import registerRoute from './router.config'
import navConfig from './nav.config'
const routesConfig = registerRoute ( navConfig )
const router = new VueRouter ( {
routes : routesConfig
} )Kemudian kunjungi situs resmi Dokumen Perpustakaan Komponen kami saat ini
Dari rendering akhir bab sebelumnya, kita dapat melihat bahwa terminal PC dibagi menjadi tiga bagian, yaitu:
Selanjutnya, mari kita mulai menampilkan API PC
Headernya relatif sederhana. Kami hanya perlu membuat file page-header.vue baru di bawah examples/src/components dan menulis konten berikut
< 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 >Untuk gaya tertentu, silakan kunjungi halaman header.vue langsung untuk melihatnya.
Di sisi kiri, kami menunjukkan rute dan judul komponen. Bahkan, itu untuk menguraikan dan menampilkan examples/src/nav.config.json .
Kami membuat file side-nav.vue baru di bawah examples/src/components . Struktur normal file adalah sebagai berikut
< 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 > Tapi kita sekarang perlu mengurai examples/src/nav.config.json berdasarkan struktur saat ini. Kode yang ditingkatkan adalah sebagai berikut
< 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 >Klik Di Sini untuk Side-Nav.vue Kode Lengkap
Kami menggunakan page-header.vue dan side-nav.vue yang kami tulis di 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 >Kemudian, kunjungi halaman lagi, hasilnya seperti yang ditunjukkan pada gambar
Prinsip -prinsip demo seluler dan PC serupa. Keduanya harus menguraikan file nav.config.json untuk ditampilkan
Saat ini, kecuali untuk halaman masuk utama MobileApp.vue , terminal seluler kami tidak memiliki ketergantungan komponen root. Selanjutnya, kami akan menyelesaikan pengembangan komponen root terlebih dahulu, membuat file demo-list.vue baru di bawah examples/src/components , dan menulis beberapa konten
< template >
< div class =" side-nav " >
< h1 class =" vui-title " > </ h1 >
< h2 class =" vui-desc " > VUI 移动组件库</ h2 >
</ div >
</ template > Maka kita perlu merujuknya di rute dan menulisnya di file mobile.js
import DemoList from './components/demo-list.vue'
routesConfig . push ( {
path : '/' ,
component : DemoList
} ) Kemudian mulailah meningkatkan file 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
美团点评长期招人,如果有兴趣的话,欢迎一起搞基,简历投递方式交流群中有说明~
小伙伴们你们还在等什么呢?赶紧先给文章点波赞,然后关注我一波,然后加群和大佬们一起交流啊~~~