Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
問(wèn)大家一個(gè)問(wèn)題,曾經(jīng)的你是否也遇到過(guò),一個(gè)項(xiàng)目中有好幾個(gè)頁(yè)面長(zhǎng)得基本相同,但又差那么一點(diǎn),想用 vue extends 繼承它又不能按需繼承html模板部分,恰好 B 頁(yè)面需要用的 A 頁(yè)面 80% 的模板,剩下的 20% 由 B 頁(yè)面自定義,舉個(gè)栗子:
我們假設(shè)這是兩個(gè)頁(yè)面,B頁(yè)面比A頁(yè)面多了個(gè)p標(biāo)簽,剩余的東西都一樣,難道僅僅是因?yàn)檫@一個(gè) p標(biāo)簽就要重新寫(xiě)一份模板嗎?相信大部分伙伴解決方式是把公共部分抽成一個(gè)組件來(lái)用,這是一個(gè)好的做法。沒(méi)錯(cuò),但是來(lái)了,老板讓你在 標(biāo)題1、標(biāo)題2下面分別插入一段內(nèi)容,這會(huì)兒你是不是頭大了?難道只能重寫(xiě)一份了嗎?當(dāng)然不是,來(lái)開(kāi)始我們的填坑之路~(當(dāng)你的業(yè)務(wù)能用插槽或者組件抽離的方式固然更好,以下內(nèi)容僅針對(duì)當(dāng)你項(xiàng)目達(dá)到一定體量,vue老三套難以處理的情況下采用)
準(zhǔn)備以下工具包:
npm install --save node-html-parser
<template extend="./xxx.vue">
</template>
<template extend="./xxx.vue">
<div>
<extend type="replace" target="#div_1">
<a>通過(guò)replace替換掉父頁(yè)面下id為div_1的元素 </a>
</extend>
</div>
</template>
最終它生成的應(yīng)該是除了 id 為 div_1元素被<a>通過(guò)replace替換掉父頁(yè)面下id為div_1的元素 </a>替換掉之外,剩下的全部和xxx.vue一樣的頁(yè)面。
子頁(yè)面繼承父頁(yè)面既可以完全繼承,也可以通過(guò)某種方式以父頁(yè)面為基板,對(duì)其進(jìn)行增、刪、改。方便理解,我們先定義一個(gè)自定義標(biāo)簽 extend,子頁(yè)面通過(guò)該標(biāo)簽對(duì)其繼承的頁(yè)面操刀動(dòng)手術(shù),為了實(shí)現(xiàn)一個(gè)比較完善的繼承拓展,extend 標(biāo)簽需要具備以下屬性:
參數(shù) | 說(shuō)明 | 類型 | 可選值 |
type | 指定擴(kuò)展類型 | string | insert(插入)、replace(替換)、remove(移除)、append(向子集追加) |
position | 指定插入的位置(僅在 type 取值 insert 時(shí)生效) | string | before(目標(biāo)前)、after(目標(biāo)后) |
指定插入的位置(僅在 type 取值 append 時(shí)生效,用于指定插入成為第幾個(gè)子節(jié)點(diǎn)) | number | - | |
target | 指定擴(kuò)展的目標(biāo) | string |
新建一個(gè)vue2的項(xiàng)目,項(xiàng)目結(jié)構(gòu)如下:
我們的繼承拓展通過(guò)自定義loader在編譯的時(shí)候?qū)崿F(xiàn),進(jìn)入到src/loader/index.js
const extend = require('./extend');
module.exports = function (source) {
// 當(dāng)前模塊目錄
const resourcePath = this.resourcePath;
// 合并
const result = new extend(source, resourcePath).mergePage();
// console.log('result :>> ', result);
// 返回合并后的內(nèi)容
this.callback(null, result);
};
實(shí)現(xiàn)繼承拓展主要邏輯代碼:src/loader/extend.js
const parser = require('node-html-parser');
const fs = require('fs');
const pathFile = require('path');
/**
* 通過(guò)node-html-parser解析頁(yè)面文件重組模板
* @param {String} source 頁(yè)面內(nèi)容
* @param {String} resourcePath 頁(yè)面目錄
* @returns {String} 重組后的文件內(nèi)容
*/
class Extend {
constructor(source, resourcePath) {
this.source = source;
this.resourcePath = resourcePath;
}
// 合并頁(yè)面
mergePage() {
// 通過(guò)node-html-parser解析模板文件
const pageAst = parser.parse(this.source).removeWhitespace();
// 獲取template標(biāo)簽extend屬性值
const extendPath = pageAst.querySelector('template').getAttribute('extend');
if (!extendPath) {
return pageAst.toString();
}
// extendPath文件內(nèi)容
const extendContent = fs.readFileSync(pathFile.resolve(pathFile.dirname(this.resourcePath), extendPath), 'utf-8');
// extendContent文件解析
const extendAst = parser.parse(extendContent).removeWhitespace();
// 獲取頁(yè)面文件標(biāo)簽為extend的元素
const extendElements = pageAst.querySelectorAll('extend');
extendElements.forEach((el) => {
// 獲取對(duì)應(yīng)屬性值
const type = el.getAttribute('type');
const target = el.getAttribute('target');
const position = parseInt(el.getAttribute('position'));
// 匹配模板符合target的元素
let templateElements = extendAst.querySelectorAll(target);
// type屬性為insert
if (type === 'insert') {
templateElements.forEach((tel) => {
// 通過(guò)position屬性判斷插入位置 默認(rèn)為after
if (position === 'before') {
el.childNodes.forEach((child) => {
tel.insertAdjacentHTML('beforebegin', child.toString());
});
} else {
el.childNodes.forEach((child) => {
tel.insertAdjacentHTML('afterend', child.toString());
});
}
});
}
// type屬性為append
if (type === 'append') {
templateElements.forEach((tel) => {
const elNodes = el.childNodes;
let tlNodes = tel.childNodes;
const len = tlNodes.filter((node) => node.nodeType === 1 || node.nodeType === 3).length;
// 未傳position屬性或不為數(shù)字、大于len、小于0時(shí)默認(rèn)插入到最后
if(isNaN(position) || position > len || position <= 0){
elNodes.forEach((child) => {
tel.insertAdjacentHTML('beforeend', child.toString());
});
}else {
tlNodes = [...tlNodes.slice(0, position-1), ...elNodes, ...tlNodes.slice(position-1)]
tel.set_content(tlNodes);
}
});
}
// type屬性為replace
if (type === 'replace') {
templateElements.forEach((tel) => {
tel.replaceWith(...el.childNodes);
});
}
// type屬性為remove
if (type === 'remove') {
templateElements.forEach((tel) => {
tel.remove();
});
}
});
// 重組文件內(nèi)容
const template = extendAst.querySelector('template').toString();
const script = pageAst.querySelector('script').toString();
const style = extendAst.querySelector('style').toString() + pageAst.querySelector('style').toString()
return`${template}${script}${style}`
}
}
module.exports = Extend;
好的,自定義loader已經(jīng)編寫(xiě)完成,在vue.config.js里面配置好我們的loader
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
configureWebpack: {
module: {
rules: [
{
test: /\.vue$/,
use: [
{
loader: require.resolve('./src/loader'),
},
],
},
],
},
},
})
接下來(lái)我們嘗試編寫(xiě)A頁(yè)面和B頁(yè)面:
A.vue:
<template>
<div class="template">
<div id="div_1" class="div">父頁(yè)面的div_1</div>
<div id="div_2" class="div">父頁(yè)面的div_2</div>
<div id="div_3" class="div">父頁(yè)面的div_3</div>
<div id="div_4" class="div">父頁(yè)面的div_4</div>
<div id="div_5" class="div">父頁(yè)面的div_5</div>
<div id="div_6" class="div">父頁(yè)面的div_6</div>
<div id="div_7" class="div">父頁(yè)面的div_7</div>
<div id="div_8" class="div">父頁(yè)面的div_8</div>
</div>
</template>
<script>
export default {
name: 'COM_A',
props: {
msg: String
}
}
</script>
<style scoped>
.div {
color: #42b983;
font-size: 1.5em;
margin: 0.5em;
padding: 0.5em;
border: 2px solid #42b983;
border-radius: 0.2em;
}
</style>
B.vue:
<template extend="./A.vue">
<div>
<extend type="insert" target="#div_1" position="after">
<div id="div_child" class="div">子頁(yè)面的div_5</div>
</extend>
<extend type="append" target="#div_3" position="2">
<a> 子頁(yè)面通過(guò)append插入的超鏈接 </a>
</extend>
</div>
</template>
<script>
import A from './A.vue'
export default {
name: 'COM_B',
extends: A,//繼承業(yè)務(wù)邏輯代碼
props: {
msg: String
}
}
</script>
<style scoped>
#div_child {
color: #d68924;
font-size: 1.5em;
margin: 0.5em;
padding: 0.5em;
border: 2px solid #d68924;
}
a {
color: blue;
font-size: 0.7em;
}
</style>
我們?cè)贏pp.vue下引入B.vue
<template>
<div id="app">
<B/>
</div>
</template>
<script>
import B from './components/B.vue'
export default {
name: 'App',
components: {
B
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
當(dāng)我們執(zhí)行編譯的時(shí)候,實(shí)際上B.vue的編譯結(jié)果如下:
<template>
<div class="template">
<div id="div_1" class="div">父頁(yè)面的div_1</div>
<div id="div_child" class="div">子頁(yè)面的div_5</div>
<div id="div_2" class="div">父頁(yè)面的div_2</div>
<div id="div_3" class="div">
父頁(yè)面的div_3
<a> 子頁(yè)面通過(guò)append插入的超鏈接 </a>
</div>
<div id="div_4" class="div">父頁(yè)面的div_4</div>
<div id="div_5" class="div">父頁(yè)面的div_5</div>
<div id="div_6" class="div">父頁(yè)面的div_6</div>
<div id="div_7" class="div">父頁(yè)面的div_7</div>
<div id="div_8" class="div">父頁(yè)面的div_8</div>
</div>
</template>
<script>
import A from './A.vue'
export default {
name: 'COM_B',
extends: A,//繼承業(yè)務(wù)邏輯代碼
props: {
msg: String
}
}
</script>
<style scoped>
.div {
color: #42b983;
font-size: 1.5em;
margin: 0.5em;
padding: 0.5em;
border: 2px solid #42b983;
border-radius: 0.2em;
}
</style>
<style scoped>
#div_child {
color: #d68924;
font-size: 1.5em;
margin: 0.5em;
padding: 0.5em;
border: 2px solid #d68924;
}
a {
color: blue;
font-size: 0.7em;
}
</style>
注意我們?cè)贐.vue使用了extends繼承了組件A,這里是為了能復(fù)用業(yè)務(wù)邏輯代碼,最后我們運(yùn)行代碼,頁(yè)面輸出為:
在真實(shí)的項(xiàng)目當(dāng)中,我們遇到大量重復(fù)的頁(yè)面但是又有小區(qū)別的頁(yè)面,是可以通過(guò)這種方式減少我們的代碼量,當(dāng)然也許有更好的辦法,也希望大伙能提出寶貴的建議。
最后引用一下 @XivLaw 老哥的評(píng)論:有很多人說(shuō)通過(guò)cv就能解決,但是當(dāng)你的業(yè)務(wù)有成千上萬(wàn)個(gè)頁(yè)面是趨同,并且具有相同的基本功能,當(dāng)界面需要統(tǒng)一調(diào)整或者需要進(jìn)行ui統(tǒng)一管控的時(shí)候,cv就成了你的累贅了。 也有朋友說(shuō)通過(guò)組件化和插槽解決,組件化是一個(gè)不錯(cuò)的方案,但是當(dāng)成千上萬(wàn)個(gè)趨同的界面存在時(shí),插槽并一定能覆蓋所有的業(yè)務(wù)定制化。 使不使用這種方式,主要看你的業(yè)務(wù)。
直白一點(diǎn)說(shuō)就是:我現(xiàn)在有一千個(gè)頁(yè)面幾乎一樣,有的頁(yè)面是頭部多一點(diǎn)東西,有的是底部,有的是某個(gè)按鈕旁邊多一個(gè)按鈕,有的是輸入框之間多個(gè)輸入框,ui或者界面或者同時(shí)需要添加固定功能,需要調(diào)整的時(shí)候,這一千個(gè)頁(yè)面要怎么調(diào)?
作者:小小小小_柏
鏈接:https://juejin.cn/post/7347973138787467274
于經(jīng)常需要處理PDF文件的用戶來(lái)說(shuō),合并多個(gè)PDF文件是一項(xiàng)重要且經(jīng)常使用的操作技能。為了更好地保存、管理和使用這些文件,他們希望能夠很容易地將多個(gè)PDF文件合并成一個(gè)。同時(shí),他們也希望合并后的PDF文件能夠方便地發(fā)送給他人,從而提高工作效率。本期我們將分享幾種合并PDF的方法。讓我們來(lái)看看。
方法1、另存功能
PDF文件是我們工作和生活中常見(jiàn)的文件格式。有時(shí),為了便于管理和共享,我們需要將多個(gè)PDF文件合并成一個(gè)文件。如果目前需要合并的PDF文件數(shù)量很大,比如只有5個(gè)以內(nèi),那么此時(shí)可以使用辦公內(nèi)置的另存功能來(lái)完成。也就是說(shuō),使用Word文檔依次打開(kāi)需要合并的PDF文件,在頂部的“文件”菜單中找到“另存為”的選項(xiàng),另存為“.pdf“格式就可以了。
方法2、手工編輯
如果需要同時(shí)引用或處理多個(gè)PDF文件,可以節(jié)省重復(fù)操作步驟。無(wú)需多次打開(kāi)、關(guān)閉或復(fù)制粘貼文件,可以提高工作效率,降低操作失誤的可能性。通過(guò)將多個(gè)PDF文件合并成一個(gè)文件,可以減少文件的數(shù)量,從而減少存儲(chǔ)空間的占用。特別是對(duì)于大量的小文件,合并后可以節(jié)省寶貴的磁盤空間。同樣,如果需要合并的PDF文件數(shù)量較少,可以選擇專門的編輯器,將所需內(nèi)容復(fù)制到一個(gè)文件中,以滿足合并要求。
方法3、高效率軟件合并文件
假如目前你需要合并大量的PDF文件,并且對(duì)合并文件有很高的要求,那么在這個(gè)時(shí)候選擇一個(gè)高效率的軟件進(jìn)行操作,這是目前最好的方法。舉例來(lái)說(shuō),啟源PDF轉(zhuǎn)換器軟件,它是一個(gè)專業(yè)的PDF處理軟件,提供了一個(gè)簡(jiǎn)單快捷的PDF合并功能。在合并PDF文件時(shí),您可以很容易地將多個(gè)PDF文件合并為一個(gè)整體,從而解決您的煩惱。
軟件的操作方法比較簡(jiǎn)單,只需直接在計(jì)算機(jī)上啟動(dòng)“啟源PDF轉(zhuǎn)換”軟件,在界面上選擇“PDF合并”功能,然后添加需要合并的PDF文件。您可以通過(guò)拖動(dòng)或點(diǎn)擊按鈕上傳文件,并調(diào)整文件的順序和頁(yè)面設(shè)置。所有設(shè)置完成后,只需點(diǎn)擊“開(kāi)始合并”按鈕,這些PDF文件就會(huì)很快合并成一個(gè)整體。
方法4、在線平臺(tái)合并文件
除了上面分享的三種方法外,如果您想在計(jì)算機(jī)上合并PDF文件,還可以選擇一些在線平臺(tái)進(jìn)行操作,例如iLovePDF工具。這是一個(gè)國(guó)外的PDF在線解決方案,其合并文件的效果也挺不錯(cuò)。您可以在計(jì)算機(jī)上打開(kāi)平臺(tái)網(wǎng)頁(yè),選擇對(duì)應(yīng)的功能,并批量添加需要合并的PDF文件。點(diǎn)擊“開(kāi)始合并”解決問(wèn)題。
關(guān)于如何將PDF文件合并的方法,小編就與大家分享到這里了,希望對(duì)大家有所幫助。
備好獎(jiǎng)狀的獲獎(jiǎng)名作為:Word獎(jiǎng)狀模板的數(shù)據(jù)源(含表頭-表格模板對(duì)應(yīng)的信息)哦!如:
打開(kāi)word制作好需要制作的獎(jiǎng)狀模板-郵件選項(xiàng)卡-選擇收件人-選擇使用現(xiàn)有列表-插入合并域(表頭中對(duì)應(yīng)的內(nèi)容)-預(yù)覽結(jié)果-完全并合并-保存-打印就可以批量制作啦 !!!
該功能還可以和郵箱聯(lián)合使用用于批量相同格式不同填充內(nèi)容的信息發(fā)放哦——比如offer發(fā)放等:大致步驟如下(暫時(shí)沒(méi)有示例。下次有了更新上)
還是先將word中的offer格式調(diào)整好(注意offer發(fā)放中不同人的姓名,薪資待遇等方面要做到帶表頭的數(shù)據(jù)表格中)-郵件-選擇收件人使用現(xiàn)有列表-編輯域-預(yù)覽-完成并合并中郵件-郵件(郵箱配合outlook使用,html格式就是word中看見(jiàn)的,附件是作為郵件附件發(fā)送)-需要在outlook郵箱顯示-outlook設(shè)為默認(rèn)的郵箱發(fā)送
*請(qǐng)認(rèn)真填寫(xiě)需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。