欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

ruoyi-vue3 集成aj-captcha實現(xiàn)滑塊、文字點選驗證碼功能

 更新時間:2023年12月18日 10:24:15   作者:七維大腦  
這篇文章主要介紹了 ruoyi-vue3 集成aj-captcha實現(xiàn)滑塊、文字點選驗證碼,本文基于后端RuoYi-Vue 3.8.7 和 前端 RuoYi-Vue3 3.8.7,集成以AJ-Captcha文字點選驗證碼為例,不需要鍵盤手動輸入,極大優(yōu)化了傳統(tǒng)驗證碼用戶體驗不佳的問題,感興趣的朋友一起看看吧

0. 前言

其實若依的官方文檔中有集成aj-captcha實現(xiàn)滑塊驗證碼的部分,但是一直給的前端示例代碼中都是Vue2的版本,而且后端部分也一直未保持更新。再比如官方文檔在集成aj-captcha后并未實現(xiàn)驗證碼開關的功能。

然后我最近正好在用若依的Vue3版本做東西,正好記錄一下。

0.1 說明

以官方文檔為模板寫的這篇文章,所以中間會穿插官方文檔中的一些文字。

文章中所涉及的截圖、代碼,由于我已經使用 若依框架包名修改器 修改過了,所以包名、模塊名前綴會和原版有出入,但僅限于包名和模塊名。請注意甄別。

本文基于后端RuoYi-Vue 3.8.7 和 前端 RuoYi-Vue3 3.8.7

官方文檔在集成后并沒有實現(xiàn)驗證碼開關功能,本文會進行實現(xiàn)。

集成以AJ-Captcha文字點選驗證碼為例,不需要鍵盤手動輸入,極大優(yōu)化了傳統(tǒng)驗證碼用戶體驗不佳的問題。目前對外提供兩種類型的驗證碼,其中包含滑動拼圖、文字點選。

1. 后端部分

1.1 添加依賴

ruoyi-framework 模塊中的 pom.xml 添加以下依賴:

<!-- 滑塊驗證碼  -->
<dependency>
	<groupId>com.github.anji-plus</groupId>
	<artifactId>captcha-spring-boot-starter</artifactId>
	<version>1.2.7</version>
</dependency>

刪除原本的 kaptcha 驗證碼依賴:

<!-- 驗證碼 -->
<dependency>
	<groupId>pro.fessional</groupId>
	<artifactId>kaptcha</artifactId>
	<exclusions>
		<exclusion>
		<artifactId>servlet-api</artifactId>
		<groupId>javax.servlet</groupId>
		</exclusion>
	</exclusions>
</dependency>

最終 pom.xml 截圖:

1.2. 修改 application.yml

修改application.yml,加入aj-captcha相關配置:
(我的項目使用的是文字點選,如需要使用滑塊,type 設置為 blockPuzzle 即可)

# 滑塊驗證碼
aj:
   captcha:
      # 緩存類型
      cache-type: redis
      # blockPuzzle 滑塊 clickWord 文字點選  default默認兩者都實例化
      type: clickWord
      # 右下角顯示字
      water-mark: B站、抖音同名搜索七維大腦
      # 校驗滑動拼圖允許誤差偏移量(默認5像素)
      slip-offset: 5
      # aes加密坐標開啟或者禁用(true|false)
      aes-status: true
      # 滑動干擾項(0/1/2)
      interference-options: 2

1.3. 新增 CaptchaRedisService 類

ruoyi-framework 模塊下,com.ruoyi.framework.web.service 包下創(chuàng)建CaptchaRedisService.java 類,內容如下:

(請復制粘貼后注意修改包路徑為自己項目真實路徑)

package xyz.ytxy.framework.web.service;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import com.anji.captcha.service.CaptchaCacheService;
/**
 * 自定義redis驗證碼緩存實現(xiàn)類
 *
 * @author ruoyi
 */
