wolfzwz

wolfzwz 查看完整档案

北京编辑  |  填写毕业院校破冰行动  |  缉毒队长 编辑填写个人主网站
编辑

good good study

个人动态

wolfzwz 发布了文章 · 2018-12-27

前端模块化结构如何拆分

模块化结构

将复杂的程序拆分成不同的文件夹或者文件
不同的模块即独立又可以相互关联

如何拆分

具体的拆分规则针对不同的项目也不一样,这里列出一点建议,更主要的还是有自己的一个规范,

物以类聚
将具有相同特性的可以拆分到一起,比如在一个vue电商网站项目中对文件夹的拆分

pages 源文件入口
    |-list 列表模块(可能包括普通列表页,闪购列表) 都可以认为是列表页属于一类
        |-list 普通列表页
            |- components 组件
            |- router 路由
            |- store vuex
            |- index.js 打包js
        |-其它页面

按功能拆分

 在上边的结构划分中,普通列表页有组件,路由,vuex,还有打包入口,这些都可以看成模块,每个模块各自负责不同的功能,
        components 负责存放普通列表页单独拥有的组件
        router 负责路由
        store 状态
        index.js 等同于普通列表页容器组件
 最终这些不同功能的模块组合成了一个完整的页面结构

这里只说了两种简单的拆分思想给大家做个入门,真正项目拆分过程其实也是这样,搞清楚自己的项目,
文件结构如何拆分真正还是取决于自己,当然可以参考业界规范,一般情况下拆了就比不拆强,所以大家可以多尝试

查看原文

赞 2 收藏 1 评论 0

wolfzwz 发布了文章 · 2018-12-17

vue常见知识点总结

学会查找api
在vue中,v-text=“”等指令中的双引号可以是任何简单的js表达式,
Js简单的表达式包括:
Js基本类型,数字,字符串等等,
还可以是三元表达式

v-show 控制显示隐藏和v-if的区别
v-show 可以清除style=”display: none”
V-if在虚拟内存中,不会清除style=”display: none”

v-text 显示文本,和{{}}的区别
页面首屏不用{{}},只在组件中使用{{}}

v-bind 两个用法
1.绑定dom元素的属性,只要是dom元素的属性都可以绑定,例如

v-bind:style=”{height: 20px}”
v-bind:class=”{active: isActive}”,默认绑定class用对象的形式

2.给子组件绑定属性值传参

<dialog v-bind:display=“true”></dialog>

v-on 两个用法
1.监听dom元素的事件

<div v-on:click=”fn”></div>

2.监听自定义组件内部触发的事件

<dialog v-on:close=“fn”></dialog>

v-if,v-else-if

<div v-if=”active === true”>v-if</div>
<div v-else=”active === false”>v-else</div>
<div v-else-if>v-else-if</div>

Computed 计算属性

由其它data中的属性计算得到,依赖属性改变是,其值将会改变
new({
    el:'',
    data:{
        cartNum: 20,
        everyPrice: 20
    },
    computed{
        totalPrice(){
            return cartNum * everyPrice
        }
    }
})

Watch 监听属性的改变和computed区别

new({
    el:'',
    data:{
        cartNum: 20,
        everyPrice: 20
    },
    Watch:{
        cartNum (newval,oldval){
            this.totalPric = newval* this.everyPrice
        },
        everyPrice(newval,oldval){
            this.totalPric = newval* this.cartNum 
        }

    }
})

很明显当一个属性有两个或者多个属性计算得到的时候用计算属性能够节省代码,

当想要某个属性最初赋值的时候就执行相应的监听

Watch:{
    isLogin(){
        //isLogin最初赋值的时候不会执行这里边的代码,只有等赋值后再次改变时执行
    }
}

解决办法

Watch:{
    handler: function (val, oldVal) {
          console.log('new d: %s, old: %s', val, oldVal)
    },
       immediate: true
}

this.$nextTick 用法

例如banner渲染
This.list = getData(); 
this.$nextTick(()=>{
    new Swiper();
})

1.vue语法不要用简写,用全称,避免和后台语法冲突
2.页面中避免使用带有>和<之类的判断语法
3.首屏模板数据渲染用v-text 不用{{}}
4.实例声明模板
new({

el:'',
//数据变量声明以d_开头,避免和methods重名
data:{
    d_arr:[],
    //类名控制一般写在class
    d_class:{
            
    },
},
computed:{
        
},
watch:{
        
},
methods:{
        
},
mounted:function(){
        
}

});
5.首屏显示内容不用组件

6.api 请求方法

