Vue 笔记

概述

Vue.js - 渐进式 JavaScript 框架 | Vue.js

        vue: 是一个javascript的渐进式框架,实质就是js文件

        渐进式: 易用、灵活、高效

        什么是响应式: 根据不同条件做出相应调整

mvvm

        MVVM理论上与Vue并没有什么联系,Vue的本质是Vue.js,官网上写的很清楚。MVVM是一种思想,并不只是Vue用,用任何语言都可以用这种思想,他提倡的是一种前后端分离的思想。

        MVVM分为三个部分:分别是M(Model,模型层 ),V(View,视图层),VM(ViewModel,V与M连接的桥梁,也可以看作为控制器)

        M:模型层,主要负责业务数据相关;

        V:视图层,顾名思义,负责视图相关,细分下来就是html+css层;

        VM:V与M沟通的桥梁,负责监听M或者V的修改,是实现MVVM双向绑定的要点;

        MVVM支持双向绑定,意思就是当M层数据进行修改时,VM层会监测到变化,并且通知V层进行相应的修改,反之修改V层则会通知M层数据进行修改,以此也实现了视图与模型层的相互解耦;

        VM这个概念非常重要。可以理解下MVC中的C(控制层)被换成了VM(ViewModel:)层。它本质上就是MVC 的改进版。MVVM层实现了前后端更好的分离

组件

组件基础

        创建一个组件

        使用组件

        html  ---> 组件 name.vue

        脚手架  vue-cli   node 服务 一路next

        使用npm

1. 安装node

        安装node(步骤省略,一路next即可)

        安装成功以后执行命令:node -v

        出现如下界面即为安装成功

        加快安装:淘宝镜像

                g = global

                npm node服务器中自带的命令

npm install -g cnpm --registry=https://registry.npm.taobao.org

2. 安装 vue-cli

npm install  -g vue-cli 

3. 安装 webpack

npm install webpack -g

4.安装打包的客户端

npm install webpack-cli -g

创建项目

npm uninstall vue-cli
npm install @vue-cli
vue create myvue2

        (若无法执行脚本,报出如下错误)

        (需要运行如下代码)

get-ExecutionPolicy
set-ExecutionPolicy RemoteSigned
get-ExecutionPolicy -List

        (这样就可以执行脚本命令了)

        先切换到项目存放的路径下

        

        项目创建成功!

        项目测试:

cd myvue
npm run serve

        浏览器访问路径:http://localhost:8080/

 Tomcat 与 Node 的区别

        1. Tomcat  java代码

                服务器  端口号  8080 端口被占用时,报错

        2. Node  服务器

                前端服务器  前端代码

        默认端口号  8080  被占用时 自动切换端口:8081   8082

路由

        定义路由的时候  path 的路径一定是唯一的

        如果写 name 对应的值 也得是唯一

App.vue 是所有组件的父类

        <router-view/>  容器   作用:存放组件   一般存放到父组件里面

        在vue 里面 @ 代表的是 src

        <template> 标签里面只能有一个根标签,多个根标签会出现如下错误

1. 写组件

<template>
    <div>
      <h1>我的第一个vue组件</h1>
    </div>
</template>

2.在router/index.js 中配置路径

3. 访问

启动命令

npm run xxx

在 package.json 文件中

组件介绍

<template>

        HTML 内容

</template>

<script>

        脚本  new Vue({   })

</script>

<style>

        CSS 样式

</style>

自定义端口号:

        

安装 axios

$ npm install axios

安装 ui

npm i element-ui

在paxkage.json中可查看是否安装,和安装的版本

使用axios 和 element

后端部分

新建项目

配置 pom.xml 文件

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
      <version>2.7.17</version>
    </dependency>

    <!--连接数据库-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.33</version>
    </dependency>

    <!--mp-->
    <dependency>
      <groupId>com.baomidou</groupId>
      <artifactId>mybatis-plus-boot-starter</artifactId>
      <version>3.5.3</version>
    </dependency>

    <!--自动生成代码-->
    <dependency>
      <groupId>com.baomidou</groupId>
      <artifactId>mybatis-plus-generator</artifactId>
      <version>3.5.3</version>
    </dependency>

    <!--模板-->
    <dependency>
      <groupId>org.apache.velocity</groupId>
      <artifactId>velocity-engine-core</artifactId>
      <version>2.3</version>
    </dependency>
    <dependency>
      <groupId>org.freemarker</groupId>
      <artifactId>freemarker</artifactId>
    </dependency>

    <!--lombok-->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.6</version>
    </dependency>
  </dependencies>

