vue.js中级进阶

vue.js中级进阶

    • 组件注册 Vue.component()
      • 组件名大小写
      • 全局注册 和 局部注册
      • 模块系统
    • 属性特性prop
      • prop的大小写
      • 传递动态或静态prop值
      • props单向数据流--父子通信
      • props的验证
      • prop的继承
    • 自定义事件
      • v-model
      • 监听原生事件 .native $listeners
      • prop的双向绑定 .sync
      • Object.freeze(obj)
    • 插槽 slot
    • 动态组件
    • 异步加载
    • 处理边界(通信)
    • 个例相关
      • 程序化的事件
      • 循环引用(终止无限循环)
      • 模版定义的替代品
      • 强制更新数据或对象
      • 低开销静态组件 v-once
    • 过渡
      • 进入/离开的过渡
      • 初始渲染的过渡
      • 多个过渡
    • 混入
    • 自定义指令
    • 过滤器

组件注册 Vue.component()

组件名大小写

  • 使用kebab-case:小写和连字符-
  • 使用PascalCase:驼峰命名。
    强烈建议,使用kebab-case命名。

当驼峰命名的首字母大写时,两种方法都能引用生效,都接受;
直接在DOM中使用时,只有kebab-case生效;

全局注册 和 局部注册

  • 作用域不同,局部注册在自己子组件内不可用
  • 打包时,全局会被打包,即使没有被使用
    因此,将component赋值变量,再组件components内引用,实现复用。

模块系统

  1. 使用Webpack和Babel的模块系统时,推荐把各组件文件夹放在components根目录中,通过import ComponentA from "./components/componentA"引用。
  2. 自动化全局注册:
//入口文件中导入自动化全局组件配置
import Vue from 'vue'
import upperFirst from 'lodash/upperFirst'
import camelCase from 'lodash/camelCase'

const requireComponent = require.context(
  // 其组件目录的相对路径
  './components',
  // 是否查询其子目录
  false,
  // 匹配基础组件文件名的正则表达式
  /Base[A-Z]\w+\.(vue|js)$/
)

requireComponent.keys().forEach(fileName => {
  // 获取组件配置
  const componentConfig = requireComponent(fileName)

  // 获取组件的 PascalCase 命名
  const componentName = upperFirst(
    camelCase(
      // 剥去文件名开头的 `./` 和结尾的扩展名
      fileName.replace(/^\.\/(.*)\.\w+$/, '$1')
    )
  )

  // 全局注册组件
  Vue.component(
    componentName,
    // 如果这个组件选项是通过 `export default` 导出的,
    // 那么就会优先使用 `.default`,
    // 否则回退到使用模块的根。
    componentConfig.default || componentConfig
  )
})

全局注册行为必须在根Vue实例创建之前。

属性特性prop

prop的大小写

HTML中特性名(属性)对大小写不敏感,不能直接在DOM中使用驼峰命名prop,但是在``template中不受限制。 建议使用kebab-case命名,避开这些问题。 书写格式:props:[“key”]props:{key:类型}`

key:类型,指定值类型string\number\boolean\array\object

传递动态或静态prop值

``v-bind:props=“val.title”`动态传值;

对象,数字,数组,布尔值等静态值,仍然需要v-bind绑定说明不是字符串,而是JS表达式:v-bind:props="42"
传入props下的一个对象时候,使用不带参数的v-bind=""取代v-bind:prop-name=""

//javascript
props:{
  post:{
    id:1,
    title:yo
  }
}
//html
<blog-post v-bind="post"></blog-post>
//等价于
<blog-post :id="post.id" :title="post.title"></blog-post>

props单向数据流–父子通信

所有的prop都是父级单向下行绑定,但是对象或数组的props传入子组件函数,被改变时会影响父组件的状态。

props的验证

props会在组件创建之前进行验证,因此实例的属性,如data、computed等在default或validator函数中,不可用.

参考:生命周期钩子

语法:

  props:{
    prop:Number,
    prop:[Number,String],
    prop:{
      //string、number、boolean、array、object、date、function、symbol
      type:String,
      required:true
    },
    prop:{
      type:Number,
      default:100
    },
    prop:{
      type:Object,
      default:function(){
        return {message:'hello'}
      }
    },
    prop:{
      validator:function(value){
        //fn...return true or false
      }
    }
  }

prop的继承

