React-父子通信-父传子

props

父子通信-父传子

import React,{Component} from 'react'

class Navbar extends Component {
    render () {
        return (
            <button>back</button>
            <div>Navbar</div>
            <button>{this.props.mytitle}</button>
        )
    }
}

export default class App extends Component {
    render () {
        return (
            <div>
                <Navbar mytitle='home'></Navbar>
                <Navbar mytitle='list'></Navbar>
                <Navbar mytitle='shopbar'></Navbar>
            </div>
        )
    }
}

属性验证

  1. 引入’prop-types’模块
  2. 利用static声明符定义类属性
  3. 在类中定义一个属性:propTypes,值为一个对象
import React,{Component} from 'react'
import MyPropType from 'prop-types'

class Navbar extends Component {
   static propTypes = {
       isShow:MyPropType.bool,
       mytitle:MyPropType.string
   }
    render () {
        return (
            <div>
                <button>left</button>
                <div>Navbar</div>
                {
                    this.props.isShow?<button>{this.props.mytitle}</button>:null
                }
            </div>
        )
    }
}

export default class App extends Component {
    render () {
        return (
            <div>
                <Navbar mytitle='home' isShow={true}/>
                <Navbar mytitle='list' isShow={false}/>
                <Navbar mytitle='shopbar' isShow={'false'}/>
                {//这里传入的是字符串而非布尔值}
            </div>
        )
    }
}

默认属性

import React,{Component} from 'react'
import MyPropTypes from 'prop-types'

class Navbar extends Component {
    static propTypes = {
        mytitle:MyPropTypes.string
    }
    static defaultProps = {
        mytitle:'Click'
    }
    render () {
        return (
            <div>
                <button>left</button>
                <div>Navbar</div>
                <button>{this.props.mytitle}</button>
            </div>
        )
    }
}

export default class App extends Component {
    render () {
        return (
            <div>
                <Navbar mytitle='Home'></Navbar>
                <Navbar></Navbar>
            </div>
        )
    }
}

React自带的属性展开语法

import React,{Component} from 'react'
import MyPropTypes from 'prop-types'

class Navbar extends Component {
    static propTypes = {
        mytitle:MyPropTypes.string,
        myshow:MyPropTypes.bool
    }
    static defaultProps = {
        mytitle:'Click',
        myshow:true
    }
    render () {
        return (
            <div>
                <button>left</button>
                <div>Navbar</div>
                <button>{this.props.mytitle}</button>
            </div>
        )
    }
}

export default class App extends Component {
    render () {
        let obj = {
            mytitle:'list',
            myshow:false
        }
        return (
            <div>
                <Navbar mytitle='Home'></Navbar>
                <Navbar></Navbar>
                <Navbar {...obj}/>
            </div>
        )
    }
}

React-条件渲染

条件渲染

显示或隐藏

.hide{display:none}
import React,{Component} from 'react'
import './css/index/css' //引入上面的css文件
export default class App extends Component {
    state = {
        isHide:false
    }
    render () {
        return (
            <div>
                <div className={isHide?'hide':''}>1111111</div>
                <button onClick={this.isshow}>show/hide</button>
            </div>
        )
    }
    isshow = ()=>{
        this.setState({
            isHide:!this.state.isHide
        })
    }
}

创建或删除

import React,{Component} from 'react'
export default class App extends Component {
    state= {
        isshow:true
    }
    render () {
        let odiv = <div>11111111111</div>
        return (
            <div>
            {
                isshow?odiv:null
            }
                <button onClick={(prevState)=>{
                        this.setState({
                            isshow:!prevState.isshow
                        })
                    }}>show/hide</button>
            </div>
        )
    }
}

React-jsx语法与组件

jsx语法与组件

JSX 将 HTML 语法直接加入到 JavaScript 代码中,再通过翻译器转换到纯 JavaScript 后由浏览器执行。在实际开发中,JSX 在产品打包阶段都已经编译成纯 JavaScript,不会带来任何副作用,反而会让代码更加直观并易于维护。 编译过程由Babel 的 JSX 编译器实现。

https://reactjs.org/docs/hello-world.html

组件首字母大写

组件首字母是大写 会被认为是自定义组件,首字母是小写,会被认为是 原生dom节点

import App from './App.js'
import React from 'react'
import ReactDOM from 'react-dom'

ReactDOM.render(<App/>,document.getElementById("root"))
//ReactDOM.render(<div>hello react</div>,document.getElementById("root"))
//只要使用jsx,必须引入React
//babel将上面的<div>hello react</div>转换成 ==> React.createElement('div','hello')

组件标签

组件最外层需要被一个标签包裹,不能有兄弟节点

return (加上小括号,可以回车)

import React,{Component} from 'react'
export default class App extends Component {
    render () {
        return (
            <div> //组件最外层标签
                <ul><li>hello</li></ul>
                <p>world</p>
            </div>
        )
    }
}

组件可以嵌套

import React,{Component} from 'react'
export default class App extends Component {
    render () {
        return (
            <div> //组件最外层标签
                <ul><li>hello</li></ul>
                <p>world</p>
                <Child/>
            </div>
        )
    }
}
class Child extends Component {
    render () {
        return (
            <div>child</div>
        )
    }
}

函数式写法

import React,{Component} from 'react'
export default class App extends Component {
    render () {
        return (
            <div> //组件最外层标签
                <ul><li>hello</li></ul>
                <p>world</p>
                <Child1/>
                <Child2/>
                <Child3/>
            </div>
        )
    }
}
class Child extends Component {
    render () {
        return (
            <div>child1</div>
        )
    }
}
function Child2 () {
    return (<div>child2</div>)
}
const Child3 = ()=>{
    return (<div>child3</div>)
}

样式

class

<div class='box'></div> ==> <div className='box'></div> 

label for

<label for='box'></label> ==> <label htmlFor='box'></label>

行内样式

let styleobj = {
    fontSize:'10px',
    color:'red'
}
...
<div style={styleboj}>111</div>
<div style={{background:'red',color:'yellow'}}>111</div>

引入格式

import './css/index.css'

事件

箭头函数

import React,{Component} from 'react'
export default class App extends Component {
    render () {
        return (
            <input type='text'/>
            <button onClick={()=>{
                console.log('click')
            }}>Add1</button>
              <button onClick={()=>{
                this.handleClick('aaa','bbb')
            }}>Add2</button>
        )
    }
    handleClick (x,y) {
        console.log(x+y)
    }
}

bind改变this指向

import React,{Component} from 'react'
export default class App extends Component {
    render () {
        return (
            <input type='text'/>
            <button onClick={this.handleClick.bind(this,'aaa','bbb')}>Add</button>
        )
    }
    handleClick (x,y) {
        console.log('click',x+y)
    }
}

ES6语法糖

import React,{Component} from 'react'
export default class App extends Component {
    render () {
        return (
            <input type='text'/>
            <button onClick={this.handleClick}>Add</button>
        )
    }
    handleClick = ()=>{
        console.log('click')
    }
}

react组件的数据挂载方式

属性(默认属性与属性验证)

状态

import React,{Component} from 'react'
export default class App extends Component {
    state = {
        myname: 'retr0'
    }
    render () {
        return (
            <div>
                <p>{myname}</p>
            </div>
        )
    }
}

Vue-slot

slot

