1. 程式人生 > 其它 >⑤ vue 中的高階用法

⑤ vue 中的高階用法

vue 中的高階用法

1 Mixin 混入的基礎語法

1.1 元件 data methods 優先順序高於 mixin data 優先順序

1.2 生命週期函式先執行 mixin 的再執行元件的

const myMixin = {
  data() {
    return { 
      number: 2,
      count: 2
    }
  },
  created() {
    console.log('mixin created');
  },
  methods: {
    handleClick() {
      console.log('maxin handleClick');
    }
  },
}
const app = Vue.createApp({
  data() {
    return { number: 1 }
  },
  created() {
    console.log('created');
  },
  mixins: [ myMixin ],
  methods: {
    handleClick() {
      console.log('handleClick');
    }
  },
  template: `
    <div>
      <div>{{number}}</div>
      <div>{{count}}</div>
      <button @click="handleClick">增加</button>
    </div>
  `
})
const vm = app.mount('#root')

1.3 區域性 mixin

const myMixin = {
  data() {
    return { 
      number: 2,
      count: 2
    }
  },
  created() {
    console.log('mixin created');
  },
  methods: {
    handleClick() {
      console.log('maxin handleClick');
    }
  },
}
const app = Vue.createApp({
  data() {
    return { number: 1 }
  },
  created() {
    console.log('created');
  },
  components: ['child'],
  mixins: [ myMixin ],
  methods: {
    handleClick() {
      console.log('handleClick');
    }
  },
  template: `
    <div>
      <div>{{number}}</div>
      <child />
      <button @click="handleClick">增加</button>
    </div>
  `
})
app.component('child', {
  mixins: [ myMixin ],
  template: '<div>{{count}}</div>'
})
const vm = app.mount('#root')

1.4 全域性 mixin

不推薦使用

const app = Vue.createApp({
  data() {
    return { number: 1 }
  },
  created() {
    console.log('created');
  },
  components: ['child'],
  // mixins: [ myMixin ],
  methods: {
    handleClick() {
      console.log('handleClick');
    }
  },
  template: `
    <div>
      <div>{{number}}</div>
      <child />
      <button @click="handleClick">增加</button>
    </div>
  `
})
app.mixin({
  data() {
    return { 
      number: 2,
      count: 2
    }
  },
  created() {
    console.log('mixin created');
  },
  methods: {
    handleClick() {
      console.log('maxin handleClick');
    }
  },
})
app.component('child', {
  // mixins: [ myMixin ],
  template: '<div>{{count}}</div>'
})

1.5 自定義屬性、元件中的屬性優先順序高於 mixin 屬性的優先順序

  • 自定義屬性通過 $options 獲取
const myMixin = {
  number: 1
}
const app = Vue.createApp({
  number: 2,
  mixins: [myMixin],
  template: `
    <div>
      <div>{{this.$options.number}}</div>
    </div>
  `
})
const vm = app.mount('#root')

1.6 通過 app.config.optionMergeStrategies 變更混入規則

const myMixin = {
  number: 1
}
const app = Vue.createApp({
  number: 2,
  mixins: [myMixin],
  template: `
    <div>
      <div>{{this.$options.number}}</div>
    </div>
  `
})
app.config.optionMergeStrategies.number = (mixinVal, appValue) => {
  return mixinVal || appValue
}
const vm = app.mount('#root')

2 開發實現 Vue 中的自定義指令

  • directive

2.1 自定義全域性指令

const app = Vue.createApp({
  template: `
    <div>
      <input v-focus />
    </div>
  `
})
app.directive('focus', {
  mounted(el) {
    el.focus();
  }
})
const vm = app.mount('#root')

2.2 自定義區域性指令

const directives = {
  focus: {
    mounted(el) {
      el.focus();
    }
  }
}
const app = Vue.createApp({
  directives,
  template: `
    <div>
      <input v-focus />
    </div>
  `
})
const vm = app.mount('#root')

2.3 自定義指令的生命週期

const app = Vue.createApp({
  template: `
    <div>
      <input v-focus />
    </div>
  `
})
app.directive('focus', {
  beforeMount() {
    console.log('beforeMount')
  },
  mounted(el) {
    el.focus()
  },
  beforeUpdate() {
    console.log('beforeUpdate')
  },
  updated() {
    console.log('updated')
  },
  beforeUnmount() {
    console.log('beforeUnmount')
  },
  unmounted() {
    console.log('unmounted')
  },
})
const vm = app.mount('#root')

