我有如下片段。在小的手机屏幕中,无法一次显示所有7个标签。因此,它会显示为两行标签这不整洁。
我想要标签,当将页面滚动到右侧或左侧的末尾时,它可以处理溢出,以便用户会注意到那里有标签。
例子是 scroollable tabs对于 java 中的 android。但是,我在 ionic 1 中需要它。假设移动设备的屏幕能够显示 7 个选项卡中的 3 个选项卡。当我向右滚动选项卡(第 3 个选项卡)时,第 4 个选项卡将显示在右侧,第 3 个选项卡现在将在中间选项卡上,而第二个选项卡在右侧。
请在片段中显示代码,以便我们可以直观地知道它正在运行。
angular.module('ionicApp', ['ionic'])
.controller('MyCtrl', function($scope,$ionicSlideBoxDelegate) {
$scope.slideIndex = 0;
// Called each time the slide changes
$scope.slideChanged = function(index) {
$scope.slideIndex = index;
};
$scope.activeSlide = function (index) {
$ionicSlideBoxDelegate.slide(index);
};
});body {
cursor: url('https://ionicframework.com/img/finger.png'), auto;
}
.slide-tab{
display: table;
overflow: hidden;
margin: 0;
width: 100%;
background-color: #eff0f2;
border-bottom: 2px solid #00897B;
}
.slide-tab li{
float: left;
line-height: 38px;
overflow: hidden;
padding: 0;
}
.slide-tab a{
background-color: #eff0f2;
border-bottom: 1px solid #fff;
color: #888;
font-weight: 500;
display: block;
letter-spacing: 0;
outline: none;
padding: 0 20px;
text-decoration: none;
-webkit-transition: all 0.2s ease-in-out;
-moz-transition: all 0.2s ease-in-out;
transition: all 0.2s ease-in-out;
border-bottom: 2px solid #00897B;
}
.current a{
color: #fff;
background: #00897B;
}<html ng-app="ionicApp">
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<title>Ionic Slide Tab</title>
<link href="//code.ionicframework.com/nightly/css/ionic.css" rel="stylesheet">
<script src="//code.ionicframework.com/nightly/js/ionic.bundle.js"></script>
</head>
<body ng-controller="MyCtrl">
<ion-header-bar class="bar-positive">
<h1 class="title">Ionic Slide Tab</h1>
</ion-header-bar>
<ion-content>
<div class="row">
<ul class="slide-tab">
<li ng-class="slideIndex == 0 ? 'current':''"><a href="#" ng-click="activeSlide(0)">Tab01</a></li>
<li ng-class="slideIndex == 1 ? 'current':''"><a href="#" ng-click="activeSlide(1)">Tab02</a></li>
<li ng-class="slideIndex == 2 ? 'current':''"><a href="#" ng-click="activeSlide(2)">Tab03</a></li>
<li ng-class="slideIndex == 3 ? 'current':''"><a href="#" ng-click="activeSlide(3)">Tab04</a>
</li>
<li ng-class="slideIndex == 4 ? 'current':''"><a href="#" ng-click="activeSlide(4)">Tab05</a></li>
<li ng-class="slideIndex == 5 ? 'current':''"><a href="#" ng-click="activeSlide(5)">Tab06</a></li>
<li ng-class="slideIndex == 6 ? 'current':''"><a href="#" ng-click="activeSlide(6)">Tab07</a></li>
</ul>
</div>
<ion-slide-box on-slide-changed="slideChanged(index)" active-slide="slideIndex" class="padding">
<ion-slide>
<h3>Tab 1</h3>
<p>Page 1</p>
</ion-slide>
<ion-slide>
<h3>Tab 2</h3>
<p>Page 2</p>
</ion-slide>
<ion-slide>
<h3>Tab 3</h3>
<p>Page 3</p>
</ion-slide>
<ion-slide>
<h3>Tab 4</h3>
<p>page 4</p>
</ion-slide>
<ion-slide>
<h3>Tab 5</h3>
<p>page 5</p>
</ion-slide>
<ion-slide>
<h3>Tab 6</h3>
<p>page 6</p>
</ion-slide>
<ion-slide>
<h3>Tab 7</h3>
<p>page 7</p>
</ion-slide>
</ion-slide-box>
</ion-content>
</body>
</html>
最佳答案
尝试这个例子,我认为它会对你有所帮助..
slidingTabs.html
<html>
<head>
<meta charset="utf-8" />
<meta name="format-detection" content="telephone=no" />
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<title>Tabbed Slide box</title>
<!-- ionic css -->
<link href="http://code.ionicframework.com/1.0.0-rc.4/css/ionic.css" rel="stylesheet">
<!-- your app's css -->
<link href="tabSlideBox.css" rel="stylesheet">
<!-- ionic/angularjs scripts -->
<script src="http://code.ionicframework.com/1.0.0-rc.4/js/ionic.bundle.min.js"></script>
<script src="tabSlideBox.js"></script>
<!-- your app's script -->
<script>
var app = angular.module('slidebox', ['ionic', 'tabSlideBox'])
.run(['$q', '$http', '$rootScope', '$location', '$window', '$timeout',
function($q, $http, $rootScope, $location, $window, $timeout){
$rootScope.$on("$locationChangeStart", function(event, next, current){
$rootScope.error = null;
console.log("Route change!!!", $location.path());
var path = $location.path();
console.log("App Loaded!!!");
});
}
]);
app.config(function($stateProvider, $urlRouterProvider) {
$stateProvider.state('index', {
url : '/',
templateUrl : 'index.html',
controller : 'IndexCtrl'
});
$urlRouterProvider.otherwise("/");
});
app.controller("IndexCtrl", ['$rootScope', "$scope", "$stateParams", "$q", "$location", "$window", '$timeout',
function($rootScope, $scope, $stateParams, $q, $location, $window, $timeout){
$scope.onSlideMove = function(data){
alert("You have selected " + data.index + " tab");
};
}
]);
</script>
<style>
.slider-slide h3{
color:#fff;
margin-top:10px;
}
.scroll{
height:100%;
}
.tabbed-slidebox .tsb-icons:after{
display:none;
}
</style>
</head>
<body ng-app="slidebox" animation="slide-left-right-ios7">
<ion-nav-bar class="nav-title-slide-ios7 bar-positive">
<ion-nav-back-button class="button-icon ion-arrow-left-c">
</ion-nav-back-button>
</ion-nav-bar>
<ion-nav-view ng-controller="IndexCtrl"></ion-nav-view>
<script id="index.html" type="text/ng-template">
<ion-view title="Scrollable Tabbed Slide box">
<ion-content scroll="false">
<tab-slide-box>
<div class="tsb-icons">
<div class="tsb-ic-wrp">
<ion-scroll direction="x" class="tsb-hscroll">
<a href="javascript:;" class="ion-home1">Home</a>
<a href="javascript:;" class="ion-ios-game-controller-b1">Games</a>
<a href="javascript:;" class="ion-email1">Email</a>
<a href="javascript:;" class="ion-model-s1">Car</a>
<a href="javascript:;" class="ion-person1">Profile</a>
<a href="javascript:;" class="ion-heart1">Favourites</a>
<a href="javascript:;" class="ion-chatbubbles1">Chats</a>
<a href="javascript:;" class="ion-gear-b1">Settings</a>
<a href="javascript:;" class="ion-camera1">Photos</a>
<a href="javascript:;" class="ion-ios-paw1">Pets</a>
</ion-scroll>
</div>
</div>
<ion-slide-box show-pager="false" on-slide-changed="slideHasChanged($index)">
<ion-slide>
<h3>Home content</h3>
</ion-slide>
<ion-slide>
<h3>Games content</h3>
</ion-slide>
<ion-slide>
<h3>Mail content</h3>
</ion-slide>
<ion-slide>
<h3>Car content</h3>
</ion-slide>
<ion-slide>
<h3>Profile content</h3>
</ion-slide>
<ion-slide>
<h3>Favourites content</h3>
</ion-slide>
<ion-slide>
<h3>Chats content</h3>
</ion-slide>
<ion-slide>
<h3>Settings content</h3>
</ion-slide>
<ion-slide>
<h3>Photos content</h3>
</ion-slide>
<ion-slide>
<h3>Pets content</h3>
</ion-slide>
</ion-slide-box>
</tab-slide-box>
</ion-content>
</ion-view>
</script>
</body>
</html>
tabSlideBox.css
.tabbed-slidebox .slider {
height: 100%;
}
.tabbed-slidebox.btm .slider {
margin-bottom: -50px;
}
.tabbed-slidebox .slider-slides {
width: 100%;
}
.tabbed-slidebox .slider-slide {
padding-top: 0px;
color: #000;
background-color: #fff;
text-align: center;
font-weight: 300;
background-color: #0398dc;
}
.tabbed-slidebox .tsb-icons {
text-align: center;
margin: 10px 0;
position: relative;
background-color:#fff;
}
.tabbed-slidebox .tsb-ic-wrp {
display: flex;
position: relative;
-webkit-transition: -webkit-transform 0.3s; /* For Safari 3.1 to 6.0 */
-webkit-transform:translate3d(0,0,0);
}
.tabbed-slidebox .tsb-icons a {
display: inline-block;
width: 54px;
font-size: 2.5em;
color: rgba(0, 0, 0, 0.3);
-webkit-transform:translate3d(0,8px,0);
}
.tabbed-slidebox .tsb-icons a.active {
color: rgba(0, 0, 0, 1);
font-size: 3.5em;
-webkit-transform:translate3d(0,0,0);
}
.tabbed-slidebox .tabbed-slidebox {
position: relative;
height: 100%;
overflow: hidden;
}
.tabbed-slidebox .tsb-icons:after {
width: 0;
height: 0;
border-style: solid;
border-width: 0 1.4em 1.4em 1.4em;
border-color: transparent transparent #0398dc transparent;
position: absolute;
content: "";
display: block;
bottom: -12px;
left: 50%;
margin-left: -14px;
}
.tsb-hscroll.scroll-view{
white-space: nowrap;
margin:0 auto;
}
.tsb-hscroll.scroll-view .scroll-bar{
visibility:hidden;
}
.tsb-hscroll.scroll-view .scroll.onscroll{
-webkit-transition: -webkit-transform 0.3s; /* For Safari 3.1 to 6.0 */
}
.tabbed-slidebox .tsb-icons .scroll a{
width:auto;
font-size: 1.5em;
line-height: 1.5em;
text-decoration: none;
margin: 0 15px;
border-bottom: 3px solid transparent;
}
.tabbed-slidebox .tsb-icons .scroll a.active {
font-size: 1.8em;
border-bottom: 3px solid #ccc;
}
tabSlideBox.js
'use strict';
function SimplePubSub() {
var events = {};
return {
on: function(names, handler) {
names.split(' ').forEach(function(name) {
if (!events[name]) {
events[name] = [];
}
events[name].push(handler);
});
return this;
},
trigger: function(name, args) {
angular.forEach(events[name], function(handler) {
handler.call(null, args);
});
return this;
}
};
};
angular.module('tabSlideBox', [])
.directive('onFinishRender', function ($timeout) {
return {
restrict: 'A',
link: function (scope, element, attr) {
if (scope.$last === true) {
$timeout(function () {
scope.$emit('ngRepeatFinished');
});
}
}
}
})
.directive('tabSlideBox', [ '$timeout', '$window', '$ionicSlideBoxDelegate', '$ionicScrollDelegate',
function($timeout, $window, $ionicSlideBoxDelegate, $ionicScrollDelegate) {
'use strict';
return {
restrict : 'A, E, C',
link : function(scope, element, attrs, ngModel) {
var ta = element[0], $ta = element;
$ta.addClass("tabbed-slidebox");
if(attrs.tabsPosition === "bottom"){
$ta.addClass("btm");
}
//Handle multiple slide/scroll boxes
var handle = ta.querySelector('.slider').getAttribute('delegate-handle');
var ionicSlideBoxDelegate = $ionicSlideBoxDelegate;
if(handle){
ionicSlideBoxDelegate = ionicSlideBoxDelegate.$getByHandle(handle);
}
var ionicScrollDelegate = $ionicScrollDelegate;
if(handle){
ionicScrollDelegate = ionicScrollDelegate.$getByHandle(handle);
}
function renderScrollableTabs(){
var iconsDiv = angular.element(ta.querySelector(".tsb-icons")), icons = iconsDiv.find("a"), wrap = iconsDiv[0].querySelector(".tsb-ic-wrp"), totalTabs = icons.length;
var scrollDiv = wrap.querySelector(".scroll");
angular.forEach(icons, function(value, key){
var a = angular.element(value);
a.on('click', function(){
ionicSlideBoxDelegate.slide(key);
});
if(a.attr('icon-off')) {
a.attr("class", a.attr('icon-off'));
}
});
var initialIndex = attrs.tab;
//Initializing the middle tab
if(typeof attrs.tab === 'undefined' || (totalTabs <= initialIndex) || initialIndex < 0){
initialIndex = Math.floor(icons.length/2);
}
//If initial element is 0, set position of the tab to 0th tab
if(initialIndex == 0){
setPosition(0);
}
$timeout(function() {
ionicSlideBoxDelegate.slide(initialIndex);
}, 0);
}
function setPosition(index){
var iconsDiv = angular.element(ta.querySelector(".tsb-icons")), icons = iconsDiv.find("a"), wrap = iconsDiv[0].querySelector(".tsb-ic-wrp"), totalTabs = icons.length;
var scrollDiv = wrap.querySelector(".scroll");
var middle = iconsDiv[0].offsetWidth/2;
var curEl = angular.element(icons[index]);
var prvEl = angular.element(iconsDiv[0].querySelector(".active"));
if(curEl && curEl.length){
var curElWidth = curEl[0].offsetWidth, curElLeft = curEl[0].offsetLeft;
if(prvEl.attr('icon-off')) {
prvEl.attr("class", prvEl.attr('icon-off'));
}else{
prvEl.removeClass("active");
}
if(curEl.attr('icon-on')) {
curEl.attr("class", curEl.attr('icon-on'));
}
curEl.addClass("active");
var leftStr = (middle - (curElLeft) - curElWidth/2 + 5);
//If tabs are not scrollable
if(!scrollDiv){
var leftStr = (middle - (curElLeft) - curElWidth/2 + 5) + "px";
wrap.style.webkitTransform = "translate3d("+leftStr+",0,0)" ;
}else{
//If scrollable tabs
var wrapWidth = wrap.offsetWidth;
var currentX = Math.abs(getX(scrollDiv.style.webkitTransform));
var leftOffset = 100;
var elementOffset = 40;
//If tabs are reaching right end or left end
if(((currentX + wrapWidth) < (curElLeft + curElWidth + elementOffset)) || (currentX > (curElLeft - leftOffset))){
if(leftStr > 0){
leftStr = 0;
}
//Use this scrollTo, so when scrolling tab manually will not flicker
ionicScrollDelegate.scrollTo(Math.abs(leftStr), 0, true);
}
}
}
};
function getX(matrix) {
matrix = matrix.replace("translate3d(","");
matrix = matrix.replace("translate(","");
return (parseInt(matrix));
}
var events = scope.events;
events.on('slideChange', function(data){
setPosition(data.index);
});
events.on('ngRepeatFinished', function(ngRepeatFinishedEvent) {
renderScrollableTabs();
});
renderScrollableTabs();
},
controller : function($scope, $attrs, $element) {
$scope.events = new SimplePubSub();
$scope.slideHasChanged = function(index){
$scope.events.trigger("slideChange", {"index" : index});
$timeout(function(){if($scope.onSlideMove) $scope.onSlideMove({"index" : eval(index)});},100);
};
$scope.$on('ngRepeatFinished', function(ngRepeatFinishedEvent) {
$scope.events.trigger("ngRepeatFinished", {"event" : ngRepeatFinishedEvent});
});
}
};
}
]);
同时检查这个例子link获得更多想法
工作 plunker
关于javascript - 可以正确处理溢出的可滚动选项卡,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44580444/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html
这是在Ruby中设置默认值的常用方法:classQuietByDefaultdefinitialize(opts={})@verbose=opts[:verbose]endend这是一个容易落入的陷阱:classVerboseNoMatterWhatdefinitialize(opts={})@verbose=opts[:verbose]||trueendend正确的做法是:classVerboseByDefaultdefinitialize(opts={})@verbose=opts.include?(:verbose)?opts[:verbose]:trueendend编写Verb
我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击
我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的
我正在阅读SandiMetz的POODR,并且遇到了一个我不太了解的编码原则。这是代码:classBicycleattr_reader:size,:chain,:tire_sizedefinitialize(args={})@size=args[:size]||1@chain=args[:chain]||2@tire_size=args[:tire_size]||3post_initialize(args)endendclassMountainBike此代码将为其各自的属性输出1,2,3,4,5。我不明白的是查找方法。当一辆山地自行车被实例化时,因为它没有自己的initialize方法
我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI
question的一些答案关于redirect_to让我想到了其他一些问题。基本上,我正在使用Rails2.1编写博客应用程序。我一直在尝试自己完成大部分工作(因为我对Rails有所了解),但在需要时会引用Internet上的教程和引用资料。我设法让一个简单的博客正常运行,然后我尝试添加评论。靠我自己,我设法让它进入了可以从script/console添加评论的阶段,但我无法让表单正常工作。我遵循的其中一个教程建议在帖子Controller中创建一个“评论”操作,以添加评论。我的问题是:这是“标准”方式吗?我的另一个问题的答案之一似乎暗示应该有一个CommentsController参