  • Props

    • name - string,用于命名插槽。
  • Usage

    元素作为组件模板之中的内容分发插槽。 元素自身将被替换。

    详细用法,请参考下面教程的链接。

  • 参考通过插槽分发内容

实例

slot=’val’

<div id='box'>
    <child>
        <div slot='a'>a</div>
        <div slot='b'>b</div>
        <div slot='c'>c</div>
    </child>
</div>
Vue.component("child",{
    template:`
        <div>
            <slot name='a'></slot>
            <slot name='b'></slot>
            <slot name='c'></slot>
        </div>
    `,
})

v-slot

<div id='box'>
    <template v-slot:a></template>
    <template v-slot:b></template>
    <template v-slot:c></template>
</div>
Vue.component("child",{
    template:`
        <div>
            <slot name='a'></slot>
            <slot name='b'></slot>
            <slot name='c'></slot>
        </div>
    `,
})

slot抽屉效果

<div id='box'>
    <child>
         <button @click='isshow=!isshow'>显示/隐藏</button>
    </child>
    <slidebar v-show='isshow'></slidebar>
</div>
Vue.component('child',{
    template:`
        <div>
            <slot></slot>
        </div>
    `
})
Vue.component('slidebar',{
    template:`
        <ul>
            ....
        </ul>
    `
})
new Vue({
    el:'@#box',
    data:{
        isshow:false
    }
})

Vue-keep-alive1

keep-alive

