赞
踩
我没系统学过VUE和element-ui,都是要用了再官网上查找,或者百度
再普通vue中调用方法是标签中写@click="方法名"
,然后再在方法中vue实例中
methods:{
方法名(){
alert("123");
//code...
}
}
但是在element-ui元素中,要 @click.native=方法名"
,调用的一样
<template> <el-pagination background layout="prev, pager, next" :total="1000" @click.native="showSome"> </el-pagination> </template> <script> export default { methods:{ showSome(){ alert("") } } }; </script>
还是上面那个例子,打开官网往下走,看到
这个current-page参数就是页数,那么事件往下面翻
看到,current-page改变时,事件名为current-change,并且有个回调参数为当前页,那么
<el-pagination background layout="prev, pager, next" :total="1000" @current-change="page"> </el-pagination> <script> export default { methods:{ page(currPage){ alert(currPage) } } }; </script>
@click
而是 @current-change
,因为上面也说了事件是这个。。然后这个事件,定义个方法名吧,就叫page
,在下面写方法page,其有个回调参数,参数名就自己瞎写了,就可以用到了使用分页功能的时候,其有个属性为page-size
(每页显示条目个数),这个记得设置,不然默认是10 ,然后:total
是(总数目),这个也要记得设置,然后页数就是:total
/page-size
就是点击一个按钮,路由改变,并且传递参数
其跳转传值有:<router-link>
直接传值跳转 和 方法内的this.$route.push(query:{})
接受值有2中方法,是params和query接受
所以是2*2=4种跳转传值方法
路由:
{
path:'/test',
name:'Test',
component:Test
},{
//占位符
path:'/test/:id',
name:'Test2',
component:Test2
}
<!-- test --> <template> <div> 我是test1 <!-- 1、直接通过 router-link 加上地址传值,id就是用到占位符了--> <router-link :to="'/test/'+id">点我跳转</router-link> </div> </template> <script> export default { name: "Test", data() { return { id:123 } } } </script>
<!-- test2 --> <template> <div> 我是跳转的 <h2>{{id}}</h2> <h2>{{this.$route.params.id}}</h2> </div> </template> <script> export default { computed:{ id(){ //从路由中的占位符拿到数据 return this.$route.params.id } } } </script>
这是用computed方式的,用created来接受然后赋值也是可以的
这个就不要用到路由注册表了,用一般的就行
{
path:'/test',
name:'Test',
component:Test
},{
path:'/test2',
name:'Test2',
component:Test2
}
<!-- test --> <template> <div> 我是test1 <!-- 一样是 :to ,但是又path和query,query传对象的 --> <router-link :to="{ path:'/test2', query:this.person}"> 点我跳转</router-link> </div> </template> <script> export default { name: "Test", data() { return { person:{ name:'lihua', id:666 } } } } </script>
<!-- test2 --> <template> <div> 我是跳转的 <h2>name:{{person.name}}</h2> <h2>id:{{person.id}}</h2> <h2>{{this.$route.query}}</h2> </div> </template> <script> export default { computed:{ person(){ //用this.$route.query来接受刚才传过来的值 return this.$route.query } } } </script>>
这个还是要占位符的
{
path:'/test',
name:'Test',
component:Test
},{
//占位符
path:'/test/:id',
name:'Test2',
component:Test2
}
<!-- test --> <template> <div> 我是test1 <!-- 1、用点击事件去完成--> <button @click="tourl">点我跳转</button> </div> </template> <script> export default { name: "Test", data() { return { id:666 } }, methods: { tourl(){ //点击事件,就传送到xxx + id this.$router.push('/test/'+this.id) } } } </script>
<!-- test2 --> <template> <div> 我是跳转的 <h2>{{id}}</h2> <h2>{{this.$route.params.id}}</h2> </div> </template> <script> export default { computed: { id() { //从路由中的占位符拿到数据 return this.$route.params.id } } } </script>
{
path:'/test',
name:'Test',
component:Test
},{
path:'/test2',
name:'Test2',
component:Test2
}
<!-- test --> <template> <div> 我是test1 <button @click="tourl">点我跳转</button> </div> </template> <script> export default { name: "Test", data() { return { person:{ name:'lihua', id:666 }, } }, methods: { tourl(){ this.$router.push({ //一样又path和query,然后那边就query接受 path:'/test2', query:this.person }) } }, } </script>
<!-- test2 --> <template> <div> 我是跳转的 <h2>name:{{person.name}}</h2> <h2>id:{{person.id}}</h2> <h2>{{this.$route.query}}</h2> </div> </template> <script> export default { computed: { person() { return this.$route.query }, } } </script>
总的来说,query是接受对象,params接受一个key的。
router-link用来做a标签的简单跳转,$router.push用在方法里面更灵活
params需要路由占位符,query不需要
在方法中使用this.$router.push("/xxx")
,就可以跳到指定路径,从而配合router-view
.
1. 不带参数 this.$router.push('/home') this.$router.push({name:'home'}) this.$router.push({path:'/home'}) 2. query传参 this.$router.push({name:'home',query: {id:'1'}}) this.$router.push({path:'/home',query: {id:'1'}}) // html 取参 $route.query.id // script 取参 this.$route.query.id 3. params传参 this.$router.push({name:'home',params: {id:'1'}}) // 只能用 name // 路由配置 path: "/home/:id" 或者 path: "/home:id" , // 不配置path ,第一次可请求,刷新页面id会消失 // 配置path,刷新页面id会保留 // html 取参 $route.params.id // script 取参 this.$route.params.id 4. query和params区别 query类似 get, 跳转之后页面 url后面会拼接参数,类似?id=1, 非重要性的可以这样传, 密码之类还是用params刷新页面id还在 params类似 post, 跳转之后页面 url后面不会拼接参数 , 但是刷新页面id 会消失
el-menu
标签中添加router
属性这个方法不一定实用于所有,因为el-menu中有el-menu-item子标签,而这个子标签的index属性就是跳转的路径,这个是特殊的
el-menu
标签添加router
属性router-view
el-menu-item
为选项的标签,其index
值就是跳转的router传
<router-link
:to="{
path:'/qa/'+ problem.id,
params:{
id:problem.id
}
}">{{problem.title}}</router-link>
/qa/id
加上id号跳转收:
mounted() {
this.problem.id = this.$route.params.id
console.log(this.problem.id)
}
在路由弄一个占位符,然后跳到这里时,根据url获得值
在router 的index.js中
{
path: '/spit',
name: 'SpitIndex',
component:SpitIndex
},{
path:'/spit/:id',
name:'SpitItem',
component:SpitItem
}
//spit.vue
<router-link :to="'/spit/'+spit._id">{{spit.content}}</router-link>
这里跳转就传如ID了
在跳到到另外一个页面的时候
///spit/:id
console.log(this.$route.params.id)
//打印出跳转的ID
<template slot-scope="scope">
这个东西,很神奇,一般这样用,只能用于template的属性
<el-table :data="tableData" border style="width: 40%"> <el-table-column fixed prop="id" label="ID" width="150"> </el-table-column> <el-table-column prop="name" label="姓名" width="120"> </el-table-column> <el-table-column prop="author" label="作者" width="120"> </el-table-column> <el-table-column fixed="right" label="操作" width="100"> <template slot-scope="scope"> <el-button @click="handleClick(scope.row)" type="text" size="small">查看</el-button> <el-button type="text" size="small">编辑</el-button> </template> </el-table-column> </el-table> <script> export default { methods: { test(){ this.$router.push("/addbook") } } } </script>
点一下查看,就是26.27行的那些代码,定义了一个slot-scope="scope"
,利用什么滚动的。。我也不懂。然后下一行@click="handleClick(scope.row)"
,表示点这个查看用到这个方法,并且有个参数,方法中,传的这个scopne.row
,可以展示这个框的数据
就是复用代码了
使用步骤
import xxx from "xxxx";
<xxx></xxx>
方案1、在main.js中引入方式(全局)
import '@/assets/css/reset.css'
方案2、在.vue文件的
@import "../assets/css/index.css";
根目录的.eslintrc.js
module.exports = { root: true, env: { node: true }, 'extends': [ // 'plugin:vue/essential', '@vue/standard' ], rules: { // 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', // 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off' }, parserOptions: { // parser: 'babel-eslint' } }
有时候用了float后,button就不起作用了,style加上这个
style="display: inline-block;"
父
<template> //用了子组件,传一个key为id,value则为bookid的值,传给子组件读取 <UserData :id="bookid"></UserData> </template> <script> import UserData from '../../components/UserData' export default { name: "FriendIndex", components: { //加载儿子 UserData }, data(){ return{ bookid:123 } } <script>
子:
<template> <div> //这里读取id,而这个id就是在子组件的props中拿到的 {{id}} </div> </template> <script> export default { name: "", //这里的props为数组形式,不是一个数组形式,就是保存父给子的key,写在这里 props:["id"], } </script> <style scoped> </style>
对象的更好,在第一个方法的基础上,添加了限定类型和默认值,其中,类型可以有
父
<template> //用了子组件,传一个key为id,value则为bookid的值,传给子组件读取 <UserData :bookName="bookName" :price="price" :stroe="stroe" :obj="obj" :doubleType="doubleType"></UserData> </template> <script> import UserData from '../../components/UserData' export default { name: "FriendIndex", components: { //加载儿子 UserData }, data(){ return{ bookName:'金瓶梅', price:666, stroe:['新华书店','旧华书店'], obj:{ msg:'hello' }, doubleType:'123' } } <script>
子:
<template> <div> //这里读取id,而这个id就是在子组件的props中拿到的 书名:{{bookName}} 价格:{{price}} </div> </template> <script> export default { name: "", //props变为对象形式,更方便 props:{ //单单限制类型 bookName:String, //限制类型并且提供默认值 price:{ type:Number, default:0, //表示这个key值必须传东西进来 required:true }, //如果是数组或者对象类型,那么默认值是要写一个函数返回的类型 stroe:{ type:Array, default: () => [] }, //对象类型 obj:{ type:Object, default(){ msg:'hello' } }, //即可是数组,也可是数字 doubleType:[String,Number] } } </script> <style scoped> </style>
就直接{{}}
可以显示数据,但是在方法或者created中想用就用不了,
就很诡异,没有值,原因是这父传子需要异步处理,所以有时候会延迟,导致传不了数据到子组件的created和mounted,所以解决办法是在子组件加上个v-if
进行判断
如
//在后面加个判断,这样有才进行传值,就不会异步了
<LastPhysicalCardSale :date="lastDate" v-if="lastDate"/>
比如发生点触事件,传值给父组件给父组件显示
思路为,子组件写一个@click点击事件
,事件里面写this.$emit(事件名,要传的参数)
,这里就完成了发送事件。
接着就是在父组件里面写一个事件 用于接受参数 的函数,函数的参数就是接受到的数
父
<template> <div> //3、父组件用到子组件,父传子的话要加一个 @事件 的监听事件,事件名是子组件中$emit定义的,函数名就自己写 <TestSon @itemClick="sonClick"></TestSon> {{ball}} </div> </template> <script> import TestSon from './testSon.vue' export default { name: "Test", data() { return { ball:'' } }, methods: { //4、这里父接受子的事件,函数写一个参数就能接受到了 sonClick(item){ console.log('item',item) this.ball=item } }, components:{ TestSon } } </script>
子
<template> <div> //1、点击事件触发函数,传值给父组件,用@click, <button v-for="item in list" @click="btnClick(item)">{{item}}</button> </div> </template> <script> export default { name: "TestSon", data() { return { list:['篮球','足球','羽毛球'] } }, methods: { //2、写函数,里面一定要这样写 this.$emit('父组件接受的事件',值) //注意是父组件接受的事件而不是函数 btnClick(item){ this.$emit('itemClick',item) } }, } </script>
点篮球
点足球
访问是只能拿到值,读取,并且可以调用方法
父
<template> <div> <TestSon ></TestSon> <button @click="btnClick">按钮</button> </div> </template> <script> import TestSon from './testSon.vue' export default { name: "Test", data() { return { } }, methods: { //2、父组件访问子组件通过$children访问,得出结果是个数组,可以拿到子组件的很多东西 btnClick(){ console.log('父组件打印子组件',this.$children) console.log('父组件打印子组件的变量:'+this.$children[0].message); this.$children[0].showMessage() } }, components:{ TestSon } } </script> <style scoped> </style>
子
<template> <div> </div> </template> <script> //1、子组件这里只提供一个变量和方法,示范是父组件访问子组件的变量和方法 export default { name: "TestSon", data() { return { message:'这是一句话' } }, methods: { //这是一个方法 showMessage(){ console.log('子组件里面打印:'+this.message) } }, created() { }, props:{ } } </script> <style scoped> </style>
打印子组件可以有很多东西的
比如父组件写很多个子组件
<TestSon ></TestSon>
<TestSon ></TestSon>
<TestSon ></TestSon>
$children
是一个数组,取第二个的值是
this.$children[1]
这样取的,但是如果某一天在第一个后面插入一个子组件,那么数组下标就变了,所以很不人性化,这时候就要使用$refs
了
因为$children
的缺陷,$children
是数组形式,$refs
是使用key的形式,每一个子组件加一个ref
标识,在读取的时候根据ref
名字读取即可
子和上面的一样
父
<template> <div> <TestSon ></TestSon> //1、给每一个子组件加一个ref的名字 <TestSon ref="son1"></TestSon> <TestSon ref="son2"></TestSon> <button @click="allSon">按钮1</button> <button @click="oneSon">按钮2</button> </div> </template> <script> import TestSon from './testSon.vue' export default { name: "Test", data() { return { } }, methods: { allSon(){ //2、this.$refs 就是打印全部子组件了 console.log(this.$refs); }, oneSon(){ //3、this.$refs.名字 就是打印某一个子组件的东西了 console.log(this.$refs.son1); console.log(this.$refs.son1.message); this.$refs.son1.showMessage() } }, components:{ TestSon } } </script> <style scoped> </style>
点击按钮1
点击按钮2
其实子访问父的很少的
父
<template> <div> <TestSon></TestSon> </div> </template> <script> import TestSon from './testSon.vue' export default { name: "Test", data() { return { message:'我是父组件的一句话' } }, components:{ TestSon } } </script>
子
<template> <div> <button @click="fu">按钮</button> </div> </template> <script> export default { name: "TestSon", data() { return { message:'这是一句话' } }, methods: { fu(){ console.log(this.$parent); } }, } </script>
这是获取父的
获取根,最上级的那个
<template> <div> <button @click="fu">按钮</button> </div> </template> <script> export default { name: "TestSon", data() { return { message:'这是一句话' } }, methods: { fu(){ console.log(this.$root); } }, } </script>
//普通地
localStorage.setItem("下标",值);
localStorage.setItem("holiday_start_date",that.holiday_time[0]);
//如果值是对象的话,先转换
localStorage.setItem("下标",JSON.stringify(值));
localStorage.setItem("holiday_emp",JSON.stringify(response.data.data[0]));
//普通
localStorage.getItem("下标")
localStorage.getItem("is_week")
//对象,
var xx = (JSON.parse(localStorage.getItem("下标")))
var id = (JSON.parse(localStorage.getItem("holiday_emp"))).id;
localStorage.removeItem("下标")
setUserInfo(mobile){
var that = this
var user = {mobile:mobile}
}
数据库是datetime 的2021-03-27 15:25:39,页面显示的是1616858739000
npm install moment --save
main.js中添加
import Moment from 'moment'
// 定义全局时间戳过滤器
Vue.filter('formatDate', function(value) {
return Moment(value).format('YYYY-MM-DD HH:mm:ss')
})
然后在用的地方
<span class="el-icon-time">注册时间{{user.regdate | formatDate}}</span>
14的时间格式书写就是用过滤器来写的,一般是这么写的
{{参数| 过滤器名}}
data: {
},
filters:{
过滤器名(参数){
return 一般是返回什么格式的
}
}
不用每个过滤器都写在一个组件啦,全局配置一个,大家都能用
//main.js
import * as filters from './filters'
Object.keys(filters).forEach(key => {
Vue.filter(key, filters[key])
})
// src/filter/index.js
import Moment from 'moment'
import {trans_tp, payment_type} from '@/views/scenesPay/dict'
/**
* @param {日期} dateStr
* @param {格式化模式} pattern
*/
export function dateFormat(dateStr, pattern) {
if (!dateStr) return ''
return Moment(dateStr).format(pattern)
}
然后平时用就{{ a | dateFormat }}
这样使用
<el-pagination
background
layout="prev, pager, next"
:total="hotListTotal"
page-size="5"
@current-change="pageHot">
</el-pagination>
@current-change="pageHot"
点击页数的时候,触发的函数首页加载时,创建这个函数
getNewProblemList(){
var that = this
axios.get('http://192.168.12.128:9012/qa/problem/newlist/1/5').then(function(response) {
if(response.data.flag==true){
//数据
that.$data.problemNewList = response.data.data.rows
//总有多少条数据
that.$data.newListTotal = response.data.data.total
}
console.log(response);
})
},
记得在data加上newListTotal 和problemNewList
到这里,获得了多少个函数和初始化了,接下来就是点击页数的时候,触发的函数
//当被点击页数的时候,跳转
pageHot(currPage){
var that=this;
axios.get('http://192.168.12.128:9012/qa/problem/hotlist/'+currPage+'/5').then(function (response) {
if(response.data.flag==true){
//数据覆盖
that.$data.problemHotList = response.data.data.rows
}
console.log(response);
})
},
这个B,这个参数和平时的不一样
平时是
var tempData={
userid:userid
}
axios.post('http://192.168.12.128:9012',tempData).then(function (response) {
console.log(response);
})
而delete是
var tempData = {
userid:JSON.parse(localStorage.getItem("userInfo")).id,
targetuser:targetuser
}
axios.delete('http://192.168.12.128:9012/user/user/follow',{data:tempData}).then(function(response) {
if(response.data.flag==true){
// that.$message("删除成功")
}
that.$message(response.data.message)
console.log(response);
})
就比如
<router-link :to="'/user/'+problem.userid">提出
一个跳转这里使用动态id,比如problem.userid
值为5
,就会跳转到/user/5
,而跳到那个页面,怎么获取这个5呢?
先在路由写
{
path:'/user/:id' ,
name:'UserItem',
component:UserItem
}
:id
是一个占位符<template> <div> {{userid}} </div> </template> <script> export default { name: "", data() { return { userid:'' } }, methods: { }, created() { this.userid = this.$route.params.id } } </script> <style scoped> </style>
级联选择器
其数据是这样的
options: [
{
text: '浙江省',
value: '330000',
children: [{ text: '杭州市', value: '330100' }
{ text: '宁波市', value: '330100' },
{ text: '温州市', value: '330100' }],
},
{
text: '江苏省',
value: '320000',
children: [{ text: '南京市', value: '320100' }],
},
],
就是children嘛,如果有children(不管是不是空)就继续点下一级,没有就返回数据。但是目前一半返回的数据中,就算最后一级了,也是会有个children:[]
的,比如
[ { "id": "441900117000", "findname": "凤岗镇", "find_quanpin": "fenggangzhen", "find_jianpin": "fgz", "province": "广东省", "displayorder": 441900, "netname": "gdwebson.gdnyt.com", "netaddress": "1.1.1.1", "deptarttype": 1, "departtype": 1, "tag": "东莞市 , 广东省", "children": [ { "id": "901120000000401", "findname": "东莞凤岗站", "find_quanpin": "dongguanfenggangzhan", "find_jianpin": "dgfgz", "province": "广东省", "displayorder": null, "netname": "gdwebson.gdnyt.com", "netaddress": "1.1.1.1", "deptarttype": 2, "departtype": 2, "tag": null, "children": [], "address": "东莞市凤深大道与龙平西路交汇处东北角", "stationhotline": "0769-87513786" } ], "address": null, "stationhotline": null } ]
就算children没有数据,也是有这个字段的。如果只要还有children字段,就会显示下一级,但是下一级是空的没有得选
这个时候就要去掉最后一级得children字段
// 递归判断列表,把最后的children设为undefined
getTreeData(data) {
for (var i = 0; i < data.length; i++) {
if (data[i].children.length < 1) {
// children若为空数组,则将children设为undefined
data[i].children= undefined;
} else {
// children若不为空数组,则继续 递归调用 本方法
this.getTreeData(data[i].children);
}
}
return data;
}
或者一个标签几个动态的class,可以这样写
之前没遇到过的,比如有firstName和lastName两个属性,在页面上我们要
{{firstName}} + {{lastName}}
这样显示,就很麻烦
有个计算属性的东西,可以自动拼接字符的
{{fullName}}
<script>
xxxx省略代码
data:{
firstName:'jack',
lastName:'white'
},
computed:{
fullName:function(){
return this.firstName + ' ' + lastName
}
}
</script>
data里面没有fullName,但是在computed里面显示了,页面显示jack white
值得一提的是,data的值改变,其computed也是会重新计算一次的
其实我们这是缩写,其实本来是这样的
{{fullName}} <script> xxxx省略代码 data:{ firstName:'jack', lastName:'white' }, computed:{ //这里如果直接fullName :function(){},就是只取get方法 fullName:{ get:function(){ return this.firstName + ' ' + lastName } } </script>
老面向对象了,也是有set的。比如你什么button按钮想改变值,也是可以的
{{fullName}} <script> xxxx省略代码 data:{ firstName:'jack', lastName:'white' }, computed:{ //这里如果直接fullName :function(){},就是只取get方法 fullName:{ get:function(){ return this.firstName + ' ' + lastName }, set:function(newValue){ //这里把值给保存给data了 const names = newValue.spit(' '); this.firstName = names[0]; this.lastName = names[1]; } } </script>
{{getFullName()}}
<script>
xxxx省略代码
data:{
firstName:'jack',
lastName:'white'
},
methods:{
getFullName(){
return this.firstName + ' ' + lastName
}
}
</script>
@keyup.enter
就是触发回车的事件之类的
一个div有个点击事件,div里面有个button有个点击事件,那么点button的时候,会触发div点击事件和button点击事件。
那么我想点button只触发button而不触发div事件,可以@click.stop="xx"
自定义组件的时候,直接@click="xx"
无反应,在自定义组件的时候应该加上@click.native="xx"
<ul v-for="(value,key,index) in person">{{value}}--{{key}}--{{index}}</ul>
//js
data() {
return {
person:{
name:'小强',
age:22
}
}
},
小强–name–0
22–age–1
function sum(...num){
//code
}
sum(10,20,30,35)
数组末插入数据
this.arr.push('aa')
删除最尾的数据
this.arr.pop()
删除数组最前面的一个元素
this.arr.shift()
再数组最前面添加一个元素
this.arr.unshift('aa')
其有好几个作用
this.arr.splice(从第几个开始删,删除几个元素)
//从第二个元素开始删除,删除2个 [a,b,c,d] --> [a,b]
this.arr.splice(2,2)
this.arr.splice(从第几个开始替换,替换几个,替换的元素)
//从第二个元素开始替换,删除2个 [a,b,c,d] --> [a,b,e,f]
this.arr.splice(2,2,'e','f')
this.arr.splice(第几个后面插入,0,插入的元素)
//从第二个元素后面插入 [a,b,c,d] --> [a,b,e,f,c,d]
this.arr.splice(2,0,'e','f')
比如const nums = [10,20,111,112]
filter中的参数是回调函数,其回调函数必须返回一个boolean值。返回值是数组。filter的回调函数会循环一遍数组的
用来过滤的,比如取出数组小于100的数字,普通的
let newNums = []
for(let n in nums){
if(n<100){
newNums.push(n)
}
}
但是可以这样简写
//用newNums来接住数组,然后filter里面写回调函数,return true 或者 false
let newNums = nums.filter(function(n){
return n < 100
})
和filter差不多,只不过filter规定返回布尔值,map的返回值不规定
比如要求每个数*2
let newNums = []
for(let n in nums){
newNums.push(n*2)
}
高阶
let newNums = nums.map(function(n){
return n*2
})
对数组进行汇总,他是这样的
数组.reduce(回调函数(上一次遍历的值,当前遍历的值){
// code
},初始值)
比如将所有数加起来
const nums = [10,20,111,112]
let total = 0
for(let n in nums){
total + =n
}
可以这样写
let total = newNums.reduce(function(preValue,n){
return preValue + n
},0)
第一次遍历,preValue = 0,n=10 , return 10
第二次遍历,preValue = 10,n=20 , return 30
第三次遍历,preValue = 30,n=111 , return 143
第三次遍历,preValue = 143,n=112 , return 255
比如这个,选中哪个,就记录哪个。
之前我是每一个都弄一个点击事件,然后再push和pop操作的。
后来发现视频,不用的,直接,每一个input都是v-model绑定一个数组,然后直接在下面{{数组}}
就可
<input type="checkbox" value="篮球" v-model="hobbies">篮球
<input type="checkbox" value="唱歌" v-model="hobbies">唱歌
<input type="checkbox" value="跳舞" v-model="hobbies">跳舞
<input type="checkbox" value="足球" v-model="hobbies">足球
<h2>爱好:{{hobbies}}</h2>
//------
data() {
return {
hobbies:[]
}
},
懒加载,由于v-model双向绑定,比如input还在输入的时候,data会时时改变
<input type="text" v-model.lazy="msg">
{{msg}}
//------
data() {
return {
msg:''
}
},
但我们想在input中输完时,按下回车或者焦点离开输入框,data值才改变
还没按回车,后面的值不会改变
按下回车,值改变
就是说input的时候,只能输入数字类型,如果是<input type="number">
data里面判断类型时string而不是number,这时候这样用就可以
<input type="number" v-model.number="msg">
{{typeof msg}}
//------
data() {
return {
msg:''
}
},
比如
父
<template> //用了子组件,传一个key为id,value则为bookid的值,传给子组件读取 <UserData :id="bookid"></UserData> </template> <script> import UserData from '../../components/UserData' export default { name: "FriendIndex", components: { //加载儿子 UserData }, data(){ return{ bookid:123 } } <script>
子:
<template> <div> {{id}} //这里用了父子 <input type="text" v-model="id"> </div> </template> <script> export default { name: "", //这里的props为数组形式,不是一个数组形式,就是保存父给子的key,写在这里 props:["id"], } </script> <style scoped> </style>
v-model绑定了props而不是data,会有错误
官方建议data先拿到props,然后再对data进行双向绑定
修改后子:
<template> <div> {{reallyId}} //这里用了父子 <input type="text" v-model="reallyId"> </div> </template> <script> export default { name: "", //这里的props为数组形式,不是一个数组形式,就是保存父给子的key,写在这里 props:["id"], data(){ return { reallyId:this.id } } } </script> <style scoped> </style>
和data同级,某一值发生改变时,执行的代码
<template> <div> <input type="text" v-model="reallyId"> </div> </template> <script> export default { name: "", data(){ return { reallyId:'123' } }, watch:{ //一个新值,一个旧值 reallyId(newValue,oldValue){ //要执行的代码 } } } </script> <style scoped> </style>
插槽嘛,插入啥变变成啥
应用场景多为一个重复的组件,但是组件和组件之间又有些不一样的需求。有点类似于Java的集成,把大家共性的东西都打包,要怎么改怎么用,就是子类的事了。
导航条,左边有些事返回,有些是菜单,但是总的来说,大家都是左中右3个地方,我们就可以将这些共性打包
<!-- 子 -->
<template>
<div>
<!-- 这里都显示 -->
我是子组件
<!--1、 solt是插槽,要什么的就在这里插入 -->
<slot></slot>
<br><br>
</div>
</template>
<!-- 父 --> <template> <div> <!-- 2、在子组件里面插入你想要插入的东西,这个东西就会在solt中替换的 --> <TestSon><button>按钮</button></TestSon> <!-- 3、没有插入的就啥事没有发生 --> <TestSon></TestSon> <!-- 4、或者你插入其他的 --> <TestSon><i>我是i</i></TestSon> <!-- 5、插入多个的话,会都加载,将多个都在solt中替换 --> <TestSon> <button>我是button</button> <h2>我是h2</h2> </TestSon> </div> </template>
如果调用10次插槽,8次要求是button,2次要求是h2,那么每一个我都要些button和h2,但是button是8次啊,明显又麻烦了,所以有默认值,和Java抽象方法的默认值这种差不多
<!-- 父 -->
<template>
<div>
<!-- 2、覆写默认值 -->
<TestSon><p>老子不想要按钮</p></TestSon>
<!-- 3、空白就直接用默认值 -->
<TestSon></TestSon>
<TestSon><button>老子是自己写的按钮</button></TestSon>
</div>
</template>
<!-- 子 -->
<template>
<div>
我是子组件
<!-- 1、定义了一个solt,但有默认值 -->
<slot><button>按钮</button></slot>
<br><br>
</div>
</template>
上面是子组件里面只有一个solt,但是如果想几个solt怎么办?
<!-- 子 -->
<template>
<div>
<!-- 写3个插槽 -->
<slot>左边</slot>
<slot>中间</slot>
<slot>右边</slot>
<br><br>
</div>
</template>
<!-- 父 -->
<template>
<div>
<TestSon></TestSon>
<!-- button覆盖3个插槽 -->
<TestSon><button>按钮</button></TestSon>
</div>
</template>
如果我们只想替换中间那个,可以这样写
<!-- 子 -->
<template>
<div>
<!-- 1、给每一个插槽起名字-->
<slot name="left">左边</slot>
<slot name="center">中间</slot>
<slot name="right">右边</slot>
<br><br>
</div>
</template>
<!-- 父 -->
<template>
<div>
<TestSon></TestSon>
<TestSon>
<!-- 在子组件里面,插入template ,属性v-solt:插槽名 ,然后再在button里面插入想要的东西-->
<template v-slot:center>
<button>按钮</button>
</template>
</TestSon>
</div>
</template>
v-slot 只能添加在 <template>
中
子组件的插槽的slot中的样式是子组件写的,但是,如果我想用到子组件插槽中的数据,但是只是想改变样式而已。
就是说,比如子组件默认插槽值是
但是我想换成这样子
其中,这些值是子组件的值,这时候如果要改变样式并且拿到子组件的值,要这样做
<!-- 子 --> <template> <div> //2、把值给父组件读取,需要加上 :自定义名字="变量" ,这样父组件通过名字就能读取了 <slot :language="language"> //1、这里是slot中的默认样式 <ul> <li v-for="item in language"> {{item}} </li> </ul> </slot> <br><br> </div> </template> <script> export default { name: "TestSon", data() { return { language:['java','php','js'] } }, </script>
<!-- 父 --> <template> <div> <TestSon></TestSon> <TestSon> //3、v-slot:default="slotProps" ,这里的 slotProps就可以拿到子组件插槽中的所有变量(名字也是自己起的) <template v-slot:default="slotProps"> //4、这里读slotProps,会拿到全部值 <div>slotProps: <h2>{{slotProps}}</h2> </div> <br> //5、slotProps.什么 ,就是子组件插槽中定义的值 <div>slotProps.language: <h2>{{slotProps.language}}</h2> </div> <br> //6、遍历 <span v-for="item in slotProps.language">{{item}}-</span> </template> </TestSon> </div> </template>
js是弱语言,没有Java这么强的封装性和继承性。
如果正常导入js文件,是<script src="xx.js"></script>
,那么如果导入的几个js文件有重名变量,函数,会覆盖。
那么模块化就是把每个模块之间隔绝,重名变量就不会覆盖。
导出就是模块隔绝后,开个接口给别人用,就是导出export
导入就是导入别的模块来使用,导入import
js就写一些普通的函数,或者变量,别人用就要这样用
<script src="main.js" type="module"></script>
//a.js,定义一个变量和函数
// 1、写东西
var flag = true
function sum(num1, num2) {
return num1 + num2
}
//2、导出
export {
flag,sum
}
//b.js导入a.js,并调用东西
//3、导入js
import {flag,sum} from './a.js'
//4、引用变量和函数
if(flag){
console.log(sum(10,20))
}
var flag = true
function sum(num1, num2) {
return num1 + num2
}
//2、导出
export {
flag,sum
}
export var flag = true
export function sum(num1, num2) {
return num1 + num2
}
export class Person(){
run(){
console.log('跑')
}
}
上面的导入,都是import {xx} from 'x.js'
,但是平时vue的都是import 自己起名字 from 'a'
那么这个自己起名字就是通过export的
//a.js
var num =666
export default num
import shuzi from './a.js'
console.log(shuzi)
666
export default一个文件只能存在一个
//a.js,定义一个变量和函数
var flag = true
var num = 123
function sum(num1, num2) {
return num1 + num2
}
//2、导出
export {
flag,sum,num
}
//b.js导入a.js,并调用东西
import {flag,sum,num} from './a.js'
//4、引用变量和函数
if(flag){
console.log(sum(10,20))
}
//b.js导入a.js,并调用东西
import * as obj from './a.js'
//4、引用变量和函数
if(obj.flag){
console.log(obj.sum(10,20))
}
webpack xxx.js xx.js
npm是一个maven管理器,控制一堆包的,但是npm不像maven那么高级,所有包都放在一个仓库,他
是每一个项目都有自己的仓库,叫node_modules。
npm install xx -g
保存到全局,但有些东西是每个项目都要单独安装的,仅适用于类似webpack这种全局的打包的
https://blog.csdn.net/zz00008888/article/details/109536466
vue cli2.x才会有webpack.config.js,3.x之后就类似spring boot的自动配置一样,要加的话往里面加个vue.config.js进行修改即可
目前只知道几种解决方案
注意在cmd用管理员身份打开
其其实就是把C:\Users\master\AppData\Roaming\npm-cache删除,清下缓存
网上说的 vue -V
看的是cli版本的!!!
首先vue版本准确说是怎么看项目的vue版本,打开项目的node_modules\vue\package.json
,查看版本
可以看到我用的是vue2.x而不是3.x
emmmm
我一直以为自己用3.x了。。。。。
其实就是Java8的lambda
const obj = {
sum(num1,num2){
return num1+num2
}
}
const test = function (str){
console.log(str);
}
test(666)
obj.sum(10,20)
简写
const sum = (num1,num2) =>{
return num1+num2
}
sum(10,20)
如果函数里面,只有一个参数可以
then((data) => {
console.log(data);
then(data => {
console.log(data);
比如在https://www.jd.com/
输入location.hash='/foo'
,就到了https://www.jd.com/#/foo
但是页面没有刷新,而且也有个后退按钮
当输入history.back()
时,又退回到了https://www.jd.com/
其实这玩意就是个栈,请求一层层往上加,back就去掉一层
history.pushState({},'','home')
history.back() == history.go(-1)
history.go(-2)就回退2个
如果是history.go(1)就返回刚才的页面,其实就是这个
之前都是回用就好了,现在回顾一下
router\index.js
import Vue from 'vue' //1、先导入插件 import VueRouter from 'vue-router' import Index from '../views/Index.vue' //2、插件的使用方式,再使用Vue.use(xxx) Vue.use(VueRouter) //4、routes定义在router里面的数组 const routes = [ { path: '/', name: 'Index', component: Index }, { path: '/about', name: 'About', // route level code-splitting // this generates a separate chunk (about.[hash].js) for this route // which is lazy-loaded when the route is visited. component: () => import(/* webpackChunkName: "about" */ '../views/About.vue') } ] //3、定义一个变量,3个选项嘛,最后一个变量是数组 const router = new VueRouter({ mode: 'history', base: process.env.BASE_URL, routes }) //5、最后面要导出啦 export default router
再到根目录的main.js
import Vue from 'vue' import './plugins/axios' import App from './App.vue' //导入那个 ./router/index.js import router from './router' import store from './store' import './plugins/element.js' Vue.config.productionTip = false //这里就是new Vue了,有个router,就是简写的 router:router new Vue({ router, store, render: h => h(App) }).$mount('#app')
其实就是
{
path: '/about',
name: 'About',
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
或者是
const About = () => import(/* webpackChunkName: "about" */ '../views/About.vue')
{
path: '/about',
name: 'About',
component: About
}
好处是,这样打包后,加载速度会更块,以后都推荐这种方式
就是一个router里面的东西,vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航,有点拦截器的感觉,可以配合安全验证之类的进行拦截跳转。
官网介绍:https://router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E5%85%A8%E5%B1%80%E5%89%8D%E7%BD%AE%E5%AE%88%E5%8D%AB
比如我们想根据url显示不同的title(就是浏览器标签页中图标右边的文字)
{
path:'/test',
name:'Test',
component:Test,
meta:{
title:'测试1'
}
},{
path:'/test2',
name:'Test2',
component:Test2,
meta:{
title:'测试2'
}
}
meta是数据的描述注释之类的,除了title还有其他很多的。
//beforeEach是前置守卫,在跳转前执行的函数,其有3个变量,from跳转到to,然后next是个函数,可以中断,可以继续跳转
router.beforeEach((to, from, next) => {
//设置标题
window.document.title = to.meta.title
//可以看看有啥
console.log(to);
//next一定要有,无的话会报错
next()
})
打印to可以看到有很多信息,之后我们甚至可以判断路径url显示自定义的东西之类的,
如果有时候判断不了,例如子子组件,可以用matched来解决子的路径
next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
next(‘/’) 或者 next({ path: ‘/’ }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,且允许设置诸如 replace: true、name: ‘home’ 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项。
next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。
就是说,我们可以判断有没有登陆之类的,没有登陆就next(‘/login’)这种
router.afterEach((to, from) => {
// ...
})
就是后置啦,没有next
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
//和data,created同级 beforeRouteEnter(to, from, next) { // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 `this` // 因为当守卫执行前,组件实例还没被创建 }, beforeRouteUpdate(to, from, next) { // 在当前路由改变,但是该组件被复用时调用 // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候, // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。 // 可以访问组件实例 `this` }, beforeRouteLeave(to, from, next) { // 导航离开该组件的对应路由时调用 // 可以访问组件实例 `this` }
因为一个页面,有created和destory两个函数嘛,组件创建和毁灭,当从A到B时,A毁灭B创建。但我后退一步,又要B毁灭再A创建。这样很麻烦,虚拟dom弄了好多次,而且如果A到B再到A,那么A原本的东西就会都不见了,因为A已经被毁灭过了,保存的临时数据页销毁了。keep-alive就是解决这个问题得到。
这个案例原本可以简单点的,但是这个问题公司也会用到,一起讲了
比如我们页面是这样
跳转到到home时,识别或者重定向跳转到/home/toutiao
home有两个子:头条和新闻,和home同级的有my
当点击home时,或者点击头条时,跳转到home/toutiao
点击新闻时跳转到home/news
点击my时跳转到/my
当点击home的新闻,再点击my,再点击到home的时候,如果是使用重定向,会跳转到home/toutiao,那么我刚才浏览的明明是新闻,还要继续点一个新闻才到新闻。我想在home/news时,点my,再点home,会跳到home/news而不是home/toutiao
点my=》 点home=》
可以这样做
首先路由
{ path: '/home', name: 'home', component: home, redirect :'/home/toutiao', children: [{ path: 'news', name: 'news', component: news, }, { path: 'toutiao', name: 'toutiao', component: toutiao, }] }, { path: '/my', name: 'my', component: my },
//app.vue <template> <div> //根目录就2个按钮 <button @click="tohome">home</button> <button @click="tomy">my</button> //1、加了keep-alive就行 <keep-alive> <router-view></router-view> </keep-alive> </div> </template> <script> export default { methods: { tohome() { this.$router.push('/home') }, tomy() { this.$router.push('/my') } } } </script>
//home.js <template> <div> 我是home <br> //到了home里面,有2个按钮,根据按钮在router-view显示对应 <el-button @click="totoutiao"> 头条</el-button> <el-button @click="tonews"> 新闻</el-button> <keep-alive> <router-view></router-view> </keep-alive> </div> </template> <script> export default { data() { return { //1、先定义path,这样就类似重定向 path: '/home/toutiao' } }, methods: { totoutiao() { this.$router.push('/home/toutiao') }, tonews() { this.$router.push('/home/news') } }, //2、在keep-alive里面才有这个函数,表示当这个页面活跃的时候, //从home/new跳转到my的时候,home不会被销毁,而且记得了上一次呆的地方是news,所以再点击home时,执行activated跳到home/news activated() { this.$router.push(this.path) }, //组件内后置守卫,跳转了之后的 beforeRouteLeave(to, from, next) { console.log(this.$route.path) //要离开了,记得这次是从哪里离开的,方便再次加入 this.path = this.$route.path next() } } </script>
其实说那么多就是为了表达keep-alive是可以方式组件再次被创建和销毁的,这个案例我觉得工作会用到所以记下的
我们先看下生命周期
created和mounted,然后接下来就是平常的东西,如果或数据发生变化,发生updated,然后销毁destoryed。
keep-alive有2个函数,activated和deactivated ,一个是某个组件活跃的时候(用到的时候),另一个就是组件不活跃(没用到的时候)
比如详情页之类得,点击详情页再返回,再点击其他的详情页,因为用了keep-alive,不会再执行mouth和created,所以这个时候需要排除某些组件
<keep-alive exclude="xxx组件名">
</keep-alive>
这是因为VueRouter设置的模式是hash模式,设置成history就不是#了
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
比如,tabbar的,根据url为/index的时候,首页按钮显示红色,其他都是黑色
就是设置2个,活跃的时候,显示红色,不活跃显示黑色,这个活跃值就这样判断
if(this.$route.path.indexOf('/home') !==-1){
//code...
}
str.indexOf('key')
:判断str中是否包含key,没有则返回-1,有则返回第几个开头的字
created() {
console.log(this.$route);
if(this.$route.path.indexOf('/home/toutiao') !==-1){
console.log('trueeeeee!')
}
},
如果导入一些图片之类的,如果文件移动了,什么…/,…/…/之类的很多,取个别名就好多了
默认@就是src,比如src/main.js,就是@/main.js
其他更多的可以自定义设置名字
//vue.config.js const path = require('path'); //引入path模块 function resolve(dir){ return path.join(__dirname,dir) //path.join(__dirname)设置绝对路径 } module.exports={ chainWebpack:(config)=>{ config.resolve.alias //set第一个参数:设置的别名,第二个参数:设置的路径 .set('@',resolve('./src')) .set('assets',resolve('.src/assets')) .set('components',resolve('./src/components')) .set('views',resolve('src/views')) } }
其他用view,就
//import就这样写
import xx from 'views/xxx'
//如果非import,前面要加~
<img src="~xxx" alt="">
这是一个异步编程的一种解决方案
其实我之前敲代码也有过,比如我axios时,发送一个请求,当拿到结果后,再从拿到的结果再次发送一个请求。或许没啥事,但是当时写得是挺乱得,如果以后还有套娃嵌套娃嵌套娃,那就很恶心了,而promise就是为了让代码更好看,而且执行效率高,结构分明的东西。
Promise主要是用于有异步处理的地方
其大概结构是这样写的
new Promise((resolve, reject) => {
//...code
//成功时执行resolve函数,实际上就是执行then的函数
resolve('success');
//失败时执行reject函数,实际上就是执行catch的函数
reject('err')
}).then((data) => {
//成功之后的事
console.log(data);
}).catch((err) => {
//失败之后的事
console.log(err);
})
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('resolve')
reject('reject')
}, 1000);
}).then(data=>{
//执行成功的代码
console.log(data);
},err=>{
//执行错误的代码
console.log(err);
})
//其其实就是then(function(data),function(err))
//第一个执行成功的代码,第二个执行失败的代码
比如我们这有个套娃的,用setTimeout模仿异步请求啦
一个setTimeout里面,执行代码,然后执行完里面又有个setTimeout,执行代码,里面又有setTimeout
setTimeout(() => {
console.log('11111');
setTimeout(() => {
console.log('222222');
setTimeout(() => {
console.log('333333');
}, 1000);
}, 1000);
}, 1000);
打印是可以打印,就是有点恶心。用Promise优雅一下
new Promise((resolve, reject) => { setTimeout(() => { resolve('1111') reject('err') }, 1000); //执行第一层成功代码 }).then((data) => { console.log(data); //code.. return new Promise((resolve, reject) => { setTimeout(() => { resolve('2222') reject('err') }, 1000); //执行第二次成功代码 }).then((data) => { console.log(data); //code... return new Promise((resolve, reject) => { setTimeout(() => { resolve('3333') reject('err') }, 1000); //执行第3次成功代码 }).then((data) => { console.log(data); //执行第3次失败代码 }).catch((data) => { console.log(err); }) //执行第二次失败代码 }).catch((data) => { console.log(data); }) //处理第一层的错误代码 }).catch((data) => { console.log(data); })
虽然看起来还是恶心,但是,如果代码逻辑很复杂,这个就好
还有链式调用,还有链式调用的简写方式,但我实在学不懂了,简写以后再学吧
我觉得比较罕见,就是2个异步任务,要任务A成功,任务B成功,2个一起成功了才执行自定义代码
//all里面是个数组,每一个元素都是new一个Promise对象
Promise.all([
new Promise((resolve, reject) => {
//code
}),
new Promise((resolve, reject) => {
//code
})
//几个异步任务完成后,都是成功执行后,再来到then函数
//其中,result是一个数组,result[0]是第一个异步任务完成的回调数据,result[1]是第二个异步任务完成的回调数据,
]).then(result => {
console.log(result);
})
比如
Promise.all([ new Promise((resolve, reject) => { setTimeout(() => { resolve({ name: '小强', age: 18 }) }, 1000); }), new Promise((resolve, reject) => { setTimeout(() => { resolve({ name: '小明', age: 22 }) }, 1000); }) ]).then(result => { console.log(result); })
结果为:
[
{
"name": "小强",
"age": 18
},
{
"name": "小明",
"age": 22
}
]
就是用别人的插件之类的
目前我只会怎么用别人的插件,创建自己的插件(工具类)我还不会
用官方的vuex为例子,其他第三方插件我不知道
主要是我查不到正确的做法是什么,官方这样导入的,其他应该或许大概也是这样做的?
// store/index.js //1、导入vue和vuex import Vue from 'vue' import Vuex from 'vuex' //2、使用插件 Vue.use(插件) Vue.use(Vuex) //3、导出插件,export default 插件对象 //可以是new xx直接写 //也可以是const x = new 插件对象,写好再export default x export default new Vuex.Store({ state: { }, mutations: { }, actions: { }, modules: { } })
import Vue from 'vue'
//4、导入插件
import store from './store'
Vue.config.productionTip = false
new Vue({
//5、在这里写,这是官方的,我不知道第三方插件在new Vue里面,还是Vue.use
store,
render: h => h(App)
}).$mount('#app')
$store
使用就是之前遇到的,2个毫无相关的组件,要用同一个变量。之前是通过全局变量localStorage来实现的,但这个不是响应式的,不好做,查了下发现原来vuex就是做全局变量的,而且是响应式的。
vuex在store/index.js下
要的全局变量就在state里面加,比如
//store/index.js import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: { //设置全局变量 count:1000 }, mutations: { }, actions: { }, modules: { } })
别人用的话
我是全局变量counter:{{this.$store.state.count}}
就可
我是全局变量counter:1000
既然知道vuex是进行全局变量的,那么肯定能读能写,读就直接this.$store.state.变量名
去读,但是写的话不可以通过传统的this.$store.state.变量名 ++
,因为不单单你一个组件在写,其他组件也可能会写,这样直接改会发生异步错误处理。vuex都帮我们做好了
//store/index.js import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: { count:1000 }, mutations: { //1、vuex定义一个方法,为count++,参数加state increment(state){ state.count++ }, //vuex定义一个方法,为count-- decrement(state){ state.count-- }, //还可以传参,第一个是state,第二个就是传参数据,如果是多个传参数据,可以用对象传,再 对象.xx incrementNum(state, num) { state.count += num } }, actions: { }, modules: { } })
<template> <div> 我是全局变量counter:{{this.$store.state.count}} <!-- 2、普通的点击事件 --> <button @click="add">+</button> <button @click="jian">-</button> <button @click="addNum(5)">+5</button> <button @click="addNum(10)">+10</button> </div> </template> <script> export default { name: "", methods: { add(){ //3、事件里面 this.$store.commit('vuex中方法名') 来进行值得修改 this.$store.commit('increment') }, jian(){ this.$store.commit('decrement') }, addNum(num){ this.$store.commit('incrementNum', num) }, }, } </script>
这样子就可以改,而且可以在插件里面看到值得修改过程
这类似于普通组件的computed,什么计算属性,可以写一些tostring的东西
//store/index.js import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: { count: 1000, array: [10, 20, 30, 40] }, mutations: { }, getters: { //重构,显示对应的东西 toStringCount(state) { return 'count:' + state.count }, //可以配合过滤 more20(state) { return state.array.filter(n => { return n > 20 }) }, //参数可以加getters,调用getters的方法 more20Lent(state, getters) { return getters.more20.length }, //甚至可以自定义传参 moreNum(state) { //return 回调函数,参数num就是要大于的数 return num => { //然后过滤 return state.array.filter(n => { //得到的数过滤回来 return n > num }) } } }, actions: {}, modules: {} })
<!-- 直接显示 -->
<h2>{{this.$store.getters.toStringCount}}</h2>
<h2>{{this.$store.getters.more20}} </h2>
<h2>{{this.$store.getters.more20Lent}} </h2>
<h2>{{this.$store.getters.moreNum(10)}} </h2>
const getters = {
sid: state => state.user.sid
}
export default getters
const store = new Vuex.Store({
getters
})
然后在用的地方
import {mapGetters} from "vuex";
computed: {
...mapGetters(['sid']),
//其是会自动转换成
// sid(){
// return this.$store.state.sid
// }
},
然后就能简单地使用啦
console.log(this.sid)
上面的是普通的,下面这个特殊的
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: { count: 1000, }, mutations: { //这种接受的是一个对象 incrementNum(state, payload) { console.log(payload); state.count += payload.num } }, })
<button @click="addNum(5)">+5</button>
<button @click="addNum(10)">+10</button>
<script>
//方法
addNum(num){
//type和一个传值
this.$store.commit({
type :'incrementNum',
num
})
},
</script>
按下+10
{
"type": "incrementNum",
"num": 10
}
2中是介绍了vuex中修改数据,但那仅限于修改,增加和删除我们都没讲
比如我们要修改和删除,先看错误的.
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: { obj: { name: '小强', age: '23' } }, mutations: { updateObj(state) { //obj增加一个key state.obj['address'] = '深圳' //obj删除一个key delete state.obj.age } }, })
<h2>{{this.$store.state.obj}}</h2>
<button @click="changeObj">修改对象</button>
changeObj(){
this.$store.commit('updateObj')
}
点击修改对象按钮,也没效果
这么看来是已经修改了,但可惜的是,这2者不支持响应式布局(下面会讲哪些不是响应式的)
应该这么改
updateObj(state) {
// state.obj['address'] = '深圳'
// delete state.obj.age
//用这2个进行添加和修改
Vue.set(state.obj,'address','深圳')
Vue.delete(state.obj,'age')
}
就是,我们commit传的是字符串嘛,为了统一性,用常量来定义这个字符串,然后传入这个常量即可
//mutations_types.js
export const INCREMENT = 'increment'
// store/index.js import Vue from 'vue' import Vuex from 'vuex' //导入 import * as type from './mutations_types.js' Vue.use(Vuex) export default new Vuex.Store({ state: { count: 1000, array: [10, 20, 30, 40], obj: { name: '小强', age: '23' } }, mutations: { //vuex定义一个方法,为count++ // increment(state) { // state.count++ // }, //将名字和替换成常量 [type.INCREMENT](state) { state.count++ }, }, })
<button @click="add">+</button>
import * as type from '../store/mutations_types.js'
add() {
// this.$store.commit('increment')
this.$store.commit(type.INCREMENT)
},
上面的操作都是在mutation中进行的同步操作,但是很多情况是要异步操作的,而mutation不支持异步操作的,需要配合action使用。所以需要异步操作就方法->action->mutation
,不需要异步就方法->mutation
mutations: {
//在action中异步处理完后,在mutations中修改全局变量
muAsync(state,payload){
state.count +=payload.count
}
},
actions: {
//2、在action中,定义异步操作,在异步操作成功时context.commit到mutatuions
acAsync(context,payload){
setTimeout(() => {
context.commit('muAsync',payload)
}, 1000);
}
},
<h2>------------------</h2>
<button @click="async(2)">异步操作+2按钮</button>
{{this.$store.state.count}}
//js
//1、在方法里面进行异步修改全局变量,dispatch跳转到action,第二个参数是对象
async(num){
this.$store.dispatch('acAsync',{count:num})
}
如果actions是在某个模块里面的,比如是
export default {
actions:{
setUserId ({ commit }, userId) {
commit('SET_USER_ID', userId)
},
}
}
//store.index.js import Vue from 'vue' import Vuex from 'vuex' import getters from './getters' Vue.use(Vuex) // 文件加载 const modulesFiles = require.context('./modules', true, /\.js$/) // 遍历文件导出store对象 const modules = modulesFiles.keys().reduce((modules, modulePath) => { const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1') const value = modulesFiles(modulePath) modules[moduleName] = value.default return modules }, {}) const store = new Vuex.Store({ modules, getters }) export default store
其他地方可直接用store.dispatch('user/setUserId', userId)
就是在方法中,this.$store.dispatch('acAsync',{count:num})
成功完成后,进行的一些操作
actions: {
acAsync(context, payload) {
//返回一个promise,这样子,方法就可以继续写then了
return new Promise((resolve, reject) => {
setTimeout(() => {
//commit到mutations
context.commit('muAsync', payload)
//成功
resolve('success')
}, 1000);
})
}
},
methods: {
async (num) {
this.$store.dispatch('acAsync', {
count: num
//写回调
}).then(res => {
console.log(res);
})
}
}
因为什么都往里面塞的话,这个index.js就会很大不方便,有个模块化
const Person ={ state:{}, mutations:{}, getters:{}, actions:{} } export default new Vuex.Store({ state: { count: 1000, array: [10, 20, 30, 40], obj: { name: '小强', age: '23' } }, mutations: {}, getters: {}, actions: {}, modules: { //其实就是Person:Person的简写 Person } })
import Vue from 'vue' import Vuex from 'vuex' import * as type from './mutations_types.js' Vue.use(Vuex) const Person ={ state:{ name:'詹姆斯' }, mutations:{ //注意这里的名字不要和根或其他任何模块重名 updateName(state,payload){ //state是本模块的state state.name = payload.name } }, getters:{ //普通的getters fullname1(state){ return state.name + '1' }, //调用本模块的getters fullname2(state,getters){ return getters.fullname1 + '2' }, //还可以用根的state数据 fullname3(state,getters,rootState){ return getters.fullname2 + rootState.count } }, actions:{ //异步操作也是一样 syncUpdateName(context,payload){ console.log(context,payload); setTimeout(() => { context.commit('updateName',payload) }, 1000); } } } export default new Vuex.Store({ state: { count: 1000, array: [10, 20, 30, 40], obj: { name: '小强', age: '23' } }, mutations: {}, getters: {}, actions: {}, modules: { //其实就是Person:Person的简写 Person } })
点击异步改变名字后
我们希望进行模块化的目录结构
store下,index是总,然后actions、mutations就管理总的action之类的,然后一个modules文件夹,管理各个模块,一个模块就有自己的action、mutations之类的
vuex是个很好的全局变量管家,就是用起来有点麻烦。
要先预设什么全局变量,就在state中设置,
同步请求就在mutation中写好,方法再调用mutations
异步请求就方法调用action在action中进行异步处理,得到结果后再给mutations进行全局变量的修改
所有的全局变量修改一定要通过mutations进行修改。绕过mutations修改数据官方不建议,会造成数据错误
then和catch是每个都会有的
axios.request(config)
,其他的比如get:axios.request(url[,config])
两者用的时候,都是在方法里面用的,格式为
axios.get('路径').then(res => {
console.log(res );
}).catch(err =>{
console.log(err);
})
axios.post('路径',json类型的数据).then(res => {
console.log(res );
})
或者
axios.post('路径',{params:json类型对象}).then(res => {
console.log(res );
})
axios.put('路径',json类型的数据).then(res => {
console.log(res );
})
axios.delete('路径',{data:json类型数据}).then(res => {
console.log(res );
})
//返回的是一个数组
axios.all([axios.get('url1'), axios.get('url2')])
.then(res => {
console.log(res);
})
//或者一个个地返回,推荐这种
axios.all([axios.get('url1'), axios.get('url2')])
.then(axios.spread((res1, res2) => {
console.log(res1);
console.log(res2);
}))
一般弄完基本的东西,有特殊的可以在里面加一些配置
axios.all([ axios({ //config baseURL: 'http://192.168.12.128:9012', url: 'user/user/follow' }), axios({ //config baseURL: 'http://192.168.12.128:9012', url: 'user/user/follow', params: { type: 'all' } }), ]) .then(axios.spread((res1, res2) => { console.log(res1); console.log(res2); }))
//公共baseURL抽出来 axios.default.baseURL = 'http://192.168.12.128:9012' axios.all([ axios({ url: 'user/user/follow' }), axios({ url: 'user/user/follow', params: { type: 'all' } }), ]) .then(axios.spread((res1, res2) => { console.log(res1); console.log(res2); }))
https://github.com/axios/axios
{ // `url` 是用于请求的服务器 URL url: '/user', // `method` 是创建请求时使用的方法 method: 'get', // default // `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。 // 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL baseURL: 'https://some-domain.com/api/', // `transformRequest` 允许在向服务器发送前,修改请求数据 // 只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法 // 后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream transformRequest: [function (data, headers) { // 对 data 进行任意转换处理 return data; }], // `transformResponse` 在传递给 then/catch 前,允许修改响应数据 transformResponse: [function (data) { // 对 data 进行任意转换处理 return data; }], // `headers` 是即将被发送的自定义请求头 headers: {'X-Requested-With': 'XMLHttpRequest'}, // `params` 是即将与请求一起发送的 URL 参数 // 必须是一个无格式对象(plain object)或 URLSearchParams 对象 params: { ID: 12345 }, // `paramsSerializer` 是一个负责 `params` 序列化的函数 // (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/) paramsSerializer: function(params) { return Qs.stringify(params, {arrayFormat: 'brackets'}) }, // `data` 是作为请求主体被发送的数据 // 只适用于这些请求方法 'PUT', 'POST', 和 'PATCH' // 在没有设置 `transformRequest` 时,必须是以下类型之一: // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams // - 浏览器专属:FormData, File, Blob // - Node 专属: Stream data: { firstName: 'Fred' }, // `timeout` 指定请求超时的毫秒数(0 表示无超时时间) // 如果请求话费了超过 `timeout` 的时间,请求将被中断 timeout: 1000, // `withCredentials` 表示跨域请求时是否需要使用凭证 withCredentials: false, // default // `adapter` 允许自定义处理请求,以使测试更轻松 // 返回一个 promise 并应用一个有效的响应 (查阅 [response docs](#response-api)). adapter: function (config) { /* ... */ }, // `auth` 表示应该使用 HTTP 基础验证,并提供凭据 // 这将设置一个 `Authorization` 头,覆写掉现有的任意使用 `headers` 设置的自定义 `Authorization`头 auth: { username: 'janedoe', password: 's00pers3cret' }, // `responseType` 表示服务器响应的数据类型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream' responseType: 'json', // default // `responseEncoding` indicates encoding to use for decoding responses // Note: Ignored for `responseType` of 'stream' or client-side requests responseEncoding: 'utf8', // default // `xsrfCookieName` 是用作 xsrf token 的值的cookie的名称 xsrfCookieName: 'XSRF-TOKEN', // default // `xsrfHeaderName` is the name of the http header that carries the xsrf token value xsrfHeaderName: 'X-XSRF-TOKEN', // default // `onUploadProgress` 允许为上传处理进度事件 onUploadProgress: function (progressEvent) { // Do whatever you want with the native progress event }, // `onDownloadProgress` 允许为下载处理进度事件 onDownloadProgress: function (progressEvent) { // 对原生进度事件的处理 }, // `maxContentLength` 定义允许的响应内容的最大尺寸 maxContentLength: 2000, // `validateStatus` 定义对于给定的HTTP 响应状态码是 resolve 或 reject promise 。如果 `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),promise 将被 resolve; 否则,promise 将被 rejecte validateStatus: function (status) { return status >= 200 && status < 300; // default }, // `maxRedirects` 定义在 node.js 中 follow 的最大重定向数目 // 如果设置为0,将不会 follow 任何重定向 maxRedirects: 5, // default // `socketPath` defines a UNIX Socket to be used in node.js. // e.g. '/var/run/docker.sock' to send requests to the docker daemon. // Only either `socketPath` or `proxy` can be specified. // If both are specified, `socketPath` is used. socketPath: null, // default // `httpAgent` 和 `httpsAgent` 分别在 node.js 中用于定义在执行 http 和 https 时使用的自定义代理。允许像这样配置选项: // `keepAlive` 默认没有启用 httpAgent: new http.Agent({ keepAlive: true }), httpsAgent: new https.Agent({ keepAlive: true }), // 'proxy' 定义代理服务器的主机名称和端口 // `auth` 表示 HTTP 基础验证应当用于连接代理,并提供凭据 // 这将会设置一个 `Proxy-Authorization` 头,覆写掉已有的通过使用 `header` 设置的自定义 `Proxy-Authorization` 头。 proxy: { host: '127.0.0.1', port: 9000, auth: { username: 'mikeymike', password: 'rapunz3l' } }, // `cancelToken` 指定用于取消请求的 cancel token // (查看后面的 Cancellation 这节了解更多) cancelToken: new CancelToken(function (cancel) { }) }
如果一个文件写默认配置baseURL =xxx,那么会影响全部,但往往很多时候需要从不同的数据库拿不同的数据,那baseURL就不一定了
一种是,利用nginx反向代理,或者是spring cloudbus的那个,将所有请求统一起来再分发下去
另一种就是自己封装一层axiox实例,我们一般是用这个方法的
//request.js
//传入config,config会自动覆盖的
export function request(config){
//有个axios.create专门用于创建实例
const instance = axios.create({
baseURL:'http://192.168.12.128:9012',
timeout:5000
})
//返回的是一个promise
return instance(config)
}
用的话
import request from 'request.js'
//传入的是config,上面那个表,
request({
url: '/user/user/follow'
}).then(res => {
console.log(res);
}).catch(err => {
console.log(err);
})
分为请求拦截器和响应拦截器,写再axios得到实例封装里面的,就是返回 return instance(config)
之前
//请求拦截器
//use后第一个参数函数是成功的函数
instance.interceptors.request.use(config => {
//请求可以在这里设置一个转圈圈的东西,等在相应后,将转圈圈样式改变就可
//可以检查config里面有没有token令牌之类的
//或者检查config里面有没有不对的信息
// 都通过后再放行,如果不通过就跳转到其他页面
return config
//失败的函数
}, err => {
//code
})
//响应拦截器
instance.interceptors.response.use(res => {
//code
return res
}, err => {
//code
return err
})
//:root是定义常量的
:root{
--color-text: #666;
}
//这就是使用
.xxx{
color: var(--color-text);
}
先说一下怎么让一个div在页面上固定,给css
//比如固定住上面的导航条 .x{ position: fixed; top: 0; left: 0; right: 0; } //比如在一个中心固定住 .leftSideBackground { position: fixed; bottom: 37px; left: 20px; //这样就固定了距离左下多少 width: 7px; height: 40px; }
只是提供一个思路,用插槽完成
因为下面的tabbat不知道会有几个,所以可以先定义一个tabbar,然后一个插槽完成,插槽里面再细分到每个item,然后用总的 MainTabBar完成。
<!-- tabbar --> <template> <div id="tab-bar"> <slot></slot> </div> </template> <script> export default { name: "TabBar" } </script> <style scoped> #tab-bar { /* 本身的样式 */ background-color: #f6f6f6; height: 49px; border-top: 1px solid #eee; box-shadow: 0px -1px 1px rgba(150,150,150,.08); /* 定位相关 */ position: fixed; left: 0; right: 0; bottom: 0; /* 利用flex进行布局 */ display: flex; text-align: center; } </style>
<!-- tabbarItem,每一个插槽都要有活跃图片,未选择图片,文字 --> <template> <div id="tab-bar-item" @click="itemClick"> //记得要再slot外再用一层div包住,因为div才能用样式之类的 <div class="item-icon" v-show="!isActive"><slot name="icon"></slot></div> <div class="item-active-icon" v-show="isActive"><slot name="active-icon"></slot></div> <div class="item-text" :style="activeStyle"><slot name="text"></slot></div> </div> </template> <script> export default { name: "TabBarItem", props: { link: { type: String, required: true } }, computed: { isActive() { return this.$route.path.indexOf(this.link) !== -1 }, activeStyle() { return this.isActive ? {'color': 'red'} : {} } }, methods: { itemClick() { this.$router.replace(this.link) } } } </script> <style scoped> #tab-bar-item { /* 这个很重要 */ flex: 1; } .item-icon img, .item-active-icon img { width: 24px; height: 24px; margin-top: 5px; vertical-align: middle; } .item-text { font-size: 12px; margin-top: 3px; color: #333; } </style>
MainTabBar,往tabbar中插入一些tabbaritem <template> <tab-bar> <tab-bar-item link="/home"> <img slot="icon" src="~assets/img/tabbar/home.svg" alt=""> <img slot="active-icon" src="~assets/img/tabbar/home_active.svg" alt=""> <div slot="text">首页</div> </tab-bar-item> <tab-bar-item link="/category"> <img slot="icon" src="~assets/img/tabbar/category.svg" alt=""> <img slot="active-icon" src="~assets/img/tabbar/category_active.svg" alt=""> <div slot="text">分类</div> </tab-bar-item> <tab-bar-item link="/cart"> <img slot="icon" src="~assets/img/tabbar/cart.svg" alt=""> <img slot="active-icon" src="~assets/img/tabbar/cart_active.svg" alt=""> <div slot="text">购物车</div> </tab-bar-item> <tab-bar-item link="/profile"> <img slot="icon" src="~assets/img/tabbar/profile.svg" alt=""> <img slot="active-icon" src="~assets/img/tabbar/profile_active.svg" alt=""> <div slot="text">我的</div> </tab-bar-item> </tab-bar> </template> <script> import TabBar from 'common/tabbar/TabBar' import TabBarItem from 'common/tabbar/TabBarItem' export default { name: "MainTabBar", components: { TabBar, TabBarItem } } </script> <style scoped> </style>
css中的一个属性,用于水平布局
这个问题也是困扰了我很久,就是我的请求都直接写在每个组件方法里面,这样不好
其实可以参考spring mvc,每个组件的方法请求相当于controller,然后弄个中间层,将逻辑代码放到servlet层,因为只有读取到的数据后操作不一样,读取数据的操作都是一样的。可能A组件要根据ID找数据,B组件也是根据ID找数据,那么就可以让根据ID找数据丢在一个文件里面就行
//封装好一个request.js
//传入config,config会自动覆盖的
export function request(config){
//有个axios.create专门用于创建实例
const instance = axios.create({
baseURL:'http://192.168.12.128:9012',
timeout:5000
})
//拦截器
//返回的是一个promise
return instance(config)
}
//home.js,专门处理home的东西
import requestfrom './request'
export function getHomeMultidata() {
return axios({
url: '/home/multidata'
})
}
// 别的地方要用的话
import {getHomeMultidata} from "network/home";
//返回的就是一个promis,可以then和catch
getHomeMultidata().then(res => {
//xxx
})
可以获得当前是什么环境,怎么拿到我就不知道了。。就只会用
一个插件,叫vconsole
事情的原因是,发送一个http://localhost:8080/applySiCard/applyInfo/v1/realNameInfo的请求,等半天没反应,就觉得很奇怪,大佬说这里发送的是localhost,但实际上vue进行了设置
//vue.config.js
module.exports = {
devServer: { // 包含关系
proxy: {
'/applySiCard': {
target: 'http://10.11x.x.x:8099',
// target: 'http://192.168.xxx:8099',
changeOrigin: true //跨域
}
}
}
},
这个做了转发也做了跨域问题,只要是localhost:8080/applySiCard/xxx
的,都会跳转到10.11x.x.x:8099/applySiCard/xxx
,F12也看不到的
这里是做了一个转发的,这样就不用在每个请求都加ip和端口了
值得一提的是,这些操作devServer.proxy
都是用于开发环境的,开发环境才会有跨域问题,为了解决跨域才会有这个操作。因为本地是127.0.0.1,会有跨域。
如果是线上,前端和后端在同一个主机上,地址当然耶一样,不用再改了。
settimeout是多少秒仅执行一次后消失了嘛,这玩意是隔多少秒就执行一次
clearInterval是用来取消的
比如发验证码,60s内不允许重复发
startBusRefresh() {
if (this.busRefreshTimer) return
this.time = 60
this.busRefreshTimer = setInterval(() => {
this.time--
if (this.time == 0) {
this.stopBusRefresh()
}
}, 1 * 1000)
},
stopBusRefresh() {
this.busRefreshTimer && clearInterval(this.busRefreshTimer)
this.busRefreshTimer = null
},
async examin() {
//xxx
}
原理是调用强制更新方法this.$forceUpdate()会更新视图和数据,触发updated生命周期
能少用就少用吧,刷新一下对用户体验不友好
.el-table__expanded-cell:hover {
background-color: #f7f7f7 !important;
}
这3都是表示一个东西,修改原生样式
这得从一件诡异的事情说清
公司做一个弹窗嘛
二话不说上vant的官网复制粘贴去
然而复制粘贴后,却啥都没有
?!为啥这样,对比了一下官方的css,发现样式被覆盖了
这背景都被搞了,是被自己写的全局css覆盖了。。。
所以我们现在在vue文件里面改局部css样式就好(不要搞全局css)
这是官网的:
尽管有点不一样,但不要怕,把背景搞成白色就算赢
不知道为啥上面是有#app .van-action-sheet
,而官方是.van-action-sheet
,可能是全局变量设置了什么东西吧。。。
然后就改
.van-action-sheet{
background: white;
}
真是非常神奇呢,然后看了网上说是改原生样式,会在后面加一串东西
/deep/ .van-action-sheet{
background: white;
}
嗯?不会。。
简单且朴素
#app{
.van-action-sheet{
background: white;
}
}
我也不知道为什么后面有那串东西还能成功
.env 全局默认配置文件,不论什么环境都会加载合并
.env.development 开发环境下的配置文件
.env.production 生产环境下的配置文件
PS:属性名必须以VUE_APP_开头,比如VUE_APP_XXX
如
# .env.development
VUE_APP_MOCK_LOCAL = true
用的话:
const isMockLocal = process.env.VUE_APP_MOCK_LOCAL;
忘记哪个依赖了,install后会报错说没有安装python,然后安装个python就行(有些Linux自带py环境)。然后还有一个是淘宝镜像的问题,在后面加--registry=https://registry.npm.taobao.org
这种,可以在一个请求方法里面写,也可以搞一个通用post里面写,我这在一个请求方法里面写的
export function queryARES(param, showLoading = true) { let loading = null //等待状态 if (showLoading) { loading = Toast.loading({ duration: 40 * 1000, // 持续展示 toast forbidClick: true, message: '正在处理,请稍等' }) } return new Promise((resolve) => { return post({ param: param, url: '/openapi/v1/mohrss/call_api', }).then((res) => { //清除等待状态 loading?.clear() resolve(res); }).catch((error) => { //清除等待状态 loading?.clear() console.log(error); resolve(false); }); }); }
我以前一直以为async是为了解决异步问题,现在发现是配合promise使用的
如果一个请求返回promise,没有async为
created() {
const res = xxx(param, true)
console.log(res)
},
如果有async
async created() {
const res = await xxx(param, true)
npm install @packy-tang/vue-tinymce
把https://gitee.com/panjiachen/vue-element-admin/tree/master/src/components中的Tinymce复制下来到一样的地方(对,npm安装后还不能直接用。。而且这个是已经编写好的了,很方便)
然后用就简单了
<template> <div class="components-container"> <aside> 这是富文本编辑器,用v-model绑定html形式的值 </aside> <div> <tinymce v-model="content" :height="300" /> </div> <aside> 这是富文本编辑器的结果,用v-html绑定html形式的值。保存到数据库直接用html形式保存即可 </aside> <div class="editor-content" v-html="content" /> </div> </template> <script> import Tinymce from '@/components/Tinymce' export default { name: 'TinymceDemo', components: { Tinymce }, data() { return { content: `<h1 style="text-align: center;">Welcome to the TinyMCE demo!</h1><p style="text-align: center; font-size: 15px;"><ul> <li>Our <a href="//www.tinymce.com/docs/">documentation</a> is a great resource for learning how to configure TinyMCE.</li><li>Have a specific question? Visit the <a href="https://community.tinymce.com/forum/">Community Forum</a>.</li><li>We also offer enterprise grade support as part of <a href="https://tinymce.com/pricing">TinyMCE premium subscriptions</a>.</li> </ul>` } } } </script> <style scoped> .editor-content{ margin-top: 20px; } </style>
普通的<img src='https://dgapa.dongguantong.com.cn/dgtmgm/upload/image/20210801115039.jpg' alt="" style="height: 50px;width: 50px">
就加载不出来呢
然后百度说加这个就好了 <meta name="referrer" content="no-referrer" />
第一个方法就是vuex了,在前面已经介绍
新建一个Vue对象作为中间值
// 创建busEvent.js 作用:非父子组件间传值
import Vue from 'vue'
const busEvent = new Vue()
busEvent.dicts = []
export default busEvent
然后用的话
import busEvent from '@/utils/busEvent'
//xxxx函数里面,读取缓存
if (busEvent.dicts[dict_type]) {
this.dicts[dict_type] = busEvent.dicts[dict_type]
return busEvent.dicts[dict_type]
}
//写缓存
busEvent.dicts[dict_type] = res.data
return busEvent.dicts[dict_type]
之前不是会有$router
表示路由嘛,我们也想要$xx
自己的也可以的
//main.js
import Vue from 'vue'
import * as echarts from 'echarts';
Vue.prototype.$echarts = echarts
<template slot="content">
<!-- 要加个ref就对了-->
<userinfo-Mgt-Table ref="userinfoMgtTable" />
</template>
<script>
import userinfoMgtTable from "@/components/Table/personas/userinfoMgtTable";
export default {
components: {
userinfoMgtTable,
},
}
</script>
然后子组件userinfoMgtTable里面有个方法searchByParam
//userinfoMgtTable
searchByParam(param) {
this.pageNum = 1;
this.searchParam = Object.assign({}, param);
this.reqBillingRecordList();
},
父组件要用的话
this.$refs.子组件名.方法
this.$refs.userinfoMgtTable.searchByParam(param);
这可是个好东西,让b的属性加到a里面,
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const returnedTarget = Object.assign(target, source);
Object { a: 1, b: 4, c: 5 }
类似于for…i…
下面两段代码的结果都一样
// 创建对象
var person = {
name: 'hjm',
age: 18,
school:"SKD University",
home: 'China'
}
// 用forEach()进行遍历
var keys = Object.keys(person).forEach(function (e) {
console.log("person ", e, ": ", person[e]);
});
// 创建一个对象 var person = { name: 'hjm', age: 18, school:"SKD University", home: 'China' } // 获得对象属性名组成的数组 var keys = Object.keys(person); // 用于存储匹配的属性值 var value = []; // 用for进行遍历 for (var i = 0,len = keys.length; i < len; i++) { var key = keys[i]; value[i] = person[key]; console.log("person ", key, ": ", value[i]); }
searchForm = {
user_id: "asd",
age_tag: "qwe",
sex_tag: "r",
card_type_tag: "w",
active_tag: "q",
parking_tag: "s",
},
//将对象值为空
Object.keys(this.searchForm).forEach(key => {
this.searchForm[key] = ''
console.log(this.searchForm)
})
sex_tag
age_tag
card_type_tag
active_tag
parking_tag
ex_tag
就开发的时候嘛,有些是要用的,但是正式上线就不用了,就npm install xxx --save-dev
普通的就npm install xxx --save
以前的mock我都是参照vue element admin他里面做好的来做的,但是我直接复制过去发现不行,就参考了这个文章是可以的
PS:最好的办法还是vue element admin里面的mock方法,但是我不会抽出来,只能用比较差一点的方法
npm install mockjs --save-dev
1、在src同级目录添加mock-server文件夹内涵3个文件如下
index.js //假接口入口配置文件
similar.js //小模块,不让一整个模块都写在index里面
2、vue.config.js内配置
devServer:{
proxy: config.dev.proxyTable,//参照位置
...
before: require('./mock-server/index'), //添加
}
3、index.js
//导入拆分的模块
const similar = require('./similar')
module.exports = function (app) {
//然而我写得还是不好,还是要一个个地导入
similar.querySimilarUserPersonaListByPage(app);
similar.querySimilarUserPersonaNum(app)
}
similar.js
const Mock = require('mockjs'); const Host = process.env.VUE_APP_HOST + '/persona/label/v1' //生成mock地随机数 const json = Mock.mock({ result_code: '@integer(1, 3)', message: "success", data: { id: '@increment', title: '@title(5, 10)', } }) module.exports = { //里面就写各个的方法 querySimilarUserPersonaListByPage(app) { app.post(Host + '/querySimilarUserPersonaListByPage', function (rep, res) { res.json(Mock.mock(json)); }); }, querySimilarUserPersonaNum(app) { app.post(Host + '/querySimilarUserPersonaNum', function (rep, res) { res.json(Mock.mock(json)); }); } }
Better-Mock基于mockjs,所以可以兼容使用
Better-Mock文档
mock文档
主要是Better-Mock可以直接拦截
//main.js
import * as filters from './filters'
Object.keys(filters).forEach(key => {
Vue.filter(key, filters[key])
})
// src/filter/index.js // 导入的2个就是json import {trans_tp, payment_type} from '@/views/scenesPay/dict' export function formatScenesDict(value) { let flag = false for (let transTpElement of trans_tp) { if (value === transTpElement.code) { flag = true return transTpElement.name } } for (let paymentTypeElement of payment_type) { if (value === paymentTypeElement.code) { flag = true return paymentTypeElement.name } } if (flag == false) return value }
// src/views/scenesPay/dict export const payment_type = [ {code: '0101', name: "中银通支付"}, {code: '0102', name: "微众虚拟卡支付"}, {code: '0103', name: "东莞银行虚拟卡支付"}, {code: '0104', name: "广发银行虚拟卡支付"}, {code: '0105', name: "农商银行虚拟卡支付"}, {code: '0201', name: "联盟银行信用卡支付"}, {code: '0202', name: "非联盟信用卡支付"}, {code: '0203', name: "联盟银行储蓄卡支付"}, {code: '0204', name: "非联盟银行储蓄卡支付"}, {code: '0205', name: "社保卡支付"}, {code: '0206', name: "储蓄卡快捷支付"}, {code: '0207', name: "信用卡快捷支付"}, {code: '0301', name: "微信支付"}, {code: '0302', name: "支付宝支付"}, {code: '0303', name: "云闪付支付"}, ]
环境只有3个,开发、测试、生产,其中,开发和测试是可以直接判断的
process.env.NODE_ENV 为development时,开发环境
为production时,是生产环境
这个大有研究,从原理说起
//package.json
{
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"test-build": "vue-cli-service build --mode testpdct",
"lint": "vue-cli-service lint"
},
}
一般比如看这里嘛,第一个是开发,第二个是生产
第三个是我们自定义的,自定义为测试,后面的–mode testpdct就是让我们用了.env.testpdct这个文件
一般来说,配置什么全局变量的都是这样的
开发和生产是用vue cli创建就有的,testpdct是人工创建的,名字就是package.json里面的--mode xxxx
然后在.env.testpdct里面定义一个VUE_APP_ENV = test
,用的时候process.env.VUE_APP_ENV === 'test'
就能判断是不是测试环境了
直接npm update xxxx
比如这个
<van-empty :image="image" v-if="bus_tickets&&bus_tickets.length == 0"> <template slot="description"> <span>您还没有行程 赶紧下单吧! <br> <div class="clickTips" @click="refresh">点我刷新试试</div></span> </template> </van-empty> <style> .van-empty { padding: 0; /deep/ .van-empty__image { width: 135px; height: 85px; margin-top: 57px; margin-bottom: 15px; } /deep/.van-empty__description { margin-top: 0; .clickTips { text-align: center; color: rgb(94, 201, 255); } } } </style>
就,原本description只传个文字,但是用<template slot="description">
后,里面可以添加样式啥的,,而且那cssvan-empty__description
还能直接用??
<van-empty :image="image">
</van-empty>
<script>
data () {
return {
image: require('@/assets/images/empty.png')
}
},
</script>
$on和$emit
进行非父子组件通讯非父子组件通讯
//busEvent.js
// 创建busEvent.js 作用:非父子组件间传值
import Vue from 'vue'
const busEvent = new Vue()
export default busEvent
//一般来说这么用的
//用之前记得import busEvent
var bus = new Vue()
// 在组件 B 绑定自定义事件
bus.$on('id-selected', function (id) {
// ...
})
// 触发组件 A 中的事件
bus.$emit('id-selected', 1)
每个按钮都有@click
事件,然后按钮里面有个X也有@click
事件,但是按了X,连外面button得事件也触发了,为了解决,这就是阻止冒泡事件(大学干小南教过)
vue解决就是在X得事件加stop@click.stop="xxx"
https://cn.vuejs.org/v2/api/#v-on
一般来说,登录后,保存到localStorage和vuex,这样,不刷新不退出的情况下就能一只知道登录状态和用户了
但是一般都会刷新的,那么就用到全局路由前置守卫
router.beforeEach((to, from, next) => {
}
在每次要跳转之前,判断localStorage的用户信息是否存在,如果不存在,就没登录。如果存在,就把localStorage中的用户信息同步到vuex进行相应化数据,其他用就getter用就好了
比如
router.beforeEach((to, from, next) => { const uniUserInfo = uni.getStorageSync('userInfo') const uniToken = uni.getStorageSync('token') if (uniToken){ if (uniUserInfo){ store.dispatch('user/setToken', uniToken) store.dispatch('user/setUserInfo', uniUserInfo) }else{ setTokenAndUserInfo(uniToken) } } // console.log(uniToken) // console.log(uniUserInfo) next(); });
比如这个
<el-form-item label="上一级字典" prop="sup_dict">
<el-select v-model="sup_dict" placeholder="请选择" >
<el-option v-for="item in dictInfo" :label="item.dict_name" :value="item" :key="item.id"></el-option>
</el-select>
</el-form-item>
//dictInfo为 dictInfo:[ { "id": "d3f34d529e26494eb974772ccc8d4612", "dict_no": "1", "dict_name": "阵地打卡活动", "dict_type": "activity_type", "dict_desc": null, "sup_dict_no": null, "sup_dict_type": null, "field1": "10", "field2": null, "field3": null, "status": "1", "create_time": "2021-11-11 10:11:08", "update_time": null, "is_delete": "0" }, { "id": "e152ef7a0f374a8389b2d5219f6921fd", "dict_no": "2", "dict_name": "主题积分活动", "dict_type": "activity_type", "dict_desc": null, "sup_dict_no": null, "sup_dict_type": null, "field1": "100", "field2": null, "field3": null, "status": "1", "create_time": "2021-11-11 10:11:49", "update_time": null, "is_delete": "0" }, { "id": "181c11e860fa44e79b1c12dedf6c31ae", "dict_no": "1", "dict_name": "实体卡刷卡", "dict_type": "sign_type", "dict_desc": null, "sup_dict_no": null, "sup_dict_type": null, "field1": "呵呵", "field2": null, "field3": null, "status": "1", "create_time": "2021-11-10 15:28:46", "update_time": "2021-11-11 09:03:43", "is_delete": "0" }, { "id": "78fef122fdbb416a99f3d951b3254cfa", "dict_no": "2", "dict_name": "手动补卡", "dict_type": "sign_type", "dict_desc": null, "sup_dict_no": null, "sup_dict_type": null, "field1": "无", "field2": null, "field3": null, "status": "1", "create_time": "2021-11-11 10:09:15", "update_time": null, "is_delete": "0" }, { "id": "909176513a6240cd889c13008e803ed7", "dict_no": "3", "dict_name": "人脸打卡", "dict_type": "sign_type", "dict_desc": null, "sup_dict_no": null, "sup_dict_type": null, "field1": "无", "field2": null, "field3": null, "status": "1", "create_time": "2021-11-11 10:09:45", "update_time": null, "is_delete": "0" }, { "id": "f3e65a8b463d4f69b51700eb0c0f77b9", "dict_no": "1", "dict_name": "正常", "dict_type": "status", "dict_desc": null, "sup_dict_no": null, "sup_dict_type": null, "field1": "无", "field2": null, "field3": null, "status": "1", "create_time": "2021-11-11 10:13:00", "update_time": null, "is_delete": "0" }, { "id": "85471e06f1024bfe9dbca5c4622f6b55", "dict_no": "2", "dict_name": "失效(置黑)", "dict_type": "status", "dict_desc": null, "sup_dict_no": null, "sup_dict_type": null, "field1": "无", "field2": null, "field3": null, "status": "1", "create_time": "2021-11-11 10:13:24", "update_time": null, "is_delete": "0" } ]
就很简单的,选项为for循环,显示为dict_name,点中后值为整个item对象,通过v-model绑定到sup_dict中,但是,事实是这样
为什么都乱了。。。
查文档
就是说要在el-select加多个value-key=“id”,其中id为唯一
<el-form-item label="上一级字典" prop="sup_dict">
<el-select v-model="sup_dict" placeholder="请选择" value-key="id">
<el-option v-for="item in dictInfo" :label="item.dict_name" :value="item" :key="item.id"></el-option>
</el-select>
</el-form-item>
就好了
const date = '2018-12-24';
const time = '23:59:59';
const dateTime = moment(`${date} ${time}`, 'YYYY-MM-DD HH:mm:ss').format();
有些东西就尼玛离谱,逻辑上一点毛病都没有,但他妈的vue或者是js就是存在着这些异步同步的问题。
比如
console.log(this.form)
this.form = obj2DateRange(this.form)
console.log(this.form)
明明经过函数的变化都已经发生改变了,但2次输出都是变化后的效果,但老子要的是一个变化前和一个变化后的效果啊
再比如提交表单的
const reqParam = this.form
//然后将reqParam提交上去,进行更新
但这个,修改里面变的情况下,外面你的table也会变,但这还没提交呢
遇事不决,遇到这种人眼逻辑看起来没毛病的,我们可以统一用一种诡异的方法解决
this.form.id = row.id
this.form.act_no = row.act_no
this.form.act_name = row.act_name
this.form.act_type_no = row.act_type_no
this.form.site_no = row.site_no
this.form.act_desc = row.act_desc
this.form.status = row.status
this.form.act_duration = row.act_duration
this.form.score_once = row.score_once
this.form.dateRange = row.dateRange
this.form.start_date = row.start_date
this.form.start_time = row.start_time
this.form.end_date = row.end_date
this.form.end_time = row.end_time
//this.form = row //感觉和这一样,但效果确实不一样
或者
const { id, act_no, act_name, act_type_no, site_no, act_desc, status, act_duration, score_once, dateRange, //在做了在做了 start_date, start_time, end_date, end_time } = this.form const reqParam = { id, act_no, act_name, act_type_no, site_no, act_desc, status, act_duration, score_once, dateRange, //在做了在做了 start_date, start_time, end_date, end_time } //const treqParam = this.form //看起来和这一样,但实际上就尼玛不一样
看起来就是搁这搁这得感觉,但实际上他就是能解决一些异步得奇怪行为,就尼玛 诡异离谱
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。