在数据库中插入数据
@RestController
@RequestMapping("product/category")
public class CategoryController {
@Autowired
private CategoryService categoryService;
/**
* 查出所有分类以及子分类,以树形结构组装起来
*/
@RequestMapping("/list/tree")
public R list(){
List<CategoryEntity> entityList = categoryService.listWithTree();
return R.ok().put("data", entityList);
}
}
@Service("categoryService")
public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity> implements CategoryService {
@Override
public List<CategoryEntity> listWithTree(){
// 1. 查出所有分类
List<CategoryEntity> categoryEntities = baseMapper.selectList(null);
// 2.组装成父子的树形结构
// 查找以及分类
List<CategoryEntity> level1Menu = categoryEntities.stream().filter((categoryEntity -> {
return categoryEntity.getParentCid() == 0;
})).map((menu)->{
menu.setChildren(getChildrens(menu,categoryEntities));
return menu;
}).sorted((menu1,menu2)->{
return (menu1.getSort()==null?0:menu1.getSort())-(menu2.getSort()==null?0:menu2.getSort());
}).collect(Collectors.toList());
return level1Menu;
}
// 递归查找所有菜单的子菜单
private List<CategoryEntity> getChildrens(CategoryEntity root,List<CategoryEntity> all){
List<CategoryEntity> children = all.stream().filter(categoryEntity -> {
return categoryEntity.getParentCid() == root.getCatId();
}).map(categoryEntity -> {
// 1.找到子菜单
categoryEntity.setChildren(getChildrens(categoryEntity, all));
return categoryEntity;
}).sorted((menu1, menu2) -> {
// 2.菜单的排序
return (menu1.getSort() == null ? 0 : menu1.getSort()) - (menu2.getSort() == null ? 0 : menu2.getSort());
}).collect(Collectors.toList());
return children;
}
}
category.vue
<template>
<el-tree :data="data" :props="defaultProps" @node-click="handleNodeClick"></el-tree>
</template>
<script>
// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
// 例如:import 《组件名称》 from '《组件路径》';
export default {
// import引入的组件需要注入到对象中才能使用
components: {},
data() {
return {
data: [],
defaultProps: {
children: 'children',
label: 'label'
}
};
},
methods: {
handleNodeClick(data) {
console.log(data);
},
getMenus() {
this.dataListLoading = true
this.$http({
url: this.$http.adornUrl('/product/category/list/tree'),
method: 'get'
}).then(data=>{
console.log("成功获取到菜单数据...",data)
})
}
},
// 监听属性 类似于data概念
computed: {},
// 监控data中的数据变化
watch: {},
// 生命周期 - 创建完成(可以访问当前this实例)
created() {
this.getMenus()
},
// 生命周期 - 挂载完成(可以访问DOM元素)
mounted() {
},
beforeCreate() { }, // 生命周期 - 创建之前
beforeMount() { }, // 生命周期 - 挂载之前
beforeUpdate() { }, // 生命周期 - 更新之前
updated() { }, // 生命周期 - 更新之后
beforeDestroy() { }, // 生命周期 - 销毁之前
destroyed() { }, // 生命周期 - 销毁完成
activated() { } // 如果页面有keep-alive缓存功能,这个函数会触发
}
</script>
<style scoped></style>
修改index.js 修改为网关地址,现在前端访问后端renrenfast会报错
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>io.renren</groupId>
<artifactId>renren-fast</artifactId>
<version>3.0.0</version>
<packaging>jar</packaging>
<description>renren-fast</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<!-- <parent>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-parent</artifactId>-->
<!-- <version>2.6.6</version>-->
<!-- </parent>-->
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR9</spring-cloud.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<mybatisplus.version>3.3.1</mybatisplus.version>
<mysql.version>8.0.28</mysql.version>
<mssql.version>4.0</mssql.version>
<oracle.version>11.2.0.3</oracle.version>
<druid.version>1.1.13</druid.version>
<quartz.version>2.3.0</quartz.version>
<commons.lang.version>2.6</commons.lang.version>
<commons.fileupload.version>1.2.2</commons.fileupload.version>
<commons.io.version>2.5</commons.io.version>
<commons.codec.version>1.10</commons.codec.version>
<commons.configuration.version>1.10</commons.configuration.version>
<shiro.version>1.9.0</shiro.version>
<jwt.version>0.7.0</jwt.version>
<kaptcha.version>0.0.9</kaptcha.version>
<qiniu.version>7.2.23</qiniu.version>
<aliyun.oss.version>2.8.3</aliyun.oss.version>
<qcloud.cos.version>4.4</qcloud.cos.version>
<swagger.version>2.7.0</swagger.version>
<joda.time.version>2.9.9</joda.time.version>
<gson.version>2.8.5</gson.version>
<fastjson.version>1.2.79</fastjson.version>
<hutool.version>4.1.1</hutool.version>
<lombok.version>1.18.4</lombok.version>
<!--wagon plugin 配置-->
<service-path>/work/renren</service-path>
<pack-name>${project.artifactId}-${project.version}.jar</pack-name>
<remote-addr>192.168.1.10:22</remote-addr>
<remote-username>root</remote-username>
<remote-passwd>123456</remote-passwd>
</properties>
<dependencies>
<dependency>
<groupId>com.hejiawang.gulimall</groupId>
<artifactId>gulimall-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!--<dependency>-->
<!--<groupId>org.springframework.boot</groupId>-->
<!--<artifactId>spring-boot-devtools</artifactId>-->
<!--<optional>true</optional>-->
<!--</dependency>-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatisplus.version}</version>
<exclusions>
<exclusion>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!--oracle驱动-->
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>${oracle.version}</version>
</dependency>
<!--mssql驱动-->
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>sqljdbc4</artifactId>
<version>${mssql.version}</version>
</dependency>
<!--postgresql驱动-->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.version}</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>${quartz.version}</version>
<exclusions>
<exclusion>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>${commons.lang.version}</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>${commons.fileupload.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons.io.version}</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${commons.codec.version}</version>
</dependency>
<dependency>
<groupId>commons-configuration</groupId>
<artifactId>commons-configuration</artifactId>
<version>${commons.configuration.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jwt.version}</version>
</dependency>
<dependency>
<groupId>com.github.axet</groupId>
<artifactId>kaptcha</artifactId>
<version>${kaptcha.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
<version>${qiniu.version}</version>
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>${aliyun.oss.version}</version>
</dependency>
<dependency>
<groupId>com.qcloud</groupId>
<artifactId>cos_api</artifactId>
<version>${qcloud.cos.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>${joda.time.version}</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<extensions>
<extension>
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-ssh</artifactId>
<version>2.8</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
</configuration>
</plugin>
<!-- 跳过单元测试 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>wagon-maven-plugin</artifactId>
<version>1.0</version>
<configuration>
<fromFile>target/${pack-name}</fromFile>
<url><![CDATA[scp://${remote-username}:${remote-passwd}@${remote-addr}${service-path}]]></url>
<commands>
<!-- Kill Old Process -->
<command>kill -9 `ps -ef |grep ${project.artifactId}.jar|grep -v "grep" |awk '{print $2}'`</command>
<!-- Restart jar package,write result into renren.log -->
<command><![CDATA[nohup java -jar ${service-path}/${pack-name} --spring.profiles.active=test > ${service-path}/renren.log 2>&1 & ]]></command>
<command><![CDATA[netstat -nptl]]></command>
<command><![CDATA[ps -ef | grep java | grep -v grep]]></command>
</commands>
<!-- 运行命令 mvn clean package wagon:upload-single wagon:sshexec-->
<displayCommandOutputs>true</displayCommandOutputs>
</configuration>
</plugin>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.4.14</version>
<!--<executions>-->
<!--<execution>-->
<!--<phase>package</phase>-->
<!--<goals>-->
<!--<goal>build</goal>-->
<!--</goals>-->
<!--</execution>-->
<!--</executions>-->
<configuration>
<imageName>renren/fast</imageName>
<dockerDirectory>${project.basedir}</dockerDirectory>
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
<!-- 运行命令 mvn clean package docker:build 打包并生成docker镜像 -->
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>public</id>
<name>aliyun nexus</name>
<url>https://maven.aliyun.com/repository/public/</url>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>public</id>
<name>aliyun nexus</name>
<url>https://maven.aliyun.com/repository/public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>
修改网关配置加上/api即可路由到
spring:
# datasource:
# username: root
# password: 1q1w1e1r
# url: jdbc:mysql://127.0.0.1:3306/gulimall_sms
# driver-class-name: com.mysql.cj.jdbc.Driver
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
gateway:
routes:
- id: test_route
uri: https://www.baidu.com
predicates:
- Query=url,baidu
- id: qq_route
uri: https://www.qq.com
predicates:
- Query=url,qq
# 前端项目,/api
- id: admin_route
uri: lb://renren-fast
predicates:
- Path=/api/**
server:
port: 88
访问主页有报错
因为网关转发的时候,未带工程前缀
http://localhost:88/api/captcha.jpg ====> http://renren-fast:8080/api/captcha.jpg
修改gateway工程加上重写的工程路径
# 前端项目,/api
# http://localhost:88/api/captcha.jpg http://renren-fast:8080/api/captcha.jpg
- id: admin_route
uri: lb://renren-fast
predicates:
- Path=/api/**
filters:
- RewritePath=/api/?(?.*), /renren-fast/$\{segment}
由于浏览器为http://localhost:8001/#/login,前端中的js访问资源协议域名端口不一样即会有跨域问题
登录方法为OPTIONS
跨域解释
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS
本机调试采取方法二
在网关工程中添加配置类允许跨域
package com.hejiawang.gulimall.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsConfigurationSource;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import org.springframework.web.server.ServerWebExchange;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@Configuration
public class GulimallCorsConfiguration {
@Bean
public CorsWebFilter corsWebFilter(){
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration();
// 1.配置跨域
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
corsConfiguration.setAllowedOrigins(Collections.singletonList("*"));
corsConfiguration.setAllowCredentials(true);
source.registerCorsConfiguration("/**",corsConfiguration);
return new CorsWebFilter(source);
}
}
将renren-fast后端跨域内容注释掉,使用我们自己配的
重启服务即可成功登录
- id: product_route
uri: lb://gulimall-product
predicates:
- Path=/api/product/**
filters:
- RewritePath=/api/?(?.*), /$\{segment}
添加bootstrap文件及配置中心地址
spring.application.name=gulimall-product
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.namespace=a7d07264-e472-4466-9b28-e14caee4e0d7
添加注册发现注解
添加注册中心地址
启动服务看到product注册上来了
直接访问product可以返回数据
通过网关访问报错 http://localhost:88/api/product/category/list/tree
因为网关被拦截,优先顺序,将最模糊的路由放在最后重启
再次访问网关http://localhost:88/api/product/category/list/tree
访问成功
<template>
<el-tree :data="data" :props="defaultProps" @node-click="handleNodeClick"></el-tree>
</template>
<script>
// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
// 例如:import 《组件名称》 from '《组件路径》';
export default {
// import引入的组件需要注入到对象中才能使用
components: {},
data() {
return {
data: [],
defaultProps: {
children: 'children',
label: 'label'
}
};
},
methods: {
handleNodeClick(data) {
console.log(data);
},
getMenus() {
this.dataListLoading = true
this.$http({
url: this.$http.adornUrl('/product/category/list/tree'),
method: 'get'
}).then(data=>{
console.log("成功获取到菜单数据...",data)
})
}
},
// 监听属性 类似于data概念
computed: {},
// 监控data中的数据变化
watch: {},
// 生命周期 - 创建完成(可以访问当前this实例)
created() {
this.getMenus()
},
// 生命周期 - 挂载完成(可以访问DOM元素)
mounted() {
},
beforeCreate() { }, // 生命周期 - 创建之前
beforeMount() { }, // 生命周期 - 挂载之前
beforeUpdate() { }, // 生命周期 - 更新之前
updated() { }, // 生命周期 - 更新之后
beforeDestroy() { }, // 生命周期 - 销毁之前
destroyed() { }, // 生命周期 - 销毁完成
activated() { } // 如果页面有keep-alive缓存功能,这个函数会触发
}
</script>
<style scoped></style>
<template>
<el-tree :data="menus" :props="defaultProps" @node-click="handleNodeClick"></el-tree>
</template>
<script>
// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
// 例如:import 《组件名称》 from '《组件路径》';
export default {
// import引入的组件需要注入到对象中才能使用
components: {},
data() {
return {
menus: [],
defaultProps: {
children: 'children',
label: 'name'
}
};
},
methods: {
handleNodeClick(data) {
console.log(data);
},
getMenus() {
this.dataListLoading = true
this.$http({
url: this.$http.adornUrl('/product/category/list/tree'),
method: 'get'
}).then(({data})=>{
console.log("成功获取到菜单数据...",data.data)
this.menus = data.data
})
}
},
// 监听属性 类似于data概念
computed: {},
// 监控data中的数据变化
watch: {},
// 生命周期 - 创建完成(可以访问当前this实例)
created() {
this.getMenus()
},
// 生命周期 - 挂载完成(可以访问DOM元素)
mounted() {
},
beforeCreate() { }, // 生命周期 - 创建之前
beforeMount() { }, // 生命周期 - 挂载之前
beforeUpdate() { }, // 生命周期 - 更新之前
updated() { }, // 生命周期 - 更新之后
beforeDestroy() { }, // 生命周期 - 销毁之前
destroyed() { }, // 生命周期 - 销毁完成
activated() { } // 如果页面有keep-alive缓存功能,这个函数会触发
}
</script>
<style scoped></style>
/**
* 删除
*/
@RequestMapping("/delete")
public R delete(@RequestBody Long[] catIds){
// 原始方法先注释
// categoryService.removeByIds(Arrays.asList(catIds));
// 1、检查当前删除的菜单,是否被其他地方引用到
categoryService.removeMenuByIds(Arrays.asList(catIds));
return R.ok();
}
@Override
public void removeMenuByIds(List<Long> asList) {
// TODO: 检查当前删除的菜单是否被引用,
baseMapper.deleteBatchIds(asList);
}
package com.hejiawang.gulimall.product.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import lombok.Data;
/**
* 商品三级分类
*
* @author hejiawang
* @email [email protected]
* @date 2023-06-13 14:42:51
*/
@Data
@TableName("pms_category")
public class CategoryEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 分类id
*/
@TableId
private Long catId;
/**
* 分类名称
*/
private String name;
/**
* 父分类id
*/
private Long parentCid;
/**
* 层级
*/
private Integer catLevel;
/**
* 是否显示[0-不显示,1显示]
*/
@TableLogic(value = "1",delval = "0")
private Integer showStatus;
/**
* 排序
*/
private Integer sort;
/**
* 图标地址
*/
private String icon;
/**
* 计量单位
*/
private String productUnit;
/**
* 商品数量
*/
private Integer productCount;
@TableField(exist = false)
private List<CategoryEntity> children;
}
# MapperScan
# sql映射文件位置
mybatis-plus:
mapper-locations: classpath*:/mapper/**/*.xml
global-config:
db-config:
id-type: auto
#使用的地方相反可使用@TableLogic,全局默认配置
logic-delete-value: 1
logic-not-delete-value: 0
logging:
level:
com.hejiawang.gulimall: debug
查询初始化数据
调用接口
结果
打印sql过程为update
{
"Print to console": {
"prefix": "vue",
"body": [
"",
"$5",
"",
"",
"",
""
],
"description": "生成vue模板"
},
"http-get请求": {
"prefix": "httpget",
"body": [
"this.\\$http({",
"url: this.\\$http.adornUrl(''),",
"method: 'get',",
"params: this.\\$http.adornParams({})",
"}).then(({ data }) => {",
"})"
],
"description": "httpGET请求"
},
"http-post请求": {
"prefix": "httppost",
"body": [
"this.\\$http({",
"url: this.\\$http.adornUrl(''),",
"method: 'post',",
"data: this.\\$http.adornData(data, false)",
"}).then(({ data }) => { });"
],
"description": "httpPOST请求"
}
}
<template>
<el-tree :data="menus" :props="defaultProps" :default-expanded-keys="expandedKey" node-key="catId" show-checkbox :expand-on-click-node="false">
<span class="custom-tree-node" slot-scope="{ node, data }">
<span>{{ node.label }}</span>
<span>
<el-button v-if="node.level <= 2" type="text" size="mini" @click="() => append(data)">
Append
</el-button>
<el-button v-if="node.childNodes.length == 0" type="text" size="mini" @click="() => remove(node, data)">
Delete
</el-button>
</span>
</span>
</el-tree>
</template>
<script>
// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
// 例如:import 《组件名称》 from '《组件路径》';
export default {
// import引入的组件需要注入到对象中才能使用
components: {},
data() {
return {
expandedKey: [],
menus: [],
defaultProps: {
children: 'children',
label: 'name'
}
};
},
methods: {
append(data) {
console.log("append", data);
},
remove(node, data) {
var ids = [data.catId]
this.$confirm(`是否删除【${data.name}】菜单?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$http({
url: this.$http.adornUrl('/product/category/delete'),
method: 'post',
data: this.$http.adornData(ids, false)
}).then(({ data }) => {
console.log("删除成功");
this.$message({
message: '菜单删除成功',
type: 'success'
});
// 刷新出新的菜单
this.getMenus()
// 设置删除后默认要展示的父菜单
this.expandedKey= [node.parent.data.catId]
// if (data && data.code === 0) {
// this.$message({
// message: '操作成功',
// type: 'success',
// duration: 1500,
// onClose: () => {
// this.getDataList()
// }
// })
// } else {
// this.$message.error(data.msg)
// }
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
console.log("remove", node, data);
},
getMenus() {
this.dataListLoading = true
this.$http({
url: this.$http.adornUrl('/product/category/list/tree'),
method: 'get'
}).then(({ data }) => {
console.log("成功获取到菜单数据...", data.data)
this.menus = data.data
})
}
},
// 监听属性 类似于data概念
computed: {},
// 监控data中的数据变化
watch: {},
// 生命周期 - 创建完成(可以访问当前this实例)
created() {
this.getMenus()
},
// 生命周期 - 挂载完成(可以访问DOM元素)
mounted() {
},
beforeCreate() { }, // 生命周期 - 创建之前
beforeMount() { }, // 生命周期 - 挂载之前
beforeUpdate() { }, // 生命周期 - 更新之前
updated() { }, // 生命周期 - 更新之后
beforeDestroy() { }, // 生命周期 - 销毁之前
destroyed() { }, // 生命周期 - 销毁完成
activated() { } // 如果页面有keep-alive缓存功能,这个函数会触发
}
</script>
<style scoped></style>
前端修改
<template>
<div>
<el-tree :data="menus" :props="defaultProps" :default-expanded-keys="expandedKey" node-key="catId" show-checkbox
:expand-on-click-node="false">
<span class="custom-tree-node" slot-scope="{ node, data }">
<span>{{ node.label }}</span>
<span>
<el-button v-if="node.level <= 2" type="text" size="mini" @click="() => append(data)">
Append
</el-button>
<el-button v-if="node.childNodes.length == 0" type="text" size="mini" @click="() => remove(node, data)">
Delete
</el-button>
</span>
</span>
</el-tree>
<el-dialog title="提示" :visible.sync="dialogVisible" width="30%">
<el-form :model="category">
<el-form-item label="分类名称">
<el-input v-model="category.name" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="addCategory">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
// 例如:import 《组件名称》 from '《组件路径》';
export default {
// import引入的组件需要注入到对象中才能使用
components: {},
data() {
return {
category: { name: "", parentCid: 0, catLevel: 0, showStatus: 1, sort: 0 },
dialogVisible: false,
expandedKey: [],
menus: [],
defaultProps: {
children: 'children',
label: 'name'
}
};
},
methods: {
// 添加三级分类的方法
addCategory() {
console.log("三级分类的对象", this.category);
this.$http({
url: this.$http.adornUrl('/product/category/save'),
method: 'post',
data: this.$http.adornData(this.category, false)
}).then(({ data }) => {
console.log("菜单保存成功");
this.$message({
message: '菜单保存成功',
type: 'success'
});
// 关闭对话框
this.dialogVisible=false;
// 刷新出新的菜单
this.getMenus()
// 设置删除后默认要展示的父菜单
this.expandedKey = [this.category.parentCid];
});
},
append(data) {
console.log("append", data);
this.dialogVisible = true;
this.category.parentCid = data.catId;
this.category.catLevel = data.catLevel * 1 + 1;
this.category.showStatus = 1;
this.category.sort = 0;
},
remove(node, data) {
var ids = [data.catId]
this.$confirm(`是否删除【${data.name}】菜单?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$http({
url: this.$http.adornUrl('/product/category/delete'),
method: 'post',
data: this.$http.adornData(ids, false)
}).then(({ data }) => {
console.log("删除成功");
this.$message({
message: '菜单删除成功',
type: 'success'
});
// 刷新出新的菜单
this.getMenus()
// 设置删除后默认要展示的父菜单
this.expandedKey = [node.parent.data.catId]
// if (data && data.code === 0) {
// this.$message({
// message: '操作成功',
// type: 'success',
// duration: 1500,
// onClose: () => {
// this.getDataList()
// }
// })
// } else {
// this.$message.error(data.msg)
// }
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
console.log("remove", node, data);
},
getMenus() {
this.dataListLoading = true
this.$http({
url: this.$http.adornUrl('/product/category/list/tree'),
method: 'get'
}).then(({ data }) => {
console.log("成功获取到菜单数据...", data.data)
this.menus = data.data
})
}
},
// 监听属性 类似于data概念
computed: {},
// 监控data中的数据变化
watch: {},
// 生命周期 - 创建完成(可以访问当前this实例)
created() {
this.getMenus()
},
// 生命周期 - 挂载完成(可以访问DOM元素)
mounted() {
},
beforeCreate() { }, // 生命周期 - 创建之前
beforeMount() { }, // 生命周期 - 挂载之前
beforeUpdate() { }, // 生命周期 - 更新之前
updated() { }, // 生命周期 - 更新之后
beforeDestroy() { }, // 生命周期 - 销毁之前
destroyed() { }, // 生命周期 - 销毁完成
activated() { } // 如果页面有keep-alive缓存功能,这个函数会触发
}
</script>
<style scoped></style>
前端
<template>
<div>
<el-tree :data="menus" :props="defaultProps" :default-expanded-keys="expandedKey" node-key="catId" show-checkbox
:expand-on-click-node="false">
<span class="custom-tree-node" slot-scope="{ node, data }">
<span>{{ node.label }}</span>
<span>
<el-button v-if="node.level <= 2" type="text" size="mini" @click="() => append(data)">
Append
</el-button>
<el-button type="text" size="mini" @click="() => edit(data)">
edit
</el-button>
<el-button v-if="node.childNodes.length == 0" type="text" size="mini" @click="() => remove(node, data)">
Delete
</el-button>
</span>
</span>
</el-tree>
<el-dialog :title="title" :visible.sync="dialogVisible" width="30%" :close-on-click-modal="false">
<el-form :model="category">
<el-form-item label="分类名称">
<el-input v-model="category.name" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="图标">
<el-input v-model="category.icon" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="计量单位">
<el-input v-model="category.productUnit" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="submitData()">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
// 例如:import 《组件名称》 from '《组件路径》';
export default {
// import引入的组件需要注入到对象中才能使用
components: {},
data() {
return {
title: "",
dialogType: "", //edit,add
category: { name: "", parentCid: 0, catLevel: 0, showStatus: 1, sort: 0, catId: null, icon: "", productUnit: "" },
dialogVisible: false,
expandedKey: [],
menus: [],
defaultProps: {
children: 'children',
label: 'name'
}
};
},
methods: {
// 添加三级分类的方法
addCategory() {
console.log("三级分类的对象", this.category);
this.$http({
url: this.$http.adornUrl('/product/category/save'),
method: 'post',
data: this.$http.adornData(this.category, false)
}).then(({ data }) => {
console.log("菜单保存成功");
this.$message({
message: '菜单保存成功',
type: 'success'
});
// 关闭对话框
this.dialogVisible = false;
// 刷新出新的菜单
this.getMenus()
// 设置删除后默认要展示的父菜单
this.expandedKey = [this.category.parentCid];
});
},
// 修改三级分类的方法
editCategory() {
var {catId,name,icon,productUnit} = this.category;
var data = {catId,name,icon,productUnit}
console.log("三级分类的对象", this.category);
this.$http({
url: this.$http.adornUrl('/product/category/update'),
method: 'post',
data: this.$http.adornData(data, false)
}).then(({ data }) => {
console.log("菜单修改成功");
this.$message({
message: '菜单修改成功',
type: 'success'
});
// 关闭对话框
this.dialogVisible = false;
// 刷新出新的菜单
this.getMenus()
// 设置删除后默认要展示的父菜单
this.expandedKey = [this.category.parentCid];
});
},
submitData() {
if (this.dialogType == "add") {
this.addCategory();
}
if (this.dialogType == "edit") {
this.editCategory();
}
},
edit(data) {
console.log("要修改的数据", data);
this.title = "修改分类";
this.dialogType = "edit";
this.dialogVisible = true;
// 发送请求获取节点最新的数据
this.$http({
url: this.$http.adornUrl(`/product/category/info/${data.catId}`),
method: 'get',
}).then(({ data }) => {
console.log("要回显的数据", data);
this.category.name = data.data.name;
this.category.catId = data.data.catId;
this.category.icon = data.data.icon;
this.category.productUnit = data.data.productUnit;
this.category.parentCid = data.data.parentCid;
this.category.catLevel = data.data.catLevel;
this.category.sort = data.data.sort;
this.category.showStatus = data.data.showStatus;
})
},
append(data) {
console.log("append", data);
this.title = "添加分类";
this.dialogType = "add";
this.dialogVisible = true;
this.category.parentCid = data.catId;
this.category.catLevel = data.catLevel * 1 + 1;
this.category.showStatus = 1;
this.category.sort = 0;
this.category.name = "";
this.category.catId = null;
this.category.icon = "";
this.category.productUnit = "";
},
remove(node, data) {
var ids = [data.catId]
this.$confirm(`是否删除【${data.name}】菜单?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$http({
url: this.$http.adornUrl('/product/category/delete'),
method: 'post',
data: this.$http.adornData(ids, false)
}).then(({ data }) => {
console.log("删除成功");
this.$message({
message: '菜单删除成功',
type: 'success'
});
// 刷新出新的菜单
this.getMenus()
// 设置删除后默认要展示的父菜单
this.expandedKey = [node.parent.data.catId]
// if (data && data.code === 0) {
// this.$message({
// message: '操作成功',
// type: 'success',
// duration: 1500,
// onClose: () => {
// this.getDataList()
// }
// })
// } else {
// this.$message.error(data.msg)
// }
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
console.log("remove", node, data);
},
getMenus() {
this.dataListLoading = true
this.$http({
url: this.$http.adornUrl('/product/category/list/tree'),
method: 'get'
}).then(({ data }) => {
console.log("成功获取到菜单数据...", data.data)
this.menus = data.data
})
}
},
// 监听属性 类似于data概念
computed: {},
// 监控data中的数据变化
watch: {},
// 生命周期 - 创建完成(可以访问当前this实例)
created() {
this.getMenus()
},
// 生命周期 - 挂载完成(可以访问DOM元素)
mounted() {
},
beforeCreate() { }, // 生命周期 - 创建之前
beforeMount() { }, // 生命周期 - 挂载之前
beforeUpdate() { }, // 生命周期 - 更新之前
updated() { }, // 生命周期 - 更新之后
beforeDestroy() { }, // 生命周期 - 销毁之前
destroyed() { }, // 生命周期 - 销毁完成
activated() { } // 如果页面有keep-alive缓存功能,这个函数会触发
}
</script>
<style scoped></style>
<template>
<div>
<el-tree :data="menus" :props="defaultProps" :default-expanded-keys="expandedKey" node-key="catId" show-checkbox
draggable :allow-drop="allowDrop" :expand-on-click-node="false">
<span class="custom-tree-node" slot-scope="{ node, data }">
<span>{{ node.label }}</span>
<span>
<el-button v-if="node.level <= 2" type="text" size="mini" @click="() => append(data)">
Append
</el-button>
<el-button type="text" size="mini" @click="() => edit(data)">
edit
</el-button>
<el-button v-if="node.childNodes.length == 0" type="text" size="mini" @click="() => remove(node, data)">
Delete
</el-button>
</span>
</span>
</el-tree>
<el-dialog :title="title" :visible.sync="dialogVisible" width="30%" :close-on-click-modal="false">
<el-form :model="category">
<el-form-item label="分类名称">
<el-input v-model="category.name" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="图标">
<el-input v-model="category.icon" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="计量单位">
<el-input v-model="category.productUnit" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="submitData()">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
// 例如:import 《组件名称》 from '《组件路径》';
export default {
// import引入的组件需要注入到对象中才能使用
components: {},
data() {
return {
maxLevel: 0,
title: "",
dialogType: "", //edit,add
category: { name: "", parentCid: 0, catLevel: 0, showStatus: 1, sort: 0, catId: null, icon: "", productUnit: "" },
dialogVisible: false,
expandedKey: [],
menus: [],
defaultProps: {
children: 'children',
label: 'name'
}
};
},
methods: {
allowDrop(draggingNode, dropNode, type) {
// 1.被拖动的当前节点以及所在的父节点总层数不能大于3
// 被拖动的当前节点的总层数
console.log("allowDrop:", draggingNode, dropNode, type)
this.countNodeLevel(draggingNode.data);
// 当前正在拖动的节点+父节点所在的深度不大于3即可
let deep = (this.maxLevel - draggingNode.parent.level);
console.log("深度:",deep);
console.log(this.maxLevel);
if(type == "inner"){
return deep + dropNode.data.catLevel <=3
}else{
// 前后
return deep + dropNode.parent.level <=3
}
// return ;
},
countNodeLevel(node){
// 找到所有子节点,求出最大深度
if(node.children != null && node.children.length >0){
// 有子节点则遍历
for(let i = 0 ;i < node.children.length;i++){
if(node.children[i].catLevel > this.maxLevel){
this.maxLevel = node.children[i].catLevel;
}
this.countNodeLevel(node.children[i]);
}
}
},
// 添加三级分类的方法
addCategory() {
console.log("三级分类的对象", this.category);
this.$http({
url: this.$http.adornUrl('/product/category/save'),
method: 'post',
data: this.$http.adornData(this.category, false)
}).then(({ data }) => {
console.log("菜单保存成功");
this.$message({
message: '菜单保存成功',
type: 'success'
});
// 关闭对话框
this.dialogVisible = false;
// 刷新出新的菜单
this.getMenus()
// 设置删除后默认要展示的父菜单
this.expandedKey = [this.category.parentCid];
});
},
// 修改三级分类的方法
editCategory() {
var { catId, name, icon, productUnit } = this.category;
var data = { catId, name, icon, productUnit }
console.log("三级分类的对象", this.category);
this.$http({
url: this.$http.adornUrl('/product/category/update'),
method: 'post',
data: this.$http.adornData(data, false)
}).then(({ data }) => {
console.log("菜单修改成功");
this.$message({
message: '菜单修改成功',
type: 'success'
});
// 关闭对话框
this.dialogVisible = false;
// 刷新出新的菜单
this.getMenus()
// 设置删除后默认要展示的父菜单
this.expandedKey = [this.category.parentCid];
});
},
submitData() {
if (this.dialogType == "add") {
this.addCategory();
}
if (this.dialogType == "edit") {
this.editCategory();
}
},
edit(data) {
console.log("要修改的数据", data);
this.title = "修改分类";
this.dialogType = "edit";
this.dialogVisible = true;
// 发送请求获取节点最新的数据
this.$http({
url: this.$http.adornUrl(`/product/category/info/${data.catId}`),
method: 'get',
}).then(({ data }) => {
console.log("要回显的数据", data);
this.category.name = data.data.name;
this.category.catId = data.data.catId;
this.category.icon = data.data.icon;
this.category.productUnit = data.data.productUnit;
this.category.parentCid = data.data.parentCid;
this.category.catLevel = data.data.catLevel;
this.category.sort = data.data.sort;
this.category.showStatus = data.data.showStatus;
})
},
append(data) {
console.log("append", data);
this.title = "添加分类";
this.dialogType = "add";
this.dialogVisible = true;
this.category.parentCid = data.catId;
this.category.catLevel = data.catLevel * 1 + 1;
this.category.showStatus = 1;
this.category.sort = 0;
this.category.name = "";
this.category.catId = null;
this.category.icon = "";
this.category.productUnit = "";
},
remove(node, data) {
var ids = [data.catId]
this.$confirm(`是否删除【${data.name}】菜单?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$http({
url: this.$http.adornUrl('/product/category/delete'),
method: 'post',
data: this.$http.adornData(ids, false)
}).then(({ data }) => {
console.log("删除成功");
this.$message({
message: '菜单删除成功',
type: 'success'
});
// 刷新出新的菜单
this.getMenus()
// 设置删除后默认要展示的父菜单
this.expandedKey = [node.parent.data.catId]
// if (data && data.code === 0) {
// this.$message({
// message: '操作成功',
// type: 'success',
// duration: 1500,
// onClose: () => {
// this.getDataList()
// }
// })
// } else {
// this.$message.error(data.msg)
// }
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
console.log("remove", node, data);
},
getMenus() {
this.dataListLoading = true
this.$http({
url: this.$http.adornUrl('/product/category/list/tree'),
method: 'get'
}).then(({ data }) => {
console.log("成功获取到菜单数据...", data.data)
this.menus = data.data
})
}
},
// 监听属性 类似于data概念
computed: {},
// 监控data中的数据变化
watch: {},
// 生命周期 - 创建完成(可以访问当前this实例)
created() {
this.getMenus()
},
// 生命周期 - 挂载完成(可以访问DOM元素)
mounted() {
},
beforeCreate() { }, // 生命周期 - 创建之前
beforeMount() { }, // 生命周期 - 挂载之前
beforeUpdate() { }, // 生命周期 - 更新之前
updated() { }, // 生命周期 - 更新之后
beforeDestroy() { }, // 生命周期 - 销毁之前
destroyed() { }, // 生命周期 - 销毁完成
activated() { } // 如果页面有keep-alive缓存功能,这个函数会触发
}
</script>
<style scoped></style>
<template>
<div>
<el-tree :data="menus" :props="defaultProps" :default-expanded-keys="expandedKey" node-key="catId" show-checkbox
@node-drop="handleDrop" draggable :allow-drop="allowDrop" :expand-on-click-node="false">
<span class="custom-tree-node" slot-scope="{ node, data }">
<span>{{ node.label }}</span>
<span>
<el-button v-if="node.level <= 2" type="text" size="mini" @click="() => append(data)">
Append
</el-button>
<el-button type="text" size="mini" @click="() => edit(data)">
edit
</el-button>
<el-button v-if="node.childNodes.length == 0" type="text" size="mini" @click="() => remove(node, data)">
Delete
</el-button>
</span>
</span>
</el-tree>
<el-dialog :title="title" :visible.sync="dialogVisible" width="30%" :close-on-click-modal="false">
<el-form :model="category">
<el-form-item label="分类名称">
<el-input v-model="category.name" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="图标">
<el-input v-model="category.icon" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="计量单位">
<el-input v-model="category.productUnit" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="submitData()">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
// 例如:import 《组件名称》 from '《组件路径》';
export default {
// import引入的组件需要注入到对象中才能使用
components: {},
data() {
return {
updateNodes: [],
maxLevel: 0,
title: "",
dialogType: "", //edit,add
category: { name: "", parentCid: 0, catLevel: 0, showStatus: 1, sort: 0, catId: null, icon: "", productUnit: "" },
dialogVisible: false,
expandedKey: [],
menus: [],
defaultProps: {
children: 'children',
label: 'name'
}
};
},
methods: {
handleDrop(draggingNode, dropNode, dropType, ev) {
console.log('handleDrop: ', draggingNode, dropNode, dropType, ev);
// 1.当前节点最新的父节点id
var pCid = 0;
let sibilings = null;
if (dropType == "before" || dropType == "after") {
pCid = dropNode.parent.data.catId == undefined ? 0 : dropNode.parent.data.catId;
sibilings = dropNode.parent.childNodes;
} else {
pCid = dropNode.data.catId;
sibilings = dropNode.childNodes;
}
// 2.当前拖拽节点的最新顺序
for (let i = 0; i < sibilings.length; i++) {
if (sibilings[i].data.catId == draggingNode.data.catId) {
// 如果遍历是当前正在拖拽的节点
let catLevel = draggingNode.level
if (sibilings[i].level == draggingNode.level) {
// 当前拖拽节点的层级有变化
catLevel = sibilings[i].level;
// 递归修改子节点的层级
this.updateChildNodeLevel(sibilings[i]);
}
this.updateNodes.push({ catId: sibilings[i].data.catId, sort: i, parentCid: pCid, catLevel: catLevel });
} else {
this.updateNodes.push({ catId: sibilings[i].data.catId, sort: i })
}
}
// 3.当前拖拽节点的最新层级级
console.log("updateNodes:", this.updateNodes);
this.$http({
url: this.$http.adornUrl('/product/category/update/sort'),
method: 'post',
data: this.$http.adornData(this.updateNodes, false)
}).then(({ data }) => {
this.$message({
message: '菜单顺序等修改成功',
type: 'success'
});
// 刷新新菜单
this.getMenus()
// 设置删除后默认要展示的父菜单
this.expandedKey = [pCid];
this.updateNodes = [];
this.maxLevel = 0;
});
},
updateChildNodeLevel(node) {
if (node.childNodes.length > 0) {
for (let i = 0; i < node.childNodes.length; i++) {
var cNode = node.childNodes[i].data;
this.updateNodes.push({ catId: cNode.catId, catLevel: node.childNodes[i].level });
this.updateChildNodeLevel(node.childNodes[i]);
}
}
},
allowDrop(draggingNode, dropNode, type) {
// 1.被拖动的当前节点以及所在的父节点总层数不能大于3
// 被拖动的当前节点的总层数
console.log("allowDrop:", draggingNode, dropNode, type)
this.countNodeLevel(draggingNode.data);
// 当前正在拖动的节点+父节点所在的深度不大于3即可
let deep = (this.maxLevel - draggingNode.parent.level);
console.log("深度:", deep);
console.log(this.maxLevel);
if (type == "inner") {
return deep + dropNode.data.catLevel <= 3
} else {
// 前后
return deep + dropNode.parent.level <= 3
}
// return ;
},
countNodeLevel(node) {
// 找到所有子节点,求出最大深度
if (node.children != null && node.children.length > 0) {
// 有子节点则遍历
for (let i = 0; i < node.children.length; i++) {
if (node.children[i].catLevel > this.maxLevel) {
this.maxLevel = node.children[i].catLevel;
}
this.countNodeLevel(node.children[i]);
}
}
},
// 添加三级分类的方法
addCategory() {
console.log("三级分类的对象", this.category);
this.$http({
url: this.$http.adornUrl('/product/category/save'),
method: 'post',
data: this.$http.adornData(this.category, false)
}).then(({ data }) => {
console.log("菜单保存成功");
this.$message({
message: '菜单保存成功',
type: 'success'
});
// 关闭对话框
this.dialogVisible = false;
// 刷新出新的菜单
this.getMenus()
// 设置删除后默认要展示的父菜单
this.expandedKey = [this.category.parentCid];
});
},
// 修改三级分类的方法
editCategory() {
var { catId, name, icon, productUnit } = this.category;
var data = { catId, name, icon, productUnit }
console.log("三级分类的对象", this.category);
this.$http({
url: this.$http.adornUrl('/product/category/update'),
method: 'post',
data: this.$http.adornData(data, false)
}).then(({ data }) => {
console.log("菜单修改成功");
this.$message({
message: '菜单修改成功',
type: 'success'
});
// 关闭对话框
this.dialogVisible = false;
// 刷新出新的菜单
this.getMenus()
// 设置删除后默认要展示的父菜单
this.expandedKey = [this.category.parentCid];
});
},
submitData() {
if (this.dialogType == "add") {
this.addCategory();
}
if (this.dialogType == "edit") {
this.editCategory();
}
},
edit(data) {
console.log("要修改的数据", data);
this.title = "修改分类";
this.dialogType = "edit";
this.dialogVisible = true;
// 发送请求获取节点最新的数据
this.$http({
url: this.$http.adornUrl(`/product/category/info/${data.catId}`),
method: 'get',
}).then(({ data }) => {
console.log("要回显的数据", data);
this.category.name = data.data.name;
this.category.catId = data.data.catId;
this.category.icon = data.data.icon;
this.category.productUnit = data.data.productUnit;
this.category.parentCid = data.data.parentCid;
this.category.catLevel = data.data.catLevel;
this.category.sort = data.data.sort;
this.category.showStatus = data.data.showStatus;
})
},
append(data) {
console.log("append", data);
this.title = "添加分类";
this.dialogType = "add";
this.dialogVisible = true;
this.category.parentCid = data.catId;
this.category.catLevel = data.catLevel * 1 + 1;
this.category.showStatus = 1;
this.category.sort = 0;
this.category.name = "";
this.category.catId = null;
this.category.icon = "";
this.category.productUnit = "";
},
remove(node, data) {
var ids = [data.catId]
this.$confirm(`是否删除【${data.name}】菜单?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$http({
url: this.$http.adornUrl('/product/category/delete'),
method: 'post',
data: this.$http.adornData(ids, false)
}).then(({ data }) => {
console.log("删除成功");
this.$message({
message: '菜单删除成功',
type: 'success'
});
// 刷新出新的菜单
this.getMenus()
// 设置删除后默认要展示的父菜单
this.expandedKey = [node.parent.data.catId]
// if (data && data.code === 0) {
// this.$message({
// message: '操作成功',
// type: 'success',
// duration: 1500,
// onClose: () => {
// this.getDataList()
// }
// })
// } else {
// this.$message.error(data.msg)
// }
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
console.log("remove", node, data);
},
getMenus() {
this.dataListLoading = true
this.$http({
url: this.$http.adornUrl('/product/category/list/tree'),
method: 'get'
}).then(({ data }) => {
console.log("成功获取到菜单数据...", data.data)
this.menus = data.data
})
}
},
// 监听属性 类似于data概念
computed: {},
// 监控data中的数据变化
watch: {},
// 生命周期 - 创建完成(可以访问当前this实例)
created() {
this.getMenus()
},
// 生命周期 - 挂载完成(可以访问DOM元素)
mounted() {
},
beforeCreate() { }, // 生命周期 - 创建之前
beforeMount() { }, // 生命周期 - 挂载之前
beforeUpdate() { }, // 生命周期 - 更新之前
updated() { }, // 生命周期 - 更新之后
beforeDestroy() { }, // 生命周期 - 销毁之前
destroyed() { }, // 生命周期 - 销毁完成
activated() { } // 如果页面有keep-alive缓存功能,这个函数会触发
}
</script>
<style scoped></style>
/**
* 修改
*/
@RequestMapping("/update/sort")
public R update(@RequestBody CategoryEntity[] category){
categoryService.updateBatchById(Arrays.asList(category));
return R.ok();
}
<template>
<div>
<el-switch v-model="draggable" active-text="开启拖拽" inactive-text="关闭拖拽">
</el-switch>
<el-button v-if="draggable" @click="batchSave">批量保存</el-button>
<el-tree :data="menus" :props="defaultProps" :default-expanded-keys="expandedKey" node-key="catId" show-checkbox
@node-drop="handleDrop" :draggable="draggable" :allow-drop="allowDrop" :expand-on-click-node="false">
<span class="custom-tree-node" slot-scope="{ node, data }">
<span>{{ node.label }}</span>
<span>
<el-button v-if="node.level <= 2" type="text" size="mini" @click="() => append(data)">
Append
</el-button>
<el-button type="text" size="mini" @click="() => edit(data)">
edit
</el-button>
<el-button v-if="node.childNodes.length == 0" type="text" size="mini" @click="() => remove(node, data)">
Delete
</el-button>
</span>
</span>
</el-tree>
<el-dialog :title="title" :visible.sync="dialogVisible" width="30%" :close-on-click-modal="false">
<el-form :model="category">
<el-form-item label="分类名称">
<el-input v-model="category.name" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="图标">
<el-input v-model="category.icon" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="计量单位">
<el-input v-model="category.productUnit" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="submitData()">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
// 例如:import 《组件名称》 from '《组件路径》';
export default {
// import引入的组件需要注入到对象中才能使用
components: {},
data() {
return {
pCid: [],
draggable: false,
updateNodes: [],
maxLevel: 0,
title: "",
dialogType: "", //edit,add
category: { name: "", parentCid: 0, catLevel: 0, showStatus: 1, sort: 0, catId: null, icon: "", productUnit: "" },
dialogVisible: false,
expandedKey: [],
menus: [],
defaultProps: {
children: 'children',
label: 'name'
}
};
},
methods: {
batchSave() {
this.$http({
url: this.$http.adornUrl('/product/category/update/sort'),
method: 'post',
data: this.$http.adornData(this.updateNodes, false)
}).then(({ data }) => {
this.$message({
message: '菜单顺序等修改成功',
type: 'success'
});
// 刷新新菜单
this.getMenus()
// 设置删除后默认要展示的父菜单
this.expandedKey = this.pCid;
this.updateNodes = [];
this.maxLevel = 0;
this.pCid = [];
});
},
handleDrop(draggingNode, dropNode, dropType, ev) {
console.log('handleDrop: ', draggingNode, dropNode, dropType, ev);
// 1.当前节点最新的父节点id
var pCid = 0;
let sibilings = null;
if (dropType == "before" || dropType == "after") {
pCid = dropNode.parent.data.catId == undefined ? 0 : dropNode.parent.data.catId;
sibilings = dropNode.parent.childNodes;
} else {
pCid = dropNode.data.catId;
sibilings = dropNode.childNodes;
}
// 2.当前拖拽节点的最新顺序
for (let i = 0; i < sibilings.length; i++) {
if (sibilings[i].data.catId == draggingNode.data.catId) {
// 如果遍历是当前正在拖拽的节点
let catLevel = draggingNode.level
if (sibilings[i].level == draggingNode.level) {
// 当前拖拽节点的层级有变化
catLevel = sibilings[i].level;
// 递归修改子节点的层级
this.updateChildNodeLevel(sibilings[i]);
}
this.updateNodes.push({ catId: sibilings[i].data.catId, sort: i, parentCid: pCid, catLevel: catLevel });
} else {
this.updateNodes.push({ catId: sibilings[i].data.catId, sort: i })
}
}
// 3.当前拖拽节点的最新层级级
console.log("updateNodes:", this.updateNodes);
this.pCid.push(pCid);
},
updateChildNodeLevel(node) {
if (node.childNodes.length > 0) {
for (let i = 0; i < node.childNodes.length; i++) {
var cNode = node.childNodes[i].data;
this.updateNodes.push({ catId: cNode.catId, catLevel: node.childNodes[i].level });
this.updateChildNodeLevel(node.childNodes[i]);
}
}
},
allowDrop(draggingNode, dropNode, type) {
// 1.被拖动的当前节点以及所在的父节点总层数不能大于3
// 被拖动的当前节点的总层数
console.log("allowDrop:", draggingNode, dropNode, type)
this.countNodeLevel(draggingNode.data);
// 当前正在拖动的节点+父节点所在的深度不大于3即可
let deep = (this.maxLevel - draggingNode.parent.level);
console.log("深度:", deep);
console.log(this.maxLevel);
if (type == "inner") {
return deep + dropNode.data.catLevel <= 3
} else {
// 前后
return deep + dropNode.parent.level <= 3
}
// return ;
},
countNodeLevel(node) {
// 找到所有子节点,求出最大深度
if (node.childNodes != null && node.childNodes.length > 0) {
// 有子节点则遍历
for (let i = 0; i < node.childNodes.length; i++) {
if (node.childNodes[i].level > this.maxLevel) {
this.maxLevel = node.childNodes[i].level;
}
this.countNodeLevel(node.childNodes[i]);
}
}
},
// 添加三级分类的方法
addCategory() {
console.log("三级分类的对象", this.category);
this.$http({
url: this.$http.adornUrl('/product/category/save'),
method: 'post',
data: this.$http.adornData(this.category, false)
}).then(({ data }) => {
console.log("菜单保存成功");
this.$message({
message: '菜单保存成功',
type: 'success'
});
// 关闭对话框
this.dialogVisible = false;
// 刷新出新的菜单
this.getMenus()
// 设置删除后默认要展示的父菜单
this.expandedKey = [this.category.parentCid];
});
},
// 修改三级分类的方法
editCategory() {
var { catId, name, icon, productUnit } = this.category;
var data = { catId, name, icon, productUnit }
console.log("三级分类的对象", this.category);
this.$http({
url: this.$http.adornUrl('/product/category/update'),
method: 'post',
data: this.$http.adornData(data, false)
}).then(({ data }) => {
console.log("菜单修改成功");
this.$message({
message: '菜单修改成功',
type: 'success'
});
// 关闭对话框
this.dialogVisible = false;
// 刷新出新的菜单
this.getMenus()
// 设置删除后默认要展示的父菜单
this.expandedKey = [this.category.parentCid];
});
},
submitData() {
if (this.dialogType == "add") {
this.addCategory();
}
if (this.dialogType == "edit") {
this.editCategory();
}
},
edit(data) {
console.log("要修改的数据", data);
this.title = "修改分类";
this.dialogType = "edit";
this.dialogVisible = true;
// 发送请求获取节点最新的数据
this.$http({
url: this.$http.adornUrl(`/product/category/info/${data.catId}`),
method: 'get',
}).then(({ data }) => {
console.log("要回显的数据", data);
this.category.name = data.data.name;
this.category.catId = data.data.catId;
this.category.icon = data.data.icon;
this.category.productUnit = data.data.productUnit;
this.category.parentCid = data.data.parentCid;
this.category.catLevel = data.data.catLevel;
this.category.sort = data.data.sort;
this.category.showStatus = data.data.showStatus;
})
},
append(data) {
console.log("append", data);
this.title = "添加分类";
this.dialogType = "add";
this.dialogVisible = true;
this.category.parentCid = data.catId;
this.category.catLevel = data.catLevel * 1 + 1;
this.category.showStatus = 1;
this.category.sort = 0;
this.category.name = "";
this.category.catId = null;
this.category.icon = "";
this.category.productUnit = "";
},
remove(node, data) {
var ids = [data.catId]
this.$confirm(`是否删除【${data.name}】菜单?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$http({
url: this.$http.adornUrl('/product/category/delete'),
method: 'post',
data: this.$http.adornData(ids, false)
}).then(({ data }) => {
console.log("删除成功");
this.$message({
message: '菜单删除成功',
type: 'success'
});
// 刷新出新的菜单
this.getMenus()
// 设置删除后默认要展示的父菜单
this.expandedKey = [node.parent.data.catId]
// if (data && data.code === 0) {
// this.$message({
// message: '操作成功',
// type: 'success',
// duration: 1500,
// onClose: () => {
// this.getDataList()
// }
// })
// } else {
// this.$message.error(data.msg)
// }
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
console.log("remove", node, data);
},
getMenus() {
this.dataListLoading = true
this.$http({
url: this.$http.adornUrl('/product/category/list/tree'),
method: 'get'
}).then(({ data }) => {
console.log("成功获取到菜单数据...", data.data)
this.menus = data.data
})
}
},
// 监听属性 类似于data概念
computed: {},
// 监控data中的数据变化
watch: {},
// 生命周期 - 创建完成(可以访问当前this实例)
created() {
this.getMenus()
},
// 生命周期 - 挂载完成(可以访问DOM元素)
mounted() {
},
beforeCreate() { }, // 生命周期 - 创建之前
beforeMount() { }, // 生命周期 - 挂载之前
beforeUpdate() { }, // 生命周期 - 更新之前
updated() { }, // 生命周期 - 更新之后
beforeDestroy() { }, // 生命周期 - 销毁之前
destroyed() { }, // 生命周期 - 销毁完成
activated() { } // 如果页面有keep-alive缓存功能,这个函数会触发
}
</script>
<style scoped></style>
前端
<template>
<div>
<el-switch v-model="draggable" active-text="开启拖拽" inactive-text="关闭拖拽">
</el-switch>
<el-button v-if="draggable" @click="batchSave">批量保存</el-button>
<el-button type="danger" @click="batchDelete">批量删除</el-button>
<el-tree :data="menus" :props="defaultProps" :default-expanded-keys="expandedKey" node-key="catId" show-checkbox
@node-drop="handleDrop" :draggable="draggable" :allow-drop="allowDrop" :expand-on-click-node="false"
ref="menuTree">
<span class="custom-tree-node" slot-scope="{ node, data }">
<span>{{ node.label }}</span>
<span>
<el-button v-if="node.level <= 2" type="text" size="mini" @click="() => append(data)">
Append
</el-button>
<el-button type="text" size="mini" @click="() => edit(data)">
edit
</el-button>
<el-button v-if="node.childNodes.length == 0" type="text" size="mini" @click="() => remove(node, data)">
Delete
</el-button>
</span>
</span>
</el-tree>
<el-dialog :title="title" :visible.sync="dialogVisible" width="30%" :close-on-click-modal="false">
<el-form :model="category">
<el-form-item label="分类名称">
<el-input v-model="category.name" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="图标">
<el-input v-model="category.icon" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="计量单位">
<el-input v-model="category.productUnit" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="submitData()">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
// 例如:import 《组件名称》 from '《组件路径》';
export default {
// import引入的组件需要注入到对象中才能使用
components: {},
data() {
return {
pCid: [],
draggable: false,
updateNodes: [],
maxLevel: 0,
title: "",
dialogType: "", //edit,add
category: { name: "", parentCid: 0, catLevel: 0, showStatus: 1, sort: 0, catId: null, icon: "", productUnit: "" },
dialogVisible: false,
expandedKey: [],
menus: [],
defaultProps: {
children: 'children',
label: 'name'
}
};
},
methods: {
batchDelete() {
let catIds = []
let checkedNodes = this.$refs.menuTree.getCheckedNodes();
console.log("被选中的元素", checkedNodes);
for (let i = 0; i < checkedNodes.length; i++) {
catIds.push(checkedNodes[i].catId);
}
this.$confirm(`是否批量删除【${catIds}】菜单?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$http({
url: this.$http.adornUrl('/product/category/delete'),
method: 'post',
data: this.$http.adornData(catIds, false)
}).then(({ data }) => {
console.log("删除成功");
this.$message({
message: '菜单批量删除成功',
type: 'success'
});
// 刷新出新的菜单
this.getMenus()
// 设置删除后默认要展示的父菜单
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
},
batchSave() {
this.$http({
url: this.$http.adornUrl('/product/category/update/sort'),
method: 'post',
data: this.$http.adornData(this.updateNodes, false)
}).then(({ data }) => {
this.$message({
message: '菜单顺序等修改成功',
type: 'success'
});
// 刷新新菜单
this.getMenus()
// 设置删除后默认要展示的父菜单
this.expandedKey = this.pCid;
this.updateNodes = [];
this.maxLevel = 0;
this.pCid = [];
});
},
handleDrop(draggingNode, dropNode, dropType, ev) {
console.log('handleDrop: ', draggingNode, dropNode, dropType, ev);
// 1.当前节点最新的父节点id
var pCid = 0;
let sibilings = null;
if (dropType == "before" || dropType == "after") {
pCid = dropNode.parent.data.catId == undefined ? 0 : dropNode.parent.data.catId;
sibilings = dropNode.parent.childNodes;
} else {
pCid = dropNode.data.catId;
sibilings = dropNode.childNodes;
}
// 2.当前拖拽节点的最新顺序
for (let i = 0; i < sibilings.length; i++) {
if (sibilings[i].data.catId == draggingNode.data.catId) {
// 如果遍历是当前正在拖拽的节点
let catLevel = draggingNode.level
if (sibilings[i].level == draggingNode.level) {
// 当前拖拽节点的层级有变化
catLevel = sibilings[i].level;
// 递归修改子节点的层级
this.updateChildNodeLevel(sibilings[i]);
}
this.updateNodes.push({ catId: sibilings[i].data.catId, sort: i, parentCid: pCid, catLevel: catLevel });
} else {
this.updateNodes.push({ catId: sibilings[i].data.catId, sort: i })
}
}
// 3.当前拖拽节点的最新层级级
console.log("updateNodes:", this.updateNodes);
this.pCid.push(pCid);
},
updateChildNodeLevel(node) {
if (node.childNodes.length > 0) {
for (let i = 0; i < node.childNodes.length; i++) {
var cNode = node.childNodes[i].data;
this.updateNodes.push({ catId: cNode.catId, catLevel: node.childNodes[i].level });
this.updateChildNodeLevel(node.childNodes[i]);
}
}
},
allowDrop(draggingNode, dropNode, type) {
// 1.被拖动的当前节点以及所在的父节点总层数不能大于3
// 被拖动的当前节点的总层数
console.log("allowDrop:", draggingNode, dropNode, type)
this.countNodeLevel(draggingNode.data);
// 当前正在拖动的节点+父节点所在的深度不大于3即可
let deep = (this.maxLevel - draggingNode.parent.level);
console.log("深度:", deep);
console.log(this.maxLevel);
if (type == "inner") {
return deep + dropNode.data.catLevel <= 3
} else {
// 前后
return deep + dropNode.parent.level <= 3
}
// return ;
},
countNodeLevel(node) {
// 找到所有子节点,求出最大深度
if (node.childNodes != null && node.childNodes.length > 0) {
// 有子节点则遍历
for (let i = 0; i < node.childNodes.length; i++) {
if (node.childNodes[i].level > this.maxLevel) {
this.maxLevel = node.childNodes[i].level;
}
this.countNodeLevel(node.childNodes[i]);
}
}
},
// 添加三级分类的方法
addCategory() {
console.log("三级分类的对象", this.category);
this.$http({
url: this.$http.adornUrl('/product/category/save'),
method: 'post',
data: this.$http.adornData(this.category, false)
}).then(({ data }) => {
console.log("菜单保存成功");
this.$message({
message: '菜单保存成功',
type: 'success'
});
// 关闭对话框
this.dialogVisible = false;
// 刷新出新的菜单
this.getMenus()
// 设置删除后默认要展示的父菜单
this.expandedKey = [this.category.parentCid];
});
},
// 修改三级分类的方法
editCategory() {
var { catId, name, icon, productUnit } = this.category;
var data = { catId, name, icon, productUnit }
console.log("三级分类的对象", this.category);
this.$http({
url: this.$http.adornUrl('/product/category/update'),
method: 'post',
data: this.$http.adornData(data, false)
}).then(({ data }) => {
console.log("菜单修改成功");
this.$message({
message: '菜单修改成功',
type: 'success'
});
// 关闭对话框
this.dialogVisible = false;
// 刷新出新的菜单
this.getMenus()
// 设置删除后默认要展示的父菜单
this.expandedKey = [this.category.parentCid];
});
},
submitData() {
if (this.dialogType == "add") {
this.addCategory();
}
if (this.dialogType == "edit") {
this.editCategory();
}
},
edit(data) {
console.log("要修改的数据", data);
this.title = "修改分类";
this.dialogType = "edit";
this.dialogVisible = true;
// 发送请求获取节点最新的数据
this.$http({
url: this.$http.adornUrl(`/product/category/info/${data.catId}`),
method: 'get',
}).then(({ data }) => {
console.log("要回显的数据", data);
this.category.name = data.data.name;
this.category.catId = data.data.catId;
this.category.icon = data.data.icon;
this.category.productUnit = data.data.productUnit;
this.category.parentCid = data.data.parentCid;
this.category.catLevel = data.data.catLevel;
this.category.sort = data.data.sort;
this.category.showStatus = data.data.showStatus;
})
},
append(data) {
console.log("append", data);
this.title = "添加分类";
this.dialogType = "add";
this.dialogVisible = true;
this.category.parentCid = data.catId;
this.category.catLevel = data.catLevel * 1 + 1;
this.category.showStatus = 1;
this.category.sort = 0;
this.category.name = "";
this.category.catId = null;
this.category.icon = "";
this.category.productUnit = "";
},
remove(node, data) {
var ids = [data.catId]
this.$confirm(`是否删除【${data.name}】菜单?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$http({
url: this.$http.adornUrl('/product/category/delete'),
method: 'post',
data: this.$http.adornData(ids, false)
}).then(({ data }) => {
console.log("删除成功");
this.$message({
message: '菜单删除成功',
type: 'success'
});
// 刷新出新的菜单
this.getMenus()
// 设置删除后默认要展示的父菜单
this.expandedKey = [node.parent.data.catId]
// if (data && data.code === 0) {
// this.$message({
// message: '操作成功',
// type: 'success',
// duration: 1500,
// onClose: () => {
// this.getDataList()
// }
// })
// } else {
// this.$message.error(data.msg)
// }
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
console.log("remove", node, data);
},
getMenus() {
this.dataListLoading = true
this.$http({
url: this.$http.adornUrl('/product/category/list/tree'),
method: 'get'
}).then(({ data }) => {
console.log("成功获取到菜单数据...", data.data)
this.menus = data.data
})
}
},
// 监听属性 类似于data概念
computed: {},
// 监控data中的数据变化
watch: {},
// 生命周期 - 创建完成(可以访问当前this实例)
created() {
this.getMenus()
},
// 生命周期 - 挂载完成(可以访问DOM元素)
mounted() {
},
beforeCreate() { }, // 生命周期 - 创建之前
beforeMount() { }, // 生命周期 - 挂载之前
beforeUpdate() { }, // 生命周期 - 更新之前
updated() { }, // 生命周期 - 更新之后
beforeDestroy() { }, // 生命周期 - 销毁之前
destroyed() { }, // 生命周期 - 销毁完成
activated() { } // 如果页面有keep-alive缓存功能,这个函数会触发
}
</script>
<style scoped></style>