SSM框架整合

SSM框架整合

一、环境搭建

  • 新建一个空的Maven项目ssmbulid,在ssmbulid文件夹上右击add framework support选择里面的web,就会在项目中新建一个web文件夹
  • 在main->java下新建com.ljh.pojo、dao、service、controller
  • 连接数据库
  • 配置Tomcat
  • 导入依赖
<dependencies>
    <!--junit-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13</version>
    </dependency>
    <!--mysql-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.14</version>
    </dependency>
    <!--c3p0-->
    <dependency>
        <groupId>com.mchange</groupId>
        <artifactId>c3p0</artifactId>
        <version>0.9.5.2</version>
    </dependency>
    <!--servlet-->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.5</version>
    </dependency>
    <!--jsp-->
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>jsp-api</artifactId>
        <version>2.1</version>
    </dependency>
    <!--jstl-->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>
    <!--mybatis-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.6</version>
    </dependency>
    <!--mybatis-spring-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.6</version>
    </dependency>
    <!--spring-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.2</version>
    </dependency>
    <!--spring-jdbc-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.3.3</version>
    </dependency>
    <!--lombok-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.12</version>
    </dependency>
</dependencies>

注意:一定要在Project Structure中的Artifacts的WEB-INF目录下新建lib目录,然后把所有的Maven包复制进去一份!如果maven依赖变更,也要在lib目录中添加所需依赖!

  • 静态资源导出问题
<!--maven配置文件无法被导出或生效-->
<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
    </resources>
</build>

二、Mybatis层编写

1、数据库配置文件

resources文件夹下新建db.properties

jdbc.driver = com.mysql.cj.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/javatest?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&useSSL=false
jdbc.username = root
jdbc.password = 123456

2、Mybatis核心配置文件

resources文件夹下新建mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
  <!--别名-->
  <typeAliases>
    <package name="com.ljh.pojo"/>
  </typeAliases>
  <!--注册mapper-->
  <!--<mappers>-->
  <!--  <mapper class="com.ljh.dao.StudentMapper"/>-->
  <!--</mappers>-->
</configuration>

里面只需要起别名及注册mapper即可。

3、pojo实体类

与数据库表名一一对应

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
  private int id;
  private String name;
  private String phone;
}

4、编写dao层

1、编写Mapper接口

public interface StudentMapper {
  //添加学生
  int addStudent(Student student);
  //根据ID删除一个学生
  int deleteStudentById(@Param("studentId") int id);
  //修改一名学生信息
  int updateStudent(Student student);
  //根据Id查询学生信息
  Student queryStudent(@Param("studentId") int id);
}

2、编写Mapper接口对应的Mapper.xml

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

  <insert id="addStudent" parameterType="Student">
    insert into javatest.student values #{id},#{name},#{phone}
  </insert>

  <delete id="deleteStudentById" parameterType="int">
    delete from javatest.student where id = #{studentId}
  </delete>

  <update id="updateStudent" parameterType="Student">
    update javatest.student set name = #{name},phone=#{phone}
    where id = #{studentId}
  </update>

  <select id="queryStudent" parameterType="int" resultType="student">
    select * from javatest.student where id =#{studentId}
  </select>

</mapper>

注: 一个Mapper.xml对应一个Mapper接口,要用namespace绑定上述接口

一定要在mybatis核心配置文件中注册Mapper

<!--注册mapper-->
<mappers>
    <mapper class="com.ljh.dao.StudentMapper"/>
</mappers>

5、编写service层

1、编写service层的接口

public interface StudentService {
  //添加学生
  int addStudent(Student student);
  //根据ID删除一个学生
  int deleteStudentById(int id);
  //修改一名学生信息
  int updateStudent(Student student);
  //根据Id查询学生信息
  Student queryStudent(int id);
}

2、编写service层接口实现类

service层用来调用dao层,所以内置私有属性为dao层的Mapper接口对象