建议讲自己项目的api请求封装下,这样方便添加中间件对请求做处理
1.传参数
api(url, {ActivityID:item.ID}, function (res) {
            
});
2.参数为空
api(url, {}, function (res) {
            
});

7.vue风格指南
https://cn.vuejs.org/v2/style...

查看原文

赞 1 收藏 1 评论 0

wolfzwz 发布了文章 · 2018-12-06

jquery.extend

jquery extend

实现extend 所需要的功能性函数

        // 判断是不是函数
        function isFunction(obj) {
            // Support: Chrome <=57, Firefox <=52
            /* 
                在有些浏览器 typeof document.createElement( "object" ) 会返回function 
                所以判断是不是dom 节点
            */
            return typeof obj === "function" && typeof obj.nodeType !== "number";
        };
        // 创建一个计划对象
        let class2type = {};
        // 代理 hasOwnProperty 访问Object.hasOwnProperty的时候可以节省代码
        let hasOwn = class2type.hasOwnProperty;
        // hasOwn toString方法 注意是函数的toString方法,而不是{}toString 方法
        let fnToString = hasOwn.toString;
        // Object() 函数转成字符串 "function Object() { [native code] }"
        let ObjectFunctionString = fnToString.call(Object);
        // 代理
        let getProto = Object.getPrototypeOf;
        // 拷贝计划对象方法
        toString = class2type.toString;

        // 判断是否为计划对象
        /* 
            //在当前页面内追加换行标签和指定的HTML内容
            function w( html ){
                document.body.innerHTML += "<br/>" + html;
            }

            w( $.isPlainObject( { } ) ); // true
            w( $.isPlainObject( new Object() ) ); // true
            w( $.isPlainObject( { name: "CodePlayer"} ) ); // true
            w( $.isPlainObject( { sayHi: function(){} } ) ); // true
            w( $.isPlainObject( "CodePlayer" ) ); // false
            w( $.isPlainObject( true ) ); // false
            w( $.isPlainObject( 12 ) ); // false
            w( $.isPlainObject( [ ] ) ); // false
            w( $.isPlainObject( function(){ } ) ); // false
            w( $.isPlainObject( document.location ) ); // false(在IE中返回true)

            function Person(){
                this.name = "张三";
            }
            w( $.isPlainObject( new Person() ) ); // false
            window false
            new Date false
        */
        function isPlainObject(obj) {
            var proto, Ctor;
            // obj false,或者obj不是对象,排除null和undefined 否则getProto(obj) 报错
            if (!obj || toString.call(obj) !== "[object Object]") {
                return false;
            }
            proto = getProto(obj);
            // 如果是对象但是没有原型则是由 Object.create( null ) 创建
            if (!proto) {
                return true;
            }
            // 原型的构造函数是 Object(),则为计划对象
            Ctor = hasOwn.call(proto, "constructor") && proto.constructor;
            return typeof Ctor === "function" && fnToString.call(Ctor) === ObjectFunctionString;
        }

extend 代码分析

    // extend 代码分析
    var jQuery = {};
    /* 
        jQuery.extend()函数用于将一个或多个对象的内容合并到目标对象。
        jQuery.extend( [ deep ], target , object1 [, objectN... ] )
    */
    jQuery.extend = jQuery.prototype.extend = function () {
        // 定义后边用到的变量
        var options, name, src, copy, copyIsArray, clone,
            // 第一个参数为目标对象
            target = arguments[0] || {},
            i = 1,
            length = arguments.length,
            // 是否为深拷贝
            deep = false;

        // 深度拷贝
        /* 如果第一个参数为布尔值则代表深拷贝 */
        if (typeof target === "boolean") {
            deep = target;

            // Skip the boolean and the target 将第二个参数设置为目标对象
            target = arguments[i] || {};
            i++;
        }

        // 参数不是对象的情况
        if (typeof target !== "object" && !isFunction(target)) {
            target = {};
        }

        // 如果只有一个参数或者两个参数且第一个参数为 deep  扩展自身
        if (i === length) {
            target = this;
            i--;
        }

        for (; i < length; i++) {

            // 参数不是null 或者undefined
            /* 
                null == undefined // true
                null == null // true
            */
            if ((options = arguments[i]) != null) {

                // 扩展对象
                for (name in options) {
                    src = target[name];
                    copy = options[name];

                    /*
                        target = {a:1,b:2}
                        options = {
                            test: target
                        }
                        target.test = target; //会出现无法遍历
                    */
                    if (target === copy) {
                        continue;
                    }
                    // 判断是深拷贝,且copy为数组或者计划对象
                    /* 
                        计划对象
                        { } new Object()
                    */
                    if (deep && copy && (jQuery.isPlainObject(copy) ||
                        (copyIsArray = Array.isArray(copy)))) {
                        // 数组
                        if (copyIsArray) {
                            copyIsArray = false;
                            clone = src && Array.isArray(src) ? src : [];

                        } else {
                            // 对象
                            clone = src && jQuery.isPlainObject(src) ? src : {};
                        }

                        // Never move original objects, clone them
                        target[name] = jQuery.extend(deep, clone, copy);

                        // Don't bring in undefined values // 如果拷贝值为null/undefined 则不拷贝
                    } else if (copy !== undefined) {
                        target[name] = copy;
                    }
                }
            }
        }

        return target;
    };
