构建用户界面的渐进式框架,自底向上逐层应用
soc:关注度分离原则
MVVM:双向数据绑定
官方教程Vue.js (vuejs.org)
理解成是一个不停监听页面的ajax
idea需要安装Vue.js插件
安装 — Vue.js (vuejs.org)
Vue在线cdn
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
放在head中的JS代码会在页面加载完成之前就读取,
而放在body中的JS代码,会在整个页面加载完成之后读取
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="vue">
{{message}}
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
<!-- ViewModel层 -->
var vue = new Vue({
<!--键值之间 必须有空格,就像yml的语法一样 -->
<!--绑定id为vue的元素 -->
el: "#vue",
data: {
<!-- Model层 -->
message: "Hello Vue!"
}
})
script>
body>
html>
Vue.js 模板语法 | 菜鸟教程 (runoob.com)
所有的属性写法,全部都是key-value键值对,用yml的语法思想来理解vue
属性绑定vue数据指令
v-bind:“message” 相当于{{message}}
<div id="vue">
<span v-bind:title="message">
鼠标悬停后,可看到message的信息
span>
div>
导入链接
DOCTYPE html><html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<div id="vue">
<span v-if="message === 'A'">Aspan>
<span v-else-if="message === 'B'">Bspan>
<span v-else>Cspan>
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
let vue = new Vue({
el: "#vue",
data: {
message: "D"
}
})
script>
<div id="vue">
<li v-for="(item,index) in items">
{{item}}
li>
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
let vue = new Vue({
el: "#vue",
data: {
items: ["java", "html", "mysql", "redis"]
}
})
script>
<li v-for="(item,index) in items">
{{item}} -- {{index}}
li>
变种
<div id="vue">
<span v-for="item in items">
{{item.message}}
span>
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
let vue = new Vue({
el: "#vue",
data: {
items: [
{message: "java"},
{message: "html"},
{message: "mysql"},
{message: "redis"}
]
}
})
script>
java--0
html--1
mysql--2
redis--3
从此开始,vue.js的引入放入了head中
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
head>
vue会忽略checked,select的值,只取vue的data中的值
<div id="vue">
<select v-model="items">
<option disabled>请选择option>
<option>1option>
<option>2option>
<option>3option>
select>
<span>选中了{{items}}span>
div>
<script>
let vue = new Vue({
el: "#vue",
data: {
items: ""
}
})
script>
<div id="vue">
<button value="点我一下" v-on:click="test">button>
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script>
let vue = new Vue({
el: "#vue",
data: {
items: ["java", "html", "mysql", "redis"]
},
methods: {
test: function (){
<!--取值vue data中的items-->
for (let item in this.$data.items) {
alert(item)
}
}//test
}//method
})
script>
computed把结果缓存成一个值
<div id="vue">
<span>computed:{{getTime}}span>
<span>methods:{{getTime1()}}span>
div>
<script>
let vue = new Vue({
el: "#vue",
//computed把结果缓存成一个值,全部都能被methods替代
computed: {
getTime() {
return "时间戳" + Date.now();
}
},
//当重名时,默认调用methods
methods: {
getTime1: function () {
return Date.now();
}
}
})
script>
在控制台可以看到,computed是将值缓存到了本地
vue.getTime
'时间戳1652064179289'
//不刷新页面,多次运行,结果一样
vue.getTime
'时间戳1652064179289'
vue.getTime1()
1652064259827
//methods会刷新数据
vue.getTime1()
1652064266181
在线cdn
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
Vue - 生命周期详解 - 简书 (jianshu.com)
info中的格式:可以不写,但不要写错
<div id="vue">
<span>城市:{{info.address.city}}span>
<a :href="info.url">网址a>
div>
<script>
let vue = new Vue({
el: "#vue",
//该函数返回组件实例的 data 对象
data(){
return {
info: {
//数值可以不写,但是格式必须相同
url: null,
address: {
city: null
}
}
}
},
//vue数据挂载html模板完成后,做ajax的钩子函数,只会执行一次
mounted(){
//get实例:用response.data读取文件中的果断json数据,响应给info属性
axios.get("data/data.json").then(response=>(this.info = response.data));
}
})
script>
前端页面闪烁的问题解决方案
props中的属性名不能大写
<div id="vue">
<child v-for="item in items" v-bind:children="item">child>
div>
<script>
//组件名,组件实体
Vue.component("child",{
//传参
props: ['children'],
//模板
/**
* html标签及其中内容 最后都会变成小写
* 但是vue区分大小写
*/
template: "{{children}} "
})
let vue = new Vue({
el: "#vue",
data: {
items: ["java","mysql","html"]
}
})
script>
<div id="vue">
<child>
<slot1 slot="slot1" v-for="item in items" :item="item">slot1>
<slot2 slot="slot2" v-for="(item,index) in items" :index="index">slot2>
child>
div>
<script>
Vue.component("child",{
template: "\
\
\
"
})
//插槽1接收item数据
Vue.component("slot1",{
props: ['item'],
template: "元素:{{item}}---"
})
//插槽2接收index数据
Vue.component("slot2",{
props: ['index'],
template: "索引:{{index}}"
})
let vue = new Vue({
el: "#vue",
data: {
items: ["java","mysql","html"]
}
})
script>
实现功能:插槽中有个按纽,可以删除元素,但是删除的却是Vue实例中的对象元素
根据双向绑定原则,用前端来中介Vue实例和组件间的互相调用
vue.js中this.$emit的理解
<div id="vue">
<father v-on:test="removeItem(index)">
<child slot="child" v-for="(item,index) in items" :index="index">child>
father>
div>
<script>
Vue.component("father",{
//@click:绑定vue的点击单击监听
template: "\
\
\
\
",
methods: {
remove: function (index){
/**
把remove事件分发下去,传递参数index
当remove执行时,子级就会告知父级:触发自定义事件test,也就是Vue实例中的removeItem事件
*/
this.$emit("test",index);
}
}
})
Vue.component("child",{
props: ['index'],
template: "{{index}}"
});
let vue = new Vue({
el: "#vue",
data: {
items: ["java","mysql","html"]
},
methods: {
removeItem: function (index){
//从index位开始删除,一次删除一位
//可以增,删,改
this.$data.items.splice(index,1);
}
}
})
script>
splice使用https://blog.csdn.net/qq_44921114/article/details/108608851
node.js 理解成maven
使用阿里定制的cnpm命令行工具代替默认的npm,输入以下代码
安装成功之后,以后安装依赖包的方式和npm的是一样的,只是npm的命令换成是cnpm就可以了。
npm install -g cnpm --registry=https://registry.npm.taobao.org
检查是否安装成功:
$ cnpm -v
C:\Users\林木\AppData\Roaming\npm 包存放路径
出错了话,node.js会告诉怎么解决,直接执行他告诉你的代码就行
vue list查看可以用的包
第一个vue-cli程序
npm ERR! enoent ENOENT: no such file or directory, open ‘D:\package.json‘
异步加载模块,可以并行加载多个模块
理解成:把es6规范的前端项目,打包成es5规范
VUE-CLI Webpack安装使用
新建一个只有.idea的空项目
hello.js相当于java自定义类
//暴露一个sayHi方法给外界
exports.sayHi = function () {
//到时会在页面上写字
document.write("Hello webpack!
");
}
main.js程序主入口
//在当前目录下引入hello.js
var hello = require("./hello");
hello.sayHi();
webpack.config.js:主配置文件,webpack4.0后文件名要是webpack.config.js
//把模块导出去
module.exports = {
//入口:从哪里读取
entry: "./modules/main.js",
//输出到哪里
output: {
filename: "./js/bundle.js"
}
}
控制台运行 webpack 打包,然后会自动生成一个dist目录
测试页面引入生成的js文件,就是相当于引入hello.js
<script src="dist/js/bundle.js">script>
webpack : 无法加载文件 D:\nodejs\node_global\webpack.ps1,因为在此系统上禁止运行脚本
ERROR in Entry module not found: Error: Can’t resolve ‘./src’ in XXX的一个解决方案
webpack --watch热部署
理解成**@RequestMapping**
VueRouter路由安装使用
安装vue-router,保存到dev环境下,也就是config目录下
cnpm install vue-router --save-dev
自定义组件
Content.vue
<template>
<h1>Hello Vue-Router!This is my first VueContent.h1>
template>
<script>
//导出一个组件,名叫Content,也相当于命名当前组件为Content
export default {
name: "Content"
}
script>
<style scoped>
style>
Main.vue
<template>
<h1>Hello Vue-Router!h1>
template>
<script>
export default {
name: "Main"
}
script>
<style scoped>
style>
官方习惯把各种配置文件都叫index.js
router目录下的index.js
//导入文件和模块(从node_modules中导入),名字随意
import Vue from "vue"
import VueRouter from "vue-router"
import Main from "../components/Main"
import Content from "../components/Content";
//上面的Vue实例安装路由(添加插件)
Vue.use(VueRouter)
//将路由实例化并导出
export default new VueRouter({
routes: [
{
//地址栏输入路径后,将跳转到Content组件
path: "/content",
name: "Content",
component: Content
},
{
path: "/main",
component: Main
}
]
})
main.js Vue项目的主配置文件
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
//自动扫描目录下的index.js文件
import router from './router/index'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
//使用路由,也相当于导入所有路由
router,
components: { App },
template: ' '
})
App.vue 项目的主界面
<template>
<div id="app">
<router-link to="/main">首页router-link>
<router-link to="/content">内容页router-link>
<router-view>router-view>
div>
template>
<script>
export default {
name: 'App'
}
script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
style>
npm run dev 运行打包项目
VueRouter报错:Uncaught TypeError: Object(…) is not a function
//安装element-ui
cnpm i element-ui -S
//安装依赖
cnpm install
//安装SASS加载器( 强化 CSS 的辅助工具 ,强化CSS功能)
cnpm install sass-loader node-sass --save-dev
npm run dev
去element-ui官网,复制他们的代码
ElementLogin.vue(自定义登录组件)
<template>
<div>
<el-form ref="loginForm" :model="form" :rules="rules" label-width="80px" class="login-box">
<h3 class="login-title">欢迎登录h3>
<el-form-item label="账号" prop="username">
<el-input type="text" placeholder="请输入账号" v-model="form.username"/>
el-form-item>
<el-form-item label="密码" prop="password">
<el-input type="password" placeholder="请输入密码" v-model="form.password"/>
el-form-item>
<el-form-item>
<el-button type="primary" v-on:click="onSubmit('loginForm')">登录el-button>
el-form-item>
el-form>
<el-dialog
title="温馨提示"
:visible.sync="dialogVisible"
width="30%"
:before-close="handleClose">
<span>请输入账号和密码span>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="dialogVisible = false">确 定el-button>
span>
el-dialog>
div>
template>
<script>
export default {
name: "Login",
data() {
return {
form: {
username: '',
password: ''
},
// 表单验证,需要在 el-form-item 元素中增加 prop 属性
rules: {
username: [
{required: true, message: '账号不可为空', trigger: 'blur'}
],
password: [
{required: true, message: '密码不可为空', trigger: 'blur'}
]
},
// 对话框显示和隐藏
dialogVisible: false
}
},
methods: {
onSubmit(formName) {
// 为表单绑定验证功能
this.$refs[formName].validate((valid) => {
if (valid) {
// 使用 vue-router 路由到指定页面,该方式称之为编程式导航
this.$router.push("/main");
} else {
this.dialogVisible = true;
return false;
}
});
}
}
}
script>
<style lang="scss" scoped>
.login-box {
border: 1px solid #DCDFE6;
width: 350px;
margin: 180px auto;
padding: 35px 35px 15px 35px;
border-radius: 5px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
box-shadow: 0 0 25px #909399;
}
.login-title {
text-align: center;
margin: 0 auto 40px auto;
color: #303133;
}
style>
配置router
//导入element-ui模块,和css文件
import Element from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import ElementLogin from "../components/ElementLogin";
Vue.use(Element);
export default new VueRouter({
routes: [
{
path: "/login",
component: ElementLogin
}
]
})
main.js改变App.vue的生成方式为适配Element
new Vue({
el: '#app',
router,
//ES6的写法,就是生成一个叫App的节点,挂载到根节点上.
//https://www.jianshu.com/p/0ea899e233a9
render: h => h(App)
})
App.vue使用组件
<template>
<div id="app">
<router-link to="/login">登录router-link>
<router-view>router-view>
div>
template>
运行发布npm run dev
Module build failed: TypeError: this.getOptions is not a function 安装node-Sass报错
或者官方会告诉你用哪个版本Module build failed: Error: Node Sass version 7.0.1 is incompatible with ^4.0.0.
cnpm install [email protected] --save-dev
自动生成网站,文档 文档化 (docsify.js.org)
就是在将一个组件 放到 另一个组件下
index.js
export default new VueRouter({
routes: [
{
path: "/main",
component: Main,
//路由嵌套,最后访问/login时,必须是在/main下
children: [
{
path: "/login",
component: ElementLogin
}
]
}
})
main.vue
<template>
<div>
<h1>Hello Vue-Router!h1>
<router-link to="/login">登录router-link>
<router-view>router-view>
div>
template>
取值时,所有的元素必须被标签包裹
App.vue
<router-link :to="{name:'login',params:{id:1}}">登录router-link>
路由index.js
routes: [{
//访问路径时必须携带有id的参数
path: "/login/:id",
name: "login",
component: ElementLogin
}
]
直接接收参数
<h1>{{$route.params.id}}h1>
index.js
name: "login",
//允许传递参数
//当 props 设置为 true 时,route.params 将被设置为组件的 props。
props: true,
在被跳转页面中用props接收对应的参数,可直接使用
<h1>{{id}}h1>
export default {
name: "Login",
props: ['id'],
登录页面在导出中携带页面表单中的参数
export default {
name: "Login",
data() {
return {
form: {
username: '',
password: ''
},
// 表单验证,需要在 el-form-item 元素中增加 prop 属性
rules: {
username: [
{required: true, message: '账号不可为空', trigger: 'blur'}
],
password: [
{required: true, message: '密码不可为空', trigger: 'blur'}
]
},
// 对话框显示和隐藏
dialogVisible: false
}
},
methods: {
onSubmit(formName) {
// 为表单绑定验证功能
this.$refs[formName].validate((valid) => {
if (valid) {
// 使用 vue-router 路由到指定页面,该方式称之为编程式导航
//到达指定页面时携带参数
this.$router.push("/main/"+this.form.username);
} else {
this.dialogVisible = true;
return false;
}
});
}
}
}
index.js路由中配置参数列表
path: "/main/:name",
props: true,
component: Main
使用
<template>
<div>
<h1>{{name}}</h1>
</div>
</template>
<script>
export default {
name: "Main",
props: ['name']
}
</script>
routes: [{
path: "/element",
component: ElementLogin
}, {
path: "/login",
name: "login",
props: true,
//重定向
redirect: "/element"
}
]
//当在所有path中都不能匹配时,跳转
path: "/*",
component: Main
hash:路径带#符号
history:路径不带#符号
路由的index.js
export default new VueRouter({
mode: "history",
routes: [
vue-axios|axios中文网 | axios (axios-js.com)
测试目录一般叫mock,放在static目录下
安装axios模块:cnpm install axios,cnpm install vue-axios
导入axios模块
import Axios from "axios"
import VueAxios from "vue-axios"
//必须先绑定VueAxios,再是Axios
Vue.use(VueAxios,Axios)
export default {
name: "Main",
beforeRouteEnter: (to, from, next)=>{
console.log("进入路由之前");
//vm实现调用methods中的方法后再放行
next(vm => {
vm.getData();
});
},
beforeRouteLeave: (to, from, next)=>{
console.log("进入路由之后");
next();
},
methods: {
getData: function (){
//get方式请求文件
this.axios({
method: "get",
url: "../../../static/mock/data.json"
}).then(function (response){
//会请求到的数据封装到response中
console.log(response);
})
}
}
}