2.4 自定義指令傳值 -- binding.value

const app = Vue.createApp({
  data() {
    return {
      top: 100
    }
  },
  template: `
    <div>
      <div v-pos="top" class="header">
        <input />
      </div>
    </div>
  `
})
app.directive('pos', {
  mounted(el, binding) {
    el.style.top = binding.value + 'px'
  }
})
const vm = app.mount('#root')

2.5 自定義指令簡寫

const app = Vue.createApp({
  data() {
    return {
      top: 100
    }
  },
  template: `
    <div>
      <div v-pos="top" class="header">
        <input />
      </div>
    </div>
  `
})
app.directive('pos', (el, binding) => {
    el.style.top = binding.value + 'px'
  },
)
const vm = app.mount('#root')

2.6 自定義指令繫結引數 -- binding.arg

const app = Vue.createApp({
    data() {
      return {
        distance: 100
      }
    },
    template: `
      <div>
        <div v-pos:left="distance" class="header">
          <input />
        </div>
      </div>
    `
  })
  app.directive('pos', (el, binding) => {
      el.style[binding.arg] = binding.value + 'px'
    },
  )
  const vm = app.mount('#root')

3 Teleport 傳送門功能

  • 將元素掛載到其它元素節點上
<style>
  .area {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    width: 200px;
    height: 200px;
    background: green;
  }
  .mask {
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    background: #000;
    opacity: 0.5;
    color: #fff;
    font-size: 100px;
  }
</style>
<body>
  <div id="root"></div>
  <div id="hello"></div>
</body>
<script>
  const app = Vue.createApp({
    data() {
      return {
        show: false,
        message: 'hello'
      }
    },
    methods: {
      handleClick() {
        this.show = !this.show
      }
    },
    template: `
      <div class="area">
        <button @click="handleClick">按鈕</button>
        <teleport to="#hello">
          <div v-show="show" class="mask">{{message}}</div>
        </teleport>
      </div>
    `
  })
  const vm = app.mount('#root')
</script>

4 更加底層的 render 函式

  • template -> render -> h -> 虛擬DOM(js物件)-> 真實DOM -> 展示到頁面上
const app = Vue.createApp({
  template: `
    <my-title :level="1">
      hello
    </my-title>
  `
})
app.component('my-title', {
  props: [ 'level' ],
  render() {
    const { h } = Vue;
    // 虛擬 DOM
    return h('h' + this.level, { name: '123' }, [
      this.$slots.default(),
      h('h4', {}, 'dell')
    ])
  }
  // template: `
  //   <h1 name="123" v-if="level=== 1"><slot /></h1>
  //   <h2 v-if="level=== 2"><slot /></h2>
  //   <h3 v-if="level=== 3"><slot /></h3>
  // `
})
const vm = app.mount('#root')

5 外掛的定義和使用

  • plugin 外掛,也是把通用性的功能封裝起來
// 定義外掛
const myPlugin = {
  install(app, options) {
    app.provide('name', 'dell luo')
    app.directive('focus', {
      mounted(el) {
        el.focus()
      }
    })
    // 每掛載一次就執行一次
    app.mixin({
      mounted() {
        console.log('mixin');
      }
    })
    app.config.globalProperties.$sayHello = 'hello world';
  }
}
const app = Vue.createApp({
  template: `
    <my-title />
  `
})
app.component('my-title', {
  inject: ['name'],
  mounted() {
    console.log(this.$sayHello);
  },
  template: '<div>{{name}}<input v-focus /></div>'
})
app.use(myPlugin, { name: 'dell' })
const vm = app.mount('#root')

6 資料校驗外掛開發例項

  • 推薦使用 plugin,能夠直觀地體現出校驗器的定義;不推薦只使用 mixin
const app = Vue.createApp({
  data() {
    return { name: 'dell', age: 23 }
  },
  rules: {
    age: {
      validate: age => age > 25,
      message: 'too young, to simple'
    },
    name: {
      validate: name => name.length >= 4,
      message: 'name too short'
    }
  },
  template: `
  <div>name: {{name}}, age: {{age}} </div>
  `
})
const validatorPlugin = (app, options) => {
  app.mixin({
    created() {
      for(let key in this.$options.rules) {
        const item = this.$options.rules[key]
        this.$watch(key, value => {
          const result = item.validate(value)
          if(!result) console.log(item.message)
        })
      }
    }
  })
}
app.use(validatorPlugin)

const vm = app.mount('#root')