public class StudentServiceImpl implements StudentService{
  //dao层的Mapper接口对象
  private StudentMapper studentMapper;
  //set方法,为后续Spring注入准备
  public void setStudentMapper(StudentMapper studentMapper) {
    this.studentMapper = studentMapper;
  }

  public int addStudent(Student student) {
    return studentMapper.addStudent(student);
  }

  public int deleteStudentById(int id) {
    return studentMapper.deleteStudentById(id);
  }

  public int updateStudent(Student student) {
    return studentMapper.updateStudent(student);
  }

  public Student queryStudent(int id) {
    return studentMapper.queryStudent(id);
  }
}

三、Spring层编写

1、spring整合dao层

resources文件夹下新建spring-dao.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       https://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd">

  <!--关联数据库配置文件-->
  <context:property-placeholder location="classpath:db.properties"/>

  <!--配置c3p0连接池-->
  <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="${jdbc.driver}"/>
    <property name="jdbcUrl" value="${jdbc.url}"/>
    <property name="user" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>

    <!-- c3p0连接池的私有属性 -->
    <property name="maxPoolSize" value="30"/>
    <property name="minPoolSize" value="10"/>
    <!-- 关闭连接后不自动commit -->
    <property name="autoCommitOnClose" value="false"/>
    <!-- 获取连接超时时间 -->
    <property name="checkoutTimeout" value="10000"/>
    <!-- 当获取连接失败重试次数 -->
    <property name="acquireRetryAttempts" value="2"/>
  </bean>

  <!--sqlSessionFactory-->
  <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <!--引用上述数据源-->
    <property name="dataSource" ref="dataSource"/>
    <!--绑定MyBatis配置文件-->
    <property name="configLocation" value="classpath:mybatis-config.xml"/>
  </bean>

  <!--配置dao接口扫描包,动态实现了Dao接口可以注入到Spring容器中-->
  <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <!--注入sqlSessionFactory-->
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    <!--要扫描的dao包-->
    <property name="basePackage" value="com.ljh.dao"/>
  </bean>

</beans>

2、Spring整合service层

resources文件夹下新建spring-service.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       https://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd">

  <!--扫描service下的包,这个包下的注解就会生效-->
  <context:component-scan base-package="com.ljh.service"/>

  <!--将所有的业务类注入到Spring,可以通过配置或者注解实现-->
  <bean id="studentService" class="com.ljh.service.StudentServiceImpl">
    <!--这里的ref指向spring-dao.xml最后Spring注入的dao接口-->
    <property name="studentMapper" ref="studentMapper"/>
  </bean>

  <!--声明式事务配置-->
  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <!--注入数据源-->
    <property name="dataSource" ref="dataSource"/>
  </bean>

</beans>

四、SpringMVC层编写

1、spring-mvc

resources文件夹下新建spring-mvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       https://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc
       https://www.springframework.org/schema/mvc/spring-mvc.xsd">

  <!--开启SpringMVC注解驱动-->
  <mvc:annotation-driven/>
  <!--静态资源过滤-->
  <mvc:default-servlet-handler/>

  <context:component-scan base-package="com.ljh.controller"/>

  <!--视图解析器-->
  <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/jsp/"/>
    <property name="suffix" value=".jsp"/>
  </bean>

</beans>

注:在WEB-INF目录下新建jsp文件夹

2、配置文件整合

resources文件夹下新建applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       https://www.springframework.org/schema/beans/spring-beans.xsd">

  <import resource="spring-dao.xml"/>
  <import resource="spring-service.xml"/>
  <import resource="spring-mvc.xml"/>

</beans>

3、配置web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
  <!--DispatcherServlet-->
  <servlet>
    <servlet-name>spring-mvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:applicationContext.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>spring-mvc</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

  <!--乱码过滤-->
  <filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>utf-8</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

  <!--session过期时间-->
  <session-config>
    <session-timeout>15</session-timeout>
  </session-config>
</web-app>

4、编写controller层

在controller层中新建StudentController

