整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          Jest直通車- react表單上傳

          明:本篇測試是react+jest+@testing-library+react-router-dom+react-redux,如果react有疑問的,可以google,資源Supernumerary

          我們已經講完了表單內容,那么現場來一個案例試試水~

          表單上傳

          這里完成的任務主要是將以上所講內容進行整合,同時發起一次api請求。

          首先我們在express/index.js中加入一個post請求:

          ...
          import bodyparser from 'body-parser';
          // 解析body
          app.use(bodyparser.urlencoded({extended:false}));
          
          app.post('/home',(req,res) => {
            const body = req.body;
            console.log(body);
            res.send({
              status: 0,
              msg: 'submit success'
            })
          })

          如果您不知道為啥這里突然加了一個借口,建議回顧一下我當時項目搭建的過程:
          https://www.toutiao.com/article/7250691387551826432/

          接著新建網絡請求api/detail.ts文件

          import axios from "axios";
          const commonUrl = '/api';
          interface Obj {
              username: string,
              age: string,
              email: string,
              city: string,
              like: string,
              isLike: boolean
          }
          
          export const submitData = async (data: Obj) => {
              const path = commonUrl + '/home';
              const res = await axios.post<any>(
                  path,
                  {...data},
                  {
                      headers: {
                          'Content-Type':  'application/x-www-form-urlencoded'
                      }
                  }
              );
              return res.data
          }

          然后我們寫一個組件page/detail/Com/submit.tsx

          import React,{useEffect,useState} from "react";
          import {
              Grid,
              styled,
              Box,
              MenuItem,
              Button
          } from '@mui/material';
          
          import ZlInput from "src/component/common/Input";
          import RadioButtonsGroup from "src/component/common/radioGroup";
          import Zl_checkbox from "src/component/common/checkbox";
          
          import { submitData } from "../../../api/detail";
          
          const ItemStyle = styled('div')({
              [`& .MuiFormControl-root `]: {
                  verticalAlign: 'bottom',
                  marginLeft: '20px'
              },
              [`& span`]: {
                  display: 'inline-block',
                  width: '80px',
                  textAlign: 'right'
              },
              width: '100%'
          })
          
          const RadioStyle = styled('div')({
              display: 'flex',
              alignItems: 'center',
              [`& .MuiFormControl-root `]: {
                  verticalAlign: 'bottom',
                  marginLeft: '20px'
              },
              [`& .radio-left`]: {
                  width: '80px',
                  textAlign: 'right',
              },
          })
          const LikeStyle = styled('div')({
              display: 'flex',
              alignItems: 'center',
              marginTop: '-10px',
              [`& .MuiButtonBase-root`]: {
                  marginLeft: '6px'
              },
              [`& .radio-left`]: {
                  width: '80px',
                  textAlign: 'right',
              },
          })
          const CityStyle = styled('div')({
              [`& .MuiFormControl-root `]: {
                  verticalAlign: 'bottom',
                  marginLeft: '20px'
              },
              [`& span`]: {
                  display: 'inline-block',
                  width: '80px',
                  height: '42px',
                  textAlign: 'right'
              },
              width: '100%'
          })
          const SubmitStyle = styled('div')({
              [`& .MuiButtonBase-root `]: {
                  verticalAlign: 'bottom',
                  marginLeft: '20px'
              },
              [`& span`]: {
                  display: 'inline-block',
                  width: '80px',
                  height: '42px',
                  textAlign: 'right'
              },
              width: '100%'
          })
          interface Item {
              value: string,
              label: string
          }
          interface Obj {
              username: string,
              age: string,
              email: string,
              city: string,
              like: string,
              isLike: boolean
          }
          
          const dd = [
              { value: 'apple', label: 'apple'},
              { value: 'apple2', label: 'apple2'},
              { value: 'apple3', label: 'apple3'},
          ]
          
          const currencies = [
              {
                value: 'beijing',
                label: 'beijing',
              },
              {
                value: 'shanghai',
                label: 'shanghai',
              },
              {
                value: 'shenzhen',
                label: 'shenzhen',
              }
          ];
          
          export default function Submit() {
              const [obj,setObj] = useState<Obj>({
                  username: '',
                  age: '',
                  email: '',
                  city: '',
                  like: '',
                  isLike: false
              })
              const [like,setLike] = useState('');
              
          
              const handleLikeOption = (event: React.ChangeEvent<HTMLInputElement>) => {
                  // console.log(event.target.value,'like');
                  const target = event.target;
                  if ( target.checked ) {
                      setLike(event.target.value);
                      setObj({
                          ...obj,
                          like: event.target.value
                      })
                  } else {
                      setLike('')
                  }
                  
              }
          
              const City = () => {
                  return (
                      <ZlInput id="city" data-testid='city' inputType='select' label='city' handleInputChange={changeCity} placeholder="please input" defaultValue={currencies[0].value} variant="standard" helperText="Please select your city" sx={{ width: '400px'}}>
                          {currencies.map((option) => (
                              <MenuItem key={option.value} value={option.value}>
                                  {option.label}
                              </MenuItem>
                          ))}
                      </ZlInput>
                  )
              }
          
              const changeCity = (event: React.ChangeEvent<HTMLInputElement>) => {
                  setObj({
                      ...obj,
                      city: event.target.value
                  })
              }
          
              const handleChangeLike = (event: React.ChangeEvent<HTMLInputElement>) => {
                  setObj({
                      ...obj,
                      isLike: event.target.checked
                  })
              }
          
          
              const handleSubmit = async () => {
                  console.log('--submit data--',obj)
                  const res = await submitData(obj)
                  console.log(res,'submit')
              }
          
              const changeChange = (e: React.ChangeEvent<HTMLInputElement>) => {
                  const val = e.target.value;
                  if ( e.target.labels?.length ) {
                      // 這里有一個BUG,明明給了age輸入框一個label,但是labels獲取的NodeList為空數組,其他的卻正常
                      const labelValue = e.target?.labels[0]?.textContent;
                      switch(labelValue) {
                          case 'username':
                              setObj({
                                  ...obj,
                                  username: val
                              })
                              break;
                          case 'age':
                              setObj({
                                  ...obj,
                                  age: val
                              })
                              break;
                          case 'email':
                              setObj({
                                  ...obj,
                                  email: val
                              })
                      }
                  } else {
                      // console.log(e.target.labels,'kkk')
                      setObj({
                          ...obj,
                          age: val
                      })
                  }
              }
              return (
                  <Box sx={{ display: 'flex', flexWrap: 'wrap', width: '800px' }}>
                      <Grid container spacing={2} sx={{ padding: '20px'}}>
                          <Grid item xs={12}>
                              <ItemStyle>
                                  <span>username: </span><ZlInput label='username' data-testid='username'  handleInputChange={changeChange} defaultValue={obj.username} id="usename"  placeholder="please input" variant="standard" sx={{ width: '400px'}}  />
                              </ItemStyle>
                          </Grid>
                          
                          <Grid item xs={12}>
                              <ItemStyle>
                                  <span>age: </span><ZlInput id="age" label='age' data-testid='age'  handleInputChange={changeChange} defaultValue={obj.age}  placeholder="please input" variant="standard" sx={{ width: '400px'}} />
                              </ItemStyle>
                          </Grid>
                          <Grid item xs={12}>
                              <ItemStyle>
                                  <span>email: </span><ZlInput id="email" data-testid='email'  handleInputChange={changeChange} label='email' defaultValue={obj.email} placeholder="please input" variant="standard" sx={{ width: '400px'}} />
                              </ItemStyle>
                          </Grid>
                          <Grid item xs={12}>
                              <CityStyle>
                                  <span>city: </span><City />
                              </CityStyle>
                          </Grid>
          
                          <Grid item xs={12}>
                              <RadioStyle>
                                  <div className="radio-left">like: </div><RadioButtonsGroup data-testid='likeOptions'  id="like-btn" dd={dd}  handleChange={handleLikeOption} value={like} />
                              </RadioStyle>
                          </Grid>
                          <Grid item xs={12}>
                              <LikeStyle>
                                  <div className="radio-left">like apple: </div><Zl_checkbox 
                                      checked={obj.isLike}
                                      handleChange={handleChangeLike}
                                      data-testid='like_apple'
                                  />
                              </LikeStyle>
                          </Grid>
                          <Grid item xs={12}>
                              <SubmitStyle>
                                  <span></span>
                                  <Button variant="contained" data-testid='submit' color="success" onClick={handleSubmit}>Submit</Button>
                              </SubmitStyle>
                          </Grid>
                      </Grid>
                  </Box>
              )
          }

          看起來寫了很長,但是仔細閱讀,無非就是一些表單子內容,我們這里用到的是mui,可以賦值跑通,結果大概長這個樣子:

          頁面展示效果

          最后我們就可以寫測試文件__tests__/react/com/submit.test.tsx

          import { fireEvent, screen } from '@testing-library/dom'
          import { render, waitFor } from "@testing-library/react";
          
          import * as utils from '../../../api/detail';
          jest.mock('../../../api/detail');
          
          const submitDD = jest.spyOn(utils,'submitData');
          submitDD.mockImplementation(
              (): Promise<any> => {
                  return new Promise((resolve) => {
                      resolve({
                          status: 0,
                          msg: 'submit success2'
                      })
                  })
              }
          )
          
          // 引入jest-dom的匹配內容
          import '@testing-library/jest-dom';
          import { 
              setRadio,
              getSelectValue,
              InputField,
              changeCheckbox  
          } from '../utils';
          
          import Submit from 'src/page/detail/Com/submit';
          
          describe('test react submit', () => {
              it('test input',async () => {
                  console.log('kkk')
                  const Com = (
                      <Submit />
                  )
                  const container = render(Com);
          
                  // 三個輸入框
                  InputField({
                      testId: 'username',
                      value: 'jack'
                  })
                  InputField({
                      testId: 'age',
                      value: '12'
                  })
                  InputField({
                      testId: 'email',
                      value: '111@qq.com'
                  })
          
                  // 選擇城市
                  getSelectValue({
                      testId: 'city',
                      value: 'shanghai'
                  })
          
                  // 選擇喜歡項
                  const likeValue = setRadio({
                      value: 'apple2'
                  })
          
                  // 確定是否要apple
                  const checked2 = changeCheckbox({
                      testId: 'like_apple'
                  })
          
                  // 提交
                  const submitBtn = screen.getByTestId('submit');
                  fireEvent.click(submitBtn);
          
                  
                  await waitFor(() => {
                      expect(submitDD).toHaveBeenCalled();
                  })
                  
                  expect(container).toMatchSnapshot('submit-input')        
              })
          })

          當我們成功跑通的時候,我們就會看到如下的打印

          表明模擬了表單提交

          注意事項:

          • express注意解析body,引入body-parser
          • axios發起post請求時,我們攜帶的data如果想被express解析,那么需要加一個頭:headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
          • 注意我這里是新建了一個detail.ts來寫detail頁面的網絡請求,那么為什么我不直接寫在home.ts里面呢?原因是我測試的時候,發現如果我寫在homt.ts中時,可能由于之前我們使用了自定義mock,home.ts已經被__mocks__/home.ts所管理,導致頁面無法訪問post請求的這個方法

          組件詳談

          表單組件基本元素為這些了,那么對于列表list以及表格這塊怎么說呢,其實這兩個我們只需要給個初始值,他能夠正常渲染,覆蓋率基本上就很高了,而表格的一些高級操作,比如過濾,搜索等,如果你寫了方法,那么確實要測試一下,這個實現思路跟utils/index.ts里面的方法類似,模擬的時候操作了一遍,就能覆蓋到。

          好了,上面這個例子希望大家去嘗試,加深一下組件測試。

          • Vue 中文網
          • Vue github
          • Vue.js 是一套構建用戶界面(UI)的漸進式JavaScript框架

          庫和框架的區別

          • 我們所說的前端框架與庫的區別?

          Library

          庫,本質上是一些函數的集合。每次調用函數,實現一個特定的功能,接著把控制權交給使用者

          • 代表:jQuery
          • jQuery這個庫的核心:DOM操作,即:封裝DOM操作,簡化DOM操作

          Framework

          框架,是一套完整的解決方案,使用框架的時候,需要把你的代碼放到框架合適的地方,框架會在合適的時機調用你的代碼

          • 框架規定了自己的編程方式,是一套完整的解決方案
          • 使用框架的時候,由框架控制一切,我們只需要按照規則寫代碼

          主要區別

          • You call Library, Framework calls you
          • 核心點:誰起到主導作用(控制反轉)
            • 框架中控制整個流程的是框架
            • 使用庫,由開發人員決定如何調用庫中提供的方法(輔助)
          • 好萊塢原則:Don't call us, we'll call you.
          • 框架的侵入性很高(從頭到尾)

          MVVM的介紹

          • MVVM,一種更好的UI模式解決方案
          • 從Script到Code Blocks、Code Behind到MVC、MVP、MVVM - 科普

          MVC

          • M: Model 數據模型(專門用來操作數據,數據的CRUD)
          • V:View 視圖(對于前端來說,就是頁面)
          • C:Controller 控制器(是視圖和數據模型溝通的橋梁,用于處理業務邏輯)

          MVVM組成

          • MVVM => M / V / VM
          • M:model數據模型
          • V:view視圖
          • VM:ViewModel 視圖模型

          優勢對比

          • MVC模式,將應用程序劃分為三大部分,實現了職責分離
          • 在前端中經常要通過 JS代碼 來進行一些邏輯操作,最終還要把這些邏輯操作的結果現在頁面中。也就是需要頻繁的操作DOM
          • MVVM通過數據雙向綁定讓數據自動地雙向同步
            • V(修改數據) -> M
            • M(修改數據) -> V
            • 數據是核心
          • Vue這種MVVM模式的框架,不推薦開發人員手動操作DOM

          Vue中的MVVM

          雖然沒有完全遵循 MVVM 模型,Vue 的設計無疑受到了它的啟發。因此在文檔中經常會使用 vm (ViewModel 的簡稱) 這個變量名表示 Vue 實例

          學習Vue要轉化思想

          • 不要在想著怎么操作DOM,而是想著如何操作數據!!!

          起步 - Hello Vue

          • 安裝:npm i -S vue
          <!-- 指定vue管理內容區域,需要通過vue展示的內容都要放到找個元素中  通常我們也把它叫做邊界 數據只在邊界內部解析-->
          <div id="app">{{ msg }}</div>
          
          <!-- 引入 vue.js -->
          <script src="vue.js"></script>
          
          <!-- 使用 vue -->
          <script>
            var vm = new Vue({
              // el:提供一個在頁面上已存在的 DOM 元素作為 Vue 實例的掛載目標
              el: '#app',
              // Vue 實例的數據對象,用于給 View 提供數據
              data: {
                msg: 'Hello Vue'
              }
            })
          </script>
          

          Vue實例

          • 注意 1:先在data中聲明數據,再使用數據
          • 注意 2:可以通過 vm.$data 訪問到data中的所有屬性,或者 vm.msg
          var vm = new Vue({
            data: {
              msg: '大家好,...'
            }
          })
          
          vm.$data.msg === vm.msg // true
          

          數據綁定

          • 最常用的方式:Mustache(插值語法),也就是 {{}} 語法
          • 解釋:{{}}從數據對象data中獲取數據
          • 說明:數據對象的屬性值發生了改變,插值處的內容都會更新
          • 說明:{{}}中只能出現JavaScript表達式 而不能解析js語句
          • 注意:Mustache 語法不能作用在 HTML 元素的屬性上
          <h1>Hello, {{ msg }}.</h1>
          <p>{{ 1 + 2 }}</p>
          <p>{{ isOk ? 'yes': 'no' }}</p>
          
          <!-- !!!錯誤示范!!! -->
          <h1 title="{{ err }}"></h1>
          

          雙向數據綁定 Vue two way data binding

          • 雙向數據綁定:將DOM與Vue實例的data數據綁定到一起,彼此之間相互影響
            • 數據的改變會引起DOM的改變
            • DOM的改變也會引起數據的變化


          • 原理:Object.defineProperty中的getset方法
            • gettersetter:訪問器
            • 作用:指定讀取或設置對象屬性值的時候,執行的操作


          • Vue - 深入響應式原理
          • MDN - Object.defineProperty()
          /*  defineProperty語法 介紹 */
          var obj = {}
          Object.defineProperty(obj, 'msg', {
            // 設置 obj.msg = "1" 時set方法會被系統調用 參數分別是設置后和設置前的值
            set: function (newVal, oldVal) {  },
            // 讀取 obj.msg 時get方法會被系統調用
            get: function ( newVal, oldVal ) {}
          })
          

          Vue雙向綁定的極簡實現

          • 剖析Vue原理&實現雙向綁定MVVM
          <!-- 示例 -->
          <input type="text" id="txt" />
          <span id="sp"></span>
          
          <script>
          var txt = document.getElementById('txt'),
              sp = document.getElementById('sp'),
              obj = {}
          
          // 給對象obj添加msg屬性,并設置setter訪問器
          Object.defineProperty(obj, 'msg', {
            // 設置 obj.msg  當obj.msg反生改變時set方法將會被調用  
            set: function (newVal) {
              // 當obj.msg被賦值時 同時設置給 input/span
              txt.value = newVal
              sp.innerText = newVal
            }
          })
          
          // 監聽文本框的改變 當文本框輸入內容時 改變obj.msg
          txt.addEventListener('keyup', function (event) {
            obj.msg = event.target.value
          })
          </script>
          

          動態添加數據的注意點

          • 注意:只有data中的數據才是響應式的,動態添加進來的數據默認為非響應式
          • 可以通過以下方式實現動態添加數據的響應式
            • 1 Vue.set(object, key, value) - 適用于添加單個屬性
            • 2 Object.assign() - 適用于添加多個屬性


          var vm = new Vue({
            data: {
              stu: {
                name: 'jack',
                age: 19
              }
            }
          })
          
          /* Vue.set */
          Vue.set(vm.stu, 'gender', 'male')
          
          /* Object.assign 將參數中的所有對象屬性和值 合并到第一個參數 并返回合并后的對象*/
          vm.stu = Object.assign({}, vm.stu, { gender: 'female', height: 180 })
          

          異步DOM更新

          • 說明:Vue 異步執行 DOM 更新,監視所有數據改變,一次性更新DOM
          • 優勢:可以去除重復數據,對于避免不必要的計算和 避免重復 DOM 操作上,非常重要
          • 如果需要那到更新后dom中的數據 則需要通過 Vue.nextTick(callback):在DOM更新后,執行某個操作(屬于DOM操作)
            • 實例調用vm.$nextTick(function () {})


          methods: {
            fn() {
              this.msg = 'change'
              this.$nextTick(function () {
                console.log('$nextTick中打印:', this.$el.children[0].innerText);
              })
              console.log('直接打印:', this.$el.children[0].innerText);
            }
          }
          

          推薦大家使用Fundebug,一款很好用的BUG監控工具~


          .em字體設置

          body {font-size:100%;}
          h1 {font-size:3.75em;}
          h2 {font-size:2.5em;}
          p {font-size:0.875em;}
          復制代碼

          2.背景圖標居右

          .aa{
              background-image: url(arrow.png)no-repeat right center;
              background-image:url(nav-bar.jpg);
              background-repeat:no-repeat;
              background-position:right center;
          }
          復制代碼

          3.文本框超出部分顯示省略號:

          overflow: hidden;
          text-overflow: ellipsis;
          white-space: nowrap;    
          復制代碼


          我自己是一名從事了多年開發的web前端老程序員,目前辭職在做自己的web前端私人定制課程,今年我花了一個月整理了一份最適合2020年學習的web前端學習干貨,各種框架都有整理,送給每一位前端小伙伴,想要獲取的可以關注我的頭條號并在后臺私信我:前端,即可免費獲取。

          一蒙版出現禁止頁面滾動

          1 window.onscroll=function(){
              document.body.scrollTop = 0
          };
          
          2 $('html,body').animate({scrollTop:'0'},100);
          $(".tan").bind('touchmove',function(e){  //禁止彈出框出來時進行滑動 
              e.preventDefault();
          });
          3 document.body.style.overflow='hidden';
          若鍵盤點擊的話,就要加上:
          var move=function(e){
              e.preventDefault && e.preventDefault();
              e.returnValue=false;
              e.stopPropagation && e.stopPropagation();
              return false;
          }
          var keyFunc=function(e){
              if(37<=e.keyCode && e.keyCode<=40){
                  return move(e);
              }
          }
          document.body.onkeydown=keyFunc;
          
          復制代碼

          二、按鈕點擊事件

          var button=$(':button');
          button.on('click',function(){
              button.css('background-color','white');
              $(this).css('background-color','#FB3336');
          })
          復制代碼

          三、安卓手機里,h5頁面沒有充滿body導致左右滑動的問題

          首先聲明一下:

          <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
          然后
          html,body {width:100%;height:100%;overflow-x:hidden;}
          
          復制代碼

          四、關于頁面左右滾動的問題

          1.<body scoll=no> 全禁止
          2.<body style="overflow:scroll;overflow-y:hidden"> 禁止縱向滾動條
          3.<body style="overflow:scroll;overflow-x:hidden"> 禁止縱向滾動條
          4.overflow屬性: 檢索或設置當對象的內容超過其指定高度及寬度時如何顯示內容
          5.overflow: auto; 在需要時內容會自動添加滾動條
          6.overflow: scroll; 總是顯示滾動條
          7.overflow-x: hidden; 禁止橫向的滾動條
          8.overflow-y: scroll; 總是顯示縱向滾動條
          復制代碼

          五、 content && header之間的亮條怎么消除

          .mui-bar-nav{
              -webkit-box-shadow: none;
              box-shadow: none;
          }
          復制代碼

          六、刪除選項

          $(".shanchu").click(function(){
              $(this).parent().remove()
          })
          復制代碼

          七、表單提交按鈕時,鼠標放在上面顯示小手的方法:

          需要對元素屬性的css的cursor進行設置
          1、default    默認光標(通常是一個箭頭)
          2、auto   默認。瀏覽器設置的光標。 
          3、crosshair   光標呈現為十字線。    
          4、pointer    光標呈現為指示鏈接的指針(一只手)    
          5、move    此光標指示某對象可被移動。    
          6、e-resize    此光標指示矩形框的邊緣可被向右(東)移動。    
          7、ne-resize    此光標指示矩形框的邊緣可被向上及向右移動(北/東)。    
          8、nw-resize    此光標指示矩形框的邊緣可被向上及向左移動(北/西)。    
          9、n-resize    此光標指示矩形框的邊緣可被向上(北)移動。    
          10、se-resize    此光標指示矩形框的邊緣可被向下及向右移動(南/東)。    
          11、sw-resize    此光標指示矩形框的邊緣可被向下及向左移動(南/西)。  
          12、s-resize    此光標指示矩形框的邊緣可被向下移動(南)。    
          13、w-resize    此光標指示矩形框的邊緣可被向左移動(西)。    
          14、text    此光標指示文本。    
          15、wait    此光標指示程序正忙(通常是一只表或沙漏)。    
          16、help    此光標指示可用的幫助(通常是一個問號或一個氣球)。    
          要實現鼠標移上去顯示手形、需要在你的提交按鈕上增加css cursor屬性,并將它的值設置為pointer;
          如下:<input type="submit" name="submit" value="發布留言" class="subimt" onclick="display_alert()" style="cursor:pointer" />
          復制代碼

          八、怎么清除table里面tbody的內容

          $("#test tbody").html("");
          復制代碼

          九、動態獲取表格的行數

          var bv=$("#tabd tr").length-1;
          $("#sp4").html(bv);     //動態的獲取注數
          復制代碼

          十、多個按鈕點擊變色,再點擊還原

          $(".jixuan  input[type=button]").toggle(function(){
              $(this).css("background-color","yellow");
              $(this).css("cursor","pointer")
              },function(){
              $(this).css("background-color","white");
              $(this).css("cursor","pointer");
          }) 
          復制代碼

          十一、單選按鈕顧名思義用于單選的場合,例如,性別,職業的選擇等,語法如下:

          <input type="radio" name="gender" value="男" checked />
          常用屬性迅美科技整理如下:
          1.type="radio"
          type屬性設置為radio,表示產生單一選擇的按鈕,讓用戶單擊選擇;
          2.name="gender"
          radio組件的名稱,name屬性值相同的radio組件會視為同一組radio組件,而同一組內只能有一個radio組件被選擇;
          3.value="男"
          radio組件的值,當表單被提交時,已選擇的radio組件的value值,就會被發送進行下一步處理, radio組件的value屬性設置的值 
          無法從外觀上看出,所以必須在radio組件旁邊添加文字,此處的文字只是讓用戶了解此組件的意思.
          4.checked
          設置radio組件為已選擇,同一組radio組件的name性情值必須要相同
          復制代碼

          十二、網頁中,公共頭部和側邊欄的引用

          1、<?php include("header.html");?>
          2、使用ssi技術頁面生成shtml文件,只用在頭部文件位置加入<!--#include file="header.htm" -->,
          然后修改的時候只要修改header.htm文件就可以了。使用shtml的好處是對搜索引擎比較友好,需要處理的文件在服務器端完成的,
          不會加重訪問者的瀏覽器負擔。
          復制代碼

          十三、錨點鏈接上下定位偏移解決

          1、JS解決的方法

          if (window.location.hash.indexOf('#') >= 0) {
              $('html,body').animate({
              scrollTop: ($(window.location.hash).offset().top - 50) + "px"
              },
              300);
          }; //主要修復評論定位不準確BUG
          $('#comments a[href^=#][href!=#]').click(function() {
              var target = document.getElementById(this.hash.slice(1));
              if (!target) return;
              var targetOffset = $(target).offset().top - 50;
              $('html,body').animate({
                  scrollTop: targetOffset
              },
              300);
              return false;
          }); //主要修復評論定位不準確BUG
          復制代碼

          2、解決辦法

          能用css自然不想用js解決,因為在加載方面,css總是先加載,并且速度很快。
          
          typecho的評論HTML結構是這樣的:
          
          <li id="comment-277" class="comment-body comment-child comment-level-odd comment-even comment-by-author">
          我們給comment-body加上css
          
          .comment-body {
              position: relative;
              padding-top: 50px;
              margin-top: -50px;
          }
          /*修復評論跳轉定位問題*/
          完美兼容chrome和Firefox,其他瀏覽器未測試。
          復制代碼

          十四、蒙版彈出禁止蒙版后面的內容滾動

          .ovfHiden{overflow: hidden;height: 100%;}
          $('.bzh .l1 a').click(function(){
              $(".baok").show();
              $(".baod").show();
              $('html,body').addClass('ovfHiden');
          });
          $('.baod .img1').click(function(){
          $('html,body').removeClass('ovfHiden');
              $(".baok").hide();
              $(".baod").hide();
          });
          復制代碼

          十五、獲取復選框點擊的次數

          $("#compute").click(function(){
              $('input').live('click',function(){ 
              //alert($('input:checked').length); 
              $("#show").html($('input:checked').length);
              });
          });
          復制代碼

          十六、Tab選項卡切換

          1.js

          $('footer ul li').click(function(){
              var index = $(this).index();
              $(this).attr('class',"content").siblings('ul li').attr('class','ss');
              $('.content').eq(index).show(200).siblings('.content').hide();
              });
          
          $('.ka ul li').click(function(){
              var index = $(this).index();
              $(this).attr('class',"zi").siblings('ul li').attr('class','ll');
              $(this).parent().next().find(".zi").hide(). eq(index).show();
          });
          復制代碼

          2.html

          <div class="carindex-cnt">
                  <ul class="nav">
                      <li>續保方案</li>
                      <li>熱銷方案</li>
                      <li>自定義方案</li>
                  </ul>
                  <div class="tabcontent">
                      <div class="zi">
                          <p class="altp">此方案為您上一年的投保記錄</p>
                          <ul class="xiur">
                              <li>
                                  <label for="saveType2">交強險</label>
                                  <div  class="right-cnt">
                                      <input type="text" class="coverage" disabled="disabled" value="不投保"/>
                                      <ul class="datas" style="display: none;">
                                          <li ref="1">投保</li>
                                          <li ref="2">不投保</li>
                                      </ul>
                                  </div>
                              </li>
                              <li>
                                  <label for="saveType2">商業險</label>
                                  <div  class="right-cnt">
                                      <input type="text" class="coverage" disabled="disabled" value="不投保"/>
                                      <ul class="datas" style="display: none;">
                                          <li ref="1">投保</li>
                                          <li ref="2">不投保</li>
                                      </ul>
                                  </div>
                              </li>
                          </ul>
                          <p class="title">商業主險</p>
                          <ul class="xiur">
                              <li>
                                  <span>車輛損失險</span>
                                  <label for="abatement0" class="labels">
                                      <input class="mui-checkbox checkbox-green" type="checkbox" name="abatement" >
                                  </label>
                                  <div  class="right-cnt">
                                      <input type="text" class="coverage" disabled="disabled" value="不投保"/>
                                      <ul class="datas" style="display: none;">
                                          <li ref="1">投保</li>
                                          <li ref="2">不投保</li>
                                      </ul>
                                  </div>
                              </li>
                            
                          </ul>
                      </div>
                      <div class="zi" style="display: none">
                          <ul class="xiur">
                              <li>
                                  <label for="saveType2">交強險</label>
                                  <div  class="right-cnt">
                                      <input type="text" class="coverage" disabled="disabled" value="不投保"/>
                                      <ul class="datas" style="display: none;">
                                          <li ref="1">投保</li>
                                          <li ref="2">不投保</li>
                                      </ul>
                                  </div>
                              </li>
                              <li>
                                  <label for="saveType2">商業險</label>
                                  <div  class="right-cnt">
                                      <input type="text" class="coverage" disabled="disabled" value="不投保"/>
                                      <ul class="datas" style="display: none;">
                                          <li ref="1">投保</li>
                                          <li ref="2">不投保</li>
                                      </ul>
                                  </div>
                              </li>
                          </ul>
                      </div>
                  </div>
          </div>  
          復制代碼

          3.js

          $('.nav li').click(function () {
              var index = $(this).index();
              $(this).parent().next().find(".zi").hide().eq(index).show();
          })
          
          復制代碼

          十七、form表為空時,提交按鈕禁用

          $(function(){            
              $('.main button').click(function(){
                  if(($('.ip1').val() !="") && ($('.ip2').val() !="")){
                      $('.main button').css('background','#ff8100');
                      $('.main button').attr('disabled', true);
                      }else{
                      $('.main button').css('background','#D0D0D0');
                      $('.main button').attr('disabled', false);
                  }
              })
          })
          復制代碼

          十八、上拉事件和下拉事件

          $(window).scroll(function(){
              var scrollTop = $(this).scrollTop();               //滾動條距離頂部的高度
              var scrollHeight =$(document).height();                   //當前頁面的總高度
              var windowHeight = $(this).height();                   //當前可視的頁面高度
              if(scrollTop + windowHeight >= scrollHeight){    //距離頂部+當前高度 >=文檔總高度 即代表滑動到底部
                  alert("上拉加載,要在這調用啥方法?");
              }else if(scrollTop<=0){         //滾動條距離頂部的高度小于等于0
                  alert("下拉刷新,要在這調用啥方法?");
              }
          });                                                          ——>移動端
          
          $(function(){    
              $(window).scroll(function() {  
                  var scrollTop = $(this).scrollTop(),scrollHeight = $(document).height(),windowHeight = $(this).height();  
                  var positionValue = (scrollTop + windowHeight) - scrollHeight;  
                  if (positionValue == 0) {  
                      //do something  
                  }  
              });  
          });  
          復制代碼

          十九、左滑和右滑事件

          var obj;
          var startx;
          var starty;
          var overx;
          var overy;
              for(var i=1;i<=$("li").length;i++){          //為每個li標簽添加事件
              obj = document.getElementById(i);       //獲取this元素
              evenlistener(obj);      //調用evenlistener函數并將dom元素傳入,為該元素綁定事件
          }
          
          function evenlistener(obj){
              obj.addEventListener('touchstart', function(event) {        //touchstart事件,當鼠標點擊屏幕時觸發
              startx = event.touches[0].clientX;              //獲取當前點擊位置x坐標
              starty = event.touches[0].clientY;              //獲取當前點擊位置y坐標
              $(".sdf").text("x:"+startx+",y:"+starty+"")     //賦值到頁面顯示
              } , false);         //false參數,設置事件處理機制的優先順序,具體不多說,true優先false
              obj.addEventListener('touchmove', function(event) {         //touchmove事件,當鼠標在屏幕移動時觸發
              overx = event.touches[0].clientX;           //獲取當前點擊位置x坐標
              overy = event.touches[0].clientY;           //獲取當前點擊位置y坐標
              var $this = $(this);            //將dom對象轉化為jq對象,由于項目用到jquery,直接使用其animate方法
          
              if(startx-overx>10){         //左滑動判斷,當左滑動的距離大于開始的距離10進入
              $($this).animate({marginLeft:"-55px"},150);         //實現左滑動效果
              }else if(overx-startx>10){       //右滑動判斷,當右滑動的距離大于開始的距離10進入
              $($this).animate({marginLeft:"0px"},150);           //恢復
              }
          } , false);
              obj.addEventListener('touchend', function(event) {          //touchend事件,當鼠標離開屏幕時觸發,項目中無用到,舉例
              $(".sf").text("x:"+overx+",y:"+overy+"")
              } , false);
          }
          復制代碼

          二十、各大瀏覽器的判斷

          var Sys = {};
          var ua = navigator.userAgent.toLowerCase();
          var s;
          (s = ua.match(/rv:([\d.]+)\) like gecko/)) ? Sys.ie = s[1] :
          (s = ua.match(/msie ([\d.]+)/)) ? Sys.ie = s[1] :
          (s = ua.match(/firefox\/([\d.]+)/)) ? Sys.firefox = s[1] :
          (s = ua.match(/chrome\/([\d.]+)/)) ? Sys.chrome = s[1] :
          (s = ua.match(/opera.([\d.]+)/)) ? Sys.opera = s[1] :
          (s = ua.match(/version\/([\d.]+).*safari/)) ? Sys.safari = s[1] : 0;
          if (Sys.ie){
              $("*").css({fontFamily:"微軟雅黑"});
          };
          if (window.ActiveXObject){
          Sys.ie = ua.match(/msie ([\d.]+)/)[1];
          if (Sys.ie<=9){
              alert('你目前的IE版本為'+Sys.ie+'版本太低,請升級!');
              location.href="http://windows.microsoft.com/zh-CN/internet-explorer/downloads/ie";
              }
          }
          var UA=navigator.userAgent;
          if(is360se = UA.toLowerCase().indexOf('360se')>-1 ){
          
          }else{
              $("*").css({fontFamily:"微軟雅黑"});
          }
          
          360瀏覽器基于IE內核的,360急速瀏覽器內核基于谷歌的
          復制代碼

          二十一、form表單中點擊button按鈕刷新問題

          button,input type=button按鈕在IE和w3c,firefox瀏覽器區別: 
          1、當在IE瀏覽器下面時,button標簽按鈕,input標簽type屬性為button的按鈕是一樣的功能,不會對表單進行任何操作。 
          2、但是在W3C瀏覽器,如Firefox下就需要注意了,button標簽按鈕會提交表單,而input標簽type屬性為button不會對表單進行任何操作。
          為button按鈕增加一個type=”button”屬性。
          復制代碼

          二十二、textrare文字輸入提示:

          <textarea name="" id="sign" maxlength=30 onKeyUp="keypress1()"></textarea>
          <div class="tish">
          <span id="number">0</span><span>/30</span>
          </div>
          
          function keypress1() //text輸入長度處理 
          { 
              var text1=document.getElementById("sign").value; 
              var len=text1.length; 
              var show=len; 
              document.getElementById("number").innerText=show; 
          } 
          復制代碼

          二十三、iframe操作

          1:父頁面操作iframe子頁面

          $('#ifrme').load(function(){
          $('#ifrme').contents().find('.baod .img1').click(function(){
              $(.ifrme').contents().find('.baod').hide();
              $('.baok',window.parent.document).hide();
              $('html,body',window.parent.document).removeClass('ovfHiden');
              });
          })
          * .ifrme父頁面的ID為iframe的父級
              .baod .img1是iframe頁面里的元素
          復制代碼

          2:子頁面操作父頁面

          $('.baod .bt1').click(function(){
              $('.baod').hide();
              $('.edit',window.parent.document).hide();
              $(".baok", window.parent.document).hide(); 
              $('html,body',window.parent.document).removeClass('ovfHiden');
          });
          *.baod .bt1子頁面里的元素
          window.parent.document父級窗口
          .edit父級頁面元素
          復制代碼

          二十四、toggle開關切換圖標或是元素的隱藏

          $('.other .pg').click(function(){
              $(this).toggleClass ("pots");
              $('.below').slideToggle(300);
          })
          
          * .other .pg元素名稱
          pots 點擊元素要切換的圖標(以background()形式的圖標)
          .below要進行toggle的內容
          復制代碼

          二十五、彈框居中

          $(".btnDel").click(function() {  
          //$(".box-mask").css({"display":"block"});  
              $(".box-mask").fadeIn(500);  
              center($(".box"));  
              //載入彈出窗口上的按鈕事件  
              checkEvent($(this).parent(),            $(".btnSure"), $(".btnCancel"));  
          });  *center  彈框名稱
          
          function center(obj) {  
              //obj這個參數是彈出框的整個對象  
              var screenWidth = $(window).width(), screenHeigth = $(window).height();  
              //獲取屏幕寬高  
              var scollTop = $(document).scrollTop();  
              //當前窗口距離頁面頂部的距離  
              var objLeft = (screenWidth - obj.width()) / 2;  
              ///彈出框距離左側距離  
              var objTop = (screenHeigth - obj.height()) / 2 + scollTop;  
              ///彈出框距離頂部的距離  
              obj.css({  
                  left:objLeft + "px",  
                  top:objTop + "px"  
              });  
              obj.fadeIn(500);  
              //彈出框淡入  
              isOpen = 1;  
              //彈出框打開后這個變量置1 說明彈出框是打開裝填  
              //當窗口大小發生改變時  
              $(window).resize(function() {  
                  //只有isOpen狀態下才執行  
                  if (isOpen == 1) {  
                      //重新獲取數據  
                      screenWidth = $(window).width();  
                      screenHeigth = $(window).height();  
                      var scollTop = $(document).scrollTop();  
                      objLeft = (screenWidth - obj.width()) / 2;  
                      var objTop = (screenHeigth - obj.height()) / 2 + scollTop;  
                      obj.css({  
                          left:objLeft + "px",  
                          top:objTop + "px"  
                      });  
                      obj.fadeIn(500);  
                  }  
          });  
              //當滾動條發生改變的時候  
          $(window).scroll(function() {  
              if (isOpen == 1) {  
                  //重新獲取數據  
                  screenWidth = $(window).width();  
                  screenHeigth = $(window).height();  
                  var scollTop = $(document).scrollTop();  
                  objLeft = (screenWidth - obj.width()) / 2;  
                  var objTop = (screenHeigth - obj.height()) / 2 + scollTop;  
                  obj.css({  
                      left:objLeft + "px",  
                      top:objTop + "px"  
                  });  
                  obj.fadeIn(500);  
              }  
          });  
          復制代碼

          二十六、css和js進行奇偶選擇器

          css

          :nth-child(odd){background-color:#FFE4C4;}奇數行
          :nth-child(even){background-color:#F0F0F0;}偶數行
          復制代碼

          js

          $("table  tr:nth-child(even)").css("background-color","#FFE4C4");    //設置偶數行的背景色
          $("table  tr:nth-child(odd)").css("background-color","#F0F0F0");    //設置奇數行的背景色
          復制代碼

          二十七、jQuery中live()使用報錯,TypeError: $(...).live is not a function

          jquery中的live()方法在jquery1.9及以上的版本中已被廢棄了,如果使用,會拋出TypeError: $(...).live is not a function錯誤。
          
          解決方法:
          
          之前的用法:
          
          .live(events, function)  
          
          新方法:
          
          .on(eventType, selector, function)
          
          若selector不需要,可傳入null
          
          
          例子1:
          
          之前:
          
          $('#mainmenu a').live('click', function)
          
          之后:
          
          $('#mainmenu').on('click', 'a', function)
          
          
          例子2:
          
          之前:
          
          $('.myButton').live('click', function)
          
          之后(應使用距離myButton最近的節點):
          
          $('#parentElement').on('click', ‘.myButton’, function)
          
          若不知最近的節點,可使用如下的方法:
          
          $('body').on('click', ‘.myButton’, function)
          復制代碼

          二十八、iframe滾動條問題

          iframe嵌入的滾動條可以用iframe里面頁面的大小覆蓋掉iframe的滾動條
          復制代碼

          二十九、點擊圖片下載(不用新窗口打開)

          <a class="downs"  style="display:'+display+'" onclick="downimg(\''+list[i].skuTieTu+'\')">下載</a>
          復制代碼

          js方法

          /**
          * 圖片單獨下載
          */
          function downimg(skuTieTu){
              console.log(skuTieTu)
              let src = skuTieTu;
              var canvas = document.createElement('canvas');
              var img = document.createElement('img');
              img.onload = function(e) {
              canvas.width = img.width;
              canvas.height = img.height;
              var context = canvas.getContext('2d');
              context.drawImage(img, 0, 0, img.width, img.height);
              canvas.getContext('2d').drawImage(img, 0, 0, img.width, img.height);
              canvas.toBlob((blob)=>{
                  let link = document.createElement('a');
                  link.href = window.URL.createObjectURL(blob);
                  link.download = 'zzsp'; 
                  link.click();  
              }, "image/jpeg");
          }
          img.setAttribute("crossOrigin",'Anonymous');
          img.src = src;
          復制代碼

          三十、ajax里面條件判斷

          $.ajax({
              type: "post",
              data: 
              contentType:
              url: 
              beforeSend: function () {
                  if(){
                  
                  }else{
                  
                  };
              },
              success: function (data) {
                  alert("保存失敗");
              },
              error: function (data) {
                  alert("保存成功");
              }
          });
          復制代碼

          三十一、ajax里面在數據請求之前加layui.load()時,請求狀態必須是異步的才行( async: true)

          $.ajax({
              type:"post",
              url: API,
              data: {
                  'a':'project.kujiale.plan.YongliaoUser'
              },
              dataType: "json",
              async: true,
              beforeSend: function () {
                  layer.load(1);
              },
              success: function(data) {   
                  var item =data.data;
                  list = item
                  if(data.code==0){
                      layer.closeAll();
                      var url = '/module/designplan/searchplan/searchlist.jsp';
                      layer.open({
                      type: 2,
                      title: "搜索方案",
                      shadeClose: true,
                      shade: 0.8,
                      area: ['700px','500px'],
                      content: [url]
                      });
                  }else{
                      layer.msg(data.msg);
                  }
              }
          });
          
          復制代碼

          三十二、js根據元素的屬性獲取到改元素其他屬性的值

          jquery
          $("a[id=search]").attr("data-search")
          
          原生js
          document.querySelector("a[id=search]").getAttribute("data-search") //根據當前元素的屬性獲取該元素其他屬性的值
          
          document.querySelector("a[id=search]").text //根據當前屬性獲取該元素的值
          document.querySelector("a[id=search]").innerText //根據當前屬性獲取該元素的值    
          復制代碼

          三十三、數組對象提交時轉化問題

          JSON.stringify(userList)
          復制代碼

          三十四、layui使用

          1、關閉彈窗

          layer.msg('分配成功',{time: 1000},function () {
              var index = parent.layer.getFrameIndex(window.name);
              parent.layer.close(index);
          })
          復制代碼

          2、關閉彈窗,刷新頁面

          window.location.reload();//刷新當前頁面
          window.parent.location.reload();//刷新父級頁面
          復制代碼

          三十五、js創建下載方式

          download(data.data);
          
          function downpdf(data){
              var link = document.createElement('a');
              link.href = data;
              link.target = '_blank';
              link.click();
              delete link;
          }
          復制代碼

          三十六、高階函數

          const isYoung = age => age < 25;
          
          const message = msg => "He is "+ msg;
          
          function isPersonOld(age, isYoung, message) {
              const returnMessage = isYoung(age)?message("young"):message("old");
              return returnMessage;
          }
          
          // passing functions as an arguments
              console.log(isPersonOld(13,isYoung,message))
          // He is young
          復制代碼

          遞歸

          遞歸是一種函數在滿足一定條件之前調用自身的技術。只要可能,最好使用遞歸而不是循環。你必須注意這一點,瀏覽器不能處理太多遞歸和拋出錯誤。
          下面是一個演示遞歸的例子,在這個遞歸中,打印一個類似于樓梯的名稱。我們也可以使用for循環,但只要可能,我們更喜歡遞歸。
          復制代碼
          function printMyName(name, count) {
              if(count <= name.length) {
                  console.log(name.substring(0,count));
                  printMyName(name, ++count);
              }
          }
          
          console.log(printMyName("Bhargav", 1));
          
          /*
              B
              Bh
              Bha
              Bhar
              Bharg
              Bharga
              Bhargav
          */
          
          // withotu recursion
          var name = "Bhargav"
          var output = "";
          for(let i=0; i<name.length; i++) {
              output = output + name[i];
              console.log(output);
          }


          作者:山水有輕音
          鏈接:https://juejin.im/post/6873003814065012750


          主站蜘蛛池模板: 中文字幕一区二区三区精华液 | 97一区二区三区四区久久| 亚洲欧美日韩国产精品一区| 精品一区二区三区免费毛片 | 亚洲av成人一区二区三区| 国产伦理一区二区三区| 色欲AV蜜臀一区二区三区| 一区二区三区四区视频在线| 亚洲国产激情在线一区| 免费萌白酱国产一区二区三区| 无码人妻精品一区二区三区9厂| 亚洲AV无码一区东京热| 亚洲人AV永久一区二区三区久久| 精品无人区一区二区三区在线 | 午夜精品一区二区三区在线视 | 中文字幕aⅴ人妻一区二区| 国产成人欧美一区二区三区| 无码国产精品一区二区免费16| 无码精品人妻一区| 国产伦精品一区二区三区不卡| 无码少妇一区二区性色AV| 无码一区二区三区视频| 濑亚美莉在线视频一区| 亚洲中文字幕在线无码一区二区| 中文字幕精品亚洲无线码一区应用 | 日韩爆乳一区二区无码| 日韩人妻无码一区二区三区| 精品在线视频一区| 韩国一区二区三区| 亚洲一区二区三区写真| 亚洲美女视频一区| 亚洲AV无码一区东京热久久| 99精品国产高清一区二区三区| 午夜无码视频一区二区三区| 国产成人精品无码一区二区老年人| 高清精品一区二区三区一区| 久久伊人精品一区二区三区| 无码一区二区三区免费| 国产精品无码一区二区三级| 丰满少妇内射一区| 国模无码人体一区二区|