首页
统计
墙纸
留言
Search
1
PVE8优化
13 阅读
2
Debian 12 / Ubuntu 22.04 使用源安装 LAMP 教程
11 阅读
3
内核版本 4.9 以上的 Linux 系统开启/关闭 BBR 的方法
10 阅读
4
CSS动画
10 阅读
5
jenkins根据分支、文件夹打包
9 阅读
web前端
Vue
CSS
javascript
React
那些年爬过过的坑
ES6
TypeScrippt
ES7
javascript图灵 - 总结
Node
面试总结
React-Native
Web优化
基础
AngularJS
拍摄
Flutter
Dart
Docker
Linux
mysql
PVE
登录
/
注册
Search
标签搜索
vue+elementui
Cicada
累计撰写
158
篇文章
累计收到
57
条评论
首页
栏目
web前端
Vue
CSS
javascript
React
那些年爬过过的坑
ES6
TypeScrippt
ES7
javascript图灵 - 总结
Node
面试总结
React-Native
Web优化
基础
AngularJS
拍摄
Flutter
Dart
Docker
Linux
mysql
PVE
页面
统计
墙纸
留言
搜索到
149
篇与
的结果
2018-05-06
react-redux
Redux 是「React 全家桶」中极为重要的一员,它试图为 React 应用提供「可预测化的状态管理」机制。Redux 本身足够简单,除了 React,它还能够支持其他界面框架。所以如果要将 Redux 和 React 结合起来使用,就还需要一些额外的工具,其中最重要的莫过于 react-redux 了。react-redux 提供了两个重要的对象,Provider 和 connect,前者使 React 组件可被连接(connectable),后者把 React 组件和 Redux 的 store 真正连接起来。react-redux 的文档中,对 connect 的描述是一段晦涩难懂的英文,在初学 redux 的时候,我对着这段文档阅读了很久,都没有全部弄明白其中的意思(大概就是,单词我都认识,连起来啥意思就不明白了的感觉吧)。在使用了一段时间 redux 后,本文尝试再次回到这里,给这段文档(同时摘抄在附录中)一个靠谱的解读。预备知识首先回顾一下 redux 的基本用法。如果你还没有阅读过 redux 的文档,你一定要先去阅读一下。const reducer = (state = {count: 0}, action) => { switch (action.type){ case 'INCREASE': return {count: state.count + 1}; case 'DECREASE': return {count: state.count - 1}; default: return state; } } const actions = { increase: () => ({type: 'INCREASE'}), decrease: () => ({type: 'DECREASE'}) } const store = createStore(reducer); store.subscribe(() => console.log(store.getState()) ); store.dispatch(actions.increase()) // {count: 1} store.dispatch(actions.increase()) // {count: 2} store.dispatch(actions.increase()) // {count: 3}通过 reducer 创建一个 store,每当我们在 store 上 dispatch 一个 action,store 内的数据就会相应地发生变化。我们当然可以直接在 React 中使用 Redux:在最外层容器组件中初始化 store,然后将state 上的属性作为 props 层层传递下去。class App extends Component{ componentWillMount(){ store.subscribe((state)=>this.setState(state)) } render(){ return <Comp state={this.state} onIncrease={()=>store.dispatch(actions.increase())} onDecrease={()=>store.dispatch(actions.decrease())} /> } }但这并不是最佳的方式。最佳的方式是使用 react-redux 提供的 Provider 和 connect 方法。使用 react-redux首先在最外层容器中,把所有内容包裹在 Provider 组件中,将之前创建的 store 作为prop 传给 Provider。const App = () => { return ( <Provider store={store}> <Comp/> </Provider> ) };Provider 内的任何一个组件(比如这里的 Comp),如果需要使用 state 中的数据,就必须是「被 connect 过的」组件——使用 connect 方法对「你编写的组件(MyComp)」进行包装后的产物。class MyComp extends Component { // content... } const Comp = connect(...args)(MyComp);可见,connect 方法是重中之重。connect 详解究竟 connect 方法到底做了什么,我们来一探究竟。首先看下函数的签名:connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])connect() 接收四个参数,它们分别是 mapStateToProps,mapDispatchToProps,mergeProps和options。mapStateToProps(state, ownProps) : stateProps这个函数允许我们将 store 中的数据作为 props 绑定到组件上。const mapStateToProps = (state) => { return { count: state.count } }这个函数的第一个参数就是 Redux 的 store,我们从中摘取了 count 属性。因为返回了具有 count 属性的对象,所以 MyComp 会有名为 count 的 props 字段。class MyComp extends Component { render(){ return <div>计数:{this.props.count}次</div> } } const Comp = connect(...args)(MyComp);当然,你不必将 state 中的数据原封不动地传入组件,可以根据 state 中的数据,动态地输出组件需要的(最小)属性。const mapStateToProps = (state) => { return { greaterThanFive: state.count > 5 } }函数的第二个参数 ownProps,是 MyComp 自己的 props。有的时候,ownProps 也会对其产生影响。比如,当你在 store 中维护了一个用户列表,而你的组件 MyComp 只关心一个用户(通过 props 中的 userId 体现)。const mapStateToProps = (state, ownProps) => { // state 是 {userList: [{id: 0, name: '王二'}]} return { user: _.find(state.userList, {id: ownProps.userId}) } } class MyComp extends Component { static PropTypes = { userId: PropTypes.string.isRequired, user: PropTypes.object }; render(){ return <div>用户名:{this.props.user.name}</div> } } const Comp = connect(mapStateToProps)(MyComp);当 state 变化,或者 ownProps 变化的时候,mapStateToProps 都会被调用,计算出一个新的stateProps,(在与 ownProps merge 后)更新给 MyComp。这就是将 Redux store 中的数据连接到组件的基本方式。mapDispatchToProps(dispatch, ownProps): dispatchPropsconnect 的第二个参数是 mapDispatchToProps,它的功能是,将 action 作为 props 绑定到MyComp 上。const mapDispatchToProps = (dispatch, ownProps) => { return { increase: (...args) => dispatch(actions.increase(...args)), decrease: (...args) => dispatch(actions.decrease(...args)) } } class MyComp extends Component { render(){ const {count, increase, decrease} = this.props; return (<div> <div>计数:{this.props.count}次</div> <button onClick={increase}>增加</button> <button onClick={decrease}>减少</button> </div>) } } const Comp = connect(mapStateToProps, mapDispatchToProps)(MyComp);由于 mapDispatchToProps 方法返回了具有 increase 属性和 decrease 属性的对象,这两个属性也会成为 MyComp 的 props。如上所示,调用 actions.increase() 只能得到一个 action 对象 {type:'INCREASE'},要触发这个 action 必须在 store 上调用 dispatch 方法。diapatch 正是 mapDispatchToProps 的第一个参数。但是,为了不让 MyComp 组件感知到 dispatch 的存在,我们需要将 increase 和decrease 两个函数包装一下,使之成为直接可被调用的函数(即,调用该方法就会触发dispatch)。Redux 本身提供了 bindActionCreators 函数,来将 action 包装成直接可被调用的函数。import {bindActionCreators} from 'redux'; const mapDispatchToProps = (dispatch, ownProps) => { return bindActionCreators({ increase: action.increase, decrease: action.decrease }); }同样,当 ownProps 变化的时候,该函数也会被调用,生成一个新的 dispatchProps,(在与statePrope 和 ownProps merge 后)更新给 MyComp。注意,action 的变化不会引起上述过程,默认 action 在组件的生命周期中是固定的。[mergeProps(stateProps, dispatchProps, ownProps): props]之前说过,不管是 stateProps 还是 dispatchProps,都需要和 ownProps merge 之后才会被赋给 MyComp。connect 的第三个参数就是用来做这件事。通常情况下,你可以不传这个参数,connect 就会使用 Object.assign 替代该方法。其他最后还有一个 options 选项,比较简单,基本上也不大会用到(尤其是你遵循了其他的一些 React 的「最佳实践」的时候),本文就略过了。希望了解的同学可以直接看文档。注意:和react-router混用时不能把route, connect(mapStateToProps, mapDispatchToProps)(route).必须分发最高层主件原文
2018年05月06日
1 阅读
0 评论
0 点赞
2018-05-06
React-Router V4
react-router-dom:使用 HTML5 提供的 history API 来保持 UI 和 URL 的同步;:使用 URL 的 hash (例如:window.location.hash) 来保持 UI 和 URL 的同步;:能在内存保存你 “URL” 的历史纪录(并没有对地址栏读写);:从不会改变地址;Route主件path(string): 路由匹配路径。(没有path属性的Route 总是会 匹配);exact(bool):为true时,则要求路径与location.pathname必须完全匹配;strict(bool):true的时候,有结尾斜线的路径只能匹配有斜线的location.pathname;Route渲染方式:在地址匹配的时候React的组件才会被渲染,route props也会随着一起被渲染;:这种方式对于内联渲染和包装组件却不引起意料之外的重新挂载特别方便;:与render属性的工作方式基本一样,除了它是不管地址匹配与否都会被调用;Switch主件的独特之处是独它仅仅渲染一个路由。相反地,每一个包含匹配地址(location)的都会被渲染。思考下面的代码路由嵌套V4的嵌套,和V2V3相当不同V4必须在主件的内部嵌套route例子如下:import React, {Component} from 'react'; import {Route} from 'react-router-dom'; import lazyLoad from '../lazyLoad'; import Index from 'bundle-loader?lazy&name=home!./index'; export default class Login extends Component { render() { return ( <div>测试 <Route path={this.props.match.path + '/index'} render={() => { return lazyLoad(Index, { ...this.props }); }}></Route> </div> ); } }
2018年05月06日
1 阅读
0 评论
0 点赞
2018-05-04
React-eslint
eslint配置npm install --save-dev eslint eslint-plugin-html eslint-plugin-import eslint-plugin-node babel-eslint eslint-plugin-reactmodule.exports = { "parser": "babel-eslint", "plugins": [ "react" ], "parserOptions": { "ecmaVersion": 6, "sourceType": "module", "ecmaFeatures": { "jsx": true } }, "env": { "browser": true, "amd": true, "es6": true, "node": true, "mocha": true }, "rules": { "comma-dangle": 1, "quotes": [0, "single"], "no-undef": 1, "global-strict": 0, "no-extra-semi": 1, "no-underscore-dangle": 0, "no-console": 1, "no-unused-vars": 1, "no-trailing-spaces": [1, { "skipBlankLines": true }], "no-unreachable": 1, "no-alert": 0, "react/jsx-uses-react": 1, "react/jsx-uses-vars": 1, "no-extra-semi": 1, //禁止多余的冒号 "no-implicit-coercion": 1, //禁止隐式转换 "no-multi-spaces": 1, //不能用多余的空格 "no-trailing-spaces": 1, //一行结束后面不要有空格 "no-undef": 1, //不能有未定义的变量 "no-unused-vars": [2, { "vars": "all", "args": "after-used" }], //不能有声明后未被使用的变量或参数 "brace-style": [1, "1tbs"], //大括号风格 "callback-return": 1, //避免多次调用回调什么的 "comma-dangle": [2, "never"], //对象字面量项尾不能有逗号 "indent": [1, 2], //缩进风格 "new-parens": 2, //new时必须加小括号 "max-params": [1, 3], //函数最多只能有3个参数 "new-cap": 2, //函数名首行大写必须使用new方式调用,首行小写必须用不带new方式调用 "quote-props": [0, "always"], //对象字面量中的属性名是否强制双引号 "vars-on-top": 2, //var必须放在作用域顶部 //空行最多不能超过100行 "no-multiple-empty-lines": [2, { "max": 1 }], "semi": [1, "always"] //语句强制分号结尾 } }
2018年05月04日
1 阅读
0 评论
0 点赞
2018-04-24
在已有的Vue项目添加单元测试
1.在相对应的文件夹添加一下3个文件.2.安装对应的依赖npm i -D karma karma-webpack phantomjs-prebuilt karma-phantomjs-launcher karma-phantomjs-shim karma-chrome-launcher karma-sourcemap-loader mocha karma-mocha sinon chai sinon-chai karma-sinon-chai karma-spec-reporter karma-coverage运行npm run unit你会看到一下错误信息{ "message": "Error: [vuex] vuex requires a Promise polyfill in this browser.\nat webpack:///~/vuex/dist/vuex.esm.js:97:19 <- index.js:11802:55", "str": "Error: [vuex] vuex requires a Promise polyfill in this browser.\nat webpack:///~/vuex/dist/vuex.esm.js:97:19 <- index.js:11802:55" } //使用Babel polyfill解决了这个问题。以下是我所做的步骤: //安装Babel Polyfill: npm install --save-dev babel-polyfill //然后包括前内源和测试文件的填充工具文件files的部分karma.conf.js: files: [ '../node_modules/babel-polyfill/dist/polyfill.js', 'index.js' ],注意异步主件在断言时必须保证渲染完成.所以要使用nextTick
2018年04月24日
2 阅读
0 评论
0 点赞
2018-04-18
固定浏览器ULR
vm.$watch('$route', (now) => { window.history.pushState(null, null, window.location.origin);});
2018年04月18日
1 阅读
0 评论
0 点赞
2018-04-18
Vuex全局守卫
全局守卫你可以使用 router.beforeEach 注册一个全局前置守卫:const router = new VueRouter({ ... }) router.beforeEach((to, from, next) => { // ... })每个守卫方法接收三个参数:to: Route: 即将要进入的目标 路由对象from: Route: 当前导航正要离开的路由next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。next(false): 中断当前的导航。如果浏览器的 URL 改变了(可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,且允许设置诸如 replace: true、name: 'home' 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项。next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。利用router.beforeEach禁止跳转不存在的路由router.beforeEach((to, from, next) => { let routes = router.options.routes; //递归判断是否跳转路由 let jump = (arr, to, from, next) => { for (let v of arr) { if (v.path === to.path) { next(); continue; } else { if (v.children instanceof Array && v.children.length > 0) { jump(v.children, to, from, next); } next(false); } } }; jump(routes, to, from, next); });
2018年04月18日
0 阅读
0 评论
0 点赞
2018-04-17
Vue-router向路由主件传参
通过配置路由的props进行传参如果 props 被设置为 true,route.params 将会被设置为组件属性。const User = { props: ['id'], template: '<div>User {{ id }}</div>' } const router = new VueRouter({ routes: [ { path: '/user/:id', component: User, props: true } ] })如果 props 是一个对象,它会被按原样设置为组件属性。当 props 是静态的时候有用。const router = new VueRouter({ routes: [ { path: '/promotion/from-newsletter', component: Promotion, props: { newsletterPopup: false } } //主件的props:['newsletterPopup'] ] })你可以创建一个函数返回 props。const router = new VueRouter({ routes: [ { path: '/search', component: SearchUser, props: (route) => ({ query: route }) } //主件的props:['query'] ] })
2018年04月17日
0 阅读
0 评论
0 点赞
2018-04-13
JS生成器
function* 这种声明方式(function关键字后跟一个星号)会定义一个生成器函数 (generator function),它返回一个 Generator 对象。function* generator(i) { yield i; yield i + 10; } var gen = generator(10); console.log(gen.next().value); // expected output: 10 console.log(gen.next().value); // expected output: 20生成器函数在执行时能暂停,后面又能从暂停处继续执行。调用一个生成器函数并不会马上执行它里面的语句,而是返回一个这个生成器的 迭代器 (iterator )对象。当这个迭代器的 next() 方法被首次(后续)调用时,其内的语句会执行到第一个(后续)出现yield的位置为止,yield 后紧跟迭代器要返回的值。或者如果用的是 yield*(多了个星号),则表示将执行权移交给另一个生成器函数(当前生成器暂停执行)。next()方法返回一个对象,这个对象包含两个属性:value 和 done,value 属性表示本次 yield 表达式的返回值,done 属性为布尔类型,表示生成器后续是否还有 yield 语句,即生成器函数是否已经执行完毕并返回。调用 next()方法时,如果传入了参数,那么这个参数会作为上一条执行的 yield 语句的返回值function *gen(){ yield 10; y=yield 'foo'; yield y; } var gen_obj=gen(); console.log(gen_obj.next());// 执行 yield 10,返回 10 console.log(gen_obj.next());// 执行 yield 'foo',返回 'foo' console.log(gen_obj.next(10));// 将 10 赋给上一条 yield 'foo' 的左值,即执行 y=10,返回 10 console.log(gen_obj.next());// 执行完毕,value 为 undefined,done 为 true
2018年04月13日
0 阅读
0 评论
0 点赞
2018-04-13
迭代器[Symbol.iterator]
当需要对一个对象进行迭代时(比如开始用于一个for..of循环中),它的@@iterator方法都会在不传参情况下被调用,返回的迭代器用于获取要迭代的值。自定义迭代器let arr []; arr[Synbol,iterator] = fuction(){ let i = 0; let self = this; return { next() { return { done: self.length - 1 < i, value: self[i++] }; } }; } for (let v of arr) { console.log(v); }当执行 for(var i of arr) 的时候,其实是调用了 arr[Symbol.iterator]() 方法,这个方法返回了一个iterator(迭代器)。迭代器有一个next方法,for循环会不断调用这个 arr.next方法来获取下一个值,直到返回值中的 done 属性为true的时候结束循环。
2018年04月13日
0 阅读
0 评论
0 点赞
2018-04-12
Objict属性操作
属性的描述Object.defineProperty(..)修改或新增对象的属性的描述.let Obj = {}; Object.defineProperty(Obj,a,{ value:2, writable:true,//可写 enumerable:true,//可枚举 configurable:true//可配置(值为false时对象属性将不可删除,writable可以从true改为false) })禁止扩展Object.preventExtensions();禁止添加新属性.密封及不能添加也不能删除对象属性.Object.seal();冻结及不可修改,不可添加,不可新增属性.Object.freeze();如果这个对象引用了其他对象, freeze不会生效.“深度冻结”一个对象,具体方法为,首先在这个对象上调用 Object.freeze(..),然后遍历它引用的所有对象并在这些对象上调用 Object.freeze(..)。但是一定要小心,因为这样做有可能会在无意中冻结其他(共享)对象。in 操作符和hasOwnProperty()in 检查对象属性是否在对象及prototype中.hasOwnProperty 检查对象属性是否在对象不检查原型链. var Obj = {}; (a in Obj)//false Obj.hasOwnProperty('a')//false
2018年04月12日
0 阅读
0 评论
0 点赞
1
...
9
10
11
...
15