首页

app界面赏析 ——— 北京蓝蓝设计 移动端UI设计资源分享(十九)

前端达人

移动互联网的迅速崛起,让移动网页,移动客户端越来越重要,客户端的页面设计也是一门很大的学问。科技迅速发展的今手机屏幕的尺寸越来越放大化,但却始终 很有限,因此,在APP的界面设计中,精简是一贯的准则。这里所说的精简并不是内容上尽可能的少量,而是要注重重点的表达。在视觉上也要遵循用户的视觉逻 辑,用户看着顺眼了,才会真正的喜欢。


接下来为大家分享精美的app UI设计案例:

jhk-1618474542774.jpgjhk-1618474998310.pngjhk-1618475447916.pngjhk-1618475932156.jpgjhk-1618476010794.jpg


--手机appUI设计--

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服



  更多精彩文章:

       手机appUI界面设计赏析(一)

       手机appUI界面设计赏析(二)

       手机appUI界面设计赏析(三)

       手机appUI界面设计赏析(四)

       手机appUI界面设计赏析(五)

       手机appUI界面设计赏析(六)

       手机appUI界面设计赏析(七)

       手机appUI界面设计赏析(八)

       手机appUI界面设计赏析(九)

        手机appUI界面设计赏析(十)

       手机appUI界面设计赏析(十一)

       手机appUI界面设计赏析(十二)

        手机appUI界面设计赏析(十三)

       手机appUI界面设计赏析(十四)

       手机appUI界面设计赏析(十五)

       手机appUI界面设计赏析(十六)

       手机appUI界面设计赏析(十七)

      手机appUI界面设计赏析(十八)



vue 前端解决跨域问题 —代理

前端达人

前言
跨域问题来源于JavaScript的同源策略,即只有 协议+主机名+端口号(如存在)相同,则允许相互访问。也就是说JavaScript只能访问和操作自己域下的资源,不能访问和操作其他域下的资源,主要是安全问题。

在很多时候跨域问题我都是让后端解决,嘿嘿。但也有需要自己解决的项目!

  1. 首先在项目的根目录下建一个vue.config.js

  2. 如下:

  3. //改变webpack的设置
    
     const { default: Axios } = require("axios")
    
     module.exports = {
         publicPath :"./",
         devServer: {
             // 设置主机地址
             // host: 'xxx.1xx.1xx.xxx',
             // // 设置默认端口
             // port: 8051,
             // 设置代理
             proxy: {
                 '/api': {
                     // 目标 API 地址
                     target: 'http://xxx.xxx.xxx.xxx:8051',//服务器地址
                     // 如果要代理 websockets
                     ws: true,
                     // 将主机标头的原点更改为目标URL
                     changeOrigin: false
                 }
             }
        },
        chainWebpack: config => {//没有用到scss的这里就不需要啦!
           const oneOfsMap = config.module.rule('scss').oneOfs.store
            oneOfsMap.forEach(item => {
              item
                 .use('sass-resources-loader')
                 .loader('sass-resources-loader')
                 .options({
                     // 要公用的scss的路径
                     resources: './src/assets/base.scss'
                 })
                 .end()
               })
           }
       }



转自:csdn 论坛 作者:可 乐 伢


蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服


IDEA2021 tomcat10 servlet 较新版本 踩坑记录

前端达人

因为学习的时候用的版本比较新,而网上的教程又全是老版本,所以出现了很多问题,总结以下,帮同样初学的师傅们踩坑了。
废话不多说:

1:
file->new->project新建一个普通java项目:
工程名可以随意命名

2:
工程名上右键->Add Framework Support:

在Web Application上打勾,点击OK

3:
展开工程名->web->WEB-INF,在WEB-INF下新建两个文件夹,分别是classes、lib:

4:
按下ctrl+alt+shift+S,调出Project Structure,
选到Modules->Paths,单选框选到use module xxxxx,将两个路径改为刚才创建的classes。
然后选到Dependencies,点击下面的+号,选择jars or dirxxxxxxxx,选择刚创建的lib目录,让选择目录用处的话,选择jar direxxxxxxx,打上勾,点击apply,OK

5:
将tomcat/lib目录下的servlet-api.jar复制到我们创建的lib目录里。

6:
点击右上角小锤子旁边的Add Configuration,点击加号,选择tomcat server->local。这里注意不要选成tomEE的,两者图标一样,但是不是一个东西。其他配置不变,点击aplly上面的fix,application context可以随意命名,建议一个/就可以。然后aplly,OK。

7:
改一改index.jsp中带的title和end,运行一下,如果类似以下,那基本就OK了。

8:
在src里面新建一个java class,尝试写一个servlet:
这里也是与其他版本不同的地方,老版本都是import javax.servlet.xxxxx,这里是import jakarta.servlet.xxxxx,具体应该import的包,可以展开servlet-api.jar看到。
在这里插入图片描述

import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; @WebServlet(name = "login") public class Login extends HttpServlet { @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<!DOCTYPE HTML>"); out.println("<HTML>"); out.println("  <HEAD><TITLE>login</TITLE></HEAD>"); out.println("  <BODY>"); out.print("    this is login page"); out.print(this.getClass()); out.println("  </BODY>"); out.println("</HTML>"); out.flush(); out.close(); } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<!DOCTYPE HTML>"); out.println("<HTML>"); out.println("  <HEAD><TITLE>login</TITLE></HEAD>"); out.println("  <BODY>"); out.print("    this is login page"); out.print(this.getClass()); out.println("  </BODY>"); out.println("</HTML>"); out.flush(); out.close(); } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

然后修改web.xml文件,如下:
servlet-name可以任意命名,只要上下两个一致就可以,servlet-class应该与类名相同,url-pattern是与java class中的@WebServlet(name=“xxxx”)的xxxx相同,这里的xxxx就是路径。
此时编译并运行,在地址栏输入我们写的url,就可以访问到动态资源了:

全篇结束,只是记录踩坑,希望能对大家有帮助。


转自:csdn 论坛 作者:Hausa_


蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服

死磕javascript的手写面试题

前端达人

1.实现lodash的_.get方法

function _getValue(target, valuePath, defalutVal) {
  let valueType = Object.prototype.toString.call(target)
  console.log(valueType)
  // if (valueType == "[object Array]") {
    let paths = valuePath.replace(/\[(\d+)\]/, `.$1`).split('.')
    let result = target
    for(const path of paths){
      result = Object(result)[path]
      if(result == undefined){
        return defalutVal
      }
    }
    return result
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
测试:
let obj = {
  a:{
    b:[
      {
        c:2
      }
    ]
  }
}

console.log(_getValue(obj, 'a.b[0].c')) //2 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

2.写一个函数判断两个变量是否相等

function isEqual(res1, res2) {
  let a = getTypeOf(res1)
  let b = getTypeOf(res2)
  if(a !== b){
    return false
  }else if(a === 'base'){
    console.log('base',res1,res2)
    return res1 === res2
  } else if(a === 'array'){
    if(res1.length !== res2.length){
      console.log('array',res1,res2)
      return false
    }else{
      //遍历数组的值比较
      for(let i =0;i<res1.length;i++){
        if(!isEqual(res1[i],res2[i])){
          console.log('array',res1[i],res2[i])
          return false
        }
      }
      return true
    }
    return true
  }else if(a === 'object'){
    let ak = Object.keys(a)
    let bk = Object.keys(b)
    if(ak.length !== bk.length){
      return false
    }else{
      for(let o in res1){
        console.log(res1[o])
        if(!isEqual(res1[o],res2[o])){
          console.log('object',res1[o],res2[o])
          return false
        }
      }
      return true
    } 
  }else if(a === 'null' || a === 'undefined'){
    console.log('null')
    return true
  }else if(a === 'function'){
    console.log('function')
    return a === b
  }
}

function getTypeOf(res) {
  let type = Object.prototype.toString.call(res)
  switch (type) {
    case "[object Array]":
      return 'array'
    case "[object Object]":
      return 'object'
    case "[object Null]":
      return 'null'
    case "[object Undefined]":
      return 'undefined'
    case "[object Number]"||"[object String]"||"[object Boolean]":
      return 'base'
    case "[object Function]":
      return 'function'
    default:
      return 'typeError'
  }
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
测试:
let a = {
  a:20,
  b:{
    c:30,
    d:[1,2,3]
  }
}
let b = {
  a:20,
  b:{
    c:30,
    d:[1,2,3]
  }
}
console.log(isEqual(a,b)) //true 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

3.数组扁平化的方法

function _flat(arr){
  let result = []
  for(let i = 0;i<arr.length;i++){
    if(Array.isArray(arr[i])){
      result = result.concat(_flat(arr[i]))
    }else{
      result.push(arr[i])
    }
  }
  return result;
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
let arr = [1,2,[3,4,[5,6]]]
_flat(arr) //[1,2,3,4,5,6] 
  • 1
  • 2
//es6
function _flat2(arr){
  while(arr.some(item=>Array.isArray(item))){
    arr = [].concat(...arr)
  }
  return arr
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
let arr = [1,2,[3,4,[5,6]]]
_flat2(arr) //[1,2,3,4,5,6] 
  • 1
  • 2

4.深克隆

简单深克隆,不考虑内置对象和函数

function deepClone(obj){
  if(typeof obj !== 'object') return
  let newObj = obj instanceof Array?[]:{}
  for(let key in obj){
      if(obj.hasOwnProperty(key)){
          newObj[key] = typeof obj[key] === 'object'?deepClone(obj[key]):obj[key]
      }
  }
  return newObj
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

复杂版深度克隆 考虑内置对象 比如date regexp 函数 以及对象的循环引用的问题

const isObject = (target) => typeof target === "object"&& target !== null;

function deepClone2(target, map = new WeakMap()) {
  console.log(target)
    if (map.get(target)) {
        return target;
    }
    // 获取当前值的构造函数:获取它的类型
    let constructor = target.constructor;
    // 检测当前对象target是否与正则、日期格式对象匹配
    if (/^(RegExp|Date)$/i.test(constructor.name)) {
        // 创建一个新的特殊对象(正则类/日期类)的实例
        return new constructor(target);  
    }
    if (isObject(target)) {
        map.set(target, true);  // 为循环引用的对象做标记
        const cloneTarget = Array.isArray(target) ? [] : {};
        for (let prop in target) {
            if (target.hasOwnProperty(prop)) {
                cloneTarget[prop] = deepClone(target[prop], map);
            }
        }
        return cloneTarget;
    } else {
        return target;
    }
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

5.数组去重

filter去重

function _unique(arr){
  return arr.filter((item,index,array)=>{
    return array.indexOf(item) === index
  })
} 
  • 1
  • 2
  • 3
  • 4
  • 5

es6 Set

function _unique2(arr){
  return [...new Set(arr)]
} 
  • 1
  • 2
  • 3

includes

function _unique3(arr){
  let newArr = []
  arr.forEach(item => {
      if(!newArr.includes(item)){
        newArr.push(item)
      }
  });
  return newArr
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

双层for循环

function _unique4(arr){
  for(let i =0;i<arr.length;i++){
    for(let j =i+1;j<arr.length;j++){
      if(arr[i] === arr[j]){
        arr.splice(j,1)
        j--
      }
    }
  }
  return arr
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

indexof

function _unique5(arr){
  let newArr = []
  for(let i = 0;i<arr.length;i++){
    if(newArr.indexOf(arr[i] === -1){
      newArr.push(arr[i])
    })
  }
  return newArr
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

6.判断数据的类型

function _typeOf(obj){
  let res = Object.prototype.toString.call(obj).split(' ')[1]
  let mold = res.substring(0,res.length-1).toLowerCase()
  return mold
} 
  • 1
  • 2
  • 3
  • 4
  • 5
_typeOf(5) //number
_typeOf('5') //string 
  • 1
  • 2

7.解析url参数为对象

function getParamsObj(params){
  let paramsStr = params.replace(/^.+\?(.+)/,"$1")
  let paramsArr = paramsStr.split('&')
  let paramsObj = {}

  for(let [key,value] of paramsArr.entries()){
      if(/=/.test(value)){
          let valArr = value.split('=')
          val = decodeURIComponent(valArr[1]) //解码
          val = /^\d+$/.test(val)?parseFloat(val):val //判断是不是数字
          if(paramsObj.hasOwnProperty(valArr[0])){
              paramsObj[valArr[0]] = [].concat(paramsObj[valArr[0]],val)
          }else{
              paramsObj[valArr[0]] = val
          }
      }  

  }
  return paramsObj
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

8.函数柯里化

//从一次传入多个参数  编程多次调用每次传入一个参数
function add(a, b, c, d, e) {
  return a + b + c + d + e
}

function curry(fn) {
   let dFn = (...args)=>{
     if(args.length == fn.length) return fn(...args)
     return (...arg)=>{
       return dFn(...args,...arg)
     }
   }
   return dFn
}
let addCurry = curry(add)
addCurry(1,2,3)(2)(3) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

9.图片懒加载

//添加了两个功能
// 图片加载完成后 移除事件监听
// 加载完的图片从imgList中移除
let imgList = [...document.querySelectorAll('img')]
let length = imgList.length

const imgLazyLoad = function () {
  let count = 0
  let deleteIndexList = []
  imgList.forEach((img, index) => {
    let rect = img.getBoundingClientRect() 
    //获取元素到视图的距离 top元素上边到视图上边的距离 left元素左边到视图左边的距离  right... bottom...
    if (rect.top < window.innerHeight) {
      // img.src = img.dataset.src
      img.src = img.getAttribute('data-src')
      deleteIndexList.push(index)
      count++
      if (count === length) {
        document.removeEventListener('scroll', imgLazyLoad)
      }
    }
  })
  imgList = imgList.filter((img, index) => !deleteIndexList.includes(index))
}
imgLazyLoad()

document.addEventListener('scroll', imgLazyLoad) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

图片懒加载:https://juejin.cn/post/6844903856489365518#heading-19

10节流防抖

函数防抖 触发高频事件 事件在n后执行,如果n秒钟重复执行了 则时间重置

//简易版
function debounce(func,wait){
  let timer; 
  return function(){
    let context = this;
    let args = arguments;
    console.log(timer)
    clearTimeout(timer)
    timer = setTimeout(function(){
      func.apply(context,args)
    },wait)
  }

}
let btn = document.querySelector('button');
function aa(){
  console.log(111)
}
btn.onclick = debounce(aa,2000) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
// 复杂版
// 1.取消防抖  
// 2.立即执行功能(点击之后立即执行函数  但是 wait时间之后在点击才能在立即执行)  
// 3.函数可能有返回值
function debounce(func,wait,immediate){
  let timer,result;

  const debounce = function () {
    const context = this
    const args = arguments

    if(timer) clearTimeout(timer)
    if(immediate){
      console.log(timer)
      var callNow = !timer
      timer = setTimeout(function () {
          timer =null
      },wait)
      if(callNow) result = func.apply(context,args)
    }else{
      timer = setTimeout(function (params) {
        result = func.apply(context,args)
      },wait)
    }
    return result
  }

  debounce.cance = function () {
    clearTimeout(timer)
    timer=null
  }

  return debounce

}

let btn = document.querySelector('button');
function aa(){
  console.log(111)
}
btn.onclick = debounce(aa,2000,true)``` 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

函数节流 触发高频事件 且n秒只执行一次

//使用时间戳
function  throttle(func,wait) {
  var context,args;
  var previous = 0

  return function () {
    context = this;
    args = arguments;
    let nowDate = +new Date()
    if(nowDate-previous>wait){
      func.apply(context,arguments)
      previous = nowDate
    }
  }
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
//定时器
function throttle(func,wait) {
  var context,args;
  var timer;
  return function(){
    context = this;
    args = arguments;
    if(!timer){
      timer = setTimeout(function () {
        timer = null;
        func.apply(context,args)
      },wait)
    }
  }

} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
//组合版 options.leading 为true 立即执行一次 options.trailing为true  结束之后执行一次 默认为true
function throttle(func, wait ,options = {}) {
  var context, args, timer,result;
  var previous = 0;

  var later = function () {
    previous = options.leading === false ? 0 : new Date().getTime();
    timer = null;
    func.apply(context, args)
    if (!timer) context = args = null;
  }

  var throttle = function () {
    var now = new Date().getTime()
    if (!previous && options.leading === false) previous = now;
    context = this;
    args = arguments;

    //下次触发 func 剩余的时间
    var remaining = wait - (now - previous);
    if (remaining <= 0 || remaining > wait) {
      // if (timer) {
      //   clearTimeout(timer);
      //   timer = null;
      // }
      previous = now;
      func.apply(context, args);
      if (!timer) context = args = null;
    } else if (!timer&& options.trailing !== false) {
      timer = setTimeout(later, remaining);
    }
  }

  throttled.cancel = function() {
    clearTimeout(timer);
    previous = 0;
    timer = null;
  }

  return throttle
}

function aa(e) {
  console.log(111)
  console.log(e)
}

let btn = document.querySelector('button');
btn.onclick = throttle(aa, 2000,{
  leading:false,
  trailing:true 

})

转自:csdn论坛 作者:Selfimpr欧

app界面赏析 + icon 图标分享 ——— 北京蓝蓝设计 移动端UI设计资源分享(十八)

前端达人

移动互联网的迅速崛起,让移动网页,移动客户端越来越重要,客户端的页面设计也是一门很大的学问。科技迅速发展的今手机屏幕的尺寸越来越放大化,但却始终 很有限,因此,在APP的界面设计中,精简是一贯的准则。这里所说的精简并不是内容上尽可能的少量,而是要注重重点的表达。在视觉上也要遵循用户的视觉逻 辑,用户看着顺眼了,才会真正的喜欢。


接下来为大家分享精美的app UI设计案例:

jhk-1618475928898.jpgjhk-1618475937124.jpgjhk-1618475946821.jpgjhk-1618475964960.jpgjhk-1618475993734.jpg



icon的设计会贯穿全套设计稿,所以在设计的环节中必不可少,优质的icon设计会帮助品牌和企业更好的树立形象,形成自己的设计语言。

接下来为大家分享一些经典案例:

WechatIMG1677.jpegWechatIMG1678.jpegWechatIMG1679.jpegWechatIMG1680.jpegWechatIMG1681.jpeg




--手机appUI设计--

--icon图标赏析--

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服



  更多精彩文章:

       手机appUI界面设计赏析(一)

       手机appUI界面设计赏析(二)

       手机appUI界面设计赏析(三)

       手机appUI界面设计赏析(四)

       手机appUI界面设计赏析(五)

       手机appUI界面设计赏析(六)

       手机appUI界面设计赏析(七)

       手机appUI界面设计赏析(八)

       手机appUI界面设计赏析(九)

        手机appUI界面设计赏析(十)

       手机appUI界面设计赏析(十一)

       手机appUI界面设计赏析(十二)

        手机appUI界面设计赏析(十三)

       手机appUI界面设计赏析(十四)

       手机appUI界面设计赏析(十五)

       手机appUI界面设计赏析(十六)

       手机appUI界面设计赏析(十七)


Vue双向数据绑定原理

前端达人

1. vue双向数据绑定是通过 数据劫持,并结合 发布-订阅模式的方法来实现的,也就是说数据和视图同步,数据发生变化,视图跟着变化,视图变化,数据也随之发生改变

2. 核心:关于vue实现双向数据绑定,其核心是Object.defineProperty()方法

3. 介绍一下Object.defineProperty()方法

1.Object.defineProperty(obj,prop,descriptor)这个语法内有三个参数,分别是obj(要定义其上属性的对象) prop (要定义或修改的属性)descriptor (具体的改变方法)
2.简单的说 就是用这个方法来定义一个值。当调用时我们使用了它里面的get方法,当我们给这个属性赋值的时候,又用到了它里面的set方法

var obj = {}; Object.defineProperty(obj,'hello',{ get: function(){ console.log('调用了get方法') }, set: function(newValue){ console.log('调用了set方法,方法的值是' + newValue); } }); obj.hello; // => '调用了get方法' obj.hello = 'hi'; // => '调用了set方法,方法的值是hi' 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

4. 再介绍一下发布-订阅模式

在这里插入图片描述

原文来自于这里,我说一下我自己的理解,其实发布-订阅模式和观察者模式很像,但是不同的是,观察者模式只有两个角色,而且Obsever是知道Subject的,但是在发布-订阅模式中,他们两却彼此不了解,他们是在一种类似于中间件的帮助下进行通信的,换句话说,还有第三个组件,称为代理或消息代理或事件总线,Observer和Subject都知道该组件,该组件过滤所有传入消息并相应的分发他们。

5. 然后就是简单模拟实现一下Vue的双向数据绑定

<input type="text"> <p></p> 
  • 1
  • 2

我们要对上面两个DOM元素实现双向数据绑定,就是当输入inputValue时下面的p可以及时更新inputValue内容

<script> let input = document.querySelector('input') let p = document.querySelector('p') let obj = {} let value = '' Object.defineProperty(obj, 'inputvalue', { get() { return value }, set(newValue) { input.value = newValue
            p.innerHTML = newValue } }) // 订阅者 DOM元素 input.value = obj.inputvalue
    p.innerHTML = obj.inputvalue // 监听输入的事件 input.addEventListener('keyup', function (e) { // 修改inputvalue 达到修改input.value 以及input.innerHTML // 发布者 obj.inputvalue = e.target.value // 触发了set }) </script> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

所以在我们的代码中,订阅者就是页面中的DOM元素,因为他会订阅我们的inputvalue,而发布者就是监听事件中的数据,一旦监听到了数据有修改,就要发布给我们的订阅者,也就是说输入的数据一旦发生了变化,我们的页面DOM元素的数据也会发生变化,所以这个中间件就是Object.defineProperty中的set方法

6. 结果演示

在这里插入图片描述


转自:csdn 论坛 作者:Y shǔ shǔ


蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服

JavaScript学习(三十八)—面向过程与面向对象

前端达人

JavaScript学习(三十八)—面向过程与面向对象

一、程序设计语言中的两大编程思想:面向对象、面向过程

(一)、面向过程

  • 就是指完成某个需求的时候,先分析出完成该需求时所需要经历的步骤有哪些,然后按照步骤依次执行,最终实现我们想要的效果。这种编程思想就是面向过程,典型的面向过程的编程语言有C语言。

(二)、面向对象

  • 就是在完成某个需求的时候,先分析完成该需求所需要涉及的对象有哪些,然后找出这些对象所具有的属性和方法,利用这些属性和方法帮助我们完成需求。这种编程思想就是面向对象。典型的面向对象的语言有Java、C++。

在这里插入图片描述

(三)、什么是对象?

  • 所谓的对象就是指具有特定功能的无序的属性的集合。JS中的对象有内置对象,也可以根据需求自定义对象。

自定义对象的方式主要有以下几种:
字面量形式、工厂形式、构造方法

(四)、字面量形式的创建
格式:

var 对象名称={ 属性名称1:属性,1,

    属性名称2:属性值2,

    属性名称3:属性值3,

    属性名称n:属性值n, }; 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

沙场练兵:

<!-- 创建一个汽车对象 1、属性:品牌、价格、颜色等、 2、方法(功能):跑、停 --> <body> <script> var car = { brand: '宝马', price: '100万', color: 'red', run: function() { console.log('汽车跑起来了'); }, stop: function() { console.log('汽车停下来了'); } }; console.log(car); </script> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

在这里插入图片描述

 <script> var person = { name: '小王', age: '18', gender: '女', eat: function() { console.log('方便面'); }, play: function() { console.log('王者荣耀'); }, study: function() { console.log('web前端'); } }; console.log(person); </script> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

在这里插入图片描述

转自:csdn论坛 作者:乘风破浪的程序媛


蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服

JavaScript操作符in:由一个问题引发的探究

前端达人

事情是这样的:大家都知道“内存泄露”这回事吧。它有几个常见的场景:

  1. 闭包使用不当引起内存泄漏
  2. (未声明的)全局变量
  3. 分离的DOM节点
  4. (随意的)控制台的打印
  5. 遗忘的定时器
  6. 循环引用

内存泄漏需要重视,它是如此严重甚至会导致页面卡顿,影响用户体验!

其中第 3 点引起了我的注意 —— 我当然清楚地知道它说的是比如:“假设你手动移除了某个dom节点,本应释放该dom节点所占用的内存,但却因为疏忽导致某处代码仍对该被移除节点有引用,最终导致该节点所占内存无法被释放”的情况

<div id="root"> <div class="child">我是子元素</div> <button>移除</button> </div> <script> let btn = document.querySelector('button') let child = document.querySelector('.child') let root = document.querySelector('#root') btn.addEventListener('click', function() { root.removeChild(child) }) </script> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

该代码所做的操作就是点击按钮后移除.child的节点,虽然点击后,该节点确实从dom被移除了,但全局变量child仍对该节点有引用,所以导致该节点的内存一直无法被释放。

解决办法:我们可以将对.child节点的引用移动到click事件的回调函数中,那么当移除节点并退出回调函数的执行上文后就会自动清除对该节点的引用,自然也就不会存在内存泄漏的情况了。(这实际上是在事件中实时检测该节点是否存在,如果不存在则浏览器必不会触发remove函数的执行)

<div id="root"> <div class="child">我是子元素</div> <button>移除</button> </div> <script> let btn = document.querySelector('button') btn.addEventListener('click', function() { let child = document.querySelector('.child') let root = document.querySelector('#root') root.removeChild(child) }) </script> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

这段代码很完美么?不。因为它在每次事件触发后都创建了对child和root节点的引用。消耗了内存(你完全可以想象一些人会狂点按钮的情况…)。
其实还有一种办法:我们在click中去判断当前root节点中是否还存在child子节点,如果存在,则执行remove函数,否则什么也不做!

这就引发了标题中所说的行为。

怎么判断?
遍历?不,太过麻烦!
不知怎的,我突然想到了 for...in 中的 in 操作符,它可以基于原型链遍历对象!

我们来还原一下当时的场景:打开GitHub,随便找一个父节点,并获取它:
mygithub
图中画红框的就是我们要取的父元素,橘红色框的就是要判断是否存在的子元素。

let parent=document.querySelector('.position-relative'); let child=document.querySelector('.progress-pjax-loader'); 
  • 1
  • 2

这里注意,因为获取到的是DOM节点(类数组对象),所以我们在操作前一定要先处理一下:
object

let p_child=[...parent.children]; 
  • 1

array
然后

console.log(child in p_child); 
  • 1

not
!!!
为什么呢?(此时笔者还没有意识到事情的严重性)
我想,是不是哪里出了问题,用es6的includes API验证一下:

console.log(p_child.includes(child)); 
  • 1

yes
没错啊!
再用一般的数组验证一下:
Verification
???
此时,笔者才想起到MDN上查阅一番:
mdn
进而我发现:in操作符单独使用时它检测的是左侧的值(作为索引)对应的值是否在右侧的对象内部(属性 & 原型上)

回到上面的代码中,我们发现:
vertification_2
这验证了我们的结论。
很显然,“子元素”并不等同于“存在于原型链上” —— 这又引出了一个知识点:attribute和property的区别

所以经过一番“折腾”,源代码还是应该直接这样写:

<div id="root"> <div class="child">我是子元素</div> <button>移除</button> </div> <script> let btn = document.querySelector('button') let child = document.querySelector('.child') let root = document.querySelector('#root') let r_child = [...root.children] btn.addEventListener('click', function() { if(r_child.includes(child)){ // 或者你这里直接判断child是否为null也可以...吧 root.removeChild(child) } }) </script> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17



















转自:csdn论坛   作者:恪愚


蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服



JavaScript逐点突破系列之this是什么?了解完这7点很多疑惑都解决

前端达人

前言

本章将专门介绍与执行上下文创建阶段直接相关的最后一个细节——this是什么?以及它的指向到底是什么。

了解this

也许你在其他面向对象的编程语言曾经看过this,也知道它会指向某个构造器(constructor)所建立的对象。但事实上在JavaScript里面,this所代表的不仅仅是那个被建立的对象。

先来看看ECMAScript 标准规范对this 的定义:

「The this keyword evaluates to the value of the ThisBinding of the current execution context.」
「this 这个关键字代表的值为当前执行上下文的ThisBinding。」

然后再来看看MDN 对this 的定义:

「In most cases, the value of this is determined by how a function is called.」
「在大多数的情况下,this 其值取决于函数的调用方式。」

好,如果上面两行就看得懂的话那么就不用再往下看了,Congratulations!

… 我想应该不会,至少我光看这两行还是不懂。

先来看个例子吧:

var getGender = function() {
    return people1.gender;
};

var people1 = {
    gender: 'female',
    getGender: getGender
};

var people2 = {
    gender: 'male',
    getGender: getGender
};

console.log(people1.getGender());    // female
console.log(people2.getGender());    // female 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

what?怎么people2变性了呢,这不是我想要的结果啊,为什么呢?

因为getGender()返回(return)写死了people1.gender的关系,结果自然是’female’。

那么,如果我们把getGender稍改一下:

var getGender = function() {
    return this.gender;
}; 
  • 1
  • 2
  • 3
  • 4

这个时候,你应该会分别得到femalemale两种结果。

所以回到前面讲的重点,从这个例子可以看出,即便people1people2getGender方法参照的都是同一个getGender function,但由于调用的对象不同,所以执行的结果也会不同

现在我们知道了第一个重点,**this实际上是在函数被调用时发生的绑定,它指向什么完全取决于函数的调用方式。**如何的区分this呢?

this到底是谁

看完上面的例子,还是有点似懂非懂吧?那接下来我们来看看不同的调用方式对 this 值的影响。

情况一:全局对象&调用普通函数

在全局环境中,this 指向全局对象,在浏览器中,它就是 window 对象。下面的示例中,无论是否是在严格模式下,this 都是指向全局对象。

var x = 1

console.log(this.x)               // 1
console.log(this.x === x)         // true
console.log(this === window)      // true 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

如果普通函数是在全局环境中被调用,在非严格模式下,普通函数中 this 也指向全局对象;如果是在严格模式下,this 将会是 undefined。ES5 为了使 JavaScript 运行在更有限制性的环境而添加了严格模式,严格模式为了消除安全隐患,禁止了 this 关键字指向全局对象。

var x = 1

function fn() {
    console.log(this);   // Window 全局对象
    console.log(this.x);  // 1
}

fn(); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

使用严格模式后:

"use strict"     // 使用严格模式
var x = 1

function fn() {
    console.log(this);   // undefined
    console.log(this.x);  // 报错 "Cannot read property 'x' of undefined",因为此时 this 是 undefined
}

fn(); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

情况二:作为对象方法的调用

我们知道,在对象里的值如果是原生值(primitive type;例如,字符串、数值、布尔值),我们会把这个新建立的东西称为「属性(property)」;如果对象里面的值是函数(function)的话,我们则会把这个新建立的东西称为「方法(method)」。

如果函数作为对象的一个方法时,并且作为对象的一个方法被调用时,函数中的this指向这个上一级对象

var x = 1
var obj = {
    x: 2,
    fn: function() {
        console.log(this);    
        console.log(this.x);
    }
}

obj.fn()     

// obj.fn()结果打印出;
// Object {x: 2, fn: function}
// 2

var a = obj.fn
a()   

// a()结果打印出:   
// Window 全局对象
// 1 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

在上面的例子中,直接运行 obj.fn() ,调用该函数的上一级对象是 obj,所以 this 指向 obj,得到 this.x 的值是 2;之后我们将 fn 方法首先赋值给变量 a,a 运行在全局环境中,所以此时 this 指向全局对象Window,得到 this.x 为 1。

我们再来看一个例子,如果函数被多个对象嵌套调用,this 会指向什么。

var x = 1
var obj = {
  x: 2,
  y: {
    x: 3,
    fn: function() {
      console.log(this);   // Object {x: 3, fn: function}
      console.log(this.x);   // 3
    }
  }
}

obj.y.fn(); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

为什么结果不是 2 呢,因为在这种情况下记住一句话:this 始终会指向直接调用函数的上一级对象,即 y,上面例子实际执行的是下面的代码。

var y = {
  x: 3,
  fn: function() {
    console.log(this);   // Object {x: 3, fn: function}
    console.log(this.x);   // 3
  }
}

var x = 1
var obj = {
  x: 2,
  y: y
}

obj.y.fn(); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

对象可以嵌套,函数也可以,如果函数嵌套,this 会有变化吗?我们通过下面代码来探讨一下。

var obj = {
    y: function() {
        console.log(this === obj);   // true
        console.log(this);   // Object {y: function}
        fn();

        function fn() {
            console.log(this === obj);   // false
            console.log(this);   // Window 全局对象
        }
    }
}

obj.y(); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在函数 y 中,this 指向了调用它的上一级对象 obj,这是没有问题的。但是在嵌套函数 fn 中,this 并不指向 obj。嵌套的函数不会从调用它的函数中继承 this,当嵌套函数作为函数调用时,其 this 值在非严格模式下指向全局对象,在严格模式是 undefined,所以上面例子实际执行的是下面的代码。

function fn() {
    console.log(this === obj);   // false
    console.log(this);   // Window 全局对象
}

var obj = {
    y: function() {
        console.log(this === obj);   // true
        console.log(this);   // Object {y: function}
        fn();
    }
}

obj.y(); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

情况三:作为构造函数调用

我们可以使用 new 关键字,通过构造函数生成一个实例对象。此时,this 便指向这个新对象

var x = 1;

function Fn() {
   this.x = 2;
    console.log(this);  // Fn {x: 2}
}

var obj = new Fn();   // obj和Fn(..)调用中的this进行绑定
console.log(obj.x)   // 2 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

使用new来调用Fn(..)时,会构造一个新对象并把它(obj)绑定到Fn(..)调用中的this。还有值得一提的是,如果构造函数返回了非引用类型(string,number,boolean,null,undefined),this 仍然指向实例化的新对象。

var x = 1

function Fn() {
  this.x = 2

  return {
    x: 3
  }
}

var a = new Fn()

console.log(a.x)      // 3 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

因为Fn()返回(return)的是一个对象(引用类型),this 会指向这个return的对象。如果return的是一个非引用类型的值呢?

var x = 1

function Fn() {
  this.x = 2

  return 3
}

var a = new Fn()

console.log(a.x)      // 2 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

情况四:call 和 apply 方法调用

如果你想改变 this 的指向,可以使用 call 或 apply 方法。它们的第一个参数都是指定函数运行时其中的this指向。如果第一个参数不传(参数为空)或者传 null 、undefined,默认 this 指向全局对象(非严格模式)或 undefined(严格模式)。

var x = 1;

var obj = {
  x: 2
}

function fn() {
    console.log(this);
    console.log(this.x);
}

fn.call(obj)
// Object {x: 2}
// 2

fn.apply(obj)     
// Object {x: 2}
// 2

fn.call()         
// Window 全局对象
// 1

fn.apply(null)    
// Window 全局对象
// 1

fn.call(undefined)    
// Window 全局对象
// 1 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

使用 call 和 apply 时,如果给 this 传的不是对象,JavaScript 会使用相关构造函数将其转化为对象,比如传 number 类型,会进行new Number()操作,如传 string 类型,会进行new String()操作,如传 boolean 类型,会进行new Boolean()操作。

function fn() {
  console.log(Object.prototype.toString.call(this))
}

fn.call('love')      // [object String]
fn.apply(1)          // [object Number]
fn.call(true)          // [object Boolean] 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

call 和 apply 的区别在于,call 的第二个及后续参数是一个参数列表,apply 的第二个参数是数组。参数列表和参数数组都将作为函数的参数进行执行。

var x = 1

var obj = {
  x: 2
}

function Sum(y, z) {
  console.log(this.x + y + z)
}

Sum.call(obj, 3, 4)       // 9
Sum.apply(obj, [3, 4])    // 9 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

情况五:bind 方法调用

调用 f.bind(someObject) 会创建一个与 f 具有相同函数体和作用域的函数,但是在这个新函数中,新函数的 this 会永久的指向 bind 传入的第一个参数,无论这个函数是如何被调用的。

var x = 1

var obj1 = {
    x: 2
};
var obj2 = {
    x: 3
};

function fn() {
    console.log(this);
    console.log(this.x);
};

var a = fn.bind(obj1);
var b = a.bind(obj2);

fn();
// Window 全局对象
// 1

a();
// Object {x: 2}
// 2

b();
// Object {x: 2}
// 2

a.call(obj2);
// Object {x: 2}
// 2 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

在上面的例子中,虽然我们尝试给函数 a 重新指定 this 的指向,但是它依旧指向第一次 bind 传入的对象,即使是使用 call 或 apply 方法也不能改变这一事实,即永久的指向 bind 传入的第一次参数。

情况六:箭头函数中this指向

值得一提的是,从ES6 开始新增了箭头函数,先来看看MDN 上对箭头函数的说明

An arrow function expression has a shorter syntax than a function expression and does notbind its ownthis,arguments,super, ornew.target. Arrow functions are always anonymous. These function expressions are best suited for non-method functions, and they cannot be used as constructors.

这里已经清楚了说明了,箭头函数没有自己的this绑定。箭头函数中使用的this,其实是直接包含它的那个函数或函数表达式中的this。在前面情况二中函数嵌套函数的例子中,被嵌套的函数不会继承上层函数的 this,如果使用箭头函数,会发生什么变化呢?

var obj = {
  y: function() {
        console.log(this === obj);   // true
        console.log(this);           // Object {y: function}

      var fn = () => {
          console.log(this === obj);   // true
          console.log(this);           // Object {y: function}
      }
      fn();
  }
}

obj.y() 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

和普通函数不一样,箭头函数中的 this 指向了 obj,这是因为它从上一层的函数中继承了 this,你可以理解为箭头函数修正了 this 的指向。所以箭头函数的this不是调用的时候决定的,而是在定义的时候处在的对象就是它的this

换句话说,箭头函数的this看外层的是否有函数,如果有,外层函数的this就是内部箭头函数的this,如果没有,则this是window

var obj = {
  y: () => {
        console.log(this === obj);   // false
        console.log(this);           // Window 全局对象 

      var fn = () => {
          console.log(this === obj);   // false
          console.log(this);           // Window 全局对象 
      }
      fn();
  }
}

obj.y() 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

上例中,虽然存在两个箭头函数,其实this取决于最外层的箭头函数,由于obj是个对象而非函数,所以this指向为Window全局对象。

同 bind 一样,箭头函数也很“顽固”,我们无法通过 call 和 apply 来改变 this 的指向,即传入的第一个参数被忽略

var x = 1
var obj = {
    x: 2
}

var a = () => {
    console.log(this.x)
    console.log(this)
}

a.call(obj)       
// 1
// Window 全局对象

a.apply(obj)      
// 1
// Window 全局对象 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

上面的文字描述过多可能有点干涩,那么就看以下的这张流程图吧,我觉得这个图总结的很好,图中的流程只针对于单个规则。

小结

本篇文章介绍了 this 指向的几种情况,不同的运行环境和调用方式都会对 this 产生影响。总的来说,函数 this 的指向取决于当前调用该函数的对象,也就是执行时的对象。在这一节中,你需要掌握:

  • this 指向全局对象的情况;
  • 严格模式和非严格模式下 this 的区别;
  • 函数作为对象的方法调用时 this 指向的几种情况;
  • 作为构造函数时 this 的指向,以及是否 return 的区别;
  • 使用 call 和 apply 改变调用函数的对象;
  • bind 创建的函数中 this 的指向;

  • 箭头函数中的 this 指向。
  • 转自:csdn 论坛  作者:蛋黄酥要不要来一口阿

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服

vue.js前端框架:Vue.js简介

前端达人

1 Vue.js概述

  • Vue.js(读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其他重量级框架不同的是,它只关注视图层(View层),采用自底向上增量开发的设计。Vue.js的目标是通过尽可能简单的API实现相应的数据绑定和组合的视图组件。它不仅容易上手,还非常容易与其他库或已有项目进行整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue .js也完全能够为复杂的单页应用提供驱动。

1.1 什么是Vue.js

  • Vue.js实际上是一个用于开发Web前端界面的库,其本身具有响应式编程和组件化的特点。所谓响应式编程,即保持状态和视图的同步。响应式编程允许将相关模型的变化自动反映到视图上,反之亦然。Vue.js采用的是MVVM(Model-View-ViewModel)的开发模式。与传统的MVC开发模式不同,MVVM将MVC中的Controller改成了ViewModel。在这种模式下,View的变化会自动更新到ViewModel,而ViewModel的变化也会自动同步到View上进行显示。
  • ViewModel模式的示意图如下图所示:
    在这里插入图片描述
  • 与ReactJS一样,Vue.js同样拥有”一切都是组件“的理念。应用组件化的特点,可以将任意封装好的代码注册成标签,这样就在很大程度上减少了重复开发,提高了开发效率和代码复用性。如果配合Vue.js的周边工具vue-loader,可以将一个组件的HTML、CSS、JavaScript代码都写在一个文件中,这样可以实现模块化的开发。

1.2 Vue.js的特性

  • Vue.js的主要特性如下:
  •  轻量级
    相比较AngularJS和ReactJS而言,Vue.js是一个更轻量级的前端库。不但容量非常小,而且没有其它的依赖。
  •  数据绑定
    Vue.js最主要的特点就是双向的数据绑定。在传统的Web项目中,将数据在视图层展示出来后,如果需要再次修改视图,需要通过获取DOM的方法进行修改,这样才能维持数据和视图的一致。而Vue.js是一个响应式的数据绑定系统,在建立绑定后,DOM将和Vue对象中的数据保持同步,这样就无须手动获取DOM的值再同步到 js中。
  •  应用指令
    同AngularJS一样,Vue.js也提供了指令这一概念。指令用于在表达式的值发生变化时,将某些行为应用到绑定的DOM上,通过对应表达式值的变化就可以修改对应的DOM。
  •  插件化开发
    与AngularJS类似,Vue,js也可以用来开发一个完整的单页应用。在Vue.js的核心库中并不包含路由、Ajax等功能,但是可以非常方便地加载对应插件来实现这样的功能。例如,vue-router插件提供了路由管理的功能,vue-resource插件提供了数据请求的功能。

2 Vue.js的安装

2.1 直接下载并使用 script 标签引入

  • Vue.js官网:https://cn.vuejs.org/v2/guide/
  • 在Vue.js的官方网站中可以直接下载vue.js文件并使用 script标签引入。
    1、下载Vue.js
    Vue.js是一个开源的库,可以从它的官方网站中下载。下面介绍具体的下载步骤:
    (1)打开Vue.js的官方网站,进入到Vue.js的下载页面,找到如下图1.2所示的内容。
    在这里插入图片描述
    (2)根据开发者的实际情况选择不同的版本进行下载。这里以下载开发版本为例,在”开发版本“按钮上单击鼠标右键,如下图1.3所示。
    在这里插入图片描述
    (3)在弹出的快捷菜单中单击“连接另存为”选项,弹出下载对话框,如下图1.4所示,单击对话框中的“保存”按钮,将Vue.js文件下载到本地计算机上。在这里插入图片描述此时下载的文件为完整不压缩的开发版本。如果在开发环境下,推荐使用该版本,因为该版本中包含所有常见错误相关的警告。如果在生产环境下,推荐使用压缩后的生产版本,因为使用生产版本可以带来比开发环境下更快的速度体验。
  • 引入Vue.js
    将Vue.js下载到本地计算机后,还需要在项目中引用Vue.js。即将下载后的vue.js文件放置到项目的指定文件夹中。通常文件放置在JS文件夹中,然后在需要应用vue.js文件的页面中使用下面的语句,将其引入到文件中。
<script type="text/javascript" src="JS/vue.js"></script> 
  • 1

注意:引入Vue.js的 script 标签,必须放在所有的自定义脚本文件的script 之前,否则在自定义的脚本代码中应用步到Vue.js。

2.2 使用CDN方法

  • 在项目中使用Vue.js,还可以采用引用外部CDN文件的方式。在项目中直接通过 script 标签加载CDN文件,通过CDN文件引用Vue.js的代码如下:
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.21/vue.js"></script> 
  • 1

注意:为了防止出现外部CDN文件不可用的情况,还是建议用户将Vue.js下载到本地计算机中。

2.3 使用NPM方法

  • 在使用Vue.js构建大型应用时,推荐使用NPM方法进行安装,执行命令如下:
npm install vue 
  • 1

注意:使用NPM方法安装Vue.js需要在计算机中安装node.js。
node;js官网:https://nodejs.org/en/,通过node.js官网下载之后,傻瓜式安装即可。

3 前端框架开发工具

  • 利用Vue.js进行前端框架开发的常用工具有如下几个:WebStorm、IDEA、Vscode

  • 前端框架开发常用的工具下载:
    (1)WebStorm官网:https://www.jetbrains.com/webstorm/
    (2)IDEA官网:https://www.jetbrains.com/idea/
    (3)Vscode官网:https://vscode.en.softonic.com/

  • 转自:csdn 作者:小白_xm

日历

链接

个人资料

蓝蓝设计的小编 http://www.lanlanwork.com

存档