配置 application.properties

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql:///gcf?useSSL=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=root
#  时间  格式化    java.util
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
spring.jackson.serialization.write-date-keys-as-timestamps=false
#logging.level.com.baomidou.ant.test.dao=debug
#mybatis-plus my_name   myName
mybatis-plus.configuration.map-underscore-to-camel-case=true
# 配置sql 日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
#mybatis-plus.configuration.log-impl=
mybatis-plus.mapper-locations=classpath:/mapper/*.xml
# 逻辑删除   未删除的默认为 0  已删除 1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
mybatis-plus.global-config.db-config.logic-delete-value=1

自动生成代码

public class MyTest {
    public static void main(String[] args) {
        //
        FastAutoGenerator.create("jdbc:mysql:///gcf", "root", "root")
                // 全局配置
                .globalConfig((scanner, builder) -> builder
                        .author("郜超凡")
                        .outputDir("D:\\CodeFile\\mpSpringBook\\mp_sb01\\src\\main\\java")
                )
                // 包配置
                .packageConfig(
                        (scanner, builder) ->
                                builder
                                        .parent("com.aaa")
                                        .pathInfo(Collections.singletonMap(OutputFile.xml, "D:\\CodeFile\\mpSpringBook\\mp_sb01\\src\\main\\resources\\mapper")))
                // 策略配置
                .strategyConfig((scanner, builder) -> builder.addInclude(getTables(scanner.apply("请输入表名,多个英文逗号分隔?所有输入 all")))
                        .controllerBuilder().enableRestStyle().enableHyphenStyle()
                        .entityBuilder().enableLombok().addTableFills(
                                new Column("create_time", FieldFill.INSERT)
                        ).build())
                /*
                    模板引擎配置,默认 Velocity 可选模板引擎 Beetl 或 Freemarker
                   .templateEngine(new BeetlTemplateEngine())
                   .templateEngine(new FreemarkerTemplateEngine())
                 */
                .execute();
    }

    // 处理 all 情况
    protected static List<String> getTables(String tables) {
        return "all".equals(tables) ? Collections.emptyList() : Arrays.asList(tables.split(","));
    }
}

运行文件MyTest.java 输入想要生成的表名

生成结果:

后端配置跨越:

1. 注解(只有当前类或当前方法可以跨域)

2. 配置文件(全局跨域)

@Configuration
public class CrossConfig {
    @Bean
    public CorsFilter corsFilter() {
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        final CorsConfiguration corsConfiguration = new CorsConfiguration();
        // corsConfiguration.setAllowCredentials(true);
        corsConfiguration.addAllowedHeader("*");  // 允许所有的头
        corsConfiguration.addAllowedOrigin("*");   //
        corsConfiguration.addAllowedMethod("*");  // * get  put delete head post
        source.registerCorsConfiguration("/**", corsConfiguration); // 所有的路由都能够进行跨域
        return new CorsFilter(source);
    }
}

测试

@SpringBootApplication
@MapperScan("com.aaa.mapper")
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class);
    }
}

后端代码完成

前端部分

        到element官网复制一个表格样式

        稍加修改

<template>
  <el-table
      :data="tableData"
      style="width: 100%"
      :row-class-name="tableRowClassName">
    <el-table-column
        prop="deptno"
        label="部门编号">
    </el-table-column>
    <el-table-column
        prop="dname"
        label="部门名称">
    </el-table-column>
    <el-table-column
        prop="loc"
        label="地址">
    </el-table-column>
  </el-table>
</template>

        发送请求

created() {
    // vue    node 服务器  8899
    // axios  tomcat  8080
    // axios  发出请求
    // dept   http://localhost:8080/dept
    this.$axios.get("dept").then(res=>{
      console.log(res.data);
      this.tableData=res.data;
    })
  }

        效果展示

布局菜单

1. 配置菜单和路由

2. 在main 里面写一个容器

3. 配置嵌套路由

效果如下:

登录页

1. 写一个登录页面 login.vue 

2. 在 index.js 中设置,让其默认访问登录页

效果:

3. 提交后让其跳转到菜单页

404页面

        当路由不存在的时候跳转到 404 页面

        在路由文件里面写路由的规则

        router/index.js

项目优化

