2024-08-21

在Vue3项目中,我们可以通过创建一个自定义组件来封装SVG图标。这样可以在整个应用中复用SVG图标,并且可以通过props来动态调整SVG的一些属性,如颜色、大小等。

首先,在项目中创建一个新的.vue文件,例如SvgIcon.vue




<template>
  <svg :class="svgClass" aria-hidden="true">
    <use :xlink:href="iconName"></use>
  </svg>
</template>
 
<script lang="ts">
import { defineComponent, PropType } from 'vue';
 
export default defineComponent({
  name: 'SvgIcon',
  props: {
    iconClass: {
      type: String as PropType<string>,
      required: true
    },
    className: {
      type: String as PropType<string>,
      default: ''
    }
  },
  computed: {
    iconName() {
      return `#icon-${this.iconClass}`;
    },
    svgClass() {
      if (this.className) {
        return 'svg-icon ' + this.className;
      } else {
        return 'svg-icon';
      }
    }
  }
});
</script>
 
<style scoped>
.svg-icon {
  width: 1em;
  height: 1em;
  fill: currentColor;
  overflow: hidden;
}
</style>

然后,在components目录下创建一个index.ts文件,将SvgIcon.vue组件导入并注册为全局组件:




import SvgIcon from './SvgIcon.vue';
 
export default (app: any) => {
  app.component('SvgIcon', SvgIcon);
};

最后,在main.ts文件中导入并使用这个注册函数:




import { createApp } from 'vue';
import App from './App.vue';
import setupComponents from './components'; // 导入组件注册函数
 
const app = createApp(App);
setupComponents(app); // 注册全局组件
 
app.mount('#app');

现在,你可以在任何组件中使用<SvgIcon icon-class="example" />来引用SVG图标了。其中icon-class是你在SVG sprite 文件中定义的图标的ID,不包括#前缀。

2024-08-21



<template>
  <div class="search-bar">
    <input
      v-model="searchQuery"
      type="text"
      placeholder="请输入搜索内容"
      @input="handleInput"
    />
    <button @click="handleSearch">搜索</button>
    <button @click="handleReset">重置</button>
  </div>
</template>
 
<script>
export default {
  data() {
    return {
      searchQuery: '',
    };
  },
  methods: {
    handleInput() {
      // 处理输入时的逻辑,例如去除空格等
      this.searchQuery = this.searchQuery.trim();
      // 可以在这里调用父组件的方法来实时更新搜索结果
      this.$emit('input', this.searchQuery);
    },
    handleSearch() {
      // 执行搜索操作
      this.$emit('search', this.searchQuery);
    },
    handleReset() {
      // 重置搜索框内容并清除结果
      this.searchQuery = '';
      this.$emit('input', '');
      this.$emit('search', '');
    },
  },
};
</script>
 
<style scoped>
.search-bar {
  display: flex;
  align-items: center;
}
 
.search-bar input {
  margin-right: 8px;
  padding: 8px;
}
 
.search-bar button {
  margin-right: 8px;
  padding: 8px 12px;
}
</style>

这个简单的Vue组件包含了搜索框和两个按钮:一个用于搜索,一个用于重置。在输入框中输入内容时,会触发handleInput方法,可以在这里添加额外的逻辑,如自动提示、输入时实时搜索等。点击搜索按钮会触发handleSearch方法,执行实际的搜索操作。点击重置按钮会清空搜索框并可能执行其他重置逻辑,如取消高亮显示、清除搜索结果等。这个组件可以被嵌入到任何需要文本搜索的Vue应用中。

2024-08-21



<template>
  <div>
    <h2>{{ formTitle }}</h2>
    <vue-form-renderer :schema="formSchema" @submit-success="onSubmitSuccess" />
  </div>
</template>
 
<script>
import { ref } from 'vue';
import VueFormRenderer from 'vue-form-renderer';
import 'vue-form-renderer/lib/vue-form-renderer.css';
 