查看原文

赞 0 收藏 0 评论 0

wolfzwz 发布了文章 · 2018-12-03

vue源码解读-目录结构

目录结构

├── scripts ------------------------------- 构建相关的文件,一般情况下我们不需要动
│ ├── git-hooks ------------------------- git钩子
│ ├── alias.js -------------------------- 别名配置
│ ├── config.js ------------------------- rollup配置的文件
│ ├── build.js -------------------------- 构建 config.js 中所有的rollup配置
│ ├── ci.sh ----------------------------- 持续集成运行的脚本
│ ├── release.sh ------------------------ 自动发布新版本的脚本
├── dist ---------------------------------- 构建后文件的输出目录
├── examples ------------------------------ Vue开发的应用案例
├── flow ---------------------------------- 类型声明,使用开源项目 Flow
├── packages ------------------------------ 独立发布的包的目录
├── test ---------------------------------- 所有测试文件
├── src ----------------------------------- 源码
│ ├── compiler -------------------------- 编译器代码的存放目录,将 template 编译为 render 函数
│ ├── core ------------------------------ 存放通用的,与平台无关的代码
│ │ ├── observer ---------------------- 响应系统,包含数据观测的核心代码
│ │ ├── vdom -------------------------- 虚拟DOM创建(creation)和打补丁(patching)的代码
│ │ ├── instance ---------------------- Vue构造函数设计相关的代码
│ │ ├── global-api -------------------- 给Vue构造函数挂载全局方法(静态方法)或属性的代码
│ │ ├── components -------------------- 抽象出来的通用组件
│ ├── server ---------------------------- 服务端渲染(server-side rendering)的相关代码
│ ├── platforms ------------------------- 平台特有的相关代码,不同平台的不同构建的入口文件也在这里
│ │ ├── web --------------------------- web平台
│ │ │ ├── entry-runtime.js ---------- 运行时构建的入口,不包含模板(template)到render函数的编译器,所以不支持 template 选项,我们使用vue默认导出的就是这个运行时的版本。
│ │ │ ├── entry-runtime-with-compiler.js -- 独立构建版本的入口,它在 entry-runtime 的基础上添加了模板(template)到render函数的编译器
│ │ │ ├── entry-compiler.js --------- vue-template-compiler 包的入口文件
│ │ │ ├── entry-server-renderer.js -- vue-server-renderer 包的入口文件
│ │ │ ├── entry-server-basic-renderer.js -- 输出 packages/vue-server-renderer/basic.js 文件
│ │ ├── weex -------------------------- 混合应用
│ ├── sfc ------------------------------- 单文件组件(.vue文件)的解析逻辑,用于vue-template-compiler包
│ ├── shared ---------------------------- 整个代码库通用的代码
├── package.json -------------------------- 不解释
├── yarn.lock ----------------------------- yarn 锁定文件
├── .editorconfig ------------------------- 针对编辑器的编码风格配置文件
├── .flowconfig --------------------------- flow 的配置文件
├── .babelrc ------------------------------ babel 配置文件
├── .eslintrc ----------------------------- eslint 配置文件
├── .eslintignore ------------------------- eslint 忽略配置
├── .gitignore ---------------------------- git 忽略配置

查看原文

赞 0 收藏 0 评论 0

wolfzwz 回答了问题 · 2018-11-21

如何在.vue文件中访问Vue全局变量

如果是想在vue实例和组件中都添加某个方法或者属性可以考虑用插件机制来实现vue实例和组件共享属性和方法

var MyPlugins = {};
MyPlugins.install = function (Vue, options) {
  // 1. 添加全局方法或属性
  Vue.mixin({
    methods:{
        myGlobalMethod(){}
    }
  })
}
module.exports = MyPlugins

// 全局注册自己的插件
Vue.use(MyPlugins);

插件机制是支持mixin混入,只要使用了插件,所有的vue实例,组件都会拥有插件中混入的方法,
这时候在vue实例,或者组件,.vue组件都可以调用myGlobalMethod方法