public class CaptchaRedisService implements CaptchaCacheService
{
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Override
    public void set(String key, String value, long expiresInSeconds)
    {
        stringRedisTemplate.opsForValue().set(key, value, expiresInSeconds, TimeUnit.SECONDS);
    }
    @Override
    public boolean exists(String key)
    {
        return Boolean.TRUE.equals(stringRedisTemplate.hasKey(key));
    }
    @Override
    public void delete(String key)
    {
        stringRedisTemplate.delete(key);
    }
    @Override
    public String get(String key)
    {
        return stringRedisTemplate.opsForValue().get(key);
    }
    @Override
    public Long increment(String key, long val)
    {
        return stringRedisTemplate.opsForValue().increment(key, val);
    }
    @Override
    public String type()
    {
        return "redis";
    }
}

1.4. 添加必須文件

ruoyi-admin 模塊下,找到 resources 目錄

resources 目錄找到 META-INF 目錄在 META-INF 目錄中新建 services 文件夾

services 文件夾中新建 com.anji.captcha.service.CaptchaCacheService 文件(注意是文件)

com.anji.captcha.service.CaptchaCacheService 文件中輸入 xxx.xxx.framework.web.service.CaptchaRedisService (也就是剛剛創(chuàng)建的CaptchaRedisService類的真實路徑)

1.5. 移除不需要的類

  • ruoyi-admin 模塊下 com.ruoyi.web.controller.common.CaptchaController.java
  • ruoyi-framework 模塊下 com.ruoyi.framework.config.CaptchaConfig.java
  • ruoyi-framework 模塊下 com.ruoyi.framework.config.KaptchaTextCreator.java

1.6. 修改登錄方法

修改 ruoyi-admin 模塊下 com.ruoyi.web.controller.system.SysLoginController.java 類中的 login 方法:

/**
     * 登錄方法
     *
     * @param loginBody 登錄信息
     * @return 結果
     */
    @PostMapping("/login")
    public AjaxResult login(@RequestBody LoginBody loginBody)
    {
        AjaxResult ajax = AjaxResult.success();
        // 生成令牌
        String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode());
        ajax.put(Constants.TOKEN, token);
        return ajax;
    }

修改后生成令牌這一步比原版少了 loginBody.getUuid() 參數(shù)。

修改 ruoyi-framework 模塊下的com.ruoyi.framework.web.service.SysLoginService.java類:

package xyz.ytxy.framework.web.service;
import javax.annotation.Resource;
import com.anji.captcha.model.common.ResponseModel;
import com.anji.captcha.model.vo.CaptchaVO;
import com.anji.captcha.service.CaptchaService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import xyz.ytxy.common.constant.CacheConstants;
import xyz.ytxy.common.constant.Constants;
import xyz.ytxy.common.constant.UserConstants;
import xyz.ytxy.common.core.domain.entity.SysUser;
import xyz.ytxy.common.core.domain.model.LoginUser;
import xyz.ytxy.common.core.redis.RedisCache;
import xyz.ytxy.common.exception.ServiceException;
import xyz.ytxy.common.exception.user.BlackListException;
import xyz.ytxy.common.exception.user.CaptchaException;
import xyz.ytxy.common.exception.user.CaptchaExpireException;
import xyz.ytxy.common.exception.user.UserNotExistsException;
import xyz.ytxy.common.exception.user.UserPasswordNotMatchException;
import xyz.ytxy.common.utils.DateUtils;
import xyz.ytxy.common.utils.MessageUtils;
import xyz.ytxy.common.utils.StringUtils;
import xyz.ytxy.common.utils.ip.IpUtils;
import xyz.ytxy.framework.manager.AsyncManager;
import xyz.ytxy.framework.manager.factory.AsyncFactory;
import xyz.ytxy.framework.security.context.AuthenticationContextHolder;
import xyz.ytxy.system.service.ISysConfigService;
import xyz.ytxy.system.service.ISysUserService;
/**
 * 登錄校驗方法
 *
 * @author ruoyi
 */