export default {
  components: {
    VueFormRenderer
  },
  setup() {
    const formTitle = ref('用户注册');
    const formSchema = ref({
      type: 'object',
      properties: {
        username: {
          type: 'string',
          title: '用户名'
        },
        email: {
          type: 'string',
          title: '邮箱',
          format: 'email'
        },
        password: {
          type: 'string',
          title: '密码',
          'ui:widget': 'password'
        }
      },
      required: ['username', 'email', 'password']
    });
 
    const onSubmitSuccess = (formData, emit) => {
      console.log('提交的数据:', formData);
      // 这里可以实现提交数据到后端的逻辑
      // ...
    };
 
    return {
      formTitle,
      formSchema,
      onSubmitSuccess
    };
  }
};
</script>

这个代码实例展示了如何在Vue 3应用中引入和使用vue-form-renderer组件来渲染一个简单的JSON模式表单。它定义了一个包含用户名、邮箱和密码字段的表单,并且在用户提交表单时通过onSubmitSuccess处理函数输出表单数据。这个例子简单明了地展示了如何使用Vue 3和vue-form-renderer创建动态表单。

2024-08-21

在Vue中,v-for 指令用于基于源数据多次渲染元素或模板块。这是一个常用的指令,可以处理列表数据和对象属性。

基于数组的渲染




<ul id="app">
  <li v-for="item in items">{{ item.text }}</li>
</ul>



new Vue({
  el: '#app',
  data: {
    items: [
      { text: 'Item 1' },
      { text: 'Item 2' },
      { text: 'Item 3' },
    ]
  }
})

基于对象的渲染




<div id="app">
  <div v-for="(value, key) in object">{{ key }}: {{ value }}</div>
</div>



new Vue({
  el: '#app',
  data: {
    object: {
      firstName: 'John',
      lastName: 'Doe',
      age: 30
    }
  }
})

使用索引




<ul id="app">
  <li v-for="(item, index) in items">{{ index }}: {{ item.text }}</li>
</ul>

使用 v-fortemplate 进行嵌套循环




<ul id="app">
  <li v-for="item in items">
    {{ item.text }}
    <ul>
      <li v-for="subItem in item.subItems">{{ subItem }}</li>
    </ul>
  </li>
</ul>

使用 key 提高列表渲染的性能




<ul id="app">
  <li v-for="item in items" :key="item.id">{{ item.text }}</li>
</ul>

key 的值应该是唯一的,可能是每项的 id 或其他唯一标识。这有助于Vue跟踪每个节点的身份,在动态更新时最小化DOM元素的重新渲染。

以上代码展示了如何在Vue中使用 v-for 指令,包括基于数组和对象的循环渲染,以及如何使用索引和嵌套循环。使用 key 是一个最佳实践,可以提高大型列表的渲染性能。

2024-08-21

在Vue 3 + TypeScript + Pinia + Element Plus项目中,我们可以使用动态路由和用户权限来实现不同角色的用户访问不同的页面。以下是一个简化的例子:

  1. 定义路由和角色:



// router/index.ts
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
 
const routes: Array<RouteRecordRaw> = [
  {
    path: '/',
    name: 'Home',
    component: () => import('@/views/Home.vue'),
  },
  {
    path: '/admin',
    name: 'Admin',
    component: () => import('@/views/Admin.vue'),
    meta: { requiresAuth: true, roles: ['admin'] },
  },
  // 更多路由...
];
 
const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes,
});
 
export default router;
  1. 使用全局前置守卫来实现权限控制:



// router/routerGuard.ts
import router from './index';
import store from '@/store';
 
router.beforeEach(async (to, from, next) => {
  const user = store.state.user;
  if (to.matched.some(record => record.meta.requiresAuth) && !user.isLoggedIn) {
    // 如果用户未登录,则重定向到登录页面
    next('/login');
  } else if (to.matched.some(record => record.meta.roles)) {
    // 如果定义了角色,则检查用户角色是否匹配
    if (to.meta.roles.includes(user.role)) {
      next();
    } else {
      // 如果用户角色不匹配,则重定向到403页面
      next('/403');
    }
  } else {
    next(); // 如果没有定义权限要求,则允许访问
  }
});
  1. 在Pinia中管理用户状态:



// store/user.ts
import { defineStore } from 'pinia';
 
export const useUserStore = defineStore({
  id: 'user',
  state: () => ({
    isLoggedIn: false,
    role: 'guest',
  }),
  actions: {
    login(role: string) {
      this.isLoggedIn = true;
      this.role = role;
    },
    logout() {
      this.isLoggedIn = false;
      this.role = 'guest';
    },
  },
});
  1. 在登录组件中,登录成功后更新用户状态并重定向到主页:



// components/Login.vue
<script setup lang="ts">
import { useUserStore } from '@/store';
import { useRouter } from 'vue-router';
 
const userStore = useUserStore();
const router = useRouter();
 
function handleLogin(role: string) {
  userStore.login(role);
  router.push('/');
}
</script>

确保在应用的入口文件(如 main.ts)中正确地使用路由守卫:




import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import { setupPinia } from './store';
 
const app = createApp(App);
 
setupPinia(app);
 
app.use(router);
app.mount('#app');

这样,你就有了一个基于Vue 3 + TypeScript + Pinia + Element Plus的项目,它使用动态路由和用户权限来控制页面访问。

2024-08-21

在使用 yarn create vite 创建 Vue 3 项目时,可以通过命令行选择包含 TypeScript 的选项。以下是步骤和示例代码:

  1. 打开终端或命令行界面。
  2. 运行以下命令来创建一个新的 Vue 3 项目,并在创建过程中选择 TypeScript 选项:



yarn create vite
  1. 命令执行后,会出现一个选择框,选择 vue
  2. 然后选择 Manually select features,这样你可以选择是否包括 TypeScript。
  3. 接下来,选择 TypeScript 选项。
  4. 最后,为你的项目选择一个名字和选择一个文件夹来存放项目,并且可以选择使用 npm 或者 yarn 作为包管理器。

命令行会自动进行项目的初始化和安装依赖,一旦完成,你就会有一个配置好 TypeScript 的 Vue 3 项目。

如果你想要确保项目使用特定版本的 TypeScript,你可以在项目创建后,通过 yarn addnpm install 指定版本号来安装 TypeScript。例如:




yarn add typescript@4.5.0

或者




npm install typescript@4.5.0

请确保安装的版本与你的项目兼容。

2024-08-21

在Vue中实现数据代理,我们可以通过在Vue实例中定义data属性来实现。Vue会遍历data中的所有属性,并使用Object.defineProperty为这些属性定义getter和setter,实现数据劫持。

以下是一个简单的数据代理实现示例:




// 假设我们有一个Vue的简化版实现
function Vue(options) {
  this._data = options.data;
  observe(this._data, this);
}
 
function observe(data, vm) {
  if (typeof data !== 'object' || data === null) {
    return;
  }
 
  Object.keys(data).forEach(key => {
    defineReactive(data, key, data[key], vm);
  });
}
 
function defineReactive(obj, key, val, vm) {
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter() {
      console.log(`获取${key}:${val}`);
      return val;
    },
    set: function reactiveSetter(newVal) {
      if (newVal === val) return;
      console.log(`设置${key}:${newVal}`);
      val = newVal;
      // 这里可以实现响应式更新DOM等操作
      // vm.$render();
    }
  });
}
 
// 使用Vue
const vm = new Vue({
  data: {
    message: 'Hello Vue!'
  }
});
 
// 测试数据劫持
console.log(vm._data.message); // 获取message:Hello Vue!
vm._data.message = 'Hello Proxy!'; // 设置message:Hello Proxy!

在这个示例中,我们定义了一个Vue构造函数,在其data选项中定义了数据。然后,我们使用observe函数遍历data中的所有属性,并对每个属性使用defineReactive函数来定义其getter和setter。在setter中,我们可以实现响应式的更新逻辑,比如DOM的重新渲染。

这个简化版的实现没有包含Vue的完整功能,但足以展示数据代理的基本原理。在实际的Vue框架中,数据代理是实现响应式系统的基础,并且涉及到更复杂的逻辑,例如依赖追踪和虚拟DOM的更新。

2024-08-21