组件接受任意的特性,并被添加到根元素上,是因为:显性定义向一个子组件传入信息,而当不能考虑周全时,增加灵活性。
禁止特性的继承:组件选项中设置inheritAttrs:false

配合$attrs属性,手动继承属性:子组件内v-bind="$attrs"手动继承父级属性。

自定义事件

事件名对大小写敏感,但是HTML对大小写不敏感,因此推荐始终使用kebab-case命名。

v-model

组件中的v-model默认利用名为valueprop。和名为inputevent,但是单选框和复选框会将value用于不同目的,需手动componentmodel选项设置避免。
重新定义change事件和checked属性:

 Vue.component("yo",{
   model:{
     prop:"checked",
     event:"change"
   },
   props:{
     checked:"checked"
   },
   template:`
    `
 })

怎么用?

监听原生事件 .native $listeners

一个组件的根元素上监听原生事件,v-on:event.native="fn"v-on="$listeners":

//javascript
//自定义input按钮
Vue.component('base-input', {
  //取消子组件继承props
 inheritAttrs: false,
 props: ['label', 'value'],
 computed: {
   inputListeners: function () {
     var vm = this
     // `Object.assign` 将所有的对象合并为一个新对象
     return Object.assign({},
       // 我们从父级添加所有的监听器
       this.$listeners,
       // 然后我们添加自定义监听器,
       // 或覆写一些监听器的行为
       {
         // 这里确保组件配合 `v-model` 的工作
         input: function (event) {
           vm.$emit('input', event.target.value)
         }
       }
     )
   }
 },
 template: `
   
 `
})

如此,自定义组件可以监听到所有的事件,包括原生事件和内部子元素事件

prop的双向绑定 .sync

真正的双向绑定会带来维护上的问题:子组件可以修改父组件,且没有明显的改动来源。
因此,以updata:myPropName的模式触发事件,实现。
子组件$emit自定义事件updata:myPropName,传参;父组件监听事件,更新

<text-doc 
v-bind:propName="data.prop" 
v-on:updata:propName="doc.prop=$event";>
</test-doc>
//简写
<text-doc v-bind:propName.sync="doc.prop">

.syncv-bind不能使用JS表达式。无效。

Object.freeze(obj)

不追踪数据变化

插槽 slot

自定义模块可以插入slot,显示插入的任何东西,甚至是其他组件;
如:slot将要显示的内容;

但是slot的作用域在目前组件,不在模板;

可以在自定义模板的slot标签内预设默认显示;

具名插槽:;
组件:

v-slot只能用于template上;

子模板插槽prop上传,父组件v-slot:default="propName"接收propName.user.data;

解构插槽prop:propName、{propName}、{propName:otherName}重命名、{propName = defaultValue}默认值

缩写:v-slot=>#

动态插槽名:v-slot:[slotName];

实现子模板与父组件的通信与控制:插槽prop;

动态组件

使用v-bind:is=""切换不同组件,为了避免反复渲染,用包裹组件,进行缓存。

<keep-alive>
    <myComponent :is="currentComponent">myComponent>
keep-alive>

异步加载

vue自带的工厂函数,按需加载组件:

Vue.component("componentName",function(resolve,reject){
    //成功,回调函数
    resolve({template:"..."})
    //失败,返回错误
    reject("error")
})

webpack写法:

Vue.component("componentName",function(resolve){
    //Ajax请求,传入回调函数
    require(["./my-component"],resolve)
})

webpack + ES5 :

// 全局注册,Vue全局
Vue.component("async-webpack-example",
    ()=>import('./my-component')
)

// 局部注册,vm某实例下
var vm = new Vue({
    components:{
        "my-component":()=>import("./my-component")
    }
})