登录验证

        数据库:

        

        后端:

               先自动生成

                再写一个工具类  在com/aaa/util路径下  ResponseVo.java

@Data
@AllArgsConstructor // 全参构造器
@NoArgsConstructor  // 无参构造器
public class ResponseVo<T> {
    /**
     * code
     */
    private Integer code;
    /**
     * msg
     */
    private String msg;
    /**
     * data
     */
    private T data;

    public ResponseVo(T data) {
        this.data = data;
    }

    /**
     * 成功
     * @param data
     * @return
     * @param <T>
     */

    public static <T> ResponseVo SUCCESS(T data){
        return new ResponseVo(200,"操作成功!",data);
    }

    /**
     * 失败
     * @param data
     * @return
     * @param <T>
     */
    public static <T> ResponseVo FAIL(T data){
        return new ResponseVo(500,"操作失败!",data);
    }
}

                控制层 UserController

@RestController
@RequestMapping("/user")
public class UserController {
    @Resource
    private IUserService userService;

    @PostMapping
    public ResponseVo login(@RequestBody User user){
        System.out.println(user);
        Boolean login = userService.login(user);
        return new ResponseVo(login);
    }
}

                服务层接口 IUserService

public interface IUserService extends IService<User> {
    Boolean login(User user);
}

                服务层实现接口 UserServiceImpl

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Resource
    private UserMapper userMapper;

    @Override
    public Boolean login(User user) {
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("user", user.getUser());
        wrapper.eq("pwd", user.getPwd());
        User one = this.getOne(wrapper);
        return one != null;
    }
}

        前端:

                登录组件 login.vue 表单提交部分添加 post 请求

submitForm(formName) {
      this.$axios.post("user", {user: this.ruleForm.uname, pwd: this.ruleForm.pass}).then(res => {
        console.log(res);
        if (res) {
          // 标识
          // 存放用户名字
          localStorage.setItem("user",this.ruleForm.uname);

          // ruleForm
          // localStorage.setItem("userInfo",JSON.stringify(this.ruleForm));
          // location.href="/main";

          // 成功提交时,更改路由
          this.$router.push({name: 'main'});
        } else {
          console.log('error submit!!');
          return false;
        }
      });
    },

路由守卫

        在 main.js 文件中配置

// 路由守卫
router.beforeEach((to, from, next) => {
    // to   代表的是要到达的地方
    // from 即将离开的地方
    // next 路径跳转
    //
    if (to.path === '/' || localStorage.getItem("user")) {
        next()      // to 允许用户继续导航到目标页面
    } else {
        next("/") // 将用户重定向到根路径 '/'
    }
    // 确保用户在未登录状态下无法访问除根路径外的其他页面,如果用户已经登录或者访问的是根路径,则允许用户继续导航
})

拦截器

        拦截器可以在发送请求或接收响应时对数据进行全局处理,比如添加公共请求头、错误处理、数据转换等。

        在 main.js 文件中配置

/**
 *  请求拦截器
 */
instance.interceptors.request.use(config => {

    // 头里面加一个参数   myname
    config.headers.myname = localStorage.getItem("user");
    //
    // config["headers"]['myname']

    return config;
})

/**
 * 响应拦截器
 */
instance.interceptors.response.use((response) => {
    return response.data.data;    // 提取响应中的数据,并将其作为处理后的数据返回
});

分页(单表)

        前端:到 element 官网 找一个分页模板,稍加修改

<div class="block">
      <el-pagination
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
          :current-page="page.currPage"
          :page-sizes="[5, 10, 15, 20]"
          :page-size="page.pageSize"
          layout="total, sizes, prev, pager, next, jumper"
          :total="page.total">
      </el-pagination>
</div>

        后端:配置分页插件

