vue 高级应用

88 阅读1分钟

课程目标

  • vue进阶用法

知识点

  • 模板化
  • 组件化

模板化

插槽 slot

  1. 默认插槽
  • 组件外部维护参数以及结构,内部安排位置
//App.vue
<template>
    <hello-world>
        <p>{{ msg }}</p>
    </hello-world>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
exprot default {
    components: { HelloWorld },
    name: 'App',
    data() {
        return {
            msg: 'helloworld'
        }
    }
}
</script>

//HelloWorld.vue
<template>
    <slot></slot>
</template>

如果有多个内容,需要放在不同地方怎么办?

  1. 具名插槽
  • name标识插槽的身份,从而在组件内部做到可区分
//App.vue
<template>
    <hello-world>
        <p>{{ msg }}</p>
        <template v-slot:header></template>
        <template v-slot:body></template>
    </hello-world>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
exprot default {
    components: { HelloWorld },
    name: 'App',
    data() {
        return {
            msg: 'helloworld',
            header: 'header',
            body: 'body'
        }
    }
}
</script>

//HelloWorld.vue
<template>
    //默认插槽
    <slot></slot>
    //具名插槽
    <slot name:header></slot>
    <slot name:body></slot>
</template>
  1. 作用域插槽
  • 外部做结构描述勾勒,内部做传参
  • slot-scope(vue2.6版本之前)
//App.vue
<template>
    <hello-world>
        <p>{{ msg }}</p>
        <template v-slot:header></template>
        <template v-slot:body></template>
        
       <template slot="content" slot-scope="slotProps">{{ slotProps }}</template>
    </hello-world>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
exprot default {
    components: { HelloWorld },
    name: 'App',
    data() {
        return {
            msg: 'helloworld',
            header: 'header',
            body: 'body'
        }
    }
}
</script>

//HelloWorld.vue
<template>
    //默认插槽
    <slot></slot>
    //具名插槽
    <slot name:header></slot>
    <slot name:body></slot>
    //可传递参数的slot
    <slot :slotProps = "slotProps">
</template>
<script>
exprot default {
    data() {
        return {
            slotProps: 'start'
        }
    }
}
</script>
  • v-slot(新版本2.6之后)
//App.vue
<template>
    <hello-world>
        //老版
       <template slot="content" slot-scope="slotProps">{{ slotProps }}</template>
       //新版
       <template v-slot:slotProps="slotProps">{{ slotProps }}</template>
    </hello-world>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
exprot default {
    components: { HelloWorld },
    name: 'App',
    data() {
        return {
            msg: 'helloworld',
        }
    }
}
</script>

//HelloWorld.vue
<template>
    //可传递参数的slot
    <slot :slotProps = "slotProps">
</template>
<script>
exprot default {
    data() {
        return {
            slotProps: 'start'
        }
    }
}

模板数据的二次加工

  1. watchcomputed -- 相应流过于复杂(computed赋值)
  • 方案一:函数 - 独立、管道 / 缺点:无法响应式
  • 方案二:v-html
//HelloWorld.vue
<template>
    <h1 v-html="money > 99 ? 99 : money"></h1>
</template>
<script>
exprot default {
    data() {
        return {
            money: 100
        }
    }
}
  • 方案三:过滤器 过滤器没有上下文(没有this
  • time: 绑定的值
  • format: 过滤器的名字
{{ time | format }}
//HelloWorld.vue
<template>
    <h1 v-html="money > 99 ? 99 : money"></h1>
    //也可以使用过滤器实现
    <h1> {{ money | moneyFilter}} </h1>
</template>
<script>
exprot default {
    data() {
        return {
            money: 100
        }
    },
    filters: {
        moneyFilter(money) {
            //过滤器没有this,只能传参
            return money > 99 ? 99 : money
        }
    }
}

jsx 更自由的基于js书写

  1. v-model 如何实现 -- 双向绑定。-- 外层bind:value,内层@input
  2. 写jsx的优缺点:
  • vue的编译路径: template -> render -> vm.render -> vm.render() diff =>可以使用性能优化方案
data() {
    return {
        money: 100,
        options: [
        {text:'1', value: '1'},
        {text:'2', value: '2'},
        {text:'3', value: '3'}
        ]
    }
}
methods: {
    handleClick() {}
},
render(h) {
    const mondey = {
        <p>{this.money > 99 ? 99 :this.money}</p>
    }
    
    return (
        <ul>
            {
                this.options.map((item, index) => {
                    return (
                        <content
                            onClick = { this.handleClick }
                            item = { item }
                            value = { item.value }
                            key = { index }
                        >
                        { moneyNode }
                        </content>
                    )
                })
            }
        </ul>
    )
}

组件化

传统模板化

Vue.component('component', {
    template: '<h1>组件</h1>'
})
new Vue({
    el:'#app'
})
//functional components 函数式组件
  1. 抽象复用
  2. 精简 & 聚合

混入minxin,逻辑混入,以数组的形式返回

//demoMixin.js
exprot default {
    data() {
        return {
            msg: 'mixin',
            obj: {
                title: 'mixinTitle'
            }
        }
    }
}
//HelloWorld.vue
<template>
    <h1 v-html="money > 99 ? 99 : money"></h1>
    //也可以使用过滤器实现
    <h1> {{ money | moneyFilter}} </h1>
</template>
<script>
import demoMixin from './components/demoMixin'
exprot default {
    mixins: [ demoMixin ]
    data() {
        return {
            money: 100,
            msg: 'welcome'
        }
    },
    create() {
        console.info(this.$data)
        //输出结果  {money:100,msg: 'welcome',obj: {title: 'mixinTitle'}}
    } 
}
  1. 应用:抽离公共逻辑(逻辑相同,模板不同,可用mixin
  2. 缺点:数据来源不明确
  3. 特点:合并策略
  • 1)递归合并
  • 2) data合并冲突时,以组件优先
  • 3) 生命周期回调函数不会覆盖,会先后执行,优先级先mixin后组件