**处理加载状态**
```javascript
const AsyncComponent= ()=>({
  //加载的组件
  component:import('./Mycomponent.vue'),
  //异步加载时
  loading:loadingComponent,
  //加载失败
  error:errorComponent,
  //加载延迟时间
  delay:200,
  //超时时限,否则返回加载失败
  timeout:3000
})

处理边界(通信)

访问元素和组件

  • 子组件访问根级实例$root数据和方法;
  • 子组件访问父组件$parent,替代[prop]传递的父子通信方式;
  • 访问子组件和子元素,ref属性赋予子一个ID用以引用,父以this.$refs.refId定位;

refv-for一起时,会定位到子组件数组。
$refs只在组件渲染之后生效,且不是响应式的,避免在component和computed属性中使用。

  • 依赖注入:实例选项provide和inject;相当于大范围的props
//祖先组件注入
provide:function(){
  return {
    getMap:this.getMap
  }
},
methods:{
  getMap(){},
}

//后代组件依赖
inject:['getMap']

相关参考:Vuex

个例相关

程序化的事件

创建自定义事件$emit,监听事件$on一个事件,$once一次事件,$off停止监听。

例如:$on(eventName,eventHandler),$emit , $on , $off并不是dispatchEvent,addEventListener,removeEventListener的别名

循环引用(终止无限循环)

  • 递归组件:(自身)
    组件自身模版调用自身,只能通过name选项设置;
    当使用全局定义组件时,自动设置组件名为name值,所以可能到时无限循环,需要一个条件终止,例如v-if
  • 组件间的循环引用
    全局组件间循环,需子组件在beforeCreate时注册,或使用异步加载子组件;

模版定义的替代品

  • 内联模版
    template的inline-template特性
  • X-Templates
    script的typt="text/x-template"属性,加上id后,实例引用id的模版;

强制更新数据或对象

未被响应式系统追踪的状态,可以使用强制更新$forceUpdate
通常是某个地方处理错误,注意处理BUG;

低开销静态组件 v-once

template模版根元素加上v-once属性,可以只计算一次并且缓存。

过渡

进入/离开的过渡

单元素、组件的过度(预装transition组件)

  • 类名

六种状态:
.v-enter 进入过渡的开始状态,元素插入之前生效,下一帧移除
.v-enter-active 生效时状态,插入之前生效,过度/动画完成移除,定义开始过渡过程时间、延迟、曲线函数(包含v-enter,v-enter-to)
.v-enter-to 结束状态,元素插入下一帧生效,过度/动画完成移除
.v-leave 离开过渡的开始状态
.v-leave-active 生效时状态,定义离开过渡的时间、延迟、曲线函数(包含v-leave,v-leave-to)
.v-leave-to 结束状态

没有命名时,默认v-enter,命名后name="my-transition",使用my-transition-enter

  • 过渡

根据六种状态的类,进行CSS过渡效果;

  • 动画

过渡不同的是,在animationded事件触发后删除。

  • 过渡和动画一起使用时

VUE识别transitionedanimationed来监听过渡结束,一起时需要指明指针type="animationed/transitioned"明确申明。

  • 自定义类名的属性

类似name属性,定义类class,并使用第三方动画库结合VUE的过渡系统,达到效果:
enter-class
enter-active-class
enter-to-class
leave-class
leave-active-class
leave-to-class

  • 设置时间 duration(属性)

...
或分别设置进入移除过渡时间
...

  • javascript钩子(事件)

    <div v-if="isHide">
        动画
    div>
transiton>

添加v-bind:css="false",跳过css检测。
在enter和leave中必须使用done()函数进行回调,不然被同步调用,过渡立即完成。

初始渲染的过渡

初始渲染状态,同进入/离开的过渡一样,可以设置自定义类名属性,钩子事件

...


多个过渡

多个元素过渡,使用:key="keyValue"标记来区分,触发效果
多个组件过渡,使用动态组件:is=""即可

动画过渡特殊用法,以及状态过渡,有待开发。。。

混入

全局

Vue.mixin({
    data(){
        return{
            //...
        }
    },
    create:function(){
        //...
    },
})

局部

var mixinName = {
    //...
}
var vm = new Vue({
    mixins:[mixinName],
})

自定义指令

全局

Vue.directive("focus",{
    bind:function(el,binding,vnode,oldVnode){},
    inserted:function(el){
        el.focus()
    },
    update:function(){},
    componentUpdated:function(){},
    unbind:function(){},
})

局部

new Vue({
    el:"#app",
    directives:{
        focus:{
            inserted:function(el){
                el.focus()
            }
        }
    }
})

渲染函数 & JSX

new Vue({
	render:function(){
		//...
	}
})

过滤器

全局

Vue.filter("demo",fuction(value){
    //...
    return result
})

局部

new Vue({
    filters:{
        demo:function(value){
            //...
            return result
        }
    }
})

管道符“|”使用,可以传参数{{yo | filter("a","b")}},可以串联使用{{yo | filter1 | filter2}};

你可能感兴趣的:(Vue)