@Component
public class SysLoginService
{
    @Autowired
    private TokenService tokenService;
    @Resource
    private AuthenticationManager authenticationManager;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private ISysUserService userService;
    @Autowired
    private ISysConfigService configService;
    @Autowired
    @Lazy
    private CaptchaService captchaService;
    /**
     * 登錄驗證
     *
     * @param username 用戶名
     * @param password 密碼
     * @param code 驗證碼
     * @return 結果
     */
    public String login(String username, String password, String code)
    {
        // 驗證碼校驗
        validateCaptcha(username, code);
        // 登錄前置校驗
        loginPreCheck(username, password);
        // 用戶驗證
        Authentication authentication = null;
        try
        {
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
            AuthenticationContextHolder.setContext(authenticationToken);
            // 該方法會去調用UserDetailsServiceImpl.loadUserByUsername
            authentication = authenticationManager.authenticate(authenticationToken);
        }
        catch (Exception e)
        {
            if (e instanceof BadCredentialsException)
            {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
                throw new UserPasswordNotMatchException();
            }
            else
            {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
                throw new ServiceException(e.getMessage());
            }
        }
        finally
        {
            AuthenticationContextHolder.clearContext();
        }
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        recordLoginInfo(loginUser.getUserId());
        // 生成token
        return tokenService.createToken(loginUser);
    }
    /**
     * 校驗驗證碼
     *
     * @param username 用戶名
     * @param code 驗證碼
     * @return 結果
     */
    public void validateCaptcha(String username, String code)
    {
        boolean captchaEnabled = configService.selectCaptchaEnabled();
        if (captchaEnabled)
        {
            CaptchaVO captchaVO = new CaptchaVO();
            captchaVO.setCaptchaVerification(code);
            ResponseModel response = captchaService.verification(captchaVO);
            if (!response.isSuccess())
            {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
                throw new CaptchaException();
            }
        }
    }
    /**
     * 登錄前置校驗
     * @param username 用戶名
     * @param password 用戶密碼
     */
    public void loginPreCheck(String username, String password)
    {
        // 用戶名或密碼為空 錯誤
        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password))
        {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("not.null")));
            throw new UserNotExistsException();
        }
        // 密碼如果不在指定范圍內 錯誤
        if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
                || password.length() > UserConstants.PASSWORD_MAX_LENGTH)
        {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
            throw new UserPasswordNotMatchException();
        }
        // 用戶名不在指定范圍內 錯誤
        if (username.length() < UserConstants.USERNAME_MIN_LENGTH
                || username.length() > UserConstants.USERNAME_MAX_LENGTH)
        {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
            throw new UserPasswordNotMatchException();
        }
        // IP黑名單校驗
        String blackStr = configService.selectConfigByKey("sys.login.blackIPList");
        if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr()))
        {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("login.blocked")));
            throw new BlackListException();
        }
    }
    /**
     * 記錄登錄信息
     *
     * @param userId 用戶ID
     */
    public void recordLoginInfo(Long userId)
    {
        SysUser sysUser = new SysUser();
        sysUser.setUserId(userId);
        sysUser.setLoginIp(IpUtils.getIpAddr());
        sysUser.setLoginDate(DateUtils.getNowDate());
        userService.updateUserProfile(sysUser);
    }
}
  • login 方法比原版少了 uuid 的參數(shù)
  • validateCaptcha 方法比原版少了 uuid 的參數(shù),方法內容更改為aj-captcha的驗證方式
  • 其他內容未更改

這地方如果直接替換官方文檔中的代碼會造成部分新功能缺失。所以這里直接替換我提供的代碼即可。(注意替換后將包名改為你實際的包名)

1.7. 新增驗證碼開關獲取接口

ruoyi-admin 模塊下的 com.ruoyi.web.controller.common 包新增 CaptchaEnabledController.java

(注意將包名改為你實際的包名)

package xyz.ytxy.web.controller.common;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import xyz.ytxy.common.core.domain.AjaxResult;
import xyz.ytxy.system.service.ISysConfigService;
/**
 * 驗證碼操作處理
 *
 * @author B站、抖音搜索:七維大腦    點個關注唄
 */
@RestController
public class CaptchaEnabledController {
    @Autowired
    private ISysConfigService configService;
    /**
     * 獲取驗證碼開關
     */
    @GetMapping("/captchaEnabled")
    public AjaxResult captchaEnabled() {
        AjaxResult ajax = AjaxResult.success();
        boolean captchaEnabled = configService.selectCaptchaEnabled();
        ajax.put("captchaEnabled", captchaEnabled);
        return ajax;
    }
}

