ฉันมักจะต้องการบันทึกและสรุปบางสิ่งรวมถึงส่วนประกอบบางอย่าง เมื่อฉันสะสมจำนวนมากฉันพบว่าการสะสมที่กระจัดกระจายไม่เหมาะสำหรับการจัดการอีกต่อไป
ดังนั้นฉันจึงเริ่มคิดว่ามีวิธีที่ดีในการจัดการสิ่งที่กระจัดกระจายเหล่านี้ในลักษณะที่ค่อนข้างเป็นมาตรฐานหรือไม่? หากส่วนประกอบได้รับการจัดการในรูปแบบของไลบรารีส่วนประกอบมันจะเหมาะสำหรับการสะสมของคุณเองและอำนวยความสะดวกในการทำงานในอนาคตหรือไม่?
ดังนั้นฉันจึงเริ่มอ้างถึงไลบรารีส่วนประกอบ UI ที่ยอดเยี่ยมในตลาดเช่น element-ui , vux , vant , ฯลฯ อ่านซอร์สโค้ดเพื่อทำความเข้าใจการสร้างสถาปัตยกรรมของมันแล้วจัดเรียงชุดไลบรารี UI Mobile UI ของ vui เอง
ในเวลาว่างฉันทำงานอยู่ในชุมชนทางเทคนิคที่สำคัญ ฉันมักจะมีเพื่อนบางคนที่ทำงานอยู่พักหนึ่งหรือยังคงเตรียมที่จะหาการฝึกงานเพื่อถามคำถามผู้เขียน: วิธีการตั้งตัวเองและสร้างกรอบของคุณเองล้อและห้องสมุด? จะสร้างไลบรารีส่วนประกอบได้อย่างไร? การสร้างไลบรารีส่วนประกอบจะกลายเป็นไฮไลต์ของประวัติย่อของคุณหรือไม่? คุณสามารถเขียนบทความเกี่ยวกับการพัฒนาห้องสมุดส่วนประกอบได้หรือไม่? -
โพสต์บล็อกนี้เกิดมาในอารมณ์ของการตอบคำถามและการแบ่งปันคำถาม
หากคุณมีคำถามใด ๆ เมื่ออ่านบทความโปรดเข้าร่วมกลุ่มสนทนาเพื่อพูดคุย (นอกเหนือจากกลุ่มคนใหญ่ที่พูดคุยทุกวันนอกจากนี้ยังมีกลุ่มสาว ~)
Front-end Hodgepodge: 731175396
GitHub: https://github.com/xuqiang521
โดยไม่ต้องกังวลใจเพิ่มเติมให้ไปที่บทต่อสู้จริงโดยตรง ~
ที่นี่ฉันจะพูดถึงการติดตั้งโหนดภายใต้ MAC และหน้าต่างเท่านั้น
หากคุณยังไม่ได้ติดตั้ง homebrew Mac Package Manager ขั้นตอนแรกคือการติดตั้งก่อน
/usr/bin/ruby -e " $( curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install ) " ติดตั้ง node โดยใช้ homebrew
brew install node หากคุณต้องการไปที่เว็บไซต์อย่างเป็นทางการ window เพื่อดาวน์โหลดเวอร์ชันที่เกี่ยวข้องให้คลิกขั้นตอนต่อไปเพื่อทำการติดตั้งให้เสร็จสมบูรณ์
หลังจากการติดตั้งเสร็จสมบูรณ์ให้ตรวจสอบ node และเวอร์ชัน npm
node -v
# v9.6.1
npm -v
# 5.6.0 ตั้งแต่นั้นมาสภาพแวดล้อม node บนคอมพิวเตอร์ของคุณได้ถูกสร้างขึ้น ต่อไปเราจำเป็นต้องติดตั้งไลบรารีส่วนประกอบเพื่อสร้างนั่งร้านการพึ่งพา
# 全局安装
npm i -g vue-cli
# 查看vue-cli用法
vue -h
# 查看版本
vue -V
# 2.9.3 เริ่มต้นโครงการที่ชื่อว่า personal-components-library โดยใช้คำสั่ง init ของ vue-cli
# 项目基于 webpack
vue init webpack personal-components-libraryเมื่อสร้างการนั่งร้านจะขอให้คุณกรอกคำอธิบายและการพึ่งพาของโครงการ โปรดดูเนื้อหาที่ฉันเลือกด้านล่างเพื่อกรอกข้อมูล
# 项目名称
Project name ? personal-components-library
# 项目描述
Project description ? A Personal Vue.js components Library project
# 项目作者
Author ? qiangdada
# 项目构建 vue 版本(选择默认项)
Vue build ? standalone
# 是否下载 vue-router (后期会用到,这里选 Yes)
Install vue-router ? Yes
# 是否下载 eslint (为了制定合理的开发规范,这个必填)
Use ESLint to lint your code ? Yes
# 安装默认的标准 eslint 规则
Pick an ESLint preset ? Standard
# 构建测试案例
Set up unit tests ? Yes
# 安装 test 依赖 (选择 karma + mocha)
Pick a test runner ? karma
# 构建 e2e 测试案例 (No)
Setup e2e tests with Nightwatch ? No
# 项目初始化完是否安装依赖 (npm)
Should we run ` npm install ` for you after the project has been created ? (recom
mended) npm หลังจากที่คุณเลือกแล้วคุณสามารถรอ vue-cli จะช่วยให้คุณสร้างโครงการและทำการติดตั้งการพึ่งพา
โครงสร้างโครงการเริ่มต้นมีดังนี้:
├── build webpack打包以及本地服务的文件都在里面
├── config 不同环境的配置都在这里
├── index.html 入口html
├── node_modules npm安装的依赖包都在这里面
├── package.json 项目配置信息
├── README.md 项目介绍
├── src 我们的源代码
│ ├── App.vue vue主入口文件
│ ├── assets 资源存放(如图片)
│ ├── components 可以复用的模块放在这里面
│ ├── main.js 入口js
│ ├── router 路由管理
└── webpack.config.js webpack配置文件
├── static 被copy的静态资源存放地址
├── test 测试文档和案例หากคุณใช้ npm เพื่อดาวน์โหลดการพึ่งพาช้าเกินไปหรือมีทรัพยากรบางอย่างที่มีกำแพงล้อมรอบขอแนะนำให้ใช้ cnpm เพื่อดาวน์โหลดการอ้างอิง
# 全局安装 cnpm
npm install -g cnpm --registry=https://registry.npm.taobao.org
# 使用 cnpm 进行依赖安装
cnpm i คุณสามารถเริ่มโครงการ vue ของคุณหลังจากการติดตั้งการพึ่งพาเสร็จสมบูรณ์ ~
npm run dev จากนั้นเยี่ยมชม http://localhost:8080 และคุณสามารถเข้าถึงโครงการ vue ที่สร้างผ่าน vue-cli ได้สำเร็จ ณ จุดนี้สภาพแวดล้อมการพัฒนาที่ไลบรารีส่วนประกอบของคุณขึ้นอยู่กับได้รับการติดตั้งแล้ว
ก่อนอื่นเราต้องชี้แจงจุดประสงค์ของส่วนนี้ เราจำเป็นต้องแก้ไขไดเรกทอรีเพื่อพัฒนาไลบรารีส่วนประกอบที่ดีขึ้น
เราได้สร้างโครงการ vue ในส่วนก่อนหน้านี้แล้ว แต่ไดเรกทอรีโครงการที่เริ่มต้นไม่สามารถตอบสนองการพัฒนาและการบำรุงรักษาของไลบรารีส่วนประกอบได้ในภายหลัง ดังนั้นสิ่งที่เราต้องทำในบทนี้คือการแปลงไดเรกทอรีของโครงการ vue ที่เริ่มต้นและเปลี่ยนเป็นไดเรกทอรีที่ต้องการโดยไลบรารีส่วนประกอบ มาดำเนินการต่อไป
demo และ文档ของไลบรารีส่วนประกอบmixins ฯลฯ ของการลงทะเบียนส่วนประกอบ (สำหรับสิ่งนี้เราจำเป็นต้องแปลงไดเรกทอรี src ที่เริ่มต้น)ตกลงเริ่มแปลงไดเรกทอรีของโครงการที่คุณเริ่มต้น
จากตัวอย่างก่อนหน้านี้เรารู้ว่าเมื่อเราเริ่มบริการท้องถิ่นไฟล์รายการหลักของหน้าคือ index.html ตอนนี้ขั้นตอนแรกของเราคือการย้ายทางเข้าหลักของหน้า html และ js ไปยังไดเรกทอรี examples ไดเรกทอรี examples เฉพาะมีดังนี้
├── assets css,图片等资源都在这
├── pages 路由中所有的页面
├── src
│ ├── components demo中可以复用的模块放在这里面
│ ├── index.js 入口js
│ ├── index.tpl 页面入口
│ ├── App.vue vue主入口文件
│ ├── router.config.js 路由jsรหัสที่แก้ไขของแต่ละไฟล์มีดังนี้
index.js
import Vue from 'vue'
import App from './App'
import router from './router.config'
Vue . config . productionTip = false
/* eslint-disable no-new */
new Vue ( {
el : '#app-container' ,
router ,
components : { App } ,
template : '<App/>'
} ) index.tpl
<!DOCTYPE html >
< html lang =" en " >
< head >
< meta charset =" UTF-8 " >
< meta name =" viewport " content =" width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0 " >
< title > My Component Library </ title >
</ head >
< body >
< div id =" app-container " >
< app > </ app >
</ div >
</ body >
</ html > App.vue
< template >
< div id =" app " >
< router-view />
</ div >
</ template >
< script >
export default {
name : 'App'
}
</ script > router.config.js
import Vue from 'vue'
import Router from 'vue-router'
import hello from '../pages/hello' // 请自行去pages下面创建一个hello.vue,以方便之后的测试
Vue . use ( Router )
export default new Router ( {
routes : [
{
path : '/' ,
component : hello
}
]
} ) ไดเรกทอรี src ส่วนใหญ่จะใช้เพื่อจัดเก็บไฟล์รายการหลักวิธีการเครื่องมือ mixins และไฟล์อื่น ๆ สำหรับส่วนประกอบที่ลงทะเบียน เราสามารถรู้ได้จากไดเรกทอรี examples ด้านบนว่าไฟล์บางไฟล์ใน src ดั้งเดิมจำเป็นต้องถูกลบ ไดเรกทอรีที่แก้ไขมีดังนี้
├── mixins mixins方法存放在这
├── utils 一些常用辅助方法存放在这
├── index.js 组件注册主入口 ลองคิดดูเมื่อคุณเห็นสิ่งนี้คุณควรรู้ว่าเราต้องทำอะไรตอนนี้ ถูกต้องมันเป็นเพียงการแก้ไขไฟล์รายการของบริการท้องถิ่น หากเป็นไปได้ที่จะเรียกใช้ให้แก้ไขรายการ JS ใน entry และการอ้างอิงรายการหน้าของ html-webpack-plugin รหัสมีดังนี้ (วางรหัสคีย์เท่านั้น)
entry: {
'vendor' : [ 'vue' , 'vue-router' ] ,
'vui' : './examples/src/index.js'
} ,
// ...
plugins : [
// ...
// 将入口改成examples/src/index.tpl
new HtmlWebpackPlugin ( {
chunks : [ 'vendor' , 'vui' ] ,
template : 'examples/src/index.tpl' ,
filename : 'index.html' ,
inject : true
} )
] ตกลงแก้ไข Execute npm run dev หนึ่งครั้งและโครงการของคุณสามารถรันภายใต้ไฟล์รายการใหม่
ในส่วนนี้สิ่งที่เราต้องใช้คือบริการที่เราเริ่มต้นในพื้นที่ซึ่งสามารถใช้ส่วนประกอบด้านล่าง packages มาพัฒนาองค์ประกอบ hello ที่ง่ายที่สุดเพื่ออธิบาย
hello ภายใต้ packages เพื่อให้มีลักษณะการผูกมัดที่ดีที่นี่เรา จำกัด : ก่อนเริ่มเขียนองค์ประกอบไดเรกทอรีที่ระบุและชื่อไฟล์จะต้องได้รับการจัดการอย่างสม่ำเสมอ ไฟล์ภายใต้องค์ประกอบ hello ในไดเรกทอรี packages มีดังนี้
├── hello
│ ├── hello.vue hello.vue เนื้อหามีดังนี้
< template >
< div class =" v-hello " >
hello {{ message }}
</ div >
</ template >
< script >
export default {
name : 'v-hello' ,
props : {
message : String
}
}
</ script > src/index.js ไฟล์ sec/index.js ยังกล่าวถึงข้างต้น ส่วนใหญ่จะใช้ในการจัดการการลงทะเบียนของส่วนประกอบทั้งหมดในไลบรารีส่วนประกอบของเรา
import Hello from '../packages/hello'
const install = function ( Vue ) {
if ( install . installed ) return
Vue . component ( Hello . name , Hello )
}
if ( typeof window !== 'undefined' && window . Vue ) {
install ( window . Vue )
}
export default {
install ,
Hello
} examples/src/index.js รายการ js ไฟล์ ต่อไปฉันต้องอ้างอิงองค์ประกอบ hello ที่เราเขียนไว้ใน examples ที่แก้ไขในส่วนก่อนหน้า
import vui from 'src/index.js'
// 完整引用
Vue . use ( vui )
// 独立引用
const { Hello } = vui
Vue . component ( Hello . name , Hello ) examples/pages/hello.vue ใน examples/pages เราจำเป็นต้องสร้างไฟล์ตัวอย่างที่มีชื่อเดียวกับชื่อส่วนประกอบและใช้ส่วนประกอบ
< v-hello message =" my component library " > </ v-hello >หากผลการทำงานของคุณเหมือนกับภาพด้านบนขอแสดงความยินดี คุณได้ก้าวไปอีกขั้นเพื่อพัฒนาไลบรารีส่วนประกอบ ~
หลังจากเห็นสิ่งนี้ฉันต้องการให้ผู้อ่านทุกคนจัดการไฟล์จากส่วนกลางตามความชอบของตัวเอง (แน่นอนคุณสามารถอ้างถึงการสาธิตที่ฉันให้ไว้ข้างต้น) ด้วยวิธีนี้การพัฒนาที่ตามมาของไลบรารีส่วนประกอบของเราสามารถราบรื่นได้
ในส่วนถัดไปเราจะเพิ่มประสิทธิภาพไฟล์ที่บรรจุไว้ด้านล่าง build และนำคุณไปเผยแพร่ส่วนประกอบที่พัฒนาแล้วของคุณไปยังเว็บไซต์ทางการ npm เพื่อให้ห้องสมุดส่วนประกอบของคุณสามารถใช้งานได้สะดวกยิ่งขึ้น!
ตามปกติก่อนที่ข้อความบทจะเริ่มขึ้นเราจำเป็นต้องรู้ว่าต้องทำอะไรในบทนี้และทำไม
เนื่องจากโครงการเริ่มต้นของการนั่งร้านมีเพียงไฟล์แพ็คเดี่ยวเดียวสำหรับ build ไฟล์ build webpack.prod.conf.js
เพื่อให้ไลบรารีส่วนประกอบของเราใช้งานได้ดีขึ้นในอนาคตเราจำเป็นต้องแยกโมดูลทั้งหมดที่สอดคล้องกับไลบรารีส่วนประกอบลงในไฟล์ vui.js (สิ่งที่คุณชอบชื่อ) เพื่อให้เราสามารถอ้างถึงไลบรารีส่วนประกอบของเราด้วยวิธีต่อไปนี้
import Vue from 'vue'
import vui from 'x-vui'
Vue . use ( vui ) นอกจากนี้เรายังต้องบรรจุและจัดการไฟล์ที่เกี่ยวข้องใน examples เนื่องจากเราต้องพัฒนาเว็บไซต์อย่างเป็นทางการของเอกสารของไลบรารีส่วนประกอบในภายหลังและทางเข้าที่เกี่ยวข้องของเว็บไซต์อย่างเป็นทางการของเอกสารอยู่ใน examples
เราสามารถดูได้จากโครงการเริ่มต้นว่าไฟล์ webpack ในไฟล์ build มีดังนี้
├── webpack.base.conf.js 基础配置文件
├── webpack.dev.conf.js 本地服务配置文件
├── webpack.prod.conf.js 打包配置文件
├── webpack.test.conf.js 测试配置文件(这里先不做过多描述) ไดเรกทอรี output เริ่มต้นคือ dist ไดเรกทอรีนี้เป็นไดเรกทอรีเอาต์พุตหลังจากที่มีการบรรจุโครงการทั้งหมดไม่ใช่ไดเรกทอรีที่ต้องการโดยไลบรารีส่วนประกอบของเรา เนื่องจากไม่ใช่สิ่งที่เราต้องการเราต้องการทำอะไรในไดเรกทอรีที่เราต้องการ?
lib/vui.js (ไลบรารีส่วนประกอบ JS ไฟล์หลัก)lib/vui-css/index.css (ไฟล์หลักของไลบรารีส่วนประกอบ CSS เราจะไม่อธิบายมากเกินไปเกี่ยวกับบรรจุภัณฑ์ CSS ในบทนี้และบทต่อไปนี้จะถูกอธิบายแยกกัน)examples ไฟล์ examples/dist บรรจุจากไฟล์ตัวอย่าง (ทางเข้าหลักของเว็บไซต์ทางการของเอกสารในภายหลัง) เนื่องจากมีการตั้งค่าเป้าหมายสิ่งต่อไปที่เราต้องทำคือการจัดระเบียบไฟล์บรรจุภัณฑ์ webpack ที่เกี่ยวข้องก่อนดังนี้
├── webpack.base.conf.js 基础配置文件(配置方面和webpack.dev.conf.js的配置进行部分整合)
├── webpack.dev.conf.js 本地服务配置文件(将纯配置文件进行对应的删减)
├── webpack.build.js 组件库入口文件打包配置文件(将webpack.prod.conf.js重命名)
├── webpack.build.min.js examples展示文件打包配置文件(新增文件)1. webpack.base.conf.js
ก่อนที่จะเริ่มแปลงไฟล์ webpack.base.conf.js เราต้องเข้าใจสิ่งที่ต้องทำในไฟล์แพคเกจสองไฟล์
webpack.build.js : เอาต์พุตไฟล์ไลบรารีส่วนประกอบ lib/vui.js js และจะใช้ webpack.base.conf.js และ webpack.dev.conf.js การกำหนดค่าที่เกี่ยวข้องwebpack.build.min.js : เอาต์พุต examples/dist ที่เกี่ยวข้องกับเอกสารและใช้ webpack.base.conf.js และ webpack.dev.conf.js การกำหนดค่าที่เกี่ยวข้อง เนื่องจากไฟล์บรรจุภัณฑ์ webpack ทั้งสองใช้ webpack.base.conf.js และ webpack.dev.conf.js การกำหนดค่าที่เกี่ยวข้องทำไมไม่รวมไฟล์เดียวกันบางไฟล์ลงในไฟล์ webpack.base.conf.js ? เป้าหมายชัดเจนมาติดตามฉันต่อไป
'use strict'
const path = require ( 'path' )
const utils = require ( './utils' )
const config = require ( '../config' )
const vueLoaderConfig = require ( './vue-loader.conf' )
const webpack = require ( 'webpack' )
const CopyWebpackPlugin = require ( 'copy-webpack-plugin' )
const HtmlWebpackPlugin = require ( 'html-webpack-plugin' )
function resolve ( dir ) {
return path . join ( __dirname , '..' , dir )
}
const HOST = process . env . HOST
const PORT = process . env . PORT && Number ( process . env . PORT )
const createLintingRule = ( ) => ( {
test : / .(js|vue)$ / ,
loader : 'eslint-loader' ,
enforce : 'pre' ,
include : [ resolve ( 'src' ) , resolve ( 'test' ) ] ,
options : {
formatter : require ( 'eslint-friendly-formatter' ) ,
emitWarning : ! config . dev . showEslintErrorsInOverlay
}
} )
module . exports = {
context : path . resolve ( __dirname , '../' ) ,
// 文件入口
entry : {
'vendor' : [ 'vue' , 'vue-router' ] ,
'vui' : './examples/src/index.js'
} ,
// 输出目录
output : {
path : path . join ( __dirname , '../examples/dist' ) ,
publicPath : '/' ,
filename : '[name].js'
} ,
resolve : {
extensions : [ '.js' , '.vue' , '.json' ] ,
// 此处新增了一些 alias 别名
alias : {
'vue$' : 'vue/dist/vue.esm.js' ,
'@' : resolve ( 'src' ) ,
'src' : resolve ( 'src' ) ,
'packages' : resolve ( 'packages' ) ,
'lib' : resolve ( 'lib' ) ,
'components' : resolve ( 'examples/src/components' )
}
} ,
// 延用原先的大部分配置
module : {
rules : [
// 原先的配置...
// 整合webpack.dev.conf.js中css相关配置
... utils . styleLoaders ( { sourceMap : config . dev . cssSourceMap , usePostCSS : true } )
]
} ,
// 延用原先的配置
node : {
// ...
} ,
devtool : config . dev . devtool ,
// 整合webpack.dev.conf.js中的devServer选项
devServer : {
clientLogLevel : 'warning' ,
historyApiFallback : {
rewrites : [
{ from : / .* / , to : path . posix . join ( config . dev . assetsPublicPath , 'index.html' ) } ,
] ,
} ,
hot : true ,
contentBase : false , // since we use CopyWebpackPlugin.
compress : true ,
host : HOST || config . dev . host ,
port : PORT || config . dev . port ,
open : config . dev . autoOpenBrowser ,
overlay : config . dev . errorOverlay
? { warnings : false , errors : true }
: false ,
publicPath : config . dev . assetsPublicPath ,
proxy : config . dev . proxyTable ,
quiet : true , // necessary for FriendlyErrorsPlugin
watchOptions : {
poll : config . dev . poll ,
}
} ,
// 整合webpack.dev.conf.js中的plugins选项
plugins : [
new webpack . DefinePlugin ( {
'process.env' : require ( '../config/dev.env' )
} ) ,
new webpack . HotModuleReplacementPlugin ( ) ,
new webpack . NamedModulesPlugin ( ) ,
new webpack . NoEmitOnErrorsPlugin ( ) ,
// 页面主入口
new HtmlWebpackPlugin ( {
chunks : [ 'manifest' , 'vendor' , 'vui' ] ,
template : 'examples/src/index.tpl' ,
filename : 'index.html' ,
inject : true
} )
]
}2. webpack.dev.conf.js
ที่นี่คุณจะต้องลบการกำหนดค่าที่รวมอยู่ใน webpack.base.conf.js เพื่อหลีกเลี่ยงการทำซ้ำของรหัส
'use strict'
const utils = require ( './utils' )
const config = require ( '../config' )
const baseWebpackConfig = require ( './webpack.base.conf' )
const FriendlyErrorsPlugin = require ( 'friendly-errors-webpack-plugin' )
const portfinder = require ( 'portfinder' )
module . exports = new Promise ( ( resolve , reject ) => {
portfinder . basePort = process . env . PORT || config . dev . port
portfinder . getPort ( ( err , port ) => {
if ( err ) {
reject ( err )
} else {
process . env . PORT = port
baseWebpackConfig . devServer . port = port
baseWebpackConfig . plugins . push ( new FriendlyErrorsPlugin ( {
compilationSuccessInfo : {
messages : [ `Your application is running here: http:// ${ baseWebpackConfig . devServer . host } : ${ port } ` ] ,
} ,
onErrors : config . dev . notifyOnErrors
? utils . createNotifierCallback ( )
: undefined
} ) )
resolve ( baseWebpackConfig )
}
} )
} ) หลังจากไฟล์สองไฟล์ของ webpack.base.conf.js และ webpack.dev.conf.js จะถูกปรับให้ดำเนินการ npm run dev อีกครั้ง
ภาพด้านบนดูเหมือนจะระบุว่าไฟล์บริการในพื้นที่ของคุณได้รับการแก้ไขสำเร็จตามที่คาดไว้ ~
1. webpack.build.js
วัตถุประสงค์หลักของไฟล์นี้คือการจัดทำไฟล์ที่เกี่ยวข้องกับส่วนประกอบทั้งหมดในไลบรารีส่วนประกอบเข้าด้วยกันและส่งออกไฟล์หลัก lib/vui.js
'use strict'
const webpack = require ( 'webpack' )
const config = require ( './webpack.base.conf' )
// 修改入口文件
config . entry = {
'vui' : './src/index.js'
}
// 修改输出目录
config . output = {
filename : './lib/[name].js' ,
library : 'vui' ,
libraryTarget : 'umd'
}
// 配置externals选项
config . externals = {
vue : {
root : 'Vue' ,
commonjs : 'vue' ,
commonjs2 : 'vue' ,
amd : 'vue'
}
}
// 配置plugins选项
config . plugins = [
new webpack . DefinePlugin ( {
'process.env' : require ( '../config/prod.env' )
} )
]
// 删除devtool配置
delete config . devtool
module . exports = config2. webpack.build.min.js
วัตถุประสงค์หลักของไฟล์นี้คือการเปิดที่อยู่แพ็คเกจเดียวและส่งออกไฟล์ที่เกี่ยวข้องใน examples ไปยัง examples/dist (นั่นคือการเข้าเว็บไซต์อย่างเป็นทางการของเอกสารที่ตามมา)
const path = require ( 'path' )
const webpack = require ( 'webpack' )
const merge = require ( 'webpack-merge' )
const baseWebpackConfig = require ( './webpack.base.conf' )
const config = require ( '../config' )
const ExtractTextPlugin = require ( 'extract-text-webpack-plugin' )
const webpackConfig = merge ( baseWebpackConfig , {
output : {
chunkFilename : '[id].[hash].js' ,
filename : '[name].min.[hash].js'
} ,
plugins : [
new webpack . optimize . UglifyJsPlugin ( {
compress : {
warnings : false
} ,
output : {
comments : false
} ,
sourceMap : false
} ) ,
// extract css into its own file
new ExtractTextPlugin ( {
filename : '[name].[contenthash].css' ,
allChunks : true ,
} ) ,
// keep module.id stable when vendor modules does not change
new webpack . HashedModuleIdsPlugin ( ) ,
// enable scope hoisting
new webpack . optimize . ModuleConcatenationPlugin ( ) ,
// split vendor js into its own file
new webpack . optimize . CommonsChunkPlugin ( {
name : 'vendor' ,
minChunks ( module ) {
// any required modules inside node_modules are extracted to vendor
return (
module . resource &&
/ .js$ / . test ( module . resource ) &&
module . resource . indexOf (
path . join ( __dirname , '../node_modules' )
) === 0
)
}
} ) ,
new webpack . optimize . CommonsChunkPlugin ( {
name : 'manifest' ,
minChunks : Infinity
} ) ,
new webpack . optimize . CommonsChunkPlugin ( {
name : 'app' ,
async : 'vendor-async' ,
children : true ,
minChunks : 3
} ) ,
]
} )
module . exports = webpackConfig เมื่อเรารวมไฟล์เหล่านี้ทั้งหมดเข้าด้วยกันขั้นตอนสุดท้ายคือการเขียนคำสั่งแพ็คเกจไปยัง 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 "
}, เรียกใช้คำสั่ง, npm run build:vui , ไป
ณ จุดนี้บริการท้องถิ่นและไฟล์แพคเกจสองไฟล์ได้รับการแปลง ลองใช้ npm ~
โปรดทราบว่าหากคุณไม่มีบัญชี npm ของคุณเองโปรดลงทะเบียนบัญชีด้วยตัวคุณเองที่เว็บไซต์ทางการ npm คลิกที่นี่เพื่อเข้าสู่เว็บไซต์ทางการเพื่อลงทะเบียน ขั้นตอนการลงทะเบียนค่อนข้างง่าย ฉันจะไม่อธิบายเพิ่มเติมที่นี่ หากคุณมีคำถามใด ๆ คุณสามารถถามฉันในกลุ่ม WeChat
mkdir qiangdada520-npm-test
cd qiangdada520-npm-test
# npm 包主入口js文件
touch index.js
# npm 包首页介绍(具体啥内容你自行写入即可)
touch README.md
npm init
# package name: (qiangdada520-npm-test)
# version: (1.0.0)
# description: npm test
# entry point: (index.js) index.js
# test command:
# git repository:
# keywords: npm test
# author: qiangdada
# license: (ISC) จากนั้นยืนยันว่า package.json จะถูกสร้างขึ้นดังนี้
{
"name" : "qiangdada-npm-test" ,
"version" : "1.0.0" ,
"description" : "npm test" ,
"main" : "index.js" , // npm 包主入口js文件
"scripts" : {
"test" : "echo "Error: no test specified" && exit 1"
} ,
"keywords" : [
"npm" ,
"test"
] ,
"author" : "qiangdada" ,
"license" : "MIT"
} ต่อไปเราจำเป็นต้องเชื่อมต่อกับบัญชี npm ที่ลงทะเบียนของเราในเครื่อง
npm adduser
# Username: 填写你自己的npm账号
# Password: npm账号密码
# Email: (this IS public) 你npm账号的认证邮箱
# Logged in as xuqiang521 on https://registry.npmjs.org/. 连接成功ดำเนินการ npm publish เพื่อเริ่มเผยแพร่
npm publish
# + [email protected] ใน npm นี้คุณสามารถค้นหาและดูแพ็คเกจที่คุณเพิ่งเปิดตัว ~
ในปัจจุบันเราได้เขียนองค์ประกอบ hello ที่ง่ายที่สุดในไลบรารีส่วนประกอบ แต่สิ่งนี้ไม่ส่งผลกระทบต่อการเผยแพร่ของเราไปยังเว็บไซต์ทางการ npm เลยและขั้นตอนการเผยแพร่นั้นง่ายเหมือนตัวอย่างข้างต้น
แก้ไขคำอธิบายบางอย่างในไฟล์ package.json
// npm 包js入口文件改为 lib/vui.js
"main" : "lib/vui.js" ,
// npm 发布出去的包包含的文件
"files" : [
"lib" ,
"src" ,
"packages"
] ,
// 将包的属性改为公共可发布的
"private" : false , โปรดทราบว่าเมื่อทำการทดสอบแพ็คเกจ npm ได้รับการปล่อยตัวโปรดจำไว้ว่าเวอร์ชัน version ใน package.json จะสูงกว่ารุ่นก่อนหน้า
เริ่มเผยแพร่
# 打包,输出lib/vui.js
npm run build:vui
# 发布
npm publish
# + [email protected] เลือกโครงการ VUE ในพื้นที่และเข้าสู่โครงการ
npm i component-library-test
# or
cnpm i component-library-testลงทะเบียนส่วนประกอบในไฟล์ทางเข้าโครงการ
import Vue from 'vue'
import vui from 'component-library-test'
Vue . use ( vui )ใช้บนหน้า
< v-hello message =" component library " > </ v-hello > ณ จุดนี้เราได้แปลงไฟล์บริการในท้องถิ่นได้สำเร็จใช้แพ็คเกจไฟล์หลักของไลบรารีส่วนประกอบและแพ็คเกจของเว็บไซต์เอกสารทางเข้าหลักและในที่สุดก็เรียนรู้วิธีใช้ npm สำหรับการเปิดตัวโครงการ
ในบทถัดไปฉันจะอธิบายบรรจุภัณฑ์ของไฟล์ css ในไลบรารีส่วนประกอบ
ในส่วนก่อนหน้าเราได้บรรจุไฟล์ JS แล้ว อย่างไรก็ตามสำหรับไลบรารีส่วนประกอบสิ่งที่เราต้องทำไม่เพียง แต่จัดการไฟล์ JS แต่ยังจัดการไฟล์ CSS เพื่อให้แน่ใจว่าการใช้งานไลบรารีส่วนประกอบที่ตามมา
ในส่วนนี้ฉันจะพูดคุยเกี่ยวกับวิธีการใช้ gulp อย่างสมเหตุสมผลเพื่อแยกบรรจุภัณฑ์และการจัดการไฟล์ CSS ในโครงการตามการก่อสร้าง webpack
ก่อนที่เราจะเริ่มเราต้องชี้แจงสองเป้าหมาย:
เพื่ออำนวยความสะดวกในการจัดการทุกครั้งที่เราสร้างองค์ประกอบใหม่เราจำเป็นต้องสร้างไฟล์ CSS ที่เกี่ยวข้องเพื่อจัดการสไตล์ขององค์ประกอบและบรรลุการจัดการเดี่ยว
ที่นี่เราจะจัดเก็บไฟล์ CSS ทั้งหมดในไดเรกทอรี packages/vui-css โครงสร้างเฉพาะมีดังนี้
├── src
│ ├── common 存放组件公用的css文件
│ ├── mixins 存放一些mixin的css文件
│ ├── index.css css主入口文件
│ ├── hello.css 对应hello组件的单一css文件
├── gulpfile.js css打包配置文件
├── package.json 相关的版本依赖ก่อนที่จะเริ่มเขียนองค์ประกอบ CSS เราต้องชี้แจงบางจุด:
โดยส่วนตัวแล้วฉันคิดว่าวิธีที่ดีที่สุดในตลาดคือการจัดการส่วนประกอบใน CSS เดียวและเขียน CSS โดยใช้ bem หากคุณต้องการทราบ bem คลิกลิงก์ด้านล่าง
ถัดไปขออธิบายองค์ประกอบ hello ง่ายๆ ก่อนเริ่มต้นให้ใส่เนื้อหาของ hello.vue
< template >
< div class =" v-hello " >
< p class =" v-hello__message " > hello {{ message }} </ p >
</ div >
</ template >
< script >
export default {
name : 'v-hello' ,
props : {
message : String
}
}
</ script > สร้าง hello.css ใน packages/vui-css/src ไดเรกทอรี
@b v-hello {
color : # fff ;
transform : scale ( 1 );
@e message {
background : # 0067ED ;
}
} จากนั้นนำเข้าไฟล์ hello.css ใน index.css ทางเข้าหลัก
@import './hello.css' ; แนะนำรูปแบบไลบรารีส่วนประกอบใน examples/src/index.js
import 'packages/vui-css/src/index.css' แต่จากเนื้อหา hello.css เราจะเห็นว่านี่เป็นวิธีการเขียน bem ทั่วไปและไม่สามารถแยกวิเคราะห์ได้ตามปกติ เราจำเป็นต้องแนะนำปลั๊กอิน postcss ที่เกี่ยวข้องเพื่อแยกวิเคราะห์ไวยากรณ์ bem ที่นี่เราจะใช้ปลั๊กอิน postcss-salad ที่พัฒนา饿了么团队เพื่อแยกวิเคราะห์ไวยากรณ์ bem ประการที่สองไฟล์ CSS สไตล์ sass-like นี้จำเป็นต้องใช้ปลั๊กอินที่เรียกว่า precss ติดตั้งการพึ่งพาก่อน
npm i postcss-salad precss -D หลังจากการติดตั้งการพึ่งพาเสร็จสมบูรณ์เราจำเป็นต้องสร้าง salad.config.json ในไดเรกทอรีรากของโครงการเพื่อกำหนดค่ากฎ bem กฎเฉพาะมีดังนี้
{
"browsers" : [ " ie > 8 " , " last 2 versions " ],
"features" : {
"bem" : {
"shortcuts" : {
"component" : " b " ,
"modifier" : " m " ,
"descendent" : " e "
},
"separators" : {
"descendent" : " __ " ,
"modifier" : " -- "
}
}
}
} ต่อไปเราต้องใช้ปลั๊กอิน postcss-salad และ precss ในไฟล์ .postcssrc ที่เริ่มต้นดังนี้
module . exports = {
"plugins" : {
"postcss-import" : { } ,
"postcss-salad" : require ( './salad.config.json' ) ,
"postcss-url" : { } ,
"precss" : { } ,
"autoprefixer" : { } ,
}
}ตกลงเมื่อคุณเรียกใช้โครงการอีกครั้งในเวลานี้คุณจะเห็นว่า CSS มีผลตามที่แสดงในรูป
เพื่อที่จะจัดการไฟล์ CSS ได้ดีขึ้นในไลบรารีส่วนประกอบและเพื่อให้แน่ใจว่าผู้ใช้ยังสามารถแนะนำไฟล์ CSS ที่สอดคล้องกับส่วนประกอบเมื่อมีการแนะนำส่วนประกอบเพียงหนึ่งหรือหลายส่วนในไลบรารีส่วนประกอบ ดังนั้นเราจำเป็นต้องบรรจุไฟล์ CSS แยกกัน ที่นี่เราต้องใช้ gulp เพื่อดำเนินการบรรจุภัณฑ์ที่เกี่ยวข้อง ก่อนที่คุณจะเริ่มรับรายละเอียดบรรจุภัณฑ์โปรดตรวจสอบให้แน่ใจว่าคุณได้ติดตั้ง gulp ทั่วโลกแล้ว ถ้าไม่โปรดติดตั้ง
npm i gulp -g
# 查看版本
gulp -v
# CLI version 3.9.1 ถัดไปลองดูว่าต้องใช้การพึ่งพาอะไรในไฟล์ packages/vui-css/package.json
{
"name" : "vui-css" ,
"version" : "1.0.0" ,
"description" : "vui css." ,
"main" : "lib/index.css" ,
"style" : "lib/index.css" ,
// 和组件发布一样,也需要指定目录
"files" : [
"lib" ,
"src"
] ,
"scripts" : {
"build" : "gulp build"
} ,
"license" : "MIT" ,
"devDependencies" : {
"gulp" : "^3.9.1" ,
"gulp-cssmin" : "^0.2.0" ,
"gulp-postcss" : "^7.0.1" ,
"postcss-salad" : "^2.0.1"
} ,
"dependencies" : { }
} เราจะเห็นได้ว่าสิ่งนี้คล้ายกับการพึ่งพาที่จำเป็นสำหรับไฟล์ CSS ในไลบรารีส่วนประกอบยกเว้นว่านี่คือปลั๊กอิน postcss ตาม gulp ก่อนที่จะเริ่มกำหนดค่า gulpfile.js อย่าลืมเรียกใช้ npm i สำหรับการติดตั้งการพึ่งพา
ต่อไปเราเริ่มกำหนดค่า gulpfile.js ดังนี้
const gulp = require ( 'gulp' )
const postcss = require ( 'gulp-postcss' )
const cssmin = require ( 'gulp-cssmin' )
const salad = require ( 'postcss-salad' ) ( require ( '../../salad.config.json' ) )
gulp . task ( 'compile' , function ( ) {
return gulp . src ( './src/*.css' )
// 使用postcss-salad
. pipe ( postcss ( [ salad ] ) )
// 进行css压缩
. pipe ( cssmin ( ) )
// 输出到 './lib' 目录下
. pipe ( gulp . dest ( './lib' ) )
} )
gulp . task ( 'build' , [ 'compile' ] ) ตอนนี้คุณสามารถเริ่มดำเนินการคำสั่ง gulp build เพื่อจัดทำแพ็คเกจไฟล์ CSS แน่นอนเพื่ออำนวยความสะดวกและดำเนินการตามคำสั่งบรรจุภัณฑ์ที่ดีขึ้นตอนนี้เราจำเป็นต้องเพิ่มคำสั่ง css build ลงใน package.json ในไดเรกทอรีรากของโครงการดังต่อไปนี้
"scripts" : {
"build:vui-css" : " gulp build --gulpfile packages/vui-css/gulpfile.js && rimraf lib/vui-css && cp-cli packages/vui-css/lib lib/vui-css && rimraf packages/vui-css/lib "
} เรียกใช้งาน npm run build:vui-css ไปข้างหน้าและในที่สุดก็บรรจุไฟล์ JS และ CSS ของไลบรารีส่วนประกอบดังแสดงในรูปต่อไปนี้
ตกลงมาถึงจุดนี้คุณสามารถแนะนำส่วนประกอบและสไตล์ของพวกเขาแยกกัน ในที่สุดเพื่อให้ผู้ใช้สามารถใช้ CSS ส่วนประกอบของคุณโดยตรงอย่าลืมเผยแพร่ไปยังเว็บไซต์ทางการ npm ~ ขั้นตอนดังต่อไปนี้
# 进到vui-css目录
cd packages/vui-css
# 发布
npm publishณ จุดนี้เราได้เสร็จสิ้นการจัดการและแยกบรรจุภัณฑ์ของไฟล์ CSS และเสร็จสิ้นการส่งออกเดียวของไฟล์ CSS ด้วยวิธีนี้เราสามารถมีวิธีที่ดีกว่าในการพัฒนาและจัดการไฟล์ไลบรารีส่วนประกอบ CSS ในขณะเดียวกันก็สามารถอำนวยความสะดวกในการใช้ไลบรารีส่วนประกอบ!
จนถึงตอนนี้เราได้สร้างไดเรกทอรีใหม่ที่จำเป็นสำหรับไลบรารีส่วนประกอบและเราได้เปลี่ยนบรรจุภัณฑ์ของไฟล์ JS และไฟล์ CSS เราได้เตรียมการอย่างเพียงพอสำหรับการพัฒนาห้องสมุดส่วนประกอบ แต่เรายังคงต้องทำงานล่วงหน้าที่สำคัญมากเพื่ออำนวยความสะดวกในการพัฒนาและบำรุงรักษาส่วนประกอบที่ตามมาของไลบรารีส่วนประกอบ
สำหรับการทดสอบส่วนหน้าเป็นสาขาสำคัญของวิศวกรรมส่วนหน้า ดังนั้นส่วนสำคัญดังกล่าวจะพลาดในไลบรารีส่วนประกอบของเราได้อย่างไร สำหรับการทดสอบหน่วยส่วนใหญ่มีสองประเภท
ในบทนี้ฉัน Karma นำคุณไปสู่ส่วนประกอบการทดสอบหน่วยในไลบรารีส่วนประกอบของเราโดยใช้สองเฟรมเวิร์กตามการเริ่มต้น Mocha
ฉันเชื่อว่าคนส่วนใหญ่ที่ได้รับการทดสอบหน่วยจะคุ้นเคยกับสองเฟรมเวิร์ก Karma + Mocha แต่ที่นี่ฉันคิดว่าจำเป็นต้องเปิดส่วนแยกต่างหากเพื่อให้การแนะนำสั้น ๆ กับสองเฟรมเวิร์ก
เพื่อให้ส่วนประกอบในไลบรารีส่วนประกอบของเราทำงานในเว็บเบราว์เซอร์หลักสำหรับการทดสอบเราเลือก กรรม สิ่งที่สำคัญที่สุดคือ Karma เป็นกรอบการทดสอบหน่วยที่แนะนำโดย vue-cli หากคุณต้องการทราบข้อมูลเพิ่มเติมเกี่ยวกับ กรรม โปรดตรวจสอบเว็บไซต์ทางการของ Karma
simple flexible และ funPromisecoverage รหัสbefore() , after() , beforeEach() และ afterEach() เพื่อให้เราสามารถตั้งค่าการดำเนินการที่แตกต่างกันในขั้นตอนต่าง ๆ เพื่อให้การทดสอบของเราเสร็จสมบูรณ์ ที่นี่ฉันจะแนะนำการใช้งานพื้นฐานสามประการของ mocha describe
อธิบาย (modulename, function): describe เป็น Nestable อธิบายว่า กรณีทดสอบ ถูกต้องหรือไม่
describe ( '测试模块的描述' , ( ) => {
// ....
} ) ; ** มัน (ข้อมูล, ฟังก์ชั่น): ** หนึ่ง it สอดคล้องกับกรณีทดสอบหน่วย
it ( '单元测试用例的描述' , ( ) => {
// ....
} )การใช้ห้องสมุดการยืนยัน
expect ( 1 + 1 ) . to . be . equal ( 2 ) วงจรชีวิตของ describe
describe ( 'Test Hooks' , function ( ) {
before ( function ( ) {
// 在本区块的所有测试用例之前执行
} ) ;
after ( function ( ) {
// 在本区块的所有测试用例之后执行
} ) ;
beforeEach ( function ( ) {
// 在本区块的每个测试用例之前执行
} ) ;
afterEach ( function ( ) {
// 在本区块的每个测试用例之后执行
} ) ;
// test cases
} ) ; นักเรียนที่ต้องการทราบข้อมูลเพิ่มเติมเกี่ยวกับการดำเนินงาน mocha สามารถคลิกลิงก์ด้านล่างเพื่อดูได้
ในส่วนข้างต้นฉันแนะนำกรอบการทดสอบสั้น ๆ Karma และ Mocha ซึ่งได้รับการแนะนำอย่างเป็นทางการโดย Vue ฉันหวังว่าเมื่อคุณเห็นสิ่งนี้คุณสามารถมีความเข้าใจง่าย ๆ เกี่ยวกับการทดสอบหน่วยและกรอบการทดสอบทั่วไป
ก่อนที่การทดสอบหน่วยจริงจะเริ่มขึ้นลองดูการกำหนดค่าของ กรรม ที่นี่เราดูการกำหนดค่าโดยตรงในไฟล์ karma.conf.js เริ่มต้นโดย vue-cli scaffold (ฉันได้แสดงความคิดเห็นเกี่ยวกับการใช้งานเฉพาะ)
var webpackConfig = require ( '../../build/webpack.test.conf' )
module . exports = function karmaConfig ( config ) {
config . set ( {
// 浏览器
browsers : [ 'PhantomJS' ] ,
// 测试框架
frameworks : [ 'mocha' , 'sinon-chai' , 'phantomjs-shim' ] ,
// 测试报告
reporters : [ 'spec' , 'coverage' ] ,
// 测试入口文件
files : [ './index.js' ] ,
// 预处理器 karma-webpack
preprocessors : {
'./index.js' : [ 'webpack' , 'sourcemap' ]
} ,
// webpack配置
webpack : webpackConfig ,
// webpack中间件
webpackMiddleware : {
noInfo : true
} ,
// 测试覆盖率报告
coverageReporter : {
dir : './coverage' ,
reporters : [
{ type : 'lcov' , subdir : '.' } ,
{ type : 'text-summary' }
]
}
} )
} ถัดไปเรามาทำการทดสอบอย่างง่าย ๆ เกี่ยวกับองค์ประกอบ hello ของเราเอง (เขียนกรณีทดสอบหนึ่งกรณี) สร้างไฟล์ hello.spec.js ใหม่ใน test/unit/specs และเขียนรหัสต่อไปนี้
import Vue from 'vue' // 导入Vue用于生成Vue实例
import Hello from 'packages/hello' // 导入组件
// 测试脚本里面应该包括一个或多个describe块,称为测试套件(test suite)
describe ( 'Hello.vue' , ( ) => {
// 每个describe块应该包括一个或多个it块,称为测试用例(test case)
it ( 'render default classList in hello' , ( ) => {
const Constructor = Vue . extend ( Hello ) // 获得Hello组件实例
const vm = new Constructor ( ) . $mount ( ) // 将组件挂在到DOM上
// 断言:DOM中包含class为v-hello的元素
expect ( vm . $el . classList . contains ( 'v-hello' ) ) . to . be . true
const message = vm . $el . querySelector ( '.v-hello__message' )
// 断言:DOM中包含class为v-hello__message的元素
expect ( message . classList . contains ( 'v-hello__message' ) ) . to . be . true
} )
} ) หลังจากเขียนตัวอย่างการทดสอบขั้นตอนต่อไปคือการทดสอบ ดำเนิน npm run test ไปหาคุณ ~ ส่งออกผลลัพธ์
hello.vue
✓ render default classList in hello จากอินสแตนซ์การทดสอบด้านบนขององค์ประกอบ hello เราจำเป็นต้องยกตัวอย่างส่วนประกอบเป็นอินสแตนซ์ VUE และบางครั้งเราจำเป็นต้องติดตั้งบน DOM
const Constructor = Vue . extend ( Hello )
const vm = new Constructor ( {
propsData : {
message : 'component'
}
} ) . $mount ( ) หากแต่ละองค์ประกอบมีอินสแตนซ์การทดสอบหลายหน่วยในภายหลังการเขียนนี้จะทำให้การทดสอบขั้นสุดท้ายของเราเป็นป่อง ที่นี่เราสามารถอ้างถึงเครื่องมือทดสอบหน่วย util.js ที่ห่อหุ้มด้วย element เราจำเป็นต้องห่อหุ้มวิธีการที่ใช้กันทั่วไปในการทดสอบหน่วย ด้านล่างนี้ฉันจะแสดงรายการบางวิธีที่มีให้ในเครื่องมือ
/**
* 回收 vm,一般在每个测试脚本测试完成后执行回收vm。
* @param {Object} vm
*/
exports . destroyVM = function ( vm ) { }
/**
* 创建一个 Vue 的实例对象
* @param {Object|String} Compo - 组件配置,可直接传 template
* @param {Boolean=false} mounted - 是否添加到 DOM 上
* @return {Object} vm
*/
exports . createVue = function ( Compo , mounted = false ) { }
/**
* 创建一个测试组件实例
* @param {Object} Compo - 组件对象
* @param {Object} propsData - props 数据
* @param {Boolean=false} mounted - 是否添加到 DOM 上
* @return {Object} vm
*/
exports . createTest = function ( Compo , propsData = { } , mounted = false ) { }
/**
* 触发一个事件
* 注: 一般在触发事件后使用 vm.$nextTick 方法确定事件触发完成。
* mouseenter, mouseleave, mouseover, keyup, change, click 等
* @param {Element} elm - 元素
* @param {String} name - 事件名称
* @param {*} opts - 配置项
*/
exports . triggerEvent = function ( elm , name , ... opts ) { }
/**
* 触发 “mouseup” 和 “mousedown” 事件,既触发点击事件。
* @param {Element} elm - 元素
* @param {*} opts - 配置选项
*/
exports . triggerClick = function ( elm , ... opts ) { } ด้านล่างเราจะใช้วิธีการทดสอบเครื่องมือที่กำหนดเพื่อแปลงอินสแตนซ์ทดสอบของส่วนประกอบ hello และแปลงไฟล์ hello.spec.js
import { destroyVM , createTest } from '../util'
import Hello from 'packages/hello'
describe ( 'hello.vue' , ( ) => {
let vm
// 测试用例执行之后销毁实例
afterEach ( ( ) => {
destroyVM ( vm )
} )
it ( 'render default classList in hello' , ( ) => {
vm = createTest ( Hello )
expect ( vm . $el . classList . contains ( 'v-hello' ) ) . to . be . true
const message = vm . $el . querySelector ( '.v-hello__message' )
expect ( message . classList . contains ( 'v-hello__message' ) ) . to . be . true
} )
} ) ทำการทดสอบ npm run test และส่งออกอีกครั้งผลลัพธ์
hello.vue
✓ render default classList in hello ข้างต้นเราแนะนำการใช้การทดสอบหน่วยในการตัดสินแบบคงที่ ต่อไปเราจะทดสอบกรณีการใช้แบบอะซิงโครนัสและเหตุการณ์แบบโต้ตอบบางอย่าง ก่อนการทดสอบเราต้องเปลี่ยนรหัสขององค์ประกอบ hello ของเราเล็กน้อยดังนี้
< template >
< div class =" v-hello " @click =" handleClick " >
< p class =" v-hello__message " > hello {{ message }} </ p >
</ div >
</ template >
< script >
export default {
name : 'v-hello' ,
props : {
message : String
} ,
methods : {
handleClick ( ) {
return new Promise ( ( resolve ) => {
resolve ( )
} ) . then ( ( ) => {
this . $emit ( 'click' , 'this is click emit' )
} )
}
}
}
</ script > ต่อไปเราต้องการทดสอบว่าองค์ประกอบ hello สามารถ emit ข้อมูลผ่านสัญญาได้สำเร็จหรือไม่ ตัวอย่างเช่นกรณีทดสอบมีดังนี้
it ( 'create a hello for click with promise' , ( done ) => {
let result
vm = createVue ( {
template : `<v-hello @click="handleClick"></v-hello>` ,
methods : {
handleClick ( msg ) {
result = msg
}
}
} , true )
vm . $el . click ( )
// 断言消息是异步emit出去的
expect ( result ) . to . not . exist
setTimeout ( _ => {
expect ( result ) . to . exist
expect ( result ) . to . equal ( 'this is click emit' )
done ( )
} , 20 )
} ) เริ่มการทดสอบอีกครั้งดำเนินการ npm run test ส่งออกผลลัพธ์ผลลัพธ์
hello.vue
✓ render default classList in hello
✓ create a hello for click with promiseณ จุดนี้เราได้เรียนรู้การกำหนดค่าของการทดสอบหน่วยและการใช้งานที่ใช้กันทั่วไป หากคุณต้องการทราบข้อมูลเพิ่มเติมเกี่ยวกับการทดสอบหน่วยโปรดไปที่ลิงค์ที่ฉันให้ไว้ก่อนหน้านี้เพื่อไปศึกษาที่ลึกซึ้งยิ่งขึ้น
เพื่อนติดตามฉันเพื่อฝึกฝน 5 บทก่อนหน้านี้และได้สร้างชั้นวางขั้นพื้นฐานสำหรับการพัฒนาส่วนประกอบของเรา ต่อไปฉันจะพาคุณทุกคนไปที่เว็บไซต์อย่างเป็นทางการของเอกสารที่มีส่วนประกอบที่สำคัญสูงในไลบรารีส่วนประกอบ
ทุกคนควรรู้ว่าโครงการโอเพ่นซอร์สที่ดีต้องมีเว็บไซต์เอกสารอย่างเป็นทางการดังนั้นเพื่อให้ห้องสมุด UI ของเราเป็นหนึ่งในที่ดีที่สุดเราควรใช้เว็บไซต์เอกสารอย่างเป็นทางการของเราเอง
เว็บไซต์เอกสารอย่างเป็นทางการที่ดีต้องใช้สองสิ่ง
เนื่องจากไลบรารีส่วนประกอบที่ฉันได้นำคุณไปสู่การพัฒนาเหมาะสำหรับอุปกรณ์มือถือเราจะทำให้เว็บไซต์เอกสารอย่างเป็นทางการของเรามีทั้งคำอธิบายเอกสาร API และตัวอย่างการสาธิตมือถือได้อย่างไร สิ่งนี้ต้องการให้เราพัฒนาสองชุดสำหรับการปรับตัว สิ่งต่อไปนี้ที่เราต้องทำ:
ก่อนที่การต่อสู้ที่เกิดขึ้นจริงจะมาดูโครงสร้างไดเรกทอรีที่จำเป็นในบทนี้
├── 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 动态注册路由บทนี้ส่วนใหญ่จะนำคุณไปสู่การแปลงไฟล์ markdown และการปรับเส้นทางของอุปกรณ์ที่แตกต่างกัน
หลังจากชี้แจงแนวคิดให้พัฒนาเว็บไซต์เอกสารอย่างเป็นทางการของเราต่อไป!
จากไดเรกทอรีที่ฉันให้ไว้ข้างต้นเราจะเห็นได้ว่าโฟลเดอร์ DOCS จะถูกเก็บไว้ในไฟล์ Markdown และไฟล์ Markdown แต่ละไฟล์สอดคล้องกับเอกสาร API ของส่วนประกอบ ผลลัพธ์ที่เราต้องการคือการแปลงทุกไฟล์ Markdown ในเอกสารเพื่อเปลี่ยนเป็นส่วนประกอบ Vue และลงทะเบียนส่วนประกอบ Vue ที่แปลงเป็นเส้นทางเพื่อให้สามารถเข้าถึงไฟล์ Markdown แต่ละไฟล์ผ่านเส้นทาง
สำหรับการแยกวิเคราะห์ไฟล์ Markdown เป็นส่วนประกอบ Vue มีปลั๊กอิน webpack สามพรรคหลายตัวในตลาด แน่นอนถ้าคุณมีความเข้าใจอย่างลึกซึ้งเกี่ยวกับ webpack คุณสามารถลองเลือกด้วยตัวเอง ที่นี่ฉันใช้ Vue-Markdown-Loader โดยตรงพัฒนาโดย饿了么团队
ขั้นตอนแรกคือการพึ่งพาการติดตั้ง
npm i vue-markdown-loader -D ขั้นตอนที่สองคือการใช้ vue-markdown-loader ในไฟล์ webpack.base.conf.js
{
test : / .md$ / ,
loader : 'vue-markdown-loader' ,
options : {
// 阻止提取脚本和样式标签
preventExtract : true
}
} ขั้นตอนที่สามคือลอง ก่อนอื่นเพิ่มไฟล์ hello.md ใน docs จากนั้นเขียนคำแนะนำสำหรับการใช้ส่วนประกอบ hello
## Hello
** Hello 组件,Hello 组件,Hello 组件,Hello 组件**
### 基本用法
```html
< template >
< div class = " hello-page " >
<v-hello message="my component library" @click="handleClick"></v-hello>
<p>{{ msg }}</p>
</ div >
</ template >
< script >
export default {
name : ' hello ' ,
data () {
return {
msg : ' '
}
},
methods : {
handleClick ( msg ) {
this . msg = msg
}
}
}
</ script >
```
### Attributes
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| ---------- | -------- | ---------- | ------------- | -------- |
| message | 文本信息 | string | — | — |
### Events
| 事件名称 | 说明 | 回调参数 |
| ---------- | -------- | ---------- |
| click | 点击操作 | — | ขั้นตอนที่ 4: ลงทะเบียน hello.md ในเส้นทาง
route . push ( {
path : '/component/hello' ,
component : require ( '../docs/hello.md' )
} ) สุดท้ายเยี่ยมชมหน้า ในเวลานี้คุณจะพบว่าเนื้อหาของ hello.md ได้รับการแปลงเป็นส่วนประกอบ Vue และสามารถเข้าถึงได้ผ่านการโหลดเส้นทาง แต่หน้านั้นน่าเกลียด ~ เช่นนี้
แน่นอนฉันไม่จำเป็นต้องอธิบายสถานการณ์นี้คุณอาจรู้เช่นกัน ใช่ไฟล์ Markdown ที่แยกวิเคราะห์นั้นน่าเกลียดเพียงเพราะเราไม่ได้เน้นธีมสำหรับไฟล์ markdown ของเราหรือตั้งค่าสไตล์พื้นฐานของหน้าเอกสาร ดังนั้นต่อไปเราต้องเพิ่มธีมที่เน้นที่ดีและสไตล์พื้นฐานที่สะอาดในไฟล์ Markdown ของเรา
สำหรับหัวข้อที่นี่เราจะใช้ธีม Atom-One-Dark ใน highlight.js
ขั้นตอนแรกคือการติดตั้ง highlight.js
npm i highlight -D ขั้นตอนที่สองคือการแนะนำธีมใน examples/src/App.vue และเพื่อตั้งค่าสไตล์พื้นฐานของเอกสารเราจำเป็นต้องปรับเปลี่ยนเค้าโครงของ app.vue
< template >
< div class =" app " >
< div class =" main-content " >
< div class =" page-container clearfix " >
< div class =" page-content " >
< router-view > </ router-view >
</ div >
</ div >
</ div >
</ div >
</ template >
< script >
import 'highlight.js/styles/atom-one-dark.css'
export default {
name : 'App'
}
</ script > ขั้นตอนที่สามคือการตั้งค่าสไตล์พื้นฐานของเอกสาร สร้าง docs.css ใหม่ใน assets และเขียนสไตล์เริ่มต้น เนื่องจากปริมาณรหัสมีขนาดใหญ่เกินไปฉันจะไม่โพสต์ที่นี่ คุณสามารถคัดลอกรหัสใน docs.css ลงในไฟล์ docs.css ท้องถิ่นด้วยตัวเองแล้วนำเข้าใน examples/src/index.js
import '../assets/docs.css' ในที่สุดเปลี่ยนกฎการแยกวิเคราะห์ Markdown vue-markdown-loader จัดเตรียมอินเทอร์เฟซ preprocess เพื่อให้เราทำงานได้อย่างอิสระ ต่อไปเรากำหนดโครงสร้างของไฟล์ markdown ที่แยกวิเคราะห์และเขียนไว้ในไฟล์ 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 ;
}
}
}จากนั้น revisit localhost: 8080/#/ส่วนประกอบ/สวัสดี
ตกลงไฟล์ MD ของเราได้รับการแยกวิเคราะห์เป็นส่วนประกอบ Vue อย่างประสบความสำเร็จและมีธีมไฮไลต์ที่สวยงามและสไตล์พื้นฐานที่เรียบง่าย ~
ดังที่ฉันได้กล่าวไว้ก่อนหน้านี้ไลบรารีส่วนประกอบที่พัฒนาโดยบทความนี้ถูกดัดแปลงให้เข้ากับมือถือดังนั้นเราต้องแสดงเอกสารบนพีซีและการสาธิตบนมือถือ
ในส่วนนี้ฉันจะพาคุณไปปรับเส้นทางให้เข้ากับปลายที่แตกต่างกัน แน่นอนสิ่งนี้ไม่ยาก ส่วนใหญ่ใช้ webpack เพื่อสร้างคุณสมบัติหลายหน้า แล้วจะทำอย่างไรโดยเฉพาะ? ตกลงมาเริ่มกันเลย
ขั้นตอนแรกคือการลงทะเบียนไฟล์รายการ JS และเขียนลงในไฟล์ webpack.base.conf.js
entry: {
// ...
'vui' : './examples/src/index.js' , // PC端入口js
'vui-mobile' : './examples/src/mobile.js' // 移动端入口js
} ขั้นตอนที่สองคือการลงทะเบียนทางเข้าหน้าและเขียนในไฟล์ webpack.base.conf.js
plugins: [
// ...
// PC端页面入口
new HtmlWebpackPlugin ( {
chunks : [ 'manifest' , 'vendor' , 'vui' ] ,
template : 'examples/src/index.tpl' ,
filename : 'index.html' ,
inject : true
} ) ,
// 移动端页面入口
new HtmlWebpackPlugin ( {
chunks : [ 'manifest' , 'vendor' , 'vui-mobile' ] ,
template : 'examples/src/index.tpl' ,
filename : 'mobile.html' ,
inject : true
} )
] การลงทะเบียนไฟล์รายการเสร็จสมบูรณ์และสิ่งที่เราต้องทำต่อไปคือการกำหนดสภาพแวดล้อมของอุปกรณ์ ที่นี่ฉันจะใช้ navigator.userAgent กับนิพจน์ทั่วไปเพื่อตรวจสอบว่าสภาพแวดล้อมที่ไลบรารีส่วนประกอบของเราทำงานอยู่ในด้านพีซีหรือด้านมือถือหรือไม่?
ขั้นตอนแรกคือการเขียนรหัสต่อไปนี้ใน 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 ขั้นตอนที่สองคือการเขียนกฎการตัดสินต่อไปนี้ในตัวอย่างไฟล์ js examples/src/index.js ทางด้านพีซี
import isMobile from './is-mobile'
// 是否为生产环境
const isProduction = process . env . NODE_ENV === 'production'
router . beforeEach ( ( route , redirect , next ) => {
if ( route . path !== '/' ) {
window . scrollTo ( 0 , 0 )
}
// 获取不同环境下,移动端Demo对应的地址
const pathname = isProduction ? '/vui/mobile' : '/mobile.html'
// 如果设备环境为移动端,则直接加载移动端Demo的地址
if ( isMobile ) {
window . location . replace ( pathname )
return
}
document . title = route . meta . title || document . title
next ( )
} ) ขั้นตอนที่สามคือการเขียนกฎการตัดสินคล้ายกับขั้นตอนก่อนหน้าในตัวอย่างไฟล์ JS Mobile JS examples/src/mobile.js
import isMobile from './is-mobile'
const isProduction = process . env . NODE_ENV === 'production'
router . beforeEach ( ( route , redirect , next ) => {
if ( route . path !== '/' ) {
window . scrollTo ( 0 , 0 )
}
// 获取不同环境下,PC端对应的地址
const pathname = isProduction ? '/vui/mobile' : '/mobile.html'
// 如果设备环境不是移动端,则直接加载PC端的地址
if ( ! isMobile ) {
window . location . replace ( pathname )
return
}
document . title = route . meta . title || document . title
next ( )
} ) สุดท้ายปรับปรุงไฟล์ examples/src/mobile.js และไฟล์ pory pory pory MobileApp.vue
เขียนรหัสต่อไปนี้ใน examples/src/mobile.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import MobileApp from './MobileApp'
import Vui from 'src/index'
import isMobile from './is-mobile.js'
import Hello from '../pages/hello.vue'
import 'packages/vui-css/src/index.css'
Vue . use ( Vui )
Vue . use ( VueRouter )
const isProduction = process . env . NODE_ENV === 'production'
const router = new VueRouter ( {
base : isProduction ? '/vui/' : __dirname ,
routes : [ {
path : '/component/hello' ,
component : Hello
} ]
} )
router . beforeEach ( ( route , redirect , next ) => {
if ( route . path !== '/' ) {
window . scrollTo ( 0 , 0 )
}
const pathname = isProduction ? '/vui/' : '/'
if ( ! isMobile ) {
window . location . replace ( pathname )
return
}
document . title = route . meta . title || document . title
next ( )
} )
new Vue ( {
el : '#app-container' ,
router ,
components : { MobileApp } ,
template : '<MobileApp/>'
} ) เขียนใน MobileApp.vue
< template >
< div class =" mobile-container " >
< router-view > </ router-view >
</ div >
</ template >ถัดไปคุณสามารถลองใช้เอฟเฟกต์ในเบราว์เซอร์เพื่อดูว่าสภาพแวดล้อมของอุปกรณ์ที่แตกต่างกันสามารถแสดงเนื้อหาที่เกี่ยวข้อง ~
ณ จุดนี้แผนทั้งหมดที่เราได้กำหนดไว้ในบทนี้เสร็จสมบูรณ์แล้ว การแปลงไฟล์ MD "สมบูรณ์แบบ" และการปรับการกำหนดเส้นทางในสภาพแวดล้อมอุปกรณ์ที่แตกต่างกัน การพัฒนาเว็บไซต์อย่างเป็นทางการของเอกสาร (ตอนที่ 1) กำลังจะสิ้นสุดที่นี่ ในบทต่อไปเราจะดำเนินการพัฒนางานที่เหลืออยู่ของเว็บไซต์อย่างเป็นทางการของเอกสาร!
ในบทก่อนหน้านี้เราได้กรอกเสร็จแล้ว:
ในบทนี้เราจะปรับปรุงรายละเอียดของเว็บไซต์อย่างเป็นทางการของเอกสารและพัฒนาเว็บไซต์อย่างเป็นทางการของเอกสารที่สมบูรณ์
จากไดเรกทอรีที่ให้ไว้ในบทก่อนหน้าเราสามารถรู้ได้ว่าไดเรกทอรี DOCS ใช้ในการจัดเก็บไฟล์ MD ที่พีซีจำเป็นต้องแสดงและไดเรกทอรีหน้าเว็บจะใช้ในการจัดเก็บไฟล์ตัวอย่างมือถือ ดังนั้นส่วนประกอบจะแสดงไฟล์ที่เกี่ยวข้องในสภาพแวดล้อมอุปกรณ์ที่แตกต่างกันได้อย่างไร (ด้านข้างของพีซีแสดงไฟล์ MD ที่สอดคล้องกับส่วนประกอบและด้านมือถือจะแสดงไฟล์ Vue ที่สอดคล้องกับส่วนประกอบ) เราจะจัดการเส้นทางของไลบรารีส่วนประกอบของเราได้อย่างไรในกรณีนี้ ต่อไปเราจะพัฒนาต่อไปด้านล่างตามปัญหาเหล่านี้ is-mobile.js จะถูกใช้อย่างแน่นอนเพื่อกำหนดสภาพแวดล้อมของอุปกรณ์ โปรดติดตามฉันเพื่อทำงานเฉพาะ
ขั้นตอนแรกคือการสร้างไฟล์ nav.config.json ไฟล์ใหม่ภายใต้ examples/src และเขียนเนื้อหาต่อไปนี้
{
// 为了之后组件文档多语言化
"zh-CN" : [
{
"name" : "Vui 组件" ,
"showInMobile" : true ,
"groups" : [
{
// 管理相同类型下的所有组件
"groupName" : "基础组件" ,
"list" : [
{
// 访问组件的相对路径
"path" : "/hello" ,
// 组件描述
"title" : "Hello"
}
]
}
]
}
]
} ขั้นตอนที่สองคือการปรับปรุงไฟล์ router.config.js และเปลี่ยนเป็นฟังก์ชั่นผู้ช่วยสำหรับการลงทะเบียนการกำหนดเส้นทาง
const registerRoute = ( navConfig , isMobile ) => {
let route = [ ]
// 目前只有中文版的文档
let navs = navConfig [ 'zh-CN' ]
// 遍历路由文件,逐一进行路由注册
navs . forEach ( nav => {
if ( isMobile && ! nav . showInMobile ) {
return
}
if ( nav . groups ) {
nav . groups . forEach ( group => {
group . list . forEach ( nav => {
addRoute ( nav )
} )
} )
} else if ( nav . children ) {
nav . children . forEach ( nav => {
addRoute ( nav )
} )
} else {
addRoute ( nav )
}
} )
// 进行路由注册
function addRoute ( page ) {
// 不同的设备环境引入对应的路由文件
const component = isMobile
? require ( `../pages ${ page . path } .vue` )
: require ( `../docs ${ page . path } .md` )
route . push ( {
path : '/component' + page . path ,
component : component . default || component
} )
}
return route
}
export default registerRoute ขั้นตอนที่สามคือการลงทะเบียนเส้นทางใน examples/src/index.js ของ examples/src/mobile.js หลัก/src/mobile.js ของไฟล์พอร์ทัล JS
import registerRoute from './router.config'
import navConfig from './nav.config'
const routesConfig = registerRoute ( navConfig )
const router = new VueRouter ( {
routes : routesConfig
} )จากนั้นเยี่ยมชมเว็บไซต์อย่างเป็นทางการของเอกสารประกอบห้องสมุดส่วนประกอบของเรา
จากการเรนเดอร์ขั้นสุดท้ายของบทก่อนหน้าเราจะเห็นว่าเทอร์มินัลพีซีแบ่งออกเป็นสามส่วนคือ:
ถัดไปเริ่มแสดง PC API กันเถอะ
ส่วนหัวค่อนข้างง่าย เราต้องสร้างไฟล์ page-header.vue ใหม่ภายใต้ examples/src/components และเขียนเนื้อหาต่อไปนี้
< 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 >สำหรับสไตล์ที่เฉพาะเจาะจงกรุณาเยี่ยมชมหน้าหน้าโดยตรงเพื่อดูพวกเขา
ทางด้านซ้ายเราจะแสดงเส้นทางและชื่อส่วนประกอบ ในความเป็นจริงมันคือการแยกวิเคราะห์และแสดง examples/src/nav.config.json
เราสร้างไฟล์ side-nav.vue ใหม่ภายใต้ examples/src/components โครงสร้างปกติของไฟล์มีดังนี้
< li class =" nav-item " >
< a href =" javascript:void(0) " > Vui 组件</ a >
< div class =" nav-group " >
< div class =" nav-group__title " >基础组件</ div >
< ul class =" pure-menu-list " >
< li class =" nav-item " >
< router-link
active-class =" active "
:to =" /component/hello "
v-text =" navItem.title " > Hello
</ router-link >
</ li >
</ ul >
</ div >
</ li > แต่ตอนนี้เราจำเป็นต้องแยกวิเคราะห์ examples/src/nav.config.json ตามโครงสร้างปัจจุบัน รหัสที่ได้รับการปรับปรุงมีดังนี้
< li class =" nav-item " v-for =" item in data " >
< a href =" javascript:void(0) " @click =" handleTitleClick(item) " > {{ item.name }} </ a >
< template v-if =" item.groups " >
< div class =" nav-group " v-for =" group in item.groups " >
< div class =" nav-group__title " > {{ group.groupName }} </ div >
< ul class =" pure-menu-list " >
< template v-for =" navItem in group.list " >
< li class =" nav-item " v-if =" !navItem.disabled " >
< router-link
active-class =" active "
:to =" base + navItem.path "
v-text =" navItem.title " />
</ li >
</ template >
</ ul >
</ div >
</ template >
</ li >คลิกที่นี่เพื่อดูรหัสที่สมบูรณ์ side-nav.vue
เราใช้ page-header.vue และ side-nav.vue เราเขียนใน App.vue
< template >
< div class =" app " >
< page-header > </ page-header >
< div class =" main-content " >
< div class =" page-container clearfix " >
< side-nav :data =" navConfig['zh-CN'] " base =" /component " > </ side-nav >
< div class =" page-content " >
< router-view > </ router-view >
</ div >
</ div >
</ div >
</ div >
</ template >
< script >
import 'highlight.js/styles/atom-one-dark.css'
import navConfig from './nav.config.json'
import PageHeader from './components/page-header'
import SideNav from './components/side-nav'
export default {
name : 'App' ,
components : { PageHeader , SideNav } ,
data ( ) {
return {
navConfig : navConfig
}
}
}
</ script >จากนั้นเยี่ยมชมหน้าอีกครั้งผลลัพธ์จะแสดงในรูปภาพ
หลักการของการสาธิตมือถือและพีซีนั้นคล้ายคลึงกัน ทั้งสองต้องแยกวิเคราะห์ไฟล์ nav.config.json เพื่อแสดงผล
ในปัจจุบันยกเว้นหน้าเข้าหลัก MobileApp.vue เทอร์มินัลมือถือของเราไม่มีการพึ่งพาส่วนประกอบรูท ต่อไปเราจะทำการพัฒนาส่วนประกอบรูทให้เสร็จสมบูรณ์ก่อนสร้างไฟล์ตัวอย่าง demo-list.vue ใหม่ภายใต้ examples/src/components และเขียนเนื้อหาบางส่วน
< template >
< div class =" side-nav " >
< h1 class =" vui-title " > </ h1 >
< h2 class =" vui-desc " > VUI 移动组件库</ h2 >
</ div >
</ template > จากนั้นเราต้องอ้างอิงในเส้นทางและเขียนลงในไฟล์ mobile.js
import DemoList from './components/demo-list.vue'
routesConfig . push ( {
path : '/' ,
component : DemoList
} ) จากนั้นเริ่มปรับปรุงไฟล์ demo-list.vue
< template >
< div class =" side-nav " >
< h1 class =" vui-title " > </ h1 >
< h2 class =" vui-desc " > VUI 移动组件库</ h2 >
< div class =" mobile-navs " >
< div v-for =" (item, index) in data " :key =" index " >
< div class =" mobile-nav-item " v-if =" item.showInMobile " >
< mobile-nav v-for =" (group, s) in item.groups " :group =" group " :base =" base " :key =" s " > </ mobile-nav >
</ div >
</ div >
</ div >
</ div >
</ template >
< script >
import navConfig from '../nav.config.json' ;
import MobileNav from './mobile-nav' ;
export default {
data ( ) {
return {
data : navConfig [ 'zh-CN' ] ,
base : '/component'
} ;
} ,
components : {
MobileNav
}
} ;
</ script >
< style lang =" postcss " >
.side-nav {
width: 100%;
box-sizing: border-box;
padding: 90px 15px 20px;
position: relative;
z-index: 1;
.vui-title,
.vui-desc {
text-align: center;
font-weight: normal;
user-select: none;
}
.vui-title {
padding-top: 40px;
height: 0;
overflow: hidden;
background: url(https://raw.githubusercontent.com/xuqiang521/vui/master/src/assets/logo.png) center center no-repeat;
background-size: 40px 40px;
margin-bottom: 10px;
}
.vui-desc {
font-size: 14px;
color: #666;
margin-bottom: 50px;
}
}
</ style >这里我们引用了mobile-nav.vue文件,这也是我们接下来要完成的移动端Demo 列表展示组件
在examples/src/components下新建mobile-nav.vue文件,解析nav.config.json文件,从而进行Demo 列表展示。
< template >
< div class =" mobile-nav-group " >
< div
class =" mobile-nav-group__title mobile-nav-group__basetitle "
:class =" {
'mobile-nav-group__title--open': isOpen
} "
@click =" isOpen = !isOpen " >
{{group.groupName}}
</ div >
< div class =" mobile-nav-group__list-wrapper " :class =" { 'mobile-nav-group__list-wrapper--open': isOpen } " >
< ul class =" mobile-nav-group__list " :class =" { 'mobile-nav-group__list--open': isOpen } " >
< template v-for =" navItem in group.list " >
< li
class =" mobile-nav-group__title "
v-if =" !navItem.disabled " >
< router-link
active-class =" active "
:to =" base + navItem.path " >
< p >
{{ navItem.title }}
</ p >
</ router-link >
</ li >
</ template >
</ ul >
</ div >
</ div >
</ template >
< script >
export default {
props : {
group : {
type : Object ,
default : ( ) => {
return [ ] ;
}
} ,
base : String
} ,
data ( ) {
return {
isOpen : false
} ;
}
} ;
</ script >然后写入列表样式
< style lang =" postcss " >
@component-namespace mobile {
@b nav-group {
border-radius: 2px;
margin-bottom: 15px;
background-color: #fff;
box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1);
@e basetitle {
padding-left: 20px;
}
@e title {
font-size: 16px;
color: #333;
line-height: 56px;
position: relative;
user-select: none;
@m open {
color: #38f;
}
a {
color: #333;
display: block;
user-select: none;
padding-left: 20px;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
&:active {
background: #ECECEC;
}
> p {
border-top: 1px solid #e5e5e5;
}
}
}
@e list-wrapper {
height: 0;
overflow: hidden;
@m open {
height: auto;
}
}
@e list {
transform: translateY(-50%);
transition: transform .2s ease-out;
@m open {
transform: translateY(0);
}
}
li {
list-style: none;
}
ul {
padding: 0;
margin: 0;
overflow: hidden;
}
}
}
</ style >接下来,重新访问http://localhost:8080/mobile.html ,不出意外你便能访问到我们预想的结果
到这一步为止,我们“粗陋”的组件库架子便已经全部搭建完毕。
博文到这里也差不多要结束了,文章中所有的代码都已经托管到了github上,后续我还会写一篇文章,带着搭建逐步完善我们组件库中的一些细节,让我们的组件库能够更加的完美。
github地址:https://github.com/xuqiang521/personal-component-library
文章末尾再打一波广告~~~
前端交流群:731175396
美团点评长期招人,如果有兴趣的话,欢迎一起搞基,简历投递方式交流群中有说明~
小伙伴们你们还在等什么呢?赶紧先给文章点波赞,然后关注我一波,然后加群和大佬们一起交流啊~~~