@Controller
@RequestMapping("/student")
public class StudentController {

  @Autowired
  @Qualifier("studentService")
  private StudentService studentService;

  @RequestMapping("/query")
  public String query(Model model) {
    Student student = studentService.queryStudent(4);
    model.addAttribute("stu",student);
    return "stu";//指的是/WEB-INF/jsp/stu.jsp
  }

}

在jsp文件夹下新建stu.jsp

5、编写jsp

index.jsp

<a href="${pageContext.request.contextPath}/student/query">查询学生</a>

stu.jsp

<body>
${stu}
</body>

启动即可。

五、前后端分离

前端用vue,后端用ssm框架

1、controller层

后端把视图解析器删掉,然后controller层更改代码

@RestController
@CrossOrigin
@RequestMapping("/student")
public class StudentController {

  @Autowired
  @Qualifier("studentService")
  private StudentService studentService;


  @RequestMapping("/query")
  public String query(@RequestParam("id") int id) {
    System.out.println(id);
    Student student = studentService.queryStudent(id);

    return JSON.toJSONString(student);
  }
}

@RestController不会走视图解析器,会直接返回一个字符串

@CrossOrigin解决跨域问题

@RequestParam(“xxx”),其中xxx是前端返回的值,必须和前端的命名相对应

2、Vue

vue用axios接收后端传来的数据

在main.js中导入axios并设定baseURL

import axios from 'axios'

Vue.prototype.$axios = axios;
axios.defaults.baseURL = "http://127.0.0.1:8080";

注意:上面是baseURL不是baseURI,webstorm会智能提示baseURI

编写vue单页面

<template>
  <div class="header_wrapper">
    <form action="">
      <input type="text" placeholder="请输入学号" v-model="code">
      <button @click="queryStudentById(code)">查询学生</button>
    </form>
    <div>{{stu.id}}--{{stu.name}}--{{stu.phone}}</div>
  </div>
</template>

<script>
  export default {
    name: "Header",
    data(){
      return{
        stu:{
          id:null,
          name:'',
          phone:''
        },
        code:1
      }
    },
    methods:{
      queryStudentById(id) {
        this.$axios({
          url:"/student/query",
          method:'post',
          params:{
            id:id
          }
        }).then(res=>{
          this.stu = res.data;
          console.log(res);
        }).catch(err=>{
          console.log(err);
        })
      }
    }
  }
</script>

<style>
  .header_wrapper{
    margin: 100px auto;
    text-align: center;
  }
  input{
    width: 550px;
    height: 40px;
    margin: 0 auto;
  }
</style>

写法一:

this.$axios({

url:“这里是controller层编写的路径”,

method:“get/post”,

params:{

这里写传递给后端的参数

}

}).get(res=>{res.data就是后端传来的数据})