1.8. 允許匿名訪問

ruoyi-framework模塊下的 com.ruoyi.framework.config 包下找到 SecurityConfig.java 類,修改以下內容:

原版:

// 對于登錄login 注冊register 驗證碼captchaImage 允許匿名訪問
.antMatchers("/login", "/register", "/captchaImage").permitAll()

修改為:

// 對于登錄login 注冊register 滑塊驗證碼/captcha/get /captcha/check 獲取驗證碼開關 /captchaEnabled 允許匿名訪問
.antMatchers("/login", "/register", "/captcha/get", "/captcha/check", "/captchaEnabled").permitAll()

2. 前端部分(Vue3)

2.1. 新增依賴 crypto-js

package.json"dependencies" 中新增 "crypto-js": "4.1.1"

新增后重新 install,比如我用的pnpm,直接執(zhí)行:pnpm install --registry=https://registry.npmmirror.com

2.2. 新增 Verifition 組件

此部分代碼我放到了阿里云盤:https://www.alipan.com/s/4hEbavUC4Np

下載后粘貼到 src/components 目錄下:

2.3. 修改login.js

import request from '@/utils/request'
// 登錄方法
export function login(username, password, code) {
  const data = {
    username,
    password,
    code
  }
  return request({
    url: '/login',
    headers: {
      isToken: false,
      repeatSubmit: false
    },
    method: 'post',
    data: data
  })
}
// 注冊方法
export function register(data) {
  return request({
    url: '/register',
    headers: {
      isToken: false
    },
    method: 'post',
    data: data
  })
}
// 獲取用戶詳細信息
export function getInfo() {
  return request({
    url: '/getInfo',
    method: 'get'
  })
}
// 退出方法
export function logout() {
  return request({
    url: '/logout',
    method: 'post'
  })
}
// 獲取驗證碼開關
export function isCaptchaEnabled() {
    return request({
        url: '/captchaEnabled',
        method: 'get'
    })
}
  • 修改了 login 函數(shù),去掉了 uuid 參數(shù)
  • 刪除了獲取驗證碼函數(shù) getCodeImg
  • 新增了獲取驗證碼開關函數(shù) isCaptchaEnabled

2.4. 修改 user.js

刪除 uuid 參數(shù) :

// 登錄
      login(userInfo) {
        const username = userInfo.username.trim()
        const password = userInfo.password
        const code = userInfo.code
        return new Promise((resolve, reject) => {
          login(username, password, code).then(res => {
            setToken(res.token)
            this.token = res.token
            resolve()
          }).catch(error => {
            reject(error)
          })
        })
      },

2.5. 修改login.vue

修改內容較多,建議直接替換再修改:

<template>
  <div class="login">
    <el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form">
      <h3 class="title">若依后臺管理系統(tǒng)</h3>
      <el-form-item prop="username">
        <el-input
            v-model="loginForm.username"
            type="text"
            size="large"
            auto-complete="off"
            placeholder="賬號"
        >
          <template #prefix>
            <svg-icon icon-class="user" class="el-input__icon input-icon"/>
          </template>
        </el-input>
      </el-form-item>
      <el-form-item prop="password">
        <el-input
            v-model="loginForm.password"
            type="password"
            size="large"
            auto-complete="off"
            placeholder="密碼"
            @keyup.enter="handleLogin"
        >
          <template #prefix>
            <svg-icon icon-class="password" class="el-input__icon input-icon"/>
          </template>
        </el-input>
      </el-form-item>
      <Verify
          @success="capctchaCheckSuccess"
          :mode="'pop'"
          :captchaType="'clickWord'"
          :imgSize="{ width: '330px', height: '155px' }"
          ref="verify"
          v-if="captchaEnabled"
      ></Verify>
      <el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">記住密碼</el-checkbox>
      <el-form-item style="width:100%;">
        <el-button
            :loading="loading"
            size="large"
            type="primary"
            style="width:100%;"
            @click.prevent="handleLogin"
        >
          <span v-if="!loading">登 錄</span>
          <span v-else>登 錄 中...</span>
        </el-button>
        <div style="float: right;" v-if="register">
          <router-link class="link-type" :to="'/register'">立即注冊</router-link>
        </div>
      </el-form-item>
    </el-form>
    <!--  底部  -->
    <div class="el-login-footer">
      <span>Copyright ? 2018-2023 ruoyi.vip All Rights Reserved.</span>
    </div>
  </div>