  • Props

    • include - 字符串或正则表达式。只有名称匹配的组件会被缓存。
    • exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存。
    • max - 数字。最多可以缓存多少组件实例。
  • 用法

    包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 相似,`` 是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在组件的父组件链中。

    当组件在 `` 内被切换,它的 activateddeactivated 这两个生命周期钩子函数将会被对应执行。

    在 2.2.0 及其更高版本中,activateddeactivated 将会在 `` 树内的所有嵌套组件中触发。

    主要用于保留组件状态或避免重新渲染。

    <!-- 基本 -->
    <keep-alive>
      <component :is="view"></component>
    </keep-alive>
    
    <!-- 多个条件判断的子组件 -->
    <keep-alive>
      <comp-a v-if="a > 1"></comp-a>
      <comp-b v-else></comp-b>
    </keep-alive>
    
    <!-- 和 `<transition>` 一起使用 -->
    <transition>
      <keep-alive>
        <component :is="view"></component>
      </keep-alive>
    </transition>
    

    注意, 是用在其一个直属的子组件被开关的情形。如果你在其中有 `v-for` 则不会工作。如果有上述的多个条件性的子元素, 要求同时只有一个子元素被渲染。

Vue-动态组件

动态组件

  • Props

    • is - string | ComponentDefinition | ComponentConstructor
    • inline-template - boolean
  • 用法

    渲染一个“元组件”为动态组件。依 is 的值,来决定哪个组件被渲染。

    <!-- 动态组件由 vm 实例的属性值 `componentId` 控制 -->
    <component :is="componentId"></component>
    
    <!-- 也能够渲染注册过的组件或 prop 传入的组件 -->
    <component :is="$options.components.child"></component>
    
  • 参考动态组件

  • 实例

    <div id="box">
        <!-- <home v-if='type==="home"'></home>
    <list v-else-if='type==="list"'></list>
    <shopbar v-else='type==="shopbar"'></shopbar> -->
        <keep-alive>
            <component :is="type"></component>
        </keep-alive>
        <footer>
            <ul>
                <li @click='type="home"'>首页</li>
                <li @click='type="list"'>列表</li>
                <li @click='type="shopbar"'>购物车</li>
            </ul>
        </footer>
    </div>
    