this.$axios.get/post(“url路径”,{
params:{
name:this.name,
phone:this.phone

})

3、axios请求

get请求

  • this.$axios.get
  • 可以直接在路径后面拼接?id=1
  • 添加params(推荐)

post请求

  • this.$axios.post
  • 引入qs, import qs from ‘qs’ 然后在参数那里用 qs.stringify({id:id})
  • 在函数中编写 let params = new URLSearchParams(); params.append(“id”,id); 最后在参数那里写上params

4、添加学生

controller层

@RequestMapping("/add")
public String addStu(@RequestParam("name") String name,@RequestParam("phone") String phone) {
    System.out.println(name);
    System.out.println(phone);
    Map<String,Object> map = new HashMap<String,Object>();
    map.put("name",name);
    map.put("phone",phone);
    int i = studentService.addStudent(map);
    if(i>0){
        return "成功";
    }
    return null;
}

注意:controller返回值必须是String

vue单页面

<template>
  <div class="content-wrapper">
    <form action="" method="get">
      name:<input type="text" name="name" v-model="name" placeholder="请输入姓名" required="required">
      <br>
      phone:<input type="text" name="phone" v-model="phone" required="required">
      <input type="submit" value="提交" @click="addStudent($event)">
    </form>
  </div>
</template>

<script>
  export default {
    name: "Content",
    data() {
      return {
        name: '',
        phone: ''
      }
    },
    mounted() {

    },
    methods: {
      addStudent(e) {
        e.preventDefault();
        let that = this;
        if(this.name&&this.phone) {
          this.$axios.get("/student/add",{
            params:{
              name:this.name,
              phone:this.phone
            }
          }).then(res=>{
            console.log(res.data);
            if(res.data) {
              this.$message({
                type: 'success',
                message: '添加成功!'
              });
            }else{
              this.$message.error('添加失败!');
            }
          })
        }else{
          this.$message({
            type: 'warning',
            message: '字段不允许为空!'
          });
        }

      }
    }

  }
</script>

<style scoped>

</style>

4、删除学生

controller

@RequestMapping("/del")
public String deleteStu(@RequestParam("id") int id) {
    int i = studentService.deleteStudentById(id);
    if(i>0) {
        return "删除成功!";
    }
    return null;
}

vue页面

<template>
  <div class="header_wrapper">
    <div>
      <form action="" method="post">
        <input type="text" placeholder="请输入学号" v-model="code">
        <button @click="deleteStudentById(code,$event)">删除学生</button>
      </form>
    </div>
  </div>
</template>

<script>

  export default {
    name: "Header",
    data() {
      return {}
    },
    methods: {
      deleteStudentById(id,e) {
        e.preventDefault();
        this.$axios.get("/student/del",{params:{
          id:id
        }}).then(res=>{
          console.log(res.data);
          if(res.data) {
            this.$message({
              type: 'success',
              message: '删除成功!'
            });
          }
        }).catch(()=>{
          this.$message.error('删除失败!');
        })

      }
    }
  }
</script>

<style>
  .header_wrapper {
    margin: 100px auto;
    text-align: center;
  }

  input {
    width: 550px;
    height: 40px;
    margin: 0 auto;
  }
</style>

5、修改学生信息

controller

@RequestMapping("/update")
  public String updateStu(@RequestParam("id") int id,@RequestParam("name")String name,@RequestParam("phone")String phone) {

    Student student = new Student();
    student.setId(id);
    student.setName(name);
    student.setPhone(phone);
    System.out.println(student);
    int i = studentService.updateStudent(student);
    System.out.println(i);
    if(i>0){
      return "更新成功!";
    }
    return null;
  }

vue页面

<template>
  <div>
    <div style="display: flex;margin-left: 20px" v-for="(s,index) in stu">
      <input type="text" :value="s.id" disabled><input type="text" ref="getNameValue" :value="s.name"><input type="text" ref="getPhoneValue" :value="s.phone">
      <button @click="updateStu(index,s)">修改</button>
    </div>
  </div>

</template>

<script>
  export default{
    data(){
      return {
        stu:[
          {
            id:'',
            name:'',
            phone:''
          }
        ]
      }
    },
    components: {

    },
    methods:{
      updateStu(index,stu) {
        // console.log(this.$refs.getNameValue[index].value);
        // console.log(this.$refs.getPhoneValue[index].value);
        stu.name = this.$refs.getNameValue[index].value;
        stu.phone = this.$refs.getPhoneValue[index].value;
        console.log(stu);
        let params = {
          id:stu.id,
          name:stu.name,
          phone:stu.phone
        };
        console.log(params);
        this.$axios.get("/student/update",{params}).then(res=>{
          console.log(res);
        }).catch(err=>{
          console.log(err);
        })
      }
    },
    mounted(){
      let that = this;
      this.$axios.get("/student/allstu").then(res=>{
        // console.log(res);
        that.stu = res.data;
      }).catch(err=>{
        console.log(err);
      })
    }
  }
</script>

注意:SQL语句一定要检查无误,否则排错困难。

六、Vue知识点

1、父子组件传值

  • 父组件向子组件传值或函数,子组件获得父组件的数据进行数据渲染

父组件vue

<template>
    <div>
      <h2>我是父组件</h2>
      <div>
        <Son :msg="msg"></Son>
      </div>
    </div>
</template>

<script>
  import Son from "./Son"
  export default {
    name: "Father",
    components:{
      Son
    },
    data() {
      return{
        msg:'slot'
      }
    },
    methods:{
      toSon() {
        console.log("这里是父组件");
      }
    }
  }
</script>

子组件vue

<template>
    <div>父组件传过来的值为:{{msg}}
    	<button @click="toSon">点我</button>
    </div>
</template>

<script>
  export default {
    name: "Son",
    props:{
      msg: String,
      toSon:Function
    }
      //也可以是props:['msg']
  }
</script>

除此之外,也可以在父组件中的子组件标签添加ref标签<Son ref="getMsg"></Son>可以在父元素利用this.$refs.getMsg.xxx取到子组件的值,xxx指的是子组件中data中的数据名

  • 子组件数据传给父组件,通过$emit

父组件

<template>
    <div>
      <h2>我是父组件</h2>
      <div>
        <Son @getUserName="getName" @getBtnValue="getValue"></Son>
        <p>用户名为:{{username}}</p>
        <p>按钮值为:{{btnValue}}</p>
      </div>
    </div>
</template>

<script>
  import Son from "./Son"
  export default {
    name: "Father",
    components:{
      Son
    },
    data() {
      return{
        username:'',
        btnValue:''
      }
    },
    methods:{
      getName(name) {
        this.username = name;
      },
      getValue(value) {
        this.btnValue = value;
      }
    }
  }
</script>

子组件

<template>
    <div>我是子组件
      <div>
        用户名:<input type="text" v-model="name" @change="setName">
        <button @click="setBtnValue">子组件传给父组件</button>
      </div>
    </div>

</template>

<script>
  export default {
    name: "Son",
    data() {
      return{
        name:'',
        btnValue:'我是子组件的数据'
      }
    },
    methods:{
      setName() {
        this.$emit("getUserName",this.name);
      },
      setBtnValue() {
        this.$emit("getBtnValue",this.btnValue);
      }
    }
  }
</script>

以上面按钮传值为例,子组件传给父组件通过getBtnValue这个桥梁(在父元素上面定义的@xxx,这里的xxx就是两者的桥梁),在分别在父元素和子元素中各写一个方法,父元素方法写的是具体做的事,子元素的方法就是利用this.$emit把数据传给父组件。

如果是兄弟组件传值(假设父组件为Father),则利用Father.$emitFather.$on分别作用在两个兄弟组件的方法methods和另一个组件的mounted里面即可。

2、生命周期

  • 初始化:

    • beforeCreate:一般没啥用,数据没挂载,DOM 没有渲染出来
    • created:数据已经挂载,但是 DOM 没有渲染出来,这个钩子函数里面可以做一些异步的操作,并且在这个钩子函数里面更改数据不会影响到运行时钩子函数。
    • beforeMounte:这个函数代表着 DOM 快要被渲染出来了,但是还没有被渲染出来,跟 created 一样,做一些异步的操作
    • mounted:数据已经挂载,真实 DOM 也已经渲染出来了。
  • 运行中:

    • beforeUpdate:当数据改变的时候才会执行这个函数,在这个函数里面拿到的是改变之前的数据,千万不能在这个里面更改数据,否则会造成死循环
    • updated:拿到的是更新之后的数据,在这函数里面,生成新的 DOM ,跟上一次的虚拟 DOM 做对比,比较出差异之后,然后再渲染真实的 DOM ,当数据引发 DOM 重新渲染的时候,在这个钩子函数里面就可以获取到真实的 DOM。
  • 销毁时:

    • beforeDestroy:销毁前,做一些善后的操作
    • destroyed:数据的双向绑定,监听都删除了,但是真实的 DOM 还是存在的
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页