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}`
},
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具