    Vue.component("home", {
        template: `<div>home--<input></div>`
    })
    Vue.component("list", {
        template: `<div>list</div>`
    })
    Vue.component("shopbar", {
        template: `<div>shopbar</div>`
    })
    new Vue({
        el: '#box',
        data: {
            type: 'home',
        }
    })
    

Vue-v-model通信

v-model通信

<div id="box">
    <input type="text" v-model='mytxt'>
    <child :text='mytxt'></child>
    <childmodel v-model='mytxt'></childmodel>
</div>
Vue.component("childmodel", {
    template: `
            <div>
                childmodel -- {{value}}
                <qbutton>click</qbutton>
            </div>
`,
   props:['value']
})
Vue.component("child", {
    template: `
            <div>
                child -- {{text}}
                <button>click</button>
            </div>
`,
    props: ['text']
})
new Vue({
    el: '#box',
    data: {
        mytxt: ""
    }
})

Vue-事件总线

事件总线

bus

var bus = new Vue();

<div id='box'>
    <input v-model='mytxt'>
    <child></child>
    <childmodel></childmodel>
</div>
let bus = new Vue();
Vue.component("child",{
    template:`<div>child -- <button @click='handelClick'></button></div>`,
    methods:{
        handelClick(){
            bus.$emit('event',22222);
        }
    }
})
Vue.component("childmodel",{
    template:`<div>child</div>`,
    mounted(){
        bus.$on('event',data=>{
            console.log(data)
        })
    }
})
new Vue({
    el:'#box',
    data:{
        mytxt:''
    }
})

mounted

生命周期中进行监听

  • 类型Function

  • 详细

    实例被挂载后调用,这时 el 被新创建的 vm.$el 替换了。 如果根实例挂载到了一个文档内的元素上,当mounted被调用时vm.$el也在文档内。

    注意 mounted 不会保证所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以在 mounted 内部使用 vm.$nextTick

    mounted: function () {
        this.$nextTick(function () {
            // Code that will run only after the
            // entire view has been rendered
        })
    }
    

    该钩子在服务器端渲染期间不被调用。

  • 参考生命周期图示

Vue-18 .sync和update

属性可不可以修改

严格来说,Vue子组件不能随便更改父组件传递过来的属性,但是可以通过props 配合 $emit 改变父组件传入的值

//父组件

在父组件传入值时,需要有xxx.sync修饰符;

//子组件$emit(‘update:warning’,val)

子组件可以在$emit(‘update:xxxx’,val),派发事件修改传入的值

2.3.0+ 新增

在有些情况下,我们可能需要对一个 prop 进行“双向绑定”。不幸的是,真正的双向绑定会带来维护上的问题,因为子组件可以修改父组件,且在父组件和子组件都没有明显的改动来源。

这也是为什么我们推荐以 update:myPropName 的模式触发事件取而代之。举个例子,在一个包含 title prop 的假设的组件中,我们可以用以下方法表达对其赋新值的意图:

this.$emit('update:title', newTitle)

然后父组件可以监听那个事件并根据需要更新一个本地的数据属性。例如:

<text-document
  v-bind:title="doc.title"
  v-on:update:title="doc.title = $event"
></text-document>

为了方便起见,我们为这种模式提供一个缩写,即 .sync 修饰符:

<text-document v-bind:title.sync="doc.title"></text-document>

注意带有 .sync 修饰符的 v-bind 不能和表达式一起使用 (例如 v-bind:title.sync=”doc.title + ‘!’” 是无效的)。取而代之的是,你只能提供你想要绑定的属性名,类似 v-model

当我们用一个对象同时设置多个 prop 的时候,也可以将这个 .sync 修饰符和 v-bind 配合使用:

<text-document v-bind.sync="doc"></text-document>

这样会把 doc 对象中的每一个属性 (如 title) 都作为一个独立的 prop 传进去,然后各自添加用于更新的 v-on 监听器。

v-bind.sync 用在一个字面量的对象上,例如 v-bind.sync=”{ title: doc.title }”,是无法正常工作的,因为在解析一个像这样的复杂表达式的时候,有很多边缘情况需要考虑。

实例

<div id="box">
    <child :title.sync='mytitle'></child>
    <br>
    {{mytitle}}
</div>
Vue.component('child', {
    template: `
            <div>
                child---{{title}} -- 
                <button @click='change'>click</button>
            </div>
`,
    props: ['title'],
    methods: {
        change() {
            this.$emit('update:title', this.title + 1)
        }
    }
})
new Vue({
    el: '#box',
    data: {
        mytitle: 11111
    }
})