vue3 自定义指令

复制代码
mkdir custom-directives

cd custom-directives

npm init -y

yarn add webpack@4.44.2 webpack-cli@3.3.12 webpack-dev-server@3.11.2 -D

yarn add @vue/compiler-sfc@3.1.2 vue-loader@16.5.0 vue-style-loader@4.1.3 vue-template-compiler@2.6.14 -D
复制代码

包作用解析:

@vue/compiler-sfc     (处理.vue的单文件组件)

vue-loader      (处理.vue的文件的逻辑)

vue-style-loader  (处理.vue的样式放到相应的html文件中去进行打包)

vue-template-compiler  (处理vue文件的template标签里面的东西的)

yarn add html-webpack-plugin@4.5.0 css-loader@4 sass-loader@10.1.1 sass@1.45.2 -D

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

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

sass-loader@10.1.1    <=>  sass@1.45.2

修改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'),
    }),
  ],
}
复制代码

\public\index.html  (Vue已cdn的方式引入 不参与打包 加快打包速度)   cdn查询地址 : https://www.jsdelivr.com/

复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div id="app"></div>
  <script src="https://cdn.jsdelivr.net/npm/vue@3.2.27/dist/vue.global.min.js"></script>
</body>
</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}`
  },
}
复制代码

 

posted @   云卷芸舒  阅读(491)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示