在Vue 3中使用TSX时,可以通过<slots>对象来访问和使用插槽。以下是一个简单的例子:




import { defineComponent, PropType } from 'vue';
 
const MyComponent = defineComponent({
  props: {
    title: String
  },
  render() {
    return (
      <div>
        {/* 声明插槽 */}
        <header>
          <slot name="header" />
        </header>
        <main>
          {/* 默认插槽 */}
          {this.$slots.default ? this.$slots.default() : null}
        </main>
        <footer>
          {this.title && <span>{this.title}</span>}
          {/* 命名插槽 */}
          <slot name="footer" />
        </footer>
      </div>
    );
  }
});
 
export default MyComponent;

使用该组件时:




import MyComponent from './MyComponent.vue';
 
const App = () => (
  <MyComponent title="This is a title">
    {/* 默认插槽内容 */}
    <p>This is some default slot content.</p>
    {/* 头部插槽内容 */}
    <template v-slot:header>
      <h1>This is a header slot</h1>
    </template>
    {/* 脚部插槽内容 */}
    <template v-slot:footer>
      <p>This is a footer slot</p>
    </template>
  </MyComponent>
);

在这个例子中,MyComponent组件定义了三个插槽:一个默认插槽和两个命名插槽headerfooter。在使用该组件时,通过v-slot:指令指定插槽内容。

2024-08-21

在Vue 3中引入Vue Router可以通过以下步骤进行:

  1. 安装Vue Router:



npm install vue-router@4
  1. 创建一个router.js文件,并设置Vue Router:



// router.js
import { createRouter, createWebHistory } from 'vue-router';
 
// 引入Vue组件
import HomePage from './components/HomePage.vue';
import AboutPage from './components/AboutPage.vue';
 
// 定义路由
const routes = [
  { path: '/', component: HomePage },
  { path: '/about', component: AboutPage },
];
 
// 创建router实例
const router = createRouter({
  history: createWebHistory(),
  routes,
});
 
export default router;
  1. 在Vue应用中使用创建的router实例:



// main.js
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
 
const app = createApp(App);
 
app.use(router);
 
app.mount('#app');
  1. 在Vue组件中使用<router-view>来显示当前路由内容,以及<router-link>来创建导航链接:



<!-- App.vue -->
<template>
  <router-link to="/">Home</router-link>
  <router-link to="/about">About</router-link>
 
  <router-view></router-view>
</template>
 
<script>
export default {
  name: 'App',
};
</script>

确保你的Vue 3项目中有相应的组件(例如HomePageAboutPage),并且它们被正确导入到router.js中。这样就设置好了Vue 3项目中的Vue Router,你可以通过定义的路由来导航你的应用了。

2024-08-21

在Vue中实现画面中英文切换,通常可以通过i18n国际化插件来实现。以下是简单的实现步骤:

  1. 安装vue-i18n插件。



npm install vue-i18n
  1. 设置i18n实例并配置中英文语言包。



// i18n.js
import Vue from 'vue';
import VueI18n from 'vue-i18n';
 
Vue.use(VueI18n);
 
const messages = {
  en: {
    message: {
      hello: 'Hello world',
    }
  },
  cn: {
    message: {
      hello: '你好,世界',
    }
  }
};
 
const i18n = new VueI18n({
  locale: 'cn', // 默认语言
  messages,
});
 
export default i18n;
  1. 在Vue根实例中引入i18n。



// main.js
import Vue from 'vue';
import App from './App.vue';
import i18n from './i18n';
 
new Vue({
  i18n,
  render: h => h(App),
}).$mount('#app');
  1. 在Vue组件中使用$t函数来访问翻译内容。



<template>
  <div id="app">
    <p>{{ $t("message.hello") }}</p>
    <button @click="changeLanguage('cn')">中文</button>
    <button @click="changeLanguage('en')">English</button>
  </div>
</template>
 
<script>
export default {
  methods: {
    changeLanguage(lang) {
      this.$i18n.locale = lang;
    },
  },
};
</script>

用户点击按钮时,通过changeLanguage方法改变当前语言,进而更新应用中显示的文本内容。