//demoMixin.js
exprot default {
    data() {
        return {
            msg: 'mixin',
            obj: {
                title: 'mixinTitle',
                header: 'mixinheader'
            }
        }
    }
}
//HelloWorld.vue
<template>
    <h1 v-html="money > 99 ? 99 : money"></h1>
    //也可以使用过滤器实现
    <h1> {{ money | moneyFilter}} </h1>
</template>
<script>
import demoMixin from './components/demoMixin'
exprot default {
    mixins: [ demoMixin ],
    data() {
        return {
            money: 100,
            msg: 'welcome',
            obj: {
                number: 123,
                header: 'header'
            }
        }
    },
    create() {
        console.info(this.$data)
        //输出结果  {money:100,msg: 'welcome',obj: {number: 123,header: 'header':'mixinheader'}}
    } 
}
</script>

继承拓展。extends

  • 逻辑拓展
  1. 应用: 拓展独立逻辑
  2. mixin的区别:传值mixin为数组,extends为对象
  3. 合并逻辑:
  • 1)同mixin,也是递归合并
  • 2)合并优先级: 组件 > mixin > extends
  • 3)回调优先级: extends > mixin
//demoExtends.js
exprot default {
    data() {
        return {
            msg: 'extends',
            obj: {
                title: 'extendsTitle',
                header: 'extendsHeader'
            }
        }
    }
}
//HelloWorld.vue
<template>
    <h1 v-html="money > 99 ? 99 : money"></h1>
    //也可以使用过滤器实现
    <h1> {{ money | moneyFilter}} </h1>
</template>
<script>
import demoExtends from './components/demoExtends'
exprot default {
    extends: demoExtends,
    data() {
        return {
            money: 100,
            msg: 'welcome',
            obj: {
                number: 123,
                header: 'header'
            }
        }
    },
    create() {
        console.info(this.$data)
        //输出结果  {money:100,msg: 'welcome',obj: {number: 123,header: 'header',title: 'extendsTitle'}}
    } 
}

整体拓展类 extend

从预定义的配置中拓展出来一个独立的配置项,进行合并

//extend 不一定非要写在main.js文件里,可以写在其它文件里
//main.js
//拓展一个构造器
let _baseOptions = {
    data: function() {
        return {
            course: 'text',
            session: 'aa'
        }
    },
    create() {
        console.info('extend base');
    }
} 
const BaseComponent = Vue.extend( _baseOptions )
new BaseComponent({
    created() {
        console.info('extend created');
    }
})

//输出结果
//extend base
//extend created

Vue.use 组件

  1. 注册外部插件,作为整体实例的补充。
  2. map形式注册的,会除重,不会重复注册。
  3. 手写插件
  • 外部使用Vue.use(myPlugin, options),
  • 默认调用内部的install方法
//myPlugin.js
export default {
    install: (Vue, option) >= {
        Vue.globalMethods = function() {
            //主函数
        }
        Vue.directive('my-directive', {
            bind(el, binding, vnode, oldNode){
                //全局资源
            }
        })
        Vue.mixin({
            created: function() {
                console.info(option.name + 'created');
            }
        })
        Vue.prototype.$myMethod = funciton() {}
    }

//main.js
import myPlugin from './plugin/myPlugin'
const _options = {
    name: 'my plugin'
}
Vue.use(myPlugin, _options)

组件的高级引用

  1. 递归引用
  2. 动态组件 - <component :is='name'></component>
  3. 异步组件 - import demoExtends from './components/demoExtends'; component:{demoExtends}懒加载,比如router