渐进式框架 -Vue.js
分离与不分离的好与坏
前后端分离后 后端仅返回前端所需的数据,大部分业务逻辑都是通过前端进行校验
不再渲染HTML页面,不再控制前端的效果,页面由页面服务器请求返回
而具体的数据通过JS去应用服务器去数据库请求得到
优点:减少页面的请求,页面无需去后端请求,最多去静态文件服务器拿到
前后端分工清晰,大项目开发维护教简单
缺点: 小项目如果使用前后端分离 前后端沟通成本加大
Vue初识
1.Vue 一个渐进式JS框架 实现单页面开发
一个页面小到一个变量,一个变量代表一个页面,大到整个项目通过Vue来控制
2.页面的切换不再是请求url 而是组件的替换,替换一个组件就是替换一个页面
3.从数据角度考虑标签 而不是一个标签
Vue的使用
挂载点一般定义成一个页面,一个el只对第一个 标签有效,所以挂载点一般为id
一个页面出现多个挂载点,但是一个Vue实例操作一个挂载点
所以一个el 指代一个挂载点
像{{}} 和 属性里 以 v-* 打头的都会被Vue拦截
Vue替换插值处
<div id="app"> <!-- {{ vue变量 }} 插值表达式 --> <h1>{{ h1_msg }}</h1> <h2>{{ h2_msg }}</h2> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el: '#app', // 挂载点 data: { // 为挂载点的页面结构提高数据 h1_msg: 'h1的内容', h2_msg: 'h2的内容', } }) </script>
Vue 会识别{{ name }} 里的name会被当作插值处, 去Date找到属性,替换成真正的内容
Vue使用事件和once指令
知识点:
this 可以拿到当前的 Vue对象 要拿到实例属性可以通过 this.$date.插值名
v-on:事件=“函数” 只要触发事件就会执行Vue实例的methods里的函数方法
v-once:被插值后 就无法改变
{{}} 相当于 v-text 文本
v-html 就是html 代码块
插值处可以通过索引 data[1] 拿到data 列表里具体的值
@事件 可以代替 v-on:事件
<div id="app"> <div v-on:click="pclick" >{{ msg }}}</div> </div> </body> <script src="Vue.js"></script> <script> let app =new Vue({ el:"#app", data:{ msg:"adas", }, methods:{ pclick:function () { alert(123); this.msg="hahahaha" } } }) </script>
这样就可以通过变量 驱动页面
方法传参
所有click触发效果可以绑定到一个函数里,但是我们怎么区分那个按钮点击的呢 通过传参?
形参和实参数量可以不统一
实参如果是只有函数名的话 会把Event传过去 函数名() ,如果想传事件 又想传参就得加 $event.
<div id="app"> <button v-on:click="tanchukuang(1)" v-text="h1">{{ h1 }}</button> <button v-on:click="tanchukuang(2)" v-text="h2">{{ h2 }}</button> </div> </body> <script src="Vue.js"></script> <script> let app=new Vue({ el:"#app", data:{ h1:"弹出框1", h2:"弹出框2" }, methods:{ tanchukuang:function (xxx) { alert(xxx) } } }) </script>
Vue操作属性
知识点:
v-bind:属性 和 :属性一样 如果属性值还是键值对形式 那么插值形式可以为字典
多个类 可以通过元祖的形式 class="[a1,a2]" 来表示两个 两个类 style:”{fontsize:a1,color:a2}“
<div id="app"> <button v-on:click="tanchukuang(1)" :style="xxxx" >{{ h1 }}</button> <button v-on:click="tanchukuang(1)" style="color: yellow" >{{ h1 }}</button> </div> </body> <script src="Vue.js"></script> <script> let app=new Vue({ el:"#app", data:{ h1:"弹出框1", h2:"弹出框2", xxxx:"color:yellow" }, methods:{ tanchukuang:function (xxx) { alert(xxx) } } })
变为false 之后
表单指令
v-model 控制着表单的value值 input框的value也会改变model
点击会改变 v-model的值 是个双向绑定的过程
单选框radio 万一和它的value值 相同那么就会被选上
在checked中 如果是单个的 v-model 追随为 true-value | false-value 的值 如果复选的checkbox 那么就是追随values
```html <div id="app"> <!-- v-model针对于表单元素 --> <form action="" method="get"> <!-- 1、双向绑定:服务于文本输入框 --> <!-- v-model存储的值为输入框的value值 --> <div> <input type="text" name="usr" v-model="in_val"> <input type="password" name="ps" v-model="in_val" > <textarea name="info" v-model="in_val"></textarea> </div> <!-- 2、单选框 --> <div> <!-- 单选框是以name进行分组,同组中只能发生单选 --> <!-- v-model存储的值为单选框的value值 --> 男:<input type="radio" name="sex" value="男" v-model="ra_val"> 女:<input type="radio" name="sex" value="女" v-model="ra_val"> {{ ra_val }} </div> <!-- 3、单一复选框 --> <!-- v-model存储的值为true|false --> <!-- 或者为自定义替换的值 --> <div> <input type="checkbox" v-model='sin_val' true-value="选中" false-value="未选中" /> {{ sin_val }} </div> <!-- 4、多复选框 --> <!-- v-model存储的值为存储值多复选框value的数组 --> <div> <input type="checkbox" value="喜好男的" name="cless" v-model='more_val' /> <input type="checkbox" value="喜好女的" name="cless" v-model='more_val' /> <input type="checkbox" value="不挑" name="cless" v-model='more_val' /> {{ more_val }} </div> </form> </div> <script type="text/javascript"> new Vue({ el: '#app', data: { in_val: '', // 默认值可以决定单选框默认选项 ra_val: '男', // 默认值为true,单一复选框为选中,反之false为不选中 sin_val: '', // 数组中存在的值对应的复选框默认为选中状态 more_val: ['喜好女的','不挑'] } }) </script>
条件指令
里面传递判断来决定该标签是否展示
<div v-if="true">111</div> <div v-else-if="false">222</div> <div v-else>222</div> #必有一个执行 要么if 执行 要么else执行 如果两个都不执行才执行第三个
循环指令
可以循环
列表拿到 值和索引
<li v-for="(num, index) in nums">{{ num }} {{ index }}</li> #循环第一个拿到的是数值 第二个才是索引
<li v-for="num in nums">{{ num }}</li>
字典 拿到
<li v-for="(v, k, i) in people">{{ v }} {{ k }} {{ i }}</li> #循环的是值 建 索引
解决插值表达式符号冲突
new Vue({
el: '#app',
data: {
msg: '12345'
},
delimiters: ['${', '}']
})
computed 返回值取决于局部作用域变化
里面出现的标签每发生一次变化就触发一次方法
data:{"i1":"1",i2:"2"}
computed:{
i3:function(){
return self.i1 + self.i2
}
}
watch 监听
watch 可以监控里面所有的插值值 插值值没发生一次变化就触发对应的函数
注意每个元素都必须在data出现
<div id="app01"> <input type="text" v-model="i1" > <input type="text" v-model="i2" > <input type="text" v-model="i3" > </div> </body> <script src="sadasd.js"></script> <script > new Vue({ el :"#app01", data:{ i1:"", i2:"", }, watch:{ i1:function () { alert("i1变化") }, i2:function () { alert("i2变化") } } }) </scrip
局部组件
是一个html代码 css js的集合体
知识点:
1.局部组件只有在挂载点里面使用
2.因为局部的原因 我们的组件是为了服用,所以数据要独立 所以data 是一个函数 有名称空间 返回一个字典
3. -单词 就可以匹配成大写的 A-aA ---> AAA
<a-bc></a-bc> ----> aBc
实例一个Vue对象 ,通过components注册局部组件
new Vue({
el:"#app",
components:{"abc":localTag}
})
一定要在Vue 上面!!!!
let localTag={ template'<div>111<div>' }
去通过 注册的别名来使用
<abc></abc>
全局组件
不需要在挂载点里面
Vue.component("aBc",{ template:"<div>111</div>", }); 无需注册
组件父传子
组件子传父
1.通过钩子 this.$emit("recv",this.my_info) 去触发 父组件的 方法
2.会把第二个参数传递 给 get_name
<div id="app01"> <abc @recv="get_name"></abc> <div>{{msg1}}</div> </div> </body> <script src="sadasd.js"></script> <script > Vue.component("abc",{ data:function () { return{my_info:""} }, template:`<div> <input type="text" v-model="my_info" > <input type="button" @click="cccc"> </div>`, methods:{ cccc:function () { this.$emit("recv",this.my_info) }, } }); new Vue({ el:"#app01", data:{ msg1:"" }, methods: { get_name:function (msg) { this.msg1=msg}, } }) </script>
使用服务器请求资源
既然我们要使用到单页面开发 Django的不在发挥出他的优势 我们需要寻找一种轻量级的,且最好能更好的和前端打交道的服务器
此时我们使用到了JavaScript语言的服务器 Node.js ,他的居然把 V8的引擎搬到了他的Node.js上,这也是第一次有人把前端的语言作为服务器
所以Node.js没有自己的语言,就因为他使用了强大的V8引擎,所以这一小个东西,就能发挥极强的优势
1.一个Node,js只是一个单线程 2.非阻塞io 3.事件驱动
我们就可以做到点击某个按钮跳转到其他页面就不需要请求url 而是组件的替换
需要做 安装(见我的Node.js专题栏)
以及 配置nmp为国内镜像 npm install -g cnpm --registry=https://registry.npm.taobao.org
搭建 Vue架子脚 cnpm install -g @vue/cli
起步
1.cd 项目路径
2.vue create 目录名
3.选择自定义
4.Y/N 选择大写的 ,其他都为选择第一个
5勾选 Babel jsES6语法转换ES5,Router路由 Vuex组件数据交互 Formatter格式化代码
6.完成后启动server (开发过程使用 IDE可以事实更新 npm run serve )
"""
node_modules:依赖
public:共有资源
ico:页面标签的logo
html:单页面 - 整个项目的唯一页面
src:代码主体
...:项目、插件等相关配置
"""
""" src
assets:静态资源
components:小组件
views:视图组件
App.vue:根组件
main.js:主脚本文件
router.js:路由脚本文件 vue-router
store.js:仓库脚本文件 vuex
"""
<template> <!-- 只能有一个根标签 --> html </template> <script> export default { name: "Main", data: function() { return { } }, ... } </script> <style scoped> #css作用域 /* scoped */ </style>
根组件导入自组件
<!-- App.vue根组件 --> <template> <div id="app"> <!-- 3.使用 --> <Main></Main> </div> </template> <script> // 1.导入 import Main from '@/views/Main' export default { // 2.注册 components: { Main: Main } } </script> <style> html, body { margin: 0; } </style>
组件的使用与跳转
挂载点内部 可以使用注册的name 来使用组
件 <div id="app"> <!-- 3.使用 --> <Main></Main> #必须导入之后使用 </div>
<router-link to="/home">home</router-link>会根据URL进行组件的替换 #需要在main.js里配 <router-view/>会根据当前页url 放置组件 例如 V1在main.js 对应组件1 那么url为xxx时 对应的就是这个组件
生命周期钩子以及发送AJax
生命周期钩子
钩子是个回掉函数 当触发某个条件是 会执行,那么生命周期钩子就是在组件的出现阶段调用的函数
创建之前调用这个 创建时立马调用这个 创建之后调用另一个
beforeCreate () {
console.log("实例刚刚创建");
console.log(this.msg
},
created () {
console.log("实例创建成功, data, methods已拥有");
console.log(this.msg);
},
mounted () {
console.log("页面已被vue实例渲染, data, methods已更新");
}
// 拿到需求 => 确定钩子函数 => 解决需求的逻辑代码块
AJax
1.下载npm install axios--save
2.main.js 配置全局Vue添加ajax属性
import Axios from "axios"
Vue.prototype.$ajax = Axios;
new Vue(){} 之前
3.使用
mounted () {
window.console.log('Goods组件渲染完毕');
this.aaaa = 12345;
window.console.log(this.aaaa);
// 请求后台
let _this = this;
this.$ajax({
url: 'http://127.0.0.1:8000/goods/',
method: 'post',
params: {
info: '前台数据'
}
}).then(function (result) {
let data = result.data;
// this 指向的是then的function
_this.aaaa = data;
})
}
跨域问题
django有csrf_token了 但是还是无法相信绝对安全的跨域请求
通常情况下,A网页访问B服务器资源时,不满足以下三个条件其一就是跨域访问
1. 协议不同
2. 端口不同
3. 主机不同
1. 安装django-cors-headers模块
2.# 注册app
INSTALLED_APPS = [
...
'corsheaders'
]
3 添加中间件
MIDDLEWARE = [
...
'corsheaders.middleware.CorsMiddleware'
]
4# 允许跨域源
CORS_ORIGIN_ALLOW_ALL = True