关注 9 回答 7

wolfzwz 发布了文章 · 2018-11-20

vue源码解读-构造函数

src/core/instance/index.js
此文件主要实现了Vue初始化

// 引入模块
import { initMixin } from './init'
import { stateMixin } from './state'
import { renderMixin } from './render'
import { eventsMixin } from './events'
import { lifecycleMixin } from './lifecycle'
import { warn } from '../util/index'
// 什么时候需要把代码放到util包呢,个人感觉如果代码能够复用而且脱离项目能够应用到另一个项目可以考虑放到util
/*
    构造函数 大家在这里可能会觉得,既然选择打包工具,那为啥不选择class呢,应该是和后边需要定义Vue静态方法和属性有关,
    es6语法暂不支持对静态属性的定义
*/
function Vue (options) {
  // this instanceof Vue 可以判断函数是不是 new关键字调用
  if (process.env.NODE_ENV !== 'production' &&
    !(this instanceof Vue)
  ) {
    // 封装好的警告方法 console.warn();
    warn('Vue is a constructor and should be called with the `new` keyword')
  }
  // 调用初始化方法
  this._init(options)
}

/* 
  Mixin 混入的意思在这里大家可以理解成扩展
  以下方法在vue prototype 中扩展方法
  这里通过不同的函数来给vue prototye添加不同的功能,
  这种代码拆分思想很值得借鉴,尤其是在写复杂逻辑,
  将复杂逻辑拆分成不同的功能,这样代码清晰方便维护
*/
// Vue 初始化 简言之就是 合并配置,初始化生命周期,初始化事件中心,初始化渲染,初始化 data、props、computed、watcher 
initMixin(Vue)
// 在这里state可以理解为 在vue原型vue.prototype扩展了vue实例中$date,$props,$set,$delete,$watch
stateMixin(Vue)
// 对事件的扩展 包括$on,$once,$emit,$off 应用的设计模式为观察者模式
eventsMixin(Vue)
/* 
扩展生命周期方法
Vue.prototype._update 
Vue.prototype.$forceUpdate 强制更新
Vue.prototype.$destroy  销毁
*/
lifecycleMixin(Vue)
/* 
Vue.prototype.$nextTick = function (fn: Function) {}
Vue.prototype._render = function (): VNode {}
*/
renderMixin(Vue)

export default Vue
查看原文

赞 0 收藏 0 评论 0

wolfzwz 发布了文章 · 2018-11-20

vue源码解读-Flow

版本基于2.5.17-beta.0
在阅读源码之前建议大家先了解下Flow
Flow 是 facebook 出品的 JavaScript 静态类型检查工具。Vue.js 的源码利用了 Flow 做了静态类型检查,所以了解 Flow 有助于我们阅读源码
这里简单的介绍下Flow
Flow 的工作方式
类型推断:通过变量的使用上下文来推断出变量类型,然后根据这些推断来检查类型。
类型注释:事先注释好我们期待的类型,Flow 会基于这些注释来判断。

类型推断

function split(str) {
    return str.split('')
}
split(11)

Flow 检查上述代码后会报错,因为函数 split 期待的参数是字符串,而我们输入了数字。

类型注释
添加类型注释可以提供更好更明确的检查依据

/*@flow*/
function test(x: number, y: number): number {
    return x + y
}
test('str', 0)

因为函数参数的期待类型为数字,而我们提供了字符串。flow会报错

flow中对数组,函数,类和对象都能添加类型注释
数组

/*@flow*/

var arr: Array<number> = [1, 2, 3]

arr.push('str')

类和对象

/*@flow*/

class Person {

constructor(name: string, age: string | number) {
this.name= name
this.age= age
this.sex= false
}}

var per: Person = new Person('xiaoli', 4)

var obj: { arr: Array<string>, per: Person} = {
arr: ['hello']
per: new Person('hello', 3)
}

想到数据类型大家当然忘不了 null, undefined
如果先让任意类型可以是 null 或者 undefined 则需要写成 ?T 的格式即可,注意T就是类型

/*@flow*/
var age: ?number = null
age可以为数字或者 null
查看原文

赞 0 收藏 0 评论 0

wolfzwz 回答了问题 · 2018-09-01

解决vue data 内怎么获得 vue 实例

看描述不太清楚啥意思,不过想更改this,最简单的办法就是把你想要绑的实例,var that = this/要绑的实例,
回调函数内的 this 指向是该组件自身的实例,在回调函数外边定义 var that = this/要绑的实例,
在回调函数里边用that

关注 17 回答 14

wolfzwz 回答了问题 · 2018-09-01

Vue2 如何使用Vue.set?

