react-vue-like
write react component like vue, implementation based on mbox@4.
Table of Contents:
-
- props
- components
- filters
- directives
- mixin
- data
- methods
- computed
- watch
- Lifecycle
- Scoped Style
- Slot
- Vue Internal Directives
- VueLike Internal Directives
- Event Mechanism
- Attribute Transform
- Ref
- Vue Like Props
- Vue like Methods
- Attrs Inheirt
- Class Attribute Support And Enhance
- Prop And Event Modifiers
- Provide Inject
- Vuex Store (note: Store was moved to react-vuex-like)
Installation
npm install react-vue-like --save# or yarn add react-vue-like
Support Vue feature
props
will transfrom to react's propTypes
and defaultProps
see Vue props
example:
Component static props = aa: type: String default: 'aa' required: true bb: Boolean
equals:
;Component static propTypes = aa: PropTypesstringisRequired bb: PropTypesbool static defaultProps = aa: 'aa'
components
if tag name has -
char will be treat as a component that find from self's components
section or root's components
section.
see Vue components
example:
; Component static components = AComponent { return <a-component>dd</a-component> }
filters
example:
Component static filters = { return `test:`; } { return <div> // output: test:hello } 'hello' | 'test' // output: test:helloa suffix } 'hello' | 'test''a suffix' </div>);
directives
see Vue directives
example:
Component static directives = test: { } { } { } { } { return <div v-test_arg$aa$bb=1+1 /* or */ v-test:arg$aa$bb=1+1 ></div>; }
v-test_arg$aa$bb={1+1}
, the binding
will be:
name: 'test' arg: 'arg' value: 2 modifiers: aa: true bb: true expression: '1+1'
mixin
see Vue mixin example:
Component static mixins = { return text: 'aa' ; } methods: { console; } { return <div> <span onClick=thistest>thistext</span> </div>; }
data
see Vue data example:
Component static { return text: 'aa' formData: name: 'dddd' } { return <div> <span>thistext</span> <span>thisformDataname</span> </div>; }
methods
see Vue methods
example:
Component static methods = { console; } { console; } { return <div> <span onClick=thistest1>aa</span> <span onClick=thistest2>dd</span> </div>; }
computed
see Vue computed
example:
Component static { return text: 'aa' } static computed = { return `test1:`; } test2: { return `test2:`; } { thistext = v; } { return <div> <span>thistext</span> <span>thistest1</span> <span onClick= thistest2 = 'bb'>thistest2</span> </div>; }
watch
see Vue watch
example:
Component static { return text: 'aa' } static watch = { console; } { return <div> <span>thistext</span> <button onClick= thistext = 'bb'>change</button> </div>; }
lifecycle
example:
Component { } { } { } { } { } { } { } { return <div>haha</div>; }
scoped style
if import's style file name has ?scoped
, then it will treat as scoped style
example:
.aa .bb .aa .bb >>> .cc .aa .bb:scope > .cc :global .aa .bb
;; ; Component { return <div className="aa"> haha <span>dd</span> <a-component className="bb" /> </div>; }
will transform to like this:
.aa .bb.v-123dse43 .aa .bb.v-123dse43 .cc .aa .bb.v-123dse43 > .cc .aa .bb
;; ; Component { return <div className="v-123dse43 aa"> haha <span className="v-123dse43">dd</span> <a-component className="v-123dse43 bb" /> </div>; }
slot
example:
;; Component { return <div> <slot name="header"> haha1 1 2 3 haha2 <slot name="footer"> </div>; }
;;; Component { return <ChildComponent> /* if child-component is `ReactVueLike Component` then it will has `$slots: { header, default, footer }` */ /* if child-component is `React Component` then it will has `header, footer` attributes, default slot will be it's 'children' */ <span slot="header">this is header</span> /* scoped slot */ <template> <span>this is body: username: value</span> </template> <span slot="footer">this is footer</span> </ChildComponent>; }
Vue Internal Directives
v-if/v-else-if/v-else
,v-show
,v-model
, v-html
see Vue Directives
example:
;; Component static { return vif: true vshow: true text1: '' text2: 0 text3: '' } { return <div> <span v-if=thisvif>v-if showing</span> <span v-else>else showing</span> <span v-show=thisvshow> v-show showing </span> <input v-model$trim=thistext1></input> <input type="number" v-model$number=thistext2></input> <input v-model$lazy=thistext3></input> /* equals: dangerouslySetInnerHTML={{ __html: "<a href='#'>dd</a>" }} */ <span v-html="<a href='#'>dd</a>"></span> </div>; }
Vuelike Internal Directives
v-observer
see Mobx Observer
example:
;; Component { return <div> /* will transform <Observer>{() => <span v-observer>ddd</span>}</Observer> */ <span v-observer>ddd</span> /* will transform <Observer render={() => <span v-observer>ddd</span>}</Observer>} /> */ <span v-observer$render>ddd</span> </div>; }
Event Mechanism
you can use $emit
to send event message to bind Event
that bind by $on
or onXXXX
event. see Instance-Methods-Events
;;; Component { this } { console; } { console; } { return <ChildComponent onClick=thishandleClick onCustomEvent=thishandleCusomEvent> </ChildComponent>; }
;; Component { return <div> <button onClick=this>click</button> <button onClick=this$parent>change user</button> <button onClick=this>cusom event</button> </div>; }
attribute transform
img src attribute string value transform to require
expression
example:
Component { return <div> /* src will transform to `require('./image/pic1.png')` */ <img src="./image/pic1.png"> </div>; }
ref
string ref
transform to ref function
and set ref
to $refs
. seevue ref
Component static { return list: key: 'a' value: 1 key: 'b' value: 2 key: 'c' value: 3 } { this$refssome; } { return <div> /* if ref value is string, then ref value will transform to `ref=>this.$refs['some']=ref`, otherwise do nothing. */ <SomeComponent ref="some" onClick=thistest></SomeComponent> thislist </div>; }
Vue like props
like $el
,$options
,$parent
,$root
,$refs
,$slots
,$attrs
. seeInstance-Properties
Vue like methods
like $nextTick
,$set
,$delete
,$watch
,$emit
,$on
,$off
,$once
,renderError
, ReactVueLike.use
, ReactVueLike.configure
. see Instance-Methods-Data and Instance-Methods-Events
Attrs Inheirt
default ReactVueLike component will inherit className
, style
, id
, disabled
attributes that be defined in it`s parent component
Class Attribute Support And Enhance
class attribute
in jsx will transfrom to className
, and now class/className
support String/Array/Object
types. see Vue class
Component static { return myClass: cc: true dd: false } { return <div class="root"> <span className='aa' 'bb' thismyClass 'ee' 'ff' ></span> </div>; }
Prop And Event Modifiers
; Component { return <div> /* equals <div aa={this.aa} onChangeAa={v=>this.aa=v}></div> */ <Child aa$sync=thisaa></Child> <div onClick$stop=thistest></div> <div onClick$prevent=thistest></div> <div onClick$capture=thistest></div> <div onClick$self=thistest></div> <div onClick$native=thistest></div> <div onClick$once=thistest></div> <div onClick$left=thistest></div> <div onClick$right=thistest></div> <div onClick$middle=thistest></div> <div onClick$passive=thistest></div> <div onClick$enter=thistest></div> <div onClick$13=thistest></div> </div>; }
Component { this; } { return <div> <button onClick=thischangeAa></button> </div>; }
Provide Inject
see provide/inject
;;; Component static { return text: thisformData } static { return formData: text: '111' } { return <ChildComponent> </ChildComponent>; }
;; Component static inject = 'formData'; { return <div>thisformDatatext</div>; }
Vuex Store
support Vuex.Store
and mapState
,mapMutations
,mapGetters
,mapActions
,createNamespacedHelpers
. see Vuex
Note: Store was moved to react-vuex-like.
store like Vuex.Store:
; const store = modules: child1: state: aa: true child2: state: bb: true state: user: name: 'name1' getters: { return stateglobalLoading; } mutations: 'update-user'state v stateuser = v; 'update-user-info'state v Object; actions: 'update-user-info' commit v ; ; ;
Other feature
Const Var
support __filename
, __dirname
, __packagename
, __packageversion
, __now
Instance Methods
function $computed(target, expr, value)
defined a computed in ReactVueLike Component
instance.
function $runAction(nameOfFn, fn?)
run fn
in mobx action, equals runInAction
in mobx
.
Static Methods
ReactVueLike.runAction(nameOfFn, fn?)
- equals $runAction
in component instance.
ReactVueLike.observable
- observable
method in mobx
, just re-export.
ReactVueLike.flow
- flow
method in mobx
, just re-export.
ReactVueLike.action
- action
method in mobx
, just re-export.
ReactVueLike.set
- set
method in mobx
, just re-export.
ReactVueLike.delete
- remove
method in mobx
, just re-export.
ReactVueLike.config
- config something in ReactVueLike, example: ReactVueLike.config({ enforceActions: true })
;
toJS, isObservable, isObservableProp, isObservableObject, isObservableArray, isObservableMap, isBoxedObservable, isArrayLike, isAction, isComputed, isComputedProp, observable, extendObservable, observe, decorate, reaction, intercept, computed, action, autorun, when, runInAction, createAtom, set, get, remove, has, flow, configure, onBecomeObserved, onBecomeUnobserved
mobx methods, just re-export.
Usage
webpack.config.js:
module: rules: test: /\.css$/ use: 'css-loader' 'react-vue-like/loader' ... test: /\.scss$/ use: 'css-loader' 'react-vue-like/loader' ... test: /\.less$/ use: 'css-loader' 'react-vue-like/loader' ...
babel.config.js
moduleexports = presets: '@babel/preset-env' 'react-vue-like/preset' '@babel/preset-react'
routes file:
// routes.js; const routes = path: '/' component: Test ;
router file:
// router.js;; const router = routes ; ;
global filters:
// filters.js { return `myFilter:`; } { Appfilters = this; }
global directives:
// directives.js test: { } { Appdirectives = this; }
global components:
; const PREFIX = 'Ad'; { const COMP_REGX = /^[A-Z][A-Za-z]+/; let ret = {}; Object; return ret;} // components.js { if !Appcomponents Appcomponents = {}; Object;}
entry file:
// index.js;;;;;;;;; ReactVueLike; ReactVueLike;ReactVueLike;ReactVueLike;ReactVueLike;ReactVueLike; router; ReactDOM;
root ReactVueLike component:
// app.jsx;;;;;// scoped css; Component static isRoot = true static { return formData: text: '' ; } static computed = { return `haha:`; } static methods = { console; } { return <div class="root"> /* root RouterView need `router` prop */ <RouterView router=router /> </div>; } ;
// some-component.jsx;;// scoped css; Component static computed = { return this$storestateuser; } static methods = { console; } // when render throw error, then will call renderError { return `render has some error:`; } { return <div> <slot name="header"> haha1 1 2 3 haha2 <slot name="footer"> /* src will be transformed: require('./images/pic1.png') */ <img src="./images/pic1.png" /> </div>; }
// test.jsx;;// scoped css; Component static computed = { return this$storestateuser; } static methods = { this$refssome; } { return <div> /* donot need import, it will find from it's root component's components section */ <some-component ref="some" onClick=thistest /> </div>; }
store like Vuex.Store:
; const store = modules: child1: state: aa: true child2: state: bb: true state: user: name: 'name1' getters: { return stateglobalLoading; } mutations: 'update-user'state v stateuser = v; 'update-user-info'state v Object; actions: 'update-user-info' commit v ; ; ;
Note
-
In ReactVueLike Component, try not to use
this.props
, please usethis.$attrs
instead. and you can usethis.$slots.default
instead ofthis.props.children
; -
the
prop name
that bind to ReactVueLike Component, do not begin with '_'or'$' chars, they are recognized as internal values of ReactVueLike.