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 国产一级视频在线,亚洲激情欧美,91款禁用软件永久无限大全

          整合營銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          5個(gè)不常提及的HTML技巧

          021年你需要知道的HTML標(biāo)簽和屬性

          Web開發(fā)人員都在廣泛的使用HTML。無論你使用什么框架或者選擇哪個(gè)后端語言,框架在變,但是HTML始終如一。盡管被廣泛使用,但還是有一些標(biāo)簽或者屬性是大部分開發(fā)者不熟知的。雖然現(xiàn)在有很多的模版引擎供我們使用,但是樂字節(jié)教育的老師和我們說還是需要盡可能的熟練掌握HTML內(nèi)容,就像CSS一樣。

          在我看來,最好盡可能使用HTML特性來實(shí)現(xiàn)我們的功能,而不是使用JavaScript實(shí)現(xiàn)相同的功能,盡管我承認(rèn)編寫HTML可能會(huì)是重復(fù)的和無聊的。

          盡管許多開發(fā)人員每天都在使用HTML,但他們并沒有嘗試改進(jìn)自己的項(xiàng)目,也沒有真正利用HTML的一些鮮為人知的特性。

          下面這5個(gè)通過HTML標(biāo)簽/屬性實(shí)現(xiàn)的功能我覺得需要了解一下:

          圖片懶加載

          圖片懶加載可以幫助提升網(wǎng)站的性能和響應(yīng)能力。圖片懶加載可以避免立即加載那些不在屏幕中立即顯示的圖片素材,當(dāng)用戶滾動(dòng)臨近圖片時(shí)再去開始加載。

          換言之,當(dāng)用戶滾動(dòng)到圖片出現(xiàn)時(shí)再進(jìn)行加載,否則不加載。這就降低了屏幕內(nèi)容展示過程中的圖片素材的請求數(shù)量,提升了站點(diǎn)性能。

          往往我們都是通過javascript來實(shí)現(xiàn)的,通過監(jiān)聽頁面滾動(dòng)事件來確定加載對應(yīng)的資源。但是,在不完全考慮兼容性的場景下,我們其實(shí)可以直接通過HTML來直接實(shí)現(xiàn)。

          注:本篇的提到的標(biāo)簽和屬性的兼容性需要大家根據(jù)實(shí)際場景來選取是否使用

          可以通過為圖片文件添加loading="lazy"的屬性來實(shí)現(xiàn):


          輸入提示

          當(dāng)用戶在進(jìn)行輸入搜索功能時(shí),如果能夠給出有效的提示,這會(huì)大大提升用戶體驗(yàn)。輸入建議和自動(dòng)完成功能現(xiàn)在到處可見,我們可以使用Javascript添加輸入建議,方法是在輸入框上設(shè)置事件偵聽器,然后將搜索到的關(guān)鍵詞與預(yù)定義的建議相匹配。

          其實(shí),HTML也是能夠讓我們來實(shí)現(xiàn)預(yù)定義輸入建議功能的,通過<datalist>標(biāo)簽來實(shí)現(xiàn)。需要注意的是,使用時(shí)這個(gè)標(biāo)簽的id屬性需要和input元素的list屬性一致。


          Picture標(biāo)簽

          你是否遇到過在不同場景或者不同尺寸的設(shè)備上面的時(shí)候,圖片展示適配問題呢?我想大家都遇到過。

          針對只有一個(gè)尺寸的圖片素材的時(shí)候,我們往往可以通過CSS的object-fit屬性來進(jìn)行裁切適配。但是有些時(shí)候需要針對不同的分辨率來顯示不同尺寸的圖片的場景的時(shí)候,我們是否可以直接通過HTML來實(shí)現(xiàn)呢?

          HTML提供了<picture>標(biāo)簽,允許我們來添加多張圖片資源,并且根據(jù)不同的分辨率需求來展示不同的圖片。


          我們可以定義不同區(qū)間的最小分辨率來確定圖片素材,這個(gè)標(biāo)簽的使用有些類似<audio>和<video>標(biāo)簽。

          Base URL

          當(dāng)我們的頁面有大量的錨點(diǎn)跳轉(zhuǎn)或者靜態(tài)資源加載時(shí),并且這些跳轉(zhuǎn)或者資源都在統(tǒng)一的域名的場景時(shí),我們可以通過<base>標(biāo)簽來簡化這個(gè)處理。

          例如,我們有一個(gè)列表需要跳轉(zhuǎn)到微博的不同大V的主頁,我們就可以通過設(shè)置來簡化跳轉(zhuǎn)路徑


          <base>標(biāo)記必須具有href和target屬性。

          頁面重定向(刷新)

          當(dāng)我們希望實(shí)現(xiàn)一段時(shí)間后或者是立即重定向到另一個(gè)頁面的功能時(shí),我們可以直接通過HTML來實(shí)現(xiàn)。

          我們經(jīng)常會(huì)遇到有些站點(diǎn)會(huì)有這樣一個(gè)功能,“5s后頁面將跳轉(zhuǎn)”。這個(gè)交互可以嵌入到HTML中,直接通過<meta>標(biāo)簽,設(shè)置http-equiv="refresh"來實(shí)現(xiàn)


          這里content屬性指定了重定向發(fā)生的秒數(shù)。值得一提的是,盡管谷歌聲稱這種形式的重定向和其他的重定向方式一樣可用,但是使用這種類型的重定向其實(shí)并不是那么的優(yōu)雅,往往會(huì)顯得很突兀。

          因此,最好在某些特殊的情況下使用它,比如在長時(shí)間用戶不活動(dòng)之后再重定向到目標(biāo)頁面。

          后記

          HTML和CSS是非常強(qiáng)大的,哪怕我們僅僅使用這兩種技術(shù)也能創(chuàng)建出一些奇妙的網(wǎng)站。雖然它們的使用量很大很普遍,還是有很多的開發(fā)者并沒有真正的深入了解他們,還有很多的內(nèi)容需要我們深入的去學(xué)習(xí)和理解,實(shí)踐,有很多的技巧等待著我們?nèi)グl(fā)現(xiàn)。

          文章轉(zhuǎn)載至樂字節(jié)

          最后給大家推薦幾個(gè)b站超詳細(xì)的Java自學(xué)課:

          Servlet入門教程BV1D5411373E

          Vue、Vuejs教程,BV19V41177od

          SpringBoot+Vue項(xiàng)目實(shí)戰(zhàn)BV1o64y117qQ

          iframe元素

          創(chuàng)建包含另外一個(gè)文檔的內(nèi)聯(lián)框架(即行內(nèi)框架)。

          CSS3規(guī)范,視口單位主要包括以下4個(gè):

          1、vw : 1vw 等于視口寬度的1%;

          2、vh : 1vh 等于視口高度的1%;

          3、vmin : 選取vw和vh中最小的那個(gè);

          4、vmax : 選取vw和vh中最大的那個(gè);

          100%高度和寬度:

          body {
              margin: 0; /* Reset default margin */
          }
          iframe {
              display: block;  /* iframes are inline by default */
              background: #fff;
              border: none;   /* Reset default border */
              height: 100vh;   /* Viewport-relative units */
              width: 100vw;
          }

          參考代碼

          HTML中嵌入iframe

          <!DOCTYPE html>
          <html lang="zh-CN">
          <head>
          	<title>XXXX調(diào)查表</title>
              <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
          	<style type="text/css">
          		body html{
          			margin:0;
          			padding:0;
          		}
          		#app{
          			margin: 0 auto;
          			width: 600px;
          		}
          		iframe {
          			display: block; 
          			background: #FFF;
          			border: none; 
          			width:100vw;  /* Viewport-relative units */
          			height:100vh;
          			width:100%;
          		}
          	</style>
          </head>
          <body>
          	<div id="app">
          		<div>
          			<button type="button"><span>返回</span></button>
          			<button type="button" onclick="print()"><span>打印</span></button>
          		</div>
          		<h2>公司部門調(diào)查表</h2>
          		<iframe src="C:/Users/dd/Desktop/003.html" scrolling="no"></iframe>
          	</div>
          </html>

          被嵌入頁面:

          <!doctype html>
          <html lang="zh-CN">
          <head>
          	<title>XXXX調(diào)查表</title>
              <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
          	<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
          	<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
          	<link href="https://cdn.bootcdn.net/ajax/libs/antd/4.18.2/antd.variable.css" rel="stylesheet">
          	<!--
          		https://v1-cn.vuejs.org/guide/forms.html
          	-->
          </head>
          <body>
          	<div id="app">
          		<p><h2>公司部門調(diào)查表</h2></p>
          		<form v-model="form" v-on:submit.prevent="saved()" >
          			<fieldset>
          				<legend>職員信息</legend>
          				<ol>
          					<li>
          						<label>姓名: </label>
          						<input v-model="form.name" type="text" name="name" autofocus/>
          					</li>
          					<li>
          						<label>年齡: </label>
          						<input v-model="form.age" type="number" name="age" />
          					</li>
          					<li>
          						<label>性別:</label>
          						<input v-model="form.sex" type="radio" name="sex" value="未知" />未知 
          						<input v-model="form.sex" type="radio" name="sex" value="男" />男 
          						<input v-model="form.sex" type="radio" name="sex" value="女" />女
          					</li>
          					<li>
          						<label>籍貫:</label>
          						<select v-model="form.nativePlace">
          							<optgroup label="山西省">
          								<option>太原市</option>
          							</optgroup>
          							<optgroup label="北京">
          								<option>北京市</option>
          							</optgroup>
          						</select>
          					</li>
          					<li>
          						<label>愛好:</label>
          						<input v-model='form.hobbys' type="checkbox" name="hobby" value="爬山" />爬山 
          						<input v-model='form.hobbys' type="checkbox" name="hobby" value="涉水" />涉水 
          						<input v-model='form.hobbys' type="checkbox" name="hobby" value="下棋" />下棋 
          						<input v-model='form.hobbys' type="checkbox" name="hobby" value="游戲" />游戲 
          					</li>
          					<li>
          						<label>所在部門:</label>
          						<select v-model="form.department">
          							<option v-for="(item, index) in form.departments" :key="item">{{item}}</option>
          						</select>
          					</li>
          					<li>
          						<label>職位:</label>
          						<input v-model="form.title" type="text" name="title" />
          					</li>
          					<li>
          						<label>提交建議:</label>
          						<input v-model="form.advise" type="file" name="form.advise" />
          					</li>
          					<li>
          						<label>填表日期:</label>
          						<input v-model="form.fillDate" type="date" name="fillDate">
          					</li>
          				</ol>
          			</fieldset>
          			<fieldset>
          				<legend>反饋意見</legend>
          				<ol>
          					<li>
          						<label>你對公司目前的發(fā)展表示:</label>
          						<input v-model="form.development" type="radio" name="development" value="滿意"  /> 滿意  
          						<input v-model="form.development" type="radio" name="development" value="不滿意"  /> 不滿意  
          						<input v-model="form.development" type="radio" name="development" value="一般"  /> 一般
          					</li>
          					<li>
          						<label>你對公司的任職崗位表示:</label>
          						<input v-model="form.jobIdentification" type="radio" name="jobIdentification" value="認(rèn)同"  /> 認(rèn)同  
          						<input v-model="form.jobIdentification" type="radio" name="jobIdentification" value="不認(rèn)同"  /> 不認(rèn)同  
          						<input v-model="form.jobIdentification" type="radio" name="jobIdentification" value="一般"  /> 一般
          					</li>
          					<li>
          						<label>你對公司的期望: </label> <br />
          						<textarea v-model="form.expect" rows="4" name="neme" cols="50"></textarea>
          					</li>
          				</ol>
          			</fieldset>
          			<input type="submit" value="提交">
          			<input type="reset" value="重置">
          		</form>
          	</div>
          	<script>
          		var now = new Date();
          		var year = now.getFullYear();
          		var month = now.getMonth()+1;
          		var day = now.getDay();
          		// 
          		var app = new Vue({
          			el: '#app',
          			data() {
          				return {
          					form: {
          						name:"孔子",
          						age: 2000,
          						sex: "男",
          						nativePlace: "北京市",
          						hobbys: ["爬山","下棋"],
          						departments: ["財(cái)務(wù)部","法務(wù)部","加盟部","商務(wù)部","技術(shù)部"],
          						department: "技術(shù)部",
          						title: "工程師",
          						fillDate: year + "-" + month + "-" + day,
          						development: "一般",
          						jobIdentification: "不認(rèn)同",
          						expect: "一切都美好~"
          					}
          				}
          			},
          			methods:{
          				saved(){
          					alert(JSON.stringify(this.form));
          					axios.post('http://192.168.1.116:8080/data/post',this.form,{
          						headers: { "token": "token123" }
          					}).then(res => {
          						console.log("result", JSON.stringify(res.data));
          					})
          				}
          				
          			}
          		});
          	</script>
          </html>

          VUE中嵌入:

          不管的后端還是前端表單的使用率是極高的,但風(fēng)格和團(tuán)隊(duì)之間個(gè)人的編寫風(fēng)格各異,尤其的多條件,多規(guī)則,大量表單頁面,維護(hù)和保持統(tǒng)一編寫就變的比較困難,之前使用vue2版本的框架的時(shí)候基于之前低代碼開發(fā)的經(jīng)驗(yàn)編寫了一套 基于json描述生成的 表單組件,vue版本升級到vue3之后自然也需要一套與之相匹配的,簡單易用的表單組件。

          凡事都有前置條件,因?yàn)闃I(yè)務(wù)的需要,后臺系統(tǒng)使用微前端的qiankun框架,但比較可惜的是vite尚不被qiankun支持,當(dāng)然也有一些 相應(yīng)的插件可以解決這個(gè)問題,但考慮到其非官方產(chǎn)品,企業(yè)從穩(wěn)定性出發(fā)排除了vite

          所以下面我講到的 組件是基于 vue3+typscript+webpack+elementulplus來進(jìn)行二次封裝實(shí)現(xiàn)的。


          組件的目標(biāo)

          我們要做的組件就是為了簡潔,可維護(hù),可擴(kuò)展 ,使用者不需要了解組件的內(nèi)部實(shí)現(xiàn),僅需要按照組件的配置要求進(jìn)行配置即可實(shí)現(xiàn)功能,當(dāng)然我們要盡可能的滿足需求,但覺不是100%滿足,其實(shí)一個(gè)優(yōu)秀的組件能夠完成業(yè)務(wù)的80%的需求已經(jīng)非常了不起了。在進(jìn)行通用組件設(shè)計(jì)的時(shí)候切記不可大而全,如果一個(gè)組件使用的學(xué)習(xí)成本較高,基本也失去了封裝的意義。當(dāng)然框架除外,比如vue

          我的的目標(biāo)是:

          1. 通過配置 json 并把json做為 props 傳遞給組件,
          2. 組件自動(dòng)生成基于elementUIplus的 表單
          3. 組件包含elementUiPlus實(shí)現(xiàn)的所有表單功能
          4. 組件支持部分自定義組件的插入,比如某個(gè)input框下面需要加一個(gè)相應(yīng)的文字說明或者其他什么的
          5. 組件支持所有elemnetUIPlus提供的屬性 比如 size、disabled lable...
          6. 組件表單的提交和情況
          7. 組件的初始化或反顯的實(shí)現(xiàn)
          8. 組件提交方法的自定義
          9. 內(nèi)置基于業(yè)務(wù)的表單判斷邏輯,比如 手機(jī)號,身份證,地址,上傳,等或其他一些基于企業(yè)內(nèi)部的邏輯,通過特定參數(shù)直接進(jìn)行實(shí)現(xiàn)
          10. 樣式的靈活配置。


          組件的結(jié)構(gòu)設(shè)計(jì)

          我們的設(shè)計(jì)結(jié)構(gòu)是

          module:

          module是我們組成表單的一個(gè)個(gè)的最小的自定義組件單元,。其實(shí)modle也可以不存在,直接在render函數(shù)里使用 elementUIplus里定義好的組件,這又是另一個(gè)話題了,這里我們使用自定義組件也是為了方便自定義和擴(kuò)展。

          data:

          data是一種json格式的數(shù)據(jù)結(jié)構(gòu),用來對模塊進(jìn)行描述,(低代碼平臺的實(shí)現(xiàn)本質(zhì)上也是如此。通過拖拽或其他方式對數(shù)據(jù)進(jìn)行拼裝然后展示)

          render:

          render 層是 vue3框架提供的 render函數(shù),結(jié)合h()實(shí)現(xiàn)VirtualDom的的渲染,因?yàn)槭莌()是創(chuàng)建虛擬 DOM 節(jié)點(diǎn) (vnode)的方法,因此不存在性能問題,在實(shí)現(xiàn)上和正常寫法沒有區(qū)別。

          view:

          view 做為展示層 及我們展示的頁面。

          data層 json的數(shù)據(jù)格式設(shè)計(jì)

          elementuiplus 的form組件數(shù)據(jù)層面需要傳遞兩組數(shù)據(jù)(需要提交的數(shù)據(jù)和校驗(yàn)規(guī)則)

          數(shù)據(jù)和規(guī)則分離并不合理,所以在這里我們在json里把 需要校驗(yàn)的數(shù)據(jù)和校驗(yàn)規(guī)則放在一組里。

          {
                  blockName: "Input",
                  attrsData: {
                      type: "text",
                      field: "name",
                      label: "姓名",
                      placeholder: "Please input name",
                      maxlength: 20,
                      minlength: 1,
                      showWordLimit: true,
                      clearable: true,
                      disabled: false,
                      inputStyle: { color: "red"
                      },
                      initValue:'666'
                  },
                  rule: [
                      {
                          required: true,
                          message: "Please input Activity name",
                          trigger: "blur",
                      },
                      { min: 3, max: 5, message: "Length should be 3 to 5", trigger: "blur"
                      },
                  ]
              }

          數(shù)據(jù)有三部分,即 blockName(組件名稱),attrsData(組件屬性的描述),rule(校驗(yàn)規(guī)則)


          module層組件的實(shí)現(xiàn)

          <template>
              <el-input
                  :placeholder="placeholder"
                  :maxlength="maxlength"
                  :minlength="minlength"
                  :clearable="clearable"
                  :require="require"
                  :name="name"
                  :formatter="formatter"
                  :show-password="showPassword"
                  :parser="parser"
                  :prefix-icon="prefixIcon"
                  :input-Style="inputStyle"
                  v-model="value"
              />
          </template>
          
          <script lang="ts">
          import { useGetAttrsHook } from "../hooks/common.hook";
          export default {
              setup(props, context) {
                  const {
                      clearValue,
                      test,
                      value,
                      placeholder,
                      maxlength,
                      minlength,
                      clearable,
                      formatter,
                      showPassword,
                      parser,
                      require,
                      options,
                      name,
                      field,
                      clear,
                      prefixIcon,
                      activeText,
                      inactiveText,
                  } = useGetAttrsHook(props, context);
                  return {
                      clearValue,
                      test,
                      value,
                  };
              },
          };
          </script>


          以上面的代碼為例,在組件里我們使用elemnetUIplus提供的 表單組件。并把相應(yīng)的 屬性進(jìn)行了綁定,除了value其他屬性都只需要進(jìn)行正常的 attrs 傳遞即可,value則需要實(shí)現(xiàn)數(shù)據(jù)的雙向綁定,并在我們點(diǎn)擊父組件的提交按鈕時(shí)傳遞給父組件進(jìn)行提交,所以在這里就需要做一些特別的處理。來實(shí)現(xiàn)數(shù)據(jù)雙向傳遞,注意是雙向傳遞。如果不自定義組件也可以在 h函數(shù)渲染的時(shí)候直接使用 elementUIplus提供的組件,省去這一步。但雙向綁定需要想辦法實(shí)現(xiàn),并且靈活性也差一些。不能在組件里定義一些自己的邏輯和樣式。


          數(shù)據(jù)的雙向傳遞實(shí)現(xiàn)方案:

          我們知道組件上使用v-model實(shí)現(xiàn)組件上的雙向綁定,如果是常規(guī)寫法自然沒有問題,但很遺憾我們的render 是不走尋常路的.先看下vue3的文檔的實(shí)現(xiàn)方式

          https://cn.vuejs.org/guide/components/v-model.html

          通過文檔我們知道 v-model 實(shí)際上就是一個(gè)語法糖,他的本來面目是這樣的

          <CustomInput

          :modelValue="searchText"

          @update:modelValue="newValue=>searchText = newValue"

          />

          對于我們來說這仍然是常規(guī)寫法,因?yàn)樵趆()里面這樣是行不通的。那么在h()中的寫法應(yīng)該是這樣的

          h(ASwitch, {
              modelValue: this.value,
              ["onUpdate:modelValue"]: (data) => {
                this.value = data;
              },
          });

          如果監(jiān)聽的是一個(gè)原生的input這個(gè)寫法是生效的,但可惜在我寫的的組件上并不好使。之所以在本文中寫出來是給大家一個(gè)參考或者各位有人發(fā)現(xiàn)我的錯(cuò)誤之處,可以有實(shí)現(xiàn)。

          那么還有什么方式實(shí)現(xiàn)數(shù)據(jù)的雙向傳遞呢,那就是 子組件調(diào)用父組件方法,父組件調(diào)用子組件方法,并互相進(jìn)行數(shù)據(jù)傳遞了。

          那么在vue3 中我們只能這樣去進(jìn)行實(shí)現(xiàn)了,我們先談下子組件調(diào)用父組件的方法。

          https://cn.vuejs.org/guide/components/events.html

          <createForm
            :data="fromData"
            :ruleForm="ruleForm"
            @setData="setData"
            ref="childComp"
            :reset="reset.type"
          />

          父組件通過@綁定一個(gè)方法到子組件,子組件通過使用 defineEmits()宏來聲明它要觸發(fā)的事件,然后通過emit('方法名',入?yún)?來實(shí)現(xiàn)父組件的調(diào)用。明白了這個(gè)概念就可以了,因?yàn)橹笪覀冃枰趆()上來實(shí)現(xiàn)這樣的一個(gè)功能。

          還有就是我們需要另一個(gè)功能就是父組件傳遞一個(gè)指令給子組件,子組件監(jiān)聽到命令后,執(zhí)行自己的一個(gè)方法,用來清空自己的 value 也就是組件上傳遞的屬性 :reset="reset.type" 所有子組件如果監(jiān)聽到父組件這個(gè)值的變化就清空value。

          其實(shí)除了傳遞指令還有另一個(gè)方法就是父組件調(diào)用子組件的內(nèi)的清除value的方法,但vue3父組件掉子組件的方法,因?yàn)樯婕暗絩ef的綁定 如果在h函數(shù)里實(shí)現(xiàn)比較麻煩,我沒有實(shí)現(xiàn)。有興趣的同學(xué)可以嘗試一下。


          vue3渲染函數(shù)(h函數(shù))的變化:

          vue3 h函數(shù)的寫法與vue2 有很大不同,在學(xué)習(xí) render函數(shù)的實(shí)現(xiàn)之前我們需要對 h函數(shù)的變化有所了解。

          • h 現(xiàn)在全局導(dǎo)入,而不是作為參數(shù)傳遞給渲染函數(shù)
          • 渲染函數(shù)參數(shù)更改為在有狀態(tài)組件和函數(shù)組件之間更加一致
          • vnode 現(xiàn)在有一個(gè)扁平的 prop 結(jié)構(gòu)


          vue2 props 格式化語法

          {

          class: ['button', 'is-outlined'],

          style: { color: '#34495E' },

          attrs: { id: 'submit' },

          domProps: { innerHTML: '' },

          on: { click: submitForm },

          key: 'submit-button'

          }



          vue3 props格式化語法

          {

          class: ['button', 'is-outlined'],

          style: { color: '#34495E' },

          //屬性不需要放在 attrs domProps on這些字段下了。

          id: 'submit',

          innerHTML: '',

          onClick: submitForm,

          key: 'submit-button'

          }

          我們可以看到vue3 渲染函數(shù)的屬性更加的扁平化,一些屬性不需要在包含在對應(yīng)的字段里了。我個(gè)人覺的之前的更加嚴(yán)謹(jǐn)。僅個(gè)人觀點(diǎn)。

          render函數(shù)的實(shí)現(xiàn):

          了解了渲染函數(shù)的變化我們來看下渲染方法的實(shí)現(xiàn) ,先看代碼。


          import {h,ref} from 'vue'
          import CreateBlock from './createBlock';
          import { ElFormItem} from 'element-plus';
          const renderConfig =(h, data,func,reset)=> {
              if (!data) { return console.error('no data'); }
              return h(ElFormItem, { label: data.attrsData.label, prop: data.attrsData.field }, [h(CreateBlock, {
                  ...data, clear: reset,['onSetData']:(data) => { 
                      func(data)
              } })])
          }
          
          
          export default {
              props:{
                  data: {
                      type: Array,
                      default() {
                          return [];
                      },
                  },
                  reset: {
                      type: Number,
                      default() { 
                          return 0
                      }
                  }
              },
              setup(props, context) {
                  // const list = props.data
                  const blockFunc = (data) => { 
                      // console.log('傳入的data',data)
                      context.emit('setData', data)
                  }
                  return {
                      blockFunc
                  }
              },
              render(cxt) { 
                  const list = cxt.data
                  const reset = cxt.reset
                  const childNodes = list.map((n) => renderConfig(h, n,cxt.blockFunc,reset));
                      const result = h('div',childNodes);
                      return result;
              }
          }

          createFrom.ts 做了三件事,1,接受到了父組件傳遞過來的數(shù)據(jù),2,根據(jù)傳過來的json遍歷渲染 子組件

          3.把接受到的屬性,方法,和 組件名稱 傳遞給子組件


          CreateBlock 會(huì)根據(jù)json的blackName返回相應(yīng)的組件,所以我們渲染處理的組件不順序不會(huì)有問題

          setup 函數(shù)里的context.emit('setData', data) 用來實(shí)現(xiàn)子組件向父組件傳遞數(shù)據(jù)

          renderConfig 函數(shù)里的 clear: reset 屬性則是父組件向子組件傳遞清除命令的


          整體邏輯如下;

          1.render 接收到 json數(shù)據(jù) 然后循環(huán)調(diào)用 renderConfig 函數(shù)

          2.renderConfig函數(shù) 給每個(gè)子組件外層包裹了 ElFormItem 并給ElFormItem提供了相應(yīng)的屬性如 label,prop

          3.renderConfig函數(shù)把json遍歷到的每條數(shù)據(jù)都通過 props 傳遞給了createBlock 同時(shí)給每個(gè)子組件綁定了setdata函數(shù),注意這里要用onsetData


          createBlock函數(shù)子組件渲染的實(shí)現(xiàn):

          import { h,toRefs } from 'vue'
          export default {
              setup(props, context) { 
                  const newMap: Array<object> = [];
                  try {
                      const elObj = require.context("../module", true, /\.vue$/);
                      elObj.keys().forEach((key) => {
                          const blockName = key.split("/")[1].split('.')[0];
                          const el = elObj(key).default;
                          if (!el) return;
                          newMap[blockName] = el;
                      });
                  } catch (error) {
                      console.log(error);
                  }
                  const block = newMap[context.attrs.blockName + 'Block'];
                  const attrsData = { ...context.attrs.attrsData };
                  const func = (data) => {
                      context.emit('SetData', data)
                  }
                  const getAttrs = ()=>{ 
                      return { ...context.attrs }
                  }
                  return {
                      block,
                      attrsData,
                      func,
                      getAttrs
                  }
              },
              render(cxt) { 
                  const { clear } = cxt.getAttrs()
                  return h(cxt.block, { ...cxt.attrsData,clear,['onsetData']: cxt.func})
              }
          }

          可以看到我們使用 require.context("../module", true, /\.vue$/); 來獲取 module文件夾下的所以組件,并按文件名稱轉(zhuǎn)換成數(shù)組和對應(yīng)的引用地址,存放在newMap變量里。然后使用 context.attrs.blockName獲取 父組件傳遞過來的屬性 “blockName” 找到我們需要的子組件宣傳出來。是不是很簡單。


          子組件的實(shí)現(xiàn)有很多通用方法 common.hook.ts

          import {
              toRefs,
              toRef,
              ref,
              useAttrs,
              reactive,
              watch,
              onMounted,
              watchEffect,
          } from "vue";
          
          /* eslint-disable */
          
          export const useGetAttrsHook = (props, context) => { 
              
                      const {
                          placeholder,
                          maxlength,
                          minlength,
                          clearable,
                          formatter,
                          showPassword,
                          parser,
                          require,
                          options,
                          name,
                          field,
                          clear,
                          prefixIcon,
                          initValue,
                          activeText,
                          inactiveText,
                      } = context.attrs;
              
                      let value = ref(initValue);
                      console.log("value---555", options);
                      watchEffect(() => {
                          let data = {};
                          if (typeof field === "string") {
                              data[field] = value.value;
                          }
                          context.emit("setData", data);
                      });
                      watch(
                          () => props.clear,
                          (newValue, oldValue) => {
                              console.log("oldValue, newValue--", newValue, oldValue);
                              if (newValue == 1) {
                                  clearValue();
                              }
                          }
                      );
                      const test = ref("ok");
                      const clearValue = () => {
                          value.value = "";
                      };
                      return {
                          clearValue,
                          test,
                          value,
                          placeholder,
                          maxlength,
                          minlength,
                          clearable,
                          formatter,
                          showPassword,
                          parser,
                          require,
                          options,
                          name,
                          field,
                          clear,
                          initValue,
                          prefixIcon,
                          activeText,
                          inactiveText
                      };
              
          }
          
          /* eslint-enable */


          最后一起看下實(shí)現(xiàn)的效果

          最后

          目前暴露的數(shù)據(jù)和接口比較多,還做進(jìn)一步的封裝和優(yōu)化。


          主站蜘蛛池模板: 一区二区三区在线观看中文字幕| 韩国一区二区三区| 日韩精品免费一区二区三区 | 一区二区三区视频网站| 国产经典一区二区三区蜜芽| a级午夜毛片免费一区二区| 日韩一区二区精品观看| 亚洲一区二区三区丝袜| 一区二区三区亚洲| 无码囯产精品一区二区免费| 中文字幕一区在线观看| 国产精品 一区 在线| 视频在线观看一区| 高清在线一区二区| 国产一区二区三区国产精品| 日本一区二区三区在线看| 国产SUV精品一区二区四| 精品少妇人妻AV一区二区| 99久久精品日本一区二区免费| 日韩精品无码中文字幕一区二区| 日韩精品无码视频一区二区蜜桃| 中文字幕日本一区| 一区二区三区无码视频免费福利| 国产亚洲日韩一区二区三区| 99精品久久精品一区二区| 国产裸体歌舞一区二区 | 日本一区二区三区中文字幕| 濑亚美莉在线视频一区| 国产精品无码一区二区三区在 | 亚洲午夜精品一区二区| 亚洲日韩激情无码一区| 久久久久人妻精品一区蜜桃| 精品黑人一区二区三区| 亚洲AV无码片一区二区三区| 波多野结衣电影区一区二区三区 | 国产综合视频在线观看一区 | 国产精品视频一区二区猎奇| 亚洲日韩中文字幕一区| 精品91一区二区三区| 熟女大屁股白浆一区二区| 日本内射精品一区二区视频|