@Configuration
public class PagePlugins {
    /**
     * 添加分页插件
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//如果配置多个插件,切记分页最后添加
        //interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); 如果有多数据源可以不配具体类型 否则都建议配上具体的DbType
        return interceptor;
    }
}

        调用分页插件

        效果

动态查询(单表)

        前端:

<el-form :inline="true" :model="formInline" class="demo-form-inline">
      <el-form-item label="用户名">
        <el-input v-model="formInline.user" placeholder="请输入用户名"></el-input>
      </el-form-item>
      <el-form-item>
        <el-button icon="el-icon-search" circle @click="onSubmit"></el-button>
      </el-form-item>
</el-form>

        后端:

    @GetMapping
    public ResponseVo findAll(PageInfo pageInfo, User user) {
        Page page1 = new Page(pageInfo.getCurrPage(), pageInfo.getPageSize());
        QueryWrapper queryWrapper = new QueryWrapper<>();
        // 添加动态模糊查询条件
        if (user.getUser() != null && user.getUser() != "") {
            queryWrapper.like("user", user.getUser());
        }
        Page page = userService.page(page1,queryWrapper);
        return ResponseVo.SUCCESS(page);
    }

        效果:

多表分页和动态查询

        数据库 员工表emp 和 部门表dept

        后端

        实体类Emp

@Getter
@Setter
@ToString
public class Emp implements Serializable {

    private static final long serialVersionUID = 1L;

    @TableId(value = "empno", type = IdType.AUTO)
    private Integer empno;

    private String ename;

    private String job;

    private Integer mgr;

    private LocalDate hiredate;

    private BigDecimal sal;

    private BigDecimal comm;

    private Integer deptno;

    @TableField(exist = false)  // 代表不是数据库中的一个列
    private Dept dept;
}

        mapper接口

public interface EmpMapper extends BaseMapper<Emp> {
    Page findAll(Page page1, @Param("emp") Emp emp);
}

        mapper映射

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.aaa.mapper.EmpMapper">

    <resultMap id="getAllEmp" type="com.aaa.entity.Emp" autoMapping="true">
        <id column="empno" property="empno"></id>
        <association property="dept" javaType="com.aaa.entity.Dept" autoMapping="true">
            <id column="deptno" property="deptno"></id>
        </association>
    </resultMap>

    <select id="findAll" resultMap="getAllEmp">
        SELECT * FROM emp e
        JOIN dept d ON e.deptno=d.deptno
        <where>
            <if test="emp.ename!=null and emp.ename!=''">
                and ename like concat('%',#{emp.ename},'%')
            </if>
            <if test="emp.deptno!=null and emp.deptno!=''">
                and e.deptno=#{emp.deptno}
            </if>
        </where>
    </select>
</mapper>

        service层  接口 IEmpService

public interface IEmpService extends IService<Emp> {
    Page findAll(Page page1, Emp emp);
}

        service层  接口实现 IEmpServiceImpl

@Service
public class EmpServiceImpl extends ServiceImpl<EmpMapper, Emp> implements IEmpService {

    @Resource
    private EmpMapper empMapper;
    
    @Override
    public Page findAll(Page page1, Emp emp) {
        return empMapper.findAll(page1,emp);
    }
}

        controller层  EmpController

@RestController
@RequestMapping("/emp")
public class EmpController {
    @Resource
    private IEmpService empService;

    /**
     * 查询所有的员工的信息 以及员工的部门的信息
     * 并进行分页
     * @return
     */
    @GetMapping
    public  ResponseVo getAll(PageInfo pageInfo, Emp emp){
        Page<Emp> page1 = new Page<>(pageInfo.getCurrPage(), pageInfo.getPageSize());
        Page empList =  empService.findAll(page1,emp);
        return ResponseVo.SUCCESS(empList);
    }
}

        前端

        emp.vue

<template>
  <div>
    <el-form :inline="true" :model="formInline" class="demo-form-inline">
      <el-form-item label="员工姓名">
        <el-input v-model="formInline.ename" placeholder="请输入员工姓名"></el-input>
      </el-form-item>
      <el-form-item label="部门名称">
        <el-select v-model="formInline.deptno" placeholder="请选择">
          <el-option v-for="item in options" :key="item.deptno" :label="item.dname" :value="item.deptno">
          </el-option>
        </el-select>
      </el-form-item>
      <el-form-item>
        <el-button icon="el-icon-search" circle @click="onSubmit"></el-button>
      </el-form-item>
    </el-form>

    <br>
    <el-table
        :data="tableData"
        style="width: 100%"
        :row-class-name="tableRowClassName">
      <el-table-column
          prop="empno"
          label="员工编号">
      </el-table-column>
      <el-table-column
          prop="ename"
          label="姓名">
      </el-table-column>
      <el-table-column
          prop="job"
          label="工作">
      </el-table-column>
      <el-table-column
          prop="mgr"
          label="上司编号">
      </el-table-column>
      <el-table-column
          prop="hiredate"
          label="入职日期">
      </el-table-column>
      <el-table-column
          prop="sal"
          label="工资">
      </el-table-column>
      <el-table-column
          prop="comm"
          label="提成">
      </el-table-column>
      <el-table-column
          prop="dept.dname"
          label="部门名称">
      </el-table-column>
    </el-table>
    <br>
    <div class="block">
      <el-pagination
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
          :current-page="page.currPage"
          :page-sizes="[5, 10, 15, 20]"
          :page-size="page.pageSize"
          layout="total, sizes, prev, pager, next, jumper"
          :total="page.total">
      </el-pagination>
    </div>
  </div>
