H5/JS/CSS/
第一页 1 2 3 4 5 6 7 8 9 下页 最后页 [ 显示模式: 摘要 | 列表 ]

 1. 防暴点(preventReClick)

快速点击按钮时会频繁重复调用接口,为了防止这种情况,要对相应的按钮进行防暴力重复点击处理,最好是使用函数防抖或者函数截流来处理,但是现在已经要修改的按钮太多了,于是换一种方法,用指令的方式来达到相识的效果。
1.创建utils文件夹,在该文件夹下创建preventReClick.js文件
JavaScript代码
  1. export default {  
  2.     install(Vue) {  
  3.         Vue.directive('preventReClick', {  
  4.             inserted: function (el, binding) {  
  5.                 console.log(el.disabled)  
  6.                 el.addEventListener('click', (e) => {  
  7.                     if (!el.disabled) {  
  8.                         el.disabled = true  
  9.                         setTimeout(() => {  
  10.                             el.disabled = false  
  11.                         }, binding.value || 3000)  
  12.                         //binding.value可以自行设置。如果设置了则跟着设置的时间走  
  13.                         //例如:v-preventReClick='500'  
  14.                     } else { // disabled为true时,阻止默认的@click事件  
  15.                         e.preventDefault()  
  16.                         e.stopPropagation()  
  17.                     }  
  18.                 })  
  19.             }  
  20.         }),  
  21.     }  
2.在main.js中全局引用
JavaScript代码
  1. // 防止多次点击  
  2. import preventReClick from '@/util/preventReClick '  
  3. Vue.use(preventReClick);  
3.在触发事件的按钮上就可以直接使用指令(button按钮和其他元素都可)
JavaScript代码
  1. <div class="comment-btn" @click="submitMes()" v-preventReClick="3000">发送</div>  
  2. <el-button @click="submitMes()" v-preventReClick="3000">发送</el-button>  

2. 防抖(debounce)

用户停下操作,就执行函数;只要不停止操作,永远不会执行函数内的操作
使用场景:防抖常应用于用户进行搜索输入节约请求资源,
eg:原来watch用户输入值改变马上请求接口 ,加入防抖,停止输入操作才会对接口进行访问

JavaScript代码
  1. /** 
  2.  * @description 函数防抖 触发高频时间后n秒内函数只会执行一次,如果n秒内高频时间再次触发,则重新计算时间。 
  3.  * @param {Function} func 需要执行的函数 
  4.  * @param {Number} wait 间隔时间 默认200ms 
  5.  * @param {Boolean} immediate  是否立即执行 true(默认) 表立即执行,false 表非立即执行 
  6.  * @return {*} 
  7.  */  
  8. export function VueDebounce(func, wait = 200, immediate = true) {  
  9.     let timeout = null;  // 定时器  
  10.     return function () {  
  11.         let that = this// this对象  
  12.             args = arguments; // 参数  
  13.         if (timeout) clearTimeout(timeout);  
  14.         if (immediate === true) { // 立即执行  
  15.             var callNow = !timeout;  
  16.             timeout = setTimeout(() => {  
  17.                 timeout = null;  
  18.             }, wait)  
  19.             if (callNow) {  
  20.                 // func.apply(that, args); // 普通用法  
  21.                 that[func](...args); // vue用法  
  22.             }  
  23.         }  
  24.         else { // 非立即执行  
  25.             timeout = setTimeout(() => {  
  26.                 // func.apply(this, args); // 普通用法  
  27.                 that[func](...args); // vue用法  
  28.             }, wait);  
  29.         }  
  30.     }  
  31. }  

用法:

JavaScript代码
  1. import {VueDebounce} from "@/util/index"  
  2. methods: {  
  3.     /** 
  4.      * 点击事件 函数防抖 
  5.      * 用法:<el-button @click="debounceHandel">点击测试</el-button> 
  6.      */  
  7.     debounceHandel: VueDebounce("handlerFunc"),  
  8.    
  9.     /** 
  10.      * 点击事件:真正执行的函数 
  11.      */  
  12.     handlerFunc(type) {  
  13.       console.log("测试防抖事件");  
  14.       this.$emit("click","这是参数"); // 如果用普通用法,则这里会找不到$emit,因为this还往上继承了vue的对象  
  15.     },  
  16.   }  
  17.    

3. 节流(throttle)

高频时间触发,但n秒内只会执行一次,所以节流会稀释函数的执行频率,是个固定的过程 ,如限制1s,则1s内只执行一次,无论怎样,都在会1s内执行相应的操作

使用场景:和防抖使用场景差不多,关键看固定时间内(1s)需要反馈,需要反馈使用节流,即:无论用户是否停下操作,都会固定时间执行函数操作

JavaScript代码
  1. * @description 函数节流  
  2. * @param {Function} func 函数  
  3. * @param {Number} wait 延迟执行毫秒数,默认200  
  4. * @param {Number} type 1 表时间戳版,2 表定时器版  
  5. */  
  6. xport function VueThrottle(func, wait=200 ,type) {  
  7.    if(type===1){  
  8.        let previous = 0;  
  9.    }else if(type===2){  
  10.        let timeout;  
  11.    }  
  12.    return function() {  
  13.        let that= this;  
  14.        let args = arguments;  
  15.        if(type===1){  
  16.            let now = Date.now();  
  17.   
  18.            if (now - previous > wait) {  
  19.                // func.apply(that, args); // 普通用法  
  20.                that[func](...args); // vue用法  
  21.                previous = now;  
  22.            }  
  23.        }else if(type===2){  
  24.            if (!timeout) {  
  25.                timeout = setTimeout(() => {  
  26.                    timeout = null;  
  27.                    // func.apply(that, args)  
  28.                    that[func](...args); // vue用法  
  29.                }, wait)  
  30.            }  
  31.        }  
  32.    }  

用法:

JavaScript代码
  1. import {VueThrottle} from "@/util/index"  
  2. methods: {  
  3.     /** 
  4.      * 点击事件 函数防抖 
  5.      * 用法:<el-button @click="throttleHandel">点击测试</el-button> 
  6.      */  
  7.     throttleHandel: VueThrottle("handlerFunc"),  
  8.    
  9.     /** 
  10.      * 点击事件:真正执行的函数 
  11.      */  
  12.     handlerFunc(type) {  
  13.       console.log("测试防抖事件");  
  14.       this.$emit("click","这是参数"); // 如果用普通用法,则这里会找不到$emit,因为this还往上继承了vue的对象  
  15.     },  
  16.   }  
  17.    

Mock的基本语法及使用

[不指定 2023/09/08 15:17 | by 刘新修 ]
JavaScript代码
  1. //定义/mock/index.js  
  2.   
  3. import Mock from 'mockjs'  
  4. Mock.mock("/api/login", {  
  5.     code: 200,  
  6.     msg: "登陆成功",  
  7.     user: {  
  8.         name: "zeng8",  
  9.         score: 2048,  
  10.         rank: 10  
  11.     },  
  12.     token: "kjkjalsdiiuioayeuryqowierqiwerqowiery"  
  13. })  
  14. // url可以使用正则匹配  
  15. // 拦截get请求,返回评论数据  
  16. Mock.mock(/\/api\/feed/, "get", function(config) {  
  17.     //console.log("config" , config );  
  18.     //通过config可以获取到前端发给服务器的数据  
  19.     var po = config.url.indexOf("?"); //获取问号的位置  
  20.     if (po != -1) {  
  21.         var query = config.url.slice(po + 1); //获取到查询参数current=4转换为{current: 4}  
  22.         var arr = query.split("&"); //按&分割为数组  
  23.         var search = {}; //定义个对象  
  24.         arr.forEach(item => {  
  25.             var temp = item.split("="); //把数组每个元素按等于分割[current,4]  
  26.             search[temp[0]] = temp[1]; //search[ "current"] =4  
  27.   
  28.         })  
  29.     }  
  30.   
  31.     // 返回一个随机数据  
  32.     return Mock.mock({  
  33.         "code": 0,  
  34.         "data|4": [{  
  35.             id: "@id",  
  36.             msg: "@cparagraph(2,3)", //段落2-3行  
  37.             name: "@cname", //随机中文名  
  38.             date: "@datetime" //随机日期  
  39.         }],  
  40.         "pagnation": {  
  41.             "total|10-25": 1,  
  42.             "size": 4,  
  43.             "pageTotal|4-10": 1,  
  44.             "current": search.current,  
  45.         }  
  46.     })  
  47. })  
  48.   
  49. Mock.mock("/api/test", Mock.mock({  
  50.     name: "@cname", //随机中文名  
  51.     "age|100-200": 1, //100-200的随机数  
  52.     "price|10-50.2-5": 1, //10-50随机数 小数点2-5位  
  53.     "live|1-2": true, //随机true或false  
  54.     "start|1-5": "⭐", //把字符串重复1-5次  
  55.     "friend|2": ["小红", "小明", "小刚", "小白", "小蓝"], //1是挑一个大于1是重复n次  
  56.     "props|1-3": {  
  57.         name: "mm",  
  58.         age: 22,  
  59.         leg: 2,  
  60.         job: "web",  
  61.         eye: 2  
  62.     },  
  63.     "tel": /13\d{9}/,  
  64.     "des": function() {  
  65.         return `大家好,我的名字是${this.name},今年${this.age}岁`  
  66.     },  
  67.     "data|10": [{  
  68.         "id|+1": 1024,  
  69.         "ID": "@id",  
  70.         date: "@date",  
  71.         time: "@time",  
  72.         datetime: "@datetime",  
  73.         name: "@cname",  
  74.         pic: "@dataImage('200x100')",  
  75.         description: "@cparagraph(1,3)",  
  76.         title: "@ctitle(8,12)",  
  77.         url: /http:\/\/www\.[a-z]{2,8}\.(com|cn|org)/,  
  78.         email: /[4-8]@\.(126|qq|163)\.(com|cn|org)/,  
  79.         address: "@county(true)", //省市区地址  
  80.     }]  
  81. }))  

vue封装定时器

[不指定 2023/09/07 13:29 | by 刘新修 ]

main.js 文件

JavaScript代码
  1. /*** sleep ***/  
  2. Vue.prototype.$sleep = time => {  
  3.   return new Promise((resolve, reject) => {  
  4.     window.setTimeout(() => {  
  5.       resolve(true)  
  6.     }, time)  
  7.   })  
  8. }  

增加测试页面

XML/HTML代码
  1. <!--  
  2. * @Description: npage.vue  
  3. * @Version: 1.0  
  4. * @Author: Jesse Liu
  5. * @Date: 2022-08-01 20:32:06  
  6. * @LastEditors: Jesse Liu  
  7. * @LastEditTime: 2023-09-07 13:24:11  
  8. -->  
  9. <template>  
  10.   <div class="wscn-http404-container">  
  11.       <h2 style="font-weight: normal; line-height: 160%;">userInfo ========= {{ userInfo }}</h2>  
  12.       <h2 style="font-weight: normal; line-height: 160%;">configInformation ========= {{ configInformation }}</h2>  
  13.       <h1 style="line-height:300px; text-align:center">npage.vue (新测试文件)</h1>  
  14.       <div>time:</div>  
  15.   </div>  
  16. </template>  
  17.   
  18. <script>  
  19. import { mapState } from "vuex";  
  20. import { parseTime } from '@/utils'  
  21. import { downloadFile } from "@/utils/getFile";  
  22. export default {  
  23.   name: 'PageTest',  
  24.   computed: {  
  25.     ...mapState("user", ["userInfo","configInformation"]),  
  26.     message() {  
  27.       return 'PageTest'  
  28.     },  
  29.     parseTime: parseTime  
  30.   },  
  31.   mounted() {  
  32.   
  33.     this.$store.dispatch("case/casesList/downloadFile",{}).then((res)=>{  
  34.         // let data = res.data;  
  35.         // let headers = res.headers;  
  36.           
  37.         // /*** 调用下载文件 ***/  
  38.         // downloadFile(data, headers)  
  39.     })  
  40.   
  41.     /*** 多定时器同时调用 ***/  
  42.     this.getStateA();  
  43.     this.getStateB();  
  44.   
  45.     /*** 业务请求接口调用示例 ***/  
  46.     this.casePage();  
  47.   },  
  48.   methods: {  
  49.     /*** 定时器演示方法 ***/  
  50.     async getStateA(){  
  51.   
  52.         /*** 定时器只管计算时间钩子标记 ***/  
  53.         console.log('sleepStateA ~~~ 开始')  
  54.   
  55.         /*** 多定时处理任务A ***/  
  56.         console.time('sleepStateA');  
  57.         let sleepStateA = await this.$sleep(5000);  
  58.         console.log('sleepStateA ~~~ 结束', sleepStateA)  
  59.         console.timeEnd('sleepStateA');  
  60.   
  61.         return sleepStateA;  
  62.     },  
  63.     /*** 定时器演示方法 ***/  
  64.     async getStateB(){  
  65.   
  66.         /*** 定时器只管计算时间钩子标记 ***/  
  67.         console.log('sleepStateB ~~~ 开始')  
  68.   
  69.         /*** 多定时处理任务B ***/  
  70.         console.time('sleepStateB');  
  71.         let sleepStateB = await this.$sleep(10000);  
  72.         console.log('sleepStateB ~~~ 结束', sleepStateB)  
  73.         console.timeEnd('sleepStateB');  
  74.   
  75.         return sleepStateB;  
  76.     },  
  77.   
  78.     /*** 模拟示例业务的状态 ***/  
  79.     async getCaseState(){  
  80.   
  81.         /*** 定时器只管计算时间钩子标记 ***/  
  82.         let sleepStateCase = await this.$sleep(10000);  
  83.         return sleepStateCase;  
  84.     },  
  85.     /*** 模拟示例业务主方法 ***/  
  86.     async casePage(state = true, n = 0){  
  87.   
  88.         /*** 定义及获取数据状态 ***/  
  89.         let runling = true;  
  90.         let getCaseState = await this.getCaseState();  
  91.   
  92.         /*** 业务逻辑处理及使用 ***/  
  93.         if(state && getCaseState) {  
  94.             /*** 请求接口拿状态和后端约定状态码(根据状态码去更改runling的布尔值) ***/  
  95.             // 写你的vuex调用方法,如:this.$store.dispatch('user/record', {})  
  96.   
  97.   
  98.             /*** 以下代码是为了演示模拟3次请求后,状态变更,供参考 ***/  
  99.             /*** 假设后端接口告诉你可以终止执行调用的状态 (比如后端调用3次后就更改了状态) ***/  
  100.             let index = n;  
  101.                 index +=1;  
  102.                 console.log('第['+ index + ']次调用后端接口~~');  
  103.   
  104.                 if(index >= 3) {  
  105.                   runling = false;  
  106.                 }  
  107.             this.casePage(runling, index);  
  108.         }  
  109.         else{  
  110.             console.log('===========================================\n定时器已经结束关停,累计调用共: ' + n + '次~~');  
  111.         }  
  112.     }  
  113.   
  114.   }  
  115. }  
  116. </script>  
  117.   
  118.   
  119. <style lang="scss" scoped>  
  120. </style>  

 

获取JSON对象key及vulue

[不指定 2023/09/01 09:29 | by 刘新修 ]
JavaScript代码
  1. var arr = [  
  2.     {  
  3.         "原告性别": "女",  
  4.         "出生日期": "XX1年1月1X日",  
  5.         "居住地址": "北京市丰台区XXXXX",  
  6.         "所属民族": "汉族",  
  7.         "电话号码": "XXXXXX78",  
  8.         "原告姓名": "XXX"  
  9.     },  
  10.     {  
  11.         "原告性别": "男",  
  12.         "出生日期": "1992年6月10日",  
  13.         "居住地址": "北京市通州区XXXXX",  
  14.         "所属民族": "汉族",  
  15.         "电话号码": "18701519435",  
  16.         "原告姓名": "xxx"  
  17.     }  
  18. ]  
  19.   
  20.   
  21. /*** 遍历数组中的JSON对象 ***/  
  22. for (var i=0; i<arr.length; i++){  
  23.     var keys=Object.keys(arr[i]);  
  24.     console.log('keys:', keys);  
  25. }  
  26.   
  27. //keys: (6) ['原告性别', '出生日期', '居住地址', '所属民族', '电话号码', '原告姓名']  

 平时在写js的时候遇到多层属性嵌套,一般大家敢直接用点使用吗?

有没有开发的时候好好的,某一时刻突然出现一个控制台报错类似:Uncaught TypeError: xxx is not a function
一般这种情况就是没有判断是否有值,如果数据是后端返回的,有可能后端就是没有值或者值的类型不对,这些情况都可能导致出现程序出错,一般我们需要进行判断,常见的判断就是
 
JavaScript代码
  1. if(obj.a && obj.a.b && obj.a.b.c && obj.a.b.c.d){  
  2.     // do something  
  3. }  
 

如果层级太深或者类似判断逻辑太多,写起来有点烦,能把自己蠢哭。。。 下面有一些优雅的方式解决这个问题。

方法1:

扁平化处理:后台处理 / 前端预处理, 防止出现不存在值的情况

方法2:

ES6 使用 CoffeeScript: a?.b?.c?.d

方法3:

JavaScript代码
  1. function checkNested(obj /*, level1, level2, ... levelN*/) {  
  2.   var args = Array.prototype.slice.call(arguments),  
  3.       obj = args.shift();  
  4.   
  5.   for (var i = 0; i < args.length; i++) {  
  6.     if (!obj || !obj.hasOwnProperty(args[i])) {  
  7.       return false;  
  8.     }  
  9.     obj = obj[args[i]];  
  10.   }  
  11.   return true;  
  12. }  
  13.   
  14. var test = {level1:{level2:{level3:'level3'}} };  
  15.   
  16. checkNested(test, 'level1''level2''level3'); // true  
  17. checkNested(test, 'level1''level2''foo'); // false  

方法4:

https://github.com/letsgetrandy/brototype

JavaScript代码
  1. var myURL;  
  2. if (Bro(app).doYouEven('config.environment.buildURL')) {  
  3.     myURL = app.config.environment.buildURL('dev');  
  4. }  

方法5:

lodash

JavaScript代码
  1. var object = { 'a': [{ 'b': { 'c': 3 } }] };  
  2.    
  3. _.get(object, 'a[0].b.c');  
  4. // => 3  
  5.    
  6. _.get(object, ['a''0''b''c']);  
  7. // => 3  
  8.    
  9. _.get(object, 'a.b.c''default');  
  10. // => 'default'  

 

Object.getOwnPropertyNames()

[不指定 2023/08/28 16:29 | by 刘新修 ]

 

JavaScript代码
  1. // 类数组对象  
  2. const obj = { 0: "a", 1: "b", 2: "c" };  
  3. console.log(Object.getOwnPropertyNames(obj).sort());  
  4. // ["0", "1", "2"]  
  5.   
  6. Object.getOwnPropertyNames(obj).forEach((val, idx, array) => {  
  7.     console.log(`${val} -> ${obj[val]}`);  
  8. });  

 

js比较俩个对象是否相等

[不指定 2023/08/28 15:20 | by 刘新修 ]

一、使用Object.getOwnPropertyNames()

该方法和Object.keys()功能一样,不同的地方在于Object.getOwnPropertyNames返回对象本身全部的属性,而Object.keys返回对象自身的(不含继承的)所有可枚举属性(不含Symbol属性)(即返回enumerable为false的属性)

共同点是俩者都不会返回自身原型链上的属性。

JavaScript代码
  1. var obj = {"name":"liuxinxiu","age":18,"info":"1234"}  
  2. var obj2 = obj;  
  3. var obj3 = {"name":"liuxinxiu","age":18,"info":"123"}  
  4. function checkInfo(obj1, obj2){  
  5.     //判断是否指向同一内存  
  6.     if (obj1 === obj2) return true;  
  7.     let bankInfo = Object.getOwnPropertyNames(obj1),  
  8.         oldBankInfo = Object.getOwnPropertyNames(obj2)  
  9.   
  10.     //判断长度不相同直接返回不同  
  11.     if(bankInfo.length !== oldBankInfo.length) return false  
  12.    
  13.     for(let i=0,max=bankInfo.length; i<max; i++){  
  14.         let prop_name = bankInfo[i]  
  15.         if(obj1[prop_name] !== obj2[prop_name]){  
  16.             return false  
  17.         }  
  18.     }  
  19.     return true  
  20. }  
  21. console.log(checkInfo(obj,obj3))  

二、使用Object.keys()或者Object.entries().toString()

Object.keys()是将对象中键先取出来组成数组,然后先比较键。而后通过键在比较值

Object.entries()是将键和值分别组成俩个数组。然后使用toString将键值数组转化为字符串去比较

JavaScript代码
  1.    
  2. checkInfo() {  
  3.     // object.keys  
  4.     let bankInfo = Object.keys(this.params.bankInfo),  
  5.         oldBankInfo = Object.keys(this.params.oldBankInfo)  
  6.     if (oldBankInfo.length !== bankInfo.length) return false  
  7.     for (let i = 0; i <= bankInfo.length - 1; i++) {  
  8.         let key = bankInfo[i];  
  9.         if (!oldBankInfo.includes(key)){  
  10.             return false  
  11.         }   
  12.         if (this.params.oldBankInfo[key] !== this.params.bankInfo[key]){  
  13.             return false  
  14.         }   
  15.     }  
  16.    
  17.     // object.entries  
  18.     console.log(Object.entries(this.params.bankInfo).toString() === Object.entries(this.params.oldBankInfo).toString()) //true  
  19.     console.log(Object.entries(this.params.bankInfo).toString())  //accountType,2,nationality,CHN,bankName,,bankCode,  
  20.     console.log(Object.entries(this.params.oldBankInfo).toString()) //accountType,2,nationality,CHN,bankName,,bankCode,  
  21.    
  22. }  

三、使用JSON.stringify()或。适用于俩个对象属性顺序相同

JavaScript代码
  1. let bankInfo = {  
  2.     accountType : 2,  
  3.     nationality:'CHN',  //国籍  
  4.     bankName : '',      //银行名称  
  5.     bankCode : '',      //银行code  
  6. }  
  7. let oldBankInfo = {  
  8.     accountType : 2,  
  9.     nationality:'CHN',  //国籍  
  10.     bankName : '',      //银行名称  
  11.     bankCode : '',      //银行code  
  12. }  
  13.    
  14. let flag2 = JSON.stringify(bankInfo) == JSON.stringify(oldBankInfo)  
  15. console.log(flag2)  

 

XSS已经成为非常流行的网站攻击方式,为了安全起见,尽量避免用户的输入。可是有些情况下不仅不避免,反而要求鼓励输入,比如写博客。博客园开放性很高,可以运行手写的JS。之前比较著名的例子就是,凡是看到某一篇文章的,都自动关注他。

如果避免跨站攻击的话,我们就得对用户的输入,进行转义。例如<script type='text/javascript'>alert('hello world')</script>。如果直接保存这个字符串的话,然后再输出的话,就会运行JS了。我们需要将这个字符串转义成"&lt;script type='text/javascript'&gt;alert('hello world')&lt;/script&gt;"。

转义,就是一个个字符的匹配,然后转换。看着不难,但是需要转义的字符也不少。另外当字符数量大的时候,效率成为一个问题。下面我写一个函数,让浏览器底层帮我们做到。

JavaScript代码
  1. function stringEncode(str){  
  2.        var div=document.createElement('div');  
  3.        if(div.innerText){  
  4.            div.innerText=str;  
  5.        }else{  
  6.            div.textContent=str;//Support firefox  
  7.        }  
  8.        return div.innerHTML;  
  9. }  

xss漏洞以及防御实现

[不指定 2020/05/22 18:44 | by 刘新修 ]

XSS三种类型

  • 存储型XSS:数据库中存在XSS攻击的数据,若数据未经过任何转义,返回给客户端。被浏览器渲染,就可能导致XSS攻击
  • 反射型XSS:将用户输入的存在XSS攻击的数据,发送给服务端,服务端并未对数据进行存储,也未经过任何转义,直接返回给客户端。被浏览器渲染。就可能导致XSS攻击
  • 纯粹发生在客户端的XSS攻击

XSS攻击演示

假设用户输入的参数为:

JavaScript代码
  1. <script>alert(xss)</script>  

如果后台没有对该数据做任何过滤直接显示到前端<div>标签中的话,源代码就变成了这样:

JavaScript代码
  1. <div><script>alert(xss)</script><div>  

那么在前端显示出来的是一个写着xss的弹窗,就发生了xss攻击

防御方案

我在项目中的主要的防御方案是对数据的过滤,对于数据中的危险字符进行相应的转义:

XML/HTML代码
  1. &----->&  
  2. <-----><  
  3. >----->>  
  4. "----->"  
  5. '----->'  
  6. /----->/  
手机型号尺寸(对角线)物理点宽长比例像素点倍数状态栏高度底部安全距离导航栏高度tabbar高度
iPhone 4/4S3.5英寸320x4800.667640x960@2x20-4449
iPhone 5/5S/5C4英寸320x5680.563640x1136@2x20-4449
iPhone SE4英寸320x5680.563640x1136@2x20-4449
iPhone 64.7英寸375x6670.562750x1334@2x20-4449
iPhone 6 Plus5.5英寸414x7360.5631242x2208@3x20-4449
iPhone 6S4.7英寸375x6670.562750x1334@2x20-4449
iPhone 6S Plus5.5英寸414x7360.5631242x2208@3x20-4449
iPhone 74.7英寸375x6670.562750x1334@2x20-4449
iPhone 7 Plus5.5英寸414x7360.5631242x2208@3x20-4449
iPhone 84.7英寸375x6670.562750x1334@2x20-4449
iPhone 8 Plus5.5英寸414x7360.5631242x2208@3x20-4449
iPhone X5.8英寸375x8120.4621125x2436@3x44344483
iPhone XS5.8英寸375x8120.4621125x2436@3x44344483
iPhone XS Max6.5英寸414x8960.4621242x2688@3x44344483
iPhone XR6.1英寸414x8960.462828x1792@2x44344483
iPhone 116.1英寸414x8960.462828x1792@2x44344483
iPhone 11 Pro5.8英寸375x8120.4621125x2436@3x44344483
iPhone 11 Pro Max6.5英寸414x8960.4621242x2688@3x44344483
iPhone SE 2020款4.7英寸375x6670.562750x1334@2x20-4449

 

第一页 1 2 3 4 5 6 7 8 9 下页 最后页 [ 显示模式: 摘要 | 列表 ]