</template>
<script setup>
import Cookies from "js-cookie";
import {encrypt, decrypt} from "@/utils/jsencrypt";
import useUserStore from '@/store/modules/user'
import Verify from "@/components/Verifition/Verify";
import {isCaptchaEnabled} from "@/api/login";
const userStore = useUserStore()
const route = useRoute();
const router = useRouter();
const {proxy} = getCurrentInstance();
const loginForm = ref({
  username: "admin",
  password: "admin123",
  rememberMe: false,
  code: ""
});
const loginRules = {
  username: [{required: true, trigger: "blur", message: "請輸入您的賬號"}],
  password: [{required: true, trigger: "blur", message: "請輸入您的密碼"}]
};
const loading = ref(false);
// 驗證碼開關
const captchaEnabled = ref(true);
// 注冊開關
const register = ref(false);
const redirect = ref(undefined);
watch(route, (newRoute) => {
  redirect.value = newRoute.query && newRoute.query.redirect;
}, {immediate: true});
function userRouteLogin() {
  // 調用action的登錄方法
  userStore.login(loginForm.value).then(() => {
    const query = route.query;
    const otherQueryParams = Object.keys(query).reduce((acc, cur) => {
      if (cur !== "redirect") {
        acc[cur] = query[cur];
      }
      return acc;
    }, {});
    router.push({path: redirect.value || "/", query: otherQueryParams});
  }).catch(() => {
    loading.value = false;
  });
}
function handleLogin() {
  proxy.$refs.loginRef.validate(valid => {
    if (valid && captchaEnabled.value) {
      proxy.$refs.verify.show();
    } else if (valid && !captchaEnabled.value) {
      userRouteLogin();
    }
  });
}
function getCookie() {
  const username = Cookies.get("username");
  const password = Cookies.get("password");
  const rememberMe = Cookies.get("rememberMe");
  loginForm.value = {
    username: username === undefined ? loginForm.value.username : username,
    password: password === undefined ? loginForm.value.password : decrypt(password),
    rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
  };
}
function capctchaCheckSuccess(params) {
  loginForm.value.code = params.captchaVerification;
  loading.value = true;
  // 勾選了需要記住密碼設置在 cookie 中設置記住用戶名和密碼
  if (loginForm.value.rememberMe) {
    Cookies.set("username", loginForm.value.username, {expires: 30});
    Cookies.set("password", encrypt(loginForm.value.password), {expires: 30,});
    Cookies.set("rememberMe", loginForm.value.rememberMe, {expires: 30});
  } else {
    // 否則移除
    Cookies.remove("username");
    Cookies.remove("password");
    Cookies.remove("rememberMe");
  }
  userRouteLogin();
}
// 獲取驗證碼開關
function getCaptchaEnabled() {
  isCaptchaEnabled().then(res => {
    captchaEnabled.value = res.captchaEnabled === undefined ? true : res.captchaEnabled;
  });
}
getCookie();
getCaptchaEnabled();
</script>
<style lang='scss' scoped>
.login {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
  background-image: url("../assets/images/login-background.jpg");
  background-size: cover;
}
.title {
  margin: 0px auto 30px auto;
  text-align: center;
  color: #707070;
}
.login-form {
  border-radius: 6px;
  background: #ffffff;
  width: 400px;
  padding: 25px 25px 5px 25px;
  .el-input {
    height: 40px;
    input {
      height: 40px;
    }
  }
  .input-icon {
    height: 39px;
    width: 14px;
    margin-left: 0px;
  }
}
.login-tip {
  font-size: 13px;
  text-align: center;
  color: #bfbfbf;
}
.el-login-footer {
  height: 40px;
  line-height: 40px;
  position: fixed;
  bottom: 0;
  width: 100%;
  text-align: center;
  color: #fff;
  font-family: Arial;
  font-size: 12px;
  letter-spacing: 1px;
}
</style>

2.6. 切換文字點選或滑塊驗證碼