</template>

<style>
.el-table .warning-row {
  background: oldlace;
}

.el-table .success-row {
  background: #f0f9eb;
}
</style>

<script>
export default {
  methods: {
    tableRowClassName({row, rowIndex}) {
      if (rowIndex % 4 === 1) {
        return 'warning-row';
      } else if (rowIndex % 4 === 3) {
        return 'success-row';
      }
      return '';
    },
    handleSizeChange(val) {
      this.page.pageSize=val;
      this.queryData();
    },
    handleCurrentChange(val) {
      this.page.currPage=val;
      this.queryData();
    },
    queryData(){
      let newParam={...this.page,...this.formInline};  // 把两个对象合并成一个对象
      this.$axios.get("emp",{params:newParam}).then(res=>{
        console.log(res);
        // 给total进行赋值
        this.page.total=res.total;
        this.tableData=res.records;
      })
    },
    queryDeptData() {
      this.$axios.get("dept").then(res => {
        console.log(res)
        // 给total进行赋值
        this.options = res;
      })
    },
    // 动态查询提交
    onSubmit() {
      this.queryData()
    }
  },
  data() {
    return {
      tableData: [],
      // 分页
      page:{
        currPage:1,
        pageSize:5,
        total:0
      },
      // 动态查询
      formInline: {
        ename: '',
        deptno:'',
      },
      options:[],
    }
  },
  created() {
    this.queryData();
    // 部门的信息
    this.queryDeptData();
  }

}
</script>

        效果:

组件的运用

局部组件

        先写一个简单的局部组件 jubu.vue

<template>
  <div>
    这是一个局部组件
  </div>
</template>

        写一个测试组件 test01.vue 来调用局部组件

        效果

全局组件

        quanju.vue

        在 main.js 文件中配置

       这样 在 test01.vue 中就可以直接调用了

        效果

组件传值

父传子

1. 父组件的 data 中定义有一个变量

2. 在父组件中绑定一个属性传递给子组件

3. 子组件接收这个值

        使用 props 来接收父组件中的值

        

        使用父组件传递过来的值

        

        效果

        

子传父

1. 子组件在进行传值的时候一般通过按钮传递

2. 点击按钮的时候需要自定义一个事件(通过这个事件进行传值)

3. 父组件使用一下子组件中定义的事件接收值

4. 通过函数接收值

5. 使用由子组件传递过来的值

分页组件

        paging.vue

<template>
  <div class="block">
    <el-pagination
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
        :current-page="mydata.currPage"
        :page-sizes="[5, 10, 15, 20]"
        :page-size="mydata.pageSize"
        layout="total, sizes, prev, pager, next, jumper"
        :total="mydata.total">
    </el-pagination>
  </div>
</template>

<script>
export default({
  props:['mydata'],
  methods:{
    handleSizeChange(val) {
      this.page.pageSize = val;
      this.page.currPage=this.mydata.currPage;
      this.$emit('mychangeData',this.page);
    },
    handleCurrentChange(val) {
      this.page.currPage = val;
      this.page.pageSize=this.mydata.pageSize;
      this.$emit("mychangeData",this.page);
    },
  },
  data(){
    return{
      page: {
        currPage: 1,
        pageSize: 5,
        total: 0,
      },
    }
  }
})
</script>

        在 main.js 文件中将 paging.vue 定义为全局组件

// 1. 引入组件
import paging from '@/views/component/paging.vue'

// 2. 将这个组件注册成一个全局的组件
Vue.component("my-paging",paging);

        在需要的地方使用分页

    <!--引入分页的组件-->
    <my-paging :mydata="page" @mychangeData="changeData"></my-paging>

        子组件中的值传给父组件的时候 需要绑定一个事件 如果不绑定事件没法传值

    changeData(obj){
      this.page.pageSize=obj.pageSize;
      this.page.currPage=obj.currPage;
      this.queryData();
    },

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值