丢掉这个习惯吧,直接在data上动态添加属性感觉没有意义呢,vue官网不是有搜索功能么,用啥api出错,到官网一搜就出例子,照着例子写就可以,可以减少出错,用框架只能这样,必须按照规矩来

关注 12 回答 7

wolfzwz 回答了问题 · 2018-09-01

vue中的一个组件就是一个vue实例吗?

组件就是实例,只不过用单文件组件开发,利用脚手架,内部代码的编译楼主是看不到的,不知道楼主这么问
是有啥功能无法实现?就好像一切皆对象,一个道理,用别人的框架就要遵守他的思想,首先要把框架的规约记住了,
这样学的才简单,

关注 11 回答 7

wolfzwz 回答了问题 · 2018-09-01

解决vue这么动态引入vue文件?

那要看请求的这个文件有没有其它特殊的语法,如果只是html语法和css语法,vue语法,是没有问题的,如果这个请求文件的内容是一个组件,那就把文件的内容读出来直接赋值给页面script标签,或者把html代码直接赋值到vue.extend中的template变量就可以

关注 3 回答 3

wolfzwz 回答了问题 · 2018-09-01

解决vue如何将vue进行单独的打包

楼主是要打包成多个js还是将vue文件打包成html文件,感觉不如打包成多个js文件单独去引用,开发模式是前后台
没有分离么?但却想使用vue?

关注 5 回答 2

wolfzwz 回答了问题 · 2018-08-27

为什么'vue$':'vue/dist/vue.js' 需要改成别的别名才会引用正确?

resolve:{

    
    alias:{
        'vuee$':'vue/dist/vue.js'
    }
}

这个的作用其实就是为了解决文件路径过长,方便引用,加$这种用法还是少用,像jquery,vue自身都有对$的应用,容易冲突,或许就是这么巧让你赶上了,换个名吧,建议给自己制定vue的项目规范,比如别名一般用 名称+@ vue@

关注 6 回答 4

wolfzwz 回答了问题 · 2018-08-27

解决用vue脚手架中,在main.js中引入过vue,然后在App.vue又一次引入vue,会不会重复?

不会啊,你想想,你定义了一个header组件,如果在多个js中都引入了header.vue,如果你打包的入口文件只有一个,那么最终打包的会自己去重 ,放心写吧,
相反如果你打包的入口文件有多个,那么打包的时候会在每个入口文件都打包一次,可以多了解webpack

关注 7 回答 6

wolfzwz 回答了问题 · 2018-08-27

在写flex布局的时候,有办法让两个元素,一个靠左,一个居中吗

简单粗暴的,多加一个元素,左中右,右边的空元素和左边的宽度一样,

关注 7 回答 6

wolfzwz 回答了问题 · 2018-08-27

解决vue.js onclick 函数传值计算后该怎么做替换?

@click="myPra(diary.ispraise,diary.countpraise)" 这么些是没有问题,
前提是你要保证你的data数据中已经有diary这个对象,而且diary对象中已经有ispraise,countpraise这两个属性

data:{

diary:{
    ispraise: 你的初始值,
    countpraise:  你的初始值
}

}
页面中再这样绑定就不会报错了,
@click="myPra(diary.ispraise,diary.countpraise)"

关注 3 回答 2

wolfzwz 回答了问题 · 2018-08-27

解决vue应该怎样处理这个判断语句?

很明显你这是根据不同条件给同一个变量赋值,那么变量放在判断语句外边声明就可以,就是var res;
而且正常情况就算按你的这样写是不会报错的,是不是加了语法检查

关注 6 回答 5

wolfzwz 回答了问题 · 2018-08-27

解决vue的data绑定 和 循环完成之后添加到data 的数据有什么不同?

不太清楚你说的双向绑定是哪里,是指绑定了data中的monthTableData?,那就把它放到copyData中就可以不要在data属性中放了,如下
copyData() {

        let = monthTableData: {
            paymentType:"",
            paymentMonth: '',
        },
        let list = [];
        for (var i =0; i<=5;i++) {
            for (let k in monthTableData) {
                list.push(monthTableData);
            }
        }
            this.monthTableDataNew = list;
        },

关注 4 回答 3

wolfzwz 回答了问题 · 2018-08-27

keyup事件执行了一个AJAX请求,但是input框的值不见了

贴代码吧,这种情况应该是有哪里修改了input的值,

关注 3 回答 2

wolfzwz 回答了问题 · 2018-08-23

解决vue文档中的var Vue = require('vue')是什么意思

require是加载vue模块,模块有export值,讲export值赋值给变量Vue

关注 8 回答 7