1. 程式人生 > 其它 >vue3 自定義指令

vue3 自定義指令

mkdir custom-directives

cd custom-directives

npm init -y

yarn add [email protected] [email protected] [email protected] -D

yarn add @vue/[email protected] [email protected] [email protected] [email protected] -D

包作用解析:

@vue/compiler-sfc (處理.vue的單檔案元件)

vue-loader (處理.vue的檔案的邏輯)

vue-style-loader(處理.vue的樣式放到相應的html檔案中去進行打包)

vue-template-compiler (處理vue檔案的template標籤裡面的東西的)

yarn add [email protected] css-loader@4 [email protected] [email protected] -D

注意:sass版本搭配不能出錯

sass-loader@5 <=> node-sass@4

[email protected] <=> [email protected]

修改package.json

"scripts": {
    "dev": "webpack-dev-server",
    "build": "webpack"
  },

根目錄下新建webpack.config.js檔案 遵循commonjs的規範 因為是執行在服務端

const htmlWebpackPlugin = require('html-webpack-plugin'),
  { VueLoaderPlugin } = require('vue-loader'),
  { resolve } = require('path')

module.exports = {
  mode: 'development',
  entry: './src/main.js',
  output: {
    path: resolve(__dirname, 'dist'),
    filename: 'bundle.js',
  },
  devtool: 'source-map',
  module: {
    rules: [
      {
        test: /.vue$/i,
        loader: 'vue-loader',
      },
      {
        test: /.scss$/i,
        use: ['vue-style-loader', 'css-loader', 'sass-loader'],
      },
    ],
  },
  resolve: {
    extensions: ['.js', '.jsx', '.vue'],
  },
  externals: {
    vue: 'Vue',
  },
  plugins: [
    new VueLoaderPlugin(),
    new htmlWebpackPlugin({
      template: resolve(__dirname, 'public/index.html'),
    }),
  ],
}

常規方法:\src\components\MyTab.vue

<template>
  <div>
    <a
      v-for="(item, index) in tabData"
      :key="index"
      href="javascript:;"
      @click="handleClick(index)"
      :class="['tab-item', { active: index === activeIdx }]"
    >
      {{ item.title }}
    </a>
  </div>
  <div>{{ tabContent }}</div>
</template>

<script>
export default {
  name: "my-tab",
  props: {
    tabData: {
      type: Array,
      default() {
        return [];
      },
    },
    currentIdx: {
      type: [Number, String],
      default: 0,
    },
  },
  computed: {
    tabContent() {
      return this.tabData[this.activeIdx].content;
    },
  },
  data() {
    return {
      activeIdx: this.currentIdx,
    };
  },
  methods: {
    handleClick(index) {
      this.activeIdx = index;
    },
  },
};
</script>

\src\App.vue

<template>
  <div>
    <my-tab :tabData="tabData" :currentIdx="currentIdx"></my-tab>
  </div>
</template>

<script>
import MyTab from "./components/MyTab";
export default {
  name: "App",
  components: {
    MyTab,
  },
  data() {
    return {
      tabData: [
        {
          id: 1,
          title: "選項1",
          content: "內容1",
        },
        {
          id: 2,
          title: "選項2",
          content: "內容2",
        },
        {
          id: 3,
          title: "選項3",
          content: "內容3",
        },
        {
          id: 4,
          title: "選項4",
          content: "內容4",
        },
      ],
      currentIdx: 1,
    };
  },
};
</script>

<style lang="scss">
a {
  padding-left: 20px;
  &.active {
    text-decoration: none;
    color: black;
  }
}
</style>

方法二 使用自定義指令:

\src\components\MyTab.vue

<template>
  <div
    v-nav-change="{
      tabClass: 'tab-item',
      activeClass: 'active',
      activeIdx,
    }"
  >
    <a
      v-for="(item, index) in tabData"
      :key="item.id"
      href="javascript:;"
      @click="handleClick(index)"
      class="tab-item"
    >
      {{ item.title }}
    </a>
  </div>
  <div>{{ tabContent }}</div>
</template>

<script>
import navChange from "../directives/navChange";
export default {
  name: "my-tab",
  directives: {
    navChange,
  },
  props: {
    tabData: {
      type: Array,
      default() {
        return [];
      },
    },
    currentIdx: {
      type: [Number, String],
      default: 0,
    },
  },
  computed: {
    tabContent() {
      return this.tabData[this.activeIdx].content;
    },
  },
  data() {
    return {
      activeIdx: this.currentIdx,
    };
  },
  methods: {
    handleClick(index) {
      this.activeIdx = index;
    },
  },
};
</script>

<style lang="scss">
</style>

\src\directives\navChange.js

export default {
  mounted(el, bindings) {
    const { tabClass, activeClass, activeIdx } = bindings.value
    // tabClass, activeClass el.oldTabItems 不變 掛載到el,update中不需要重新獲取
    el.tabClass = tabClass
    el.activeClass = activeClass
    el.oldTabItems = el.getElementsByClassName(el.tabClass)
    el.oldTabItems[activeIdx].className = `${tabClass} ${activeClass}`
  },
  updated(el, bindings) {
    const { activeIdx: oldIdx } = bindings.oldValue
    const { activeIdx: newIdx } = bindings.value
    const { tabClass, activeClass, oldTabItems } = el
    el.oldTabItems[oldIdx].className = `${tabClass}`
    el.oldTabItems[newIdx].className = `${tabClass} ${activeClass}`
  },
}