有兩種類型,一種是文字點選,一種是滑塊驗證,那如何切換呢?

2.6.1 后端修改

修改fcat-admin模塊下 application.yml 中的 aj — type

  • 填寫blockPuzzle 為滑塊
  • 填寫 clickWord 為文字點選

2.6.2 前端修改

修改 login.vue

<Verify
	@success="capctchaCheckSuccess"
	:mode="'pop'"
	:captchaType="'clickWord'"
	:imgSize="{ width: '330px', height: '155px' }"
	ref="verify"
	v-if="captchaEnabled"
></Verify>

修改上述代碼中的 captchaType

填寫blockPuzzle 為滑塊填寫 clickWord 為文字點選

2.7. 成果展示:

默認底圖展示,用于接口異常等情況:

滑塊驗證碼正常顯示截圖:

文字點選驗證碼正常顯示截圖:

到此這篇關于 ruoyi-vue3 集成aj-captcha實現(xiàn)滑塊、文字點選驗證碼的文章就介紹到這了,更多相關ruoyi-vue3 滑塊驗證碼內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Vue開發(fā)項目中如何使用Font Awesome 5

    Vue開發(fā)項目中如何使用Font Awesome 5

    Font Awesome是一套流行的圖標字體庫,我們在實際開發(fā)的過程中會經常遇到需要使用圖標的場景,對于一些常用的圖標,我們可以直接在Font Awesome中找到并且使用,這篇文章主要給大家介紹了關于Vue開發(fā)項目中如何使用Font Awesome5的相關資料,需要的朋友可以參考下
    2021-11-11
  • Vue3 Ref獲取真實DOM學習實戰(zhàn)

    Vue3 Ref獲取真實DOM學習實戰(zhàn)

    這篇文章主要為大家介紹了Vue3 Ref獲取真實DOM學習實戰(zhàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-06-06
  • Vue2與Vue3中Ref綁定元素方式

    Vue2與Vue3中Ref綁定元素方式

    這篇文章主要介紹了Vue2與Vue3中Ref綁定元素方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • 淺析Vue 中的 render 函數(shù)

    淺析Vue 中的 render 函數(shù)

    在vue中我們使用模板HTML語法組建頁面的,使用render函數(shù)我們可以用js語言來構建DOM,今天小編就通過本文給大家簡單介紹下Vue 中 render 函數(shù),需要的朋友可以參考下
    2020-02-02
  • vue組件間傳值的方法你知道幾種

    vue組件間傳值的方法你知道幾種

    這篇文章主要為大家詳細介紹了vue組件間傳值的方法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • 在vue2項目中使用dart-sass的問題及解決方法

    在vue2項目中使用dart-sass的問題及解決方法

    在Vue2項目中,使用dart-sass替代node-sass可以解決安裝困難和環(huán)境兼容問題,VueCLI3+用戶可直接使用,而VueCLI2用戶需升級VueCLI和項目,具體方法包括修改package.json依賴并使用.scss文件編寫樣式,此更改有助于提升項目的開發(fā)效率和跨平臺兼容性
    2024-09-09
  • vue中選中多個選項并且改變選中的樣式的實例代碼

    vue中選中多個選項并且改變選中的樣式的實例代碼

    這篇文章主要介紹了vue中選中多個選項并且改變選中的樣式,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-09-09
  • vue.js學習之UI組件開發(fā)教程

    vue.js學習之UI組件開發(fā)教程

    前端開發(fā)中,隨著業(yè)務的增多,出于效率的考慮,我們對于組件化開發(fā)的需求也越來越迫切。下面這篇文章主要給大家介紹了關于vue.js之UI組件開發(fā)的相關資料,文中介紹的非常詳細,需要的朋友們下面來一起看看吧。
    2017-07-07
  • Vue常用指令詳解分析

    Vue常用指令詳解分析

    這篇文章給大家詳細分析了關于VUE的常用的相關指令內容,對此有需要的朋友們可以學習下。
    2018-08-08
  • vue遮罩層如何阻止?jié)L動

    vue遮罩層如何阻止?jié)L動

    這篇文章主要介紹了vue遮罩層如何阻止?jié